diff --git a/build/glsl2js.js b/build/glsl2js.js index 877de65..8d5065f 100644 --- a/build/glsl2js.js +++ b/build/glsl2js.js @@ -3,16 +3,16 @@ var fs = require('fs'); glob(__dirname + '/../{src,editor}/**/*.glsl', function (err, files) { files.forEach(function (filePath) { - var esslCode = fs.readFileSync(filePath, 'utf-8'); + var glslCode = fs.readFileSync(filePath, 'utf-8'); // TODO Remove comment - esslCode = esslCode.replace(/\/\/.*\n/g, ''); - esslCode = esslCode.replace(/ +/g, ' '); + glslCode = glslCode.replace(/\/\/.*\n/g, ''); + glslCode = glslCode.replace(/ +/g, ' '); // var dir = path.dirname(filePath); // var baseName = path.basename(filePath, '.essl'); fs.writeFileSync( filePath + '.js', - 'export default ' + JSON.stringify(esslCode) + ';\n', + 'export default ' + JSON.stringify(glslCode) + ';\n', 'utf-8' ); }); diff --git a/dist/QMV.min.js b/dist/QMV.min.js deleted file mode 100644 index 9d69c7b..0000000 --- a/dist/QMV.min.js +++ /dev/null @@ -1,14 +0,0 @@ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(e.QMV={})}(this,function(e){"use strict";function t(e,t,i){"object"==typeof t&&(i=t,t=null);var a,o=this;if(!(e instanceof Function)){a=[];for(var s in e)e.hasOwnProperty(s)&&a.push(s)}var u=function(t){if(o.apply(this,arguments),e instanceof Function?r(this,e.call(this,t)):n(this,e,a),this.constructor===u)for(var i=u.__initializers__,s=0;sr?r:e}function s(){return{locations:{},attriblocations:{}}}function u(e,t,r){if(!e.getShaderParameter(t,e.COMPILE_STATUS))return[e.getShaderInfoLog(t),l(r)].join("\n")}function l(e){for(var t=e.split("\n"),r=0,n=t.length;r=400?e.onerror&&e.onerror():e.onload&&e.onload(t.response)},e.onerror&&(t.onerror=e.onerror),t.send(null)}function d(e,t){if(t.castShadow&&!e.castShadow)return!0}function _(e,t,r){var n=t;n+=256*r.roughnessChannel,n+=1024*r.metalnessChannel;for(var i=0;i1e-6?(o=Math.acos(s),u=Math.sin(o),l=Math.sin((1-n)*o)/u,c=Math.sin(n*o)/u):(l=1-n,c=n),e[0]=l*h+c*p,e[1]=l*f+c*m,e[2]=l*d+c*v,e[3]=l*_+c*g,e}function E(e){return{byte:nt.Int8Array,ubyte:nt.Uint8Array,short:nt.Int16Array,ushort:nt.Uint16Array}[e]||nt.Float32Array}function b(e){return"attr_"+e}function S(e,t,r,n){switch(this.name=e,this.type=t,this.size=r,this.semantic=n||"",this.value=null,r){case 1:this.get=function(e){return this.value[e]},this.set=function(e,t){this.value[e]=t},this.copy=function(e,t){this.value[e]=this.value[e]};break;case 2:this.get=function(e,t){var r=this.value;return t[0]=r[2*e],t[1]=r[2*e+1],t},this.set=function(e,t){var r=this.value;r[2*e]=t[0],r[2*e+1]=t[1]},this.copy=function(e,t){var r=this.value;t*=2,e*=2,r[e]=r[t],r[e+1]=r[t+1]};break;case 3:this.get=function(e,t){var r=3*e,n=this.value;return t[0]=n[r],t[1]=n[r+1],t[2]=n[r+2],t},this.set=function(e,t){var r=3*e,n=this.value;n[r]=t[0],n[r+1]=t[1],n[r+2]=t[2]},this.copy=function(e,t){var r=this.value;t*=3,e*=3,r[e]=r[t],r[e+1]=r[t+1],r[e+2]=r[t+2]};break;case 4:this.get=function(e,t){var r=this.value,n=4*e;return t[0]=r[n],t[1]=r[n+1],t[2]=r[n+2],t[3]=r[n+3],t},this.set=function(e,t){var r=this.value,n=4*e;r[n]=t[0],r[n+1]=t[1],r[n+2]=t[2],r[n+3]=t[3]},this.copy=function(e,t){var r=this.value;t*=4,e*=4,r[e]=r[t],r[e+1]=r[t+1],r[e+2]=r[t+2],r[e+3]=r[t+3]}}}function A(e,t,r,n,i){this.name=e,this.type=t,this.buffer=r,this.size=n,this.semantic=i,this.symbol="",this.needsRemove=!1}function N(e){this.buffer=e,this.count=0}function w(e,t,r,n){var i=e.accessors[r],a=t.bufferViews[i.bufferView],o=i.byteOffset||0,s=Ln[i.componentType]||nt.Float32Array,u=Dn[i.type];null==u&&n&&(u=1);var l=new s(a,o,u*i.count),c=i.extensions&&i.extensions.WEB3D_quantized_attributes;if(c){for(var h,f,d=new nt.Float32Array(u*i.count),_=c.decodeMatrix,h=new Array(u),f=new Array(u),p=0;pi)e.length=i;else for(var a=n;a=0&&!(_[g]<=t);g--);g=Math.min(g,l-2)}else{for(g=w;gt);g++);g=Math.min(g-1,l-2)}w=g,M=t;var r=_[g+1]-_[g];0!==r&&(E=(t-_[g])/r,u?(S=p[g],b=p[0===g?g:g-1],A=p[g>l-2?l-1:g+1],N=p[g>l-3?l-1:g+2],a?s(e,i,a(o(e,i),b,S,A,N,E)):h?I(b,S,A,N,E,E*E,E*E*E,o(e,i),f):s(e,i,O(b,S,A,N,E,E*E,E*E*E))):a?s(e,i,a(o(e,i),p[g],p[g+1],E)):h?L(p[g],p[g+1],E,o(e,i),f):s(e,i,C(p[g],p[g+1],E)))},P=new nn({target:e._target,life:d,loop:e._loop,delay:e._delay,onframe:R,onfinish:r});return t&&"spline"!==t&&P.setEasing(t),P}}}function U(e,t,r,n,i){this._tracks={},this._target=e,this._loop=t||!1,this._getter=r||M,this._setter=n||R,this._interpolater=i||null,this._delay=0,this._doneList=[],this._onframeList=[],this._clipList=[]}function H(e,t){var r=new Hn;return nr.get({url:e,responseType:t,onload:function(e){r.resolve(e)},onerror:function(e){r.reject(e)}}),r}function z(e){return"CANVAS"===e.nodeName||"VIDEO"===e.nodeName||e.complete}function G(e){return e.charCodeAt(0)+(e.charCodeAt(1)<<8)+(e.charCodeAt(2)<<16)+(e.charCodeAt(3)<<24)}function W(e,t,r,n){if(e[3]>0){var i=Math.pow(2,e[3]-128-8+n);t[r+0]=e[0]*i,t[r+1]=e[1]*i,t[r+2]=e[2]*i}else t[r+0]=0,t[r+1]=0,t[r+2]=0;return t[r+3]=1,t}function q(e,t,r){for(var n="",i=t;i0;)if(e[a][0]=t[r++],e[a][1]=t[r++],e[a][2]=t[r++],e[a][3]=t[r++],1===e[a][0]&&1===e[a][1]&&1===e[a][2]){for(var s=e[a][3]<>>0;s>0;s--)V(e[a-1],e[a]),a++,o--;i+=8}else a++,o--,i=0;return r}function X(e,t,r,n){if(nci)return j(e,t,r,n);var i=t[r++];if(2!=i)return j(e,t,r-1,n);if(e[0][1]=t[r++],e[0][2]=t[r++],i=t[r++],(e[0][2]<<8>>>0|i)>>>0!==n)return null;for(var i=0;i<4;i++)for(var a=0;a128){o=(127&o)>>>0;for(var s=t[r++];o--;)e[a++][i]=s}else for(;o--;)e[a++][i]=t[r++]}return r}function K(e){Ze.defaultsWithPropList(e,Ti,Ei),Y(e);for(var t="",r=0;r0;)r+=n*(i%t),i=Math.floor(i/t),n/=t;return r}function te(e){for(var t=new Uint8Array(e*e*4),r=0,n=new ot,i=0;i255?255:e}function _e(e){return e<0?0:e>1?1:e}function pe(e){return de(e.length&&"%"===e.charAt(e.length-1)?parseFloat(e)/100*255:parseInt(e,10))}function me(e){return _e(e.length&&"%"===e.charAt(e.length-1)?parseFloat(e)/100:parseFloat(e))}function ve(e,t,r){return r<0?r+=1:r>1&&(r-=1),6*r<1?e+(t-e)*r*6:2*r<1?t:3*r<2?e+(t-e)*(2/3-r)*6:e}function ge(e,t,r,n,i){return e[0]=t,e[1]=r,e[2]=n,e[3]=i,e}function ye(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e}function xe(e,t){ra&&ye(ra,t),ra=ta.put(e,ra||t.slice())}function Te(e,t){if(e){t=t||[];var r=ta.get(e);if(r)return ye(t,r);e+="";var n=e.replace(/ /g,"").toLowerCase();if(n in ea)return ye(t,ea[n]),xe(e,t),t;if("#"!==n.charAt(0)){var i=n.indexOf("("),a=n.indexOf(")");if(-1!==i&&a+1===n.length){var o=n.substr(0,i),s=n.substr(i+1,a-(i+1)).split(","),u=1;switch(o){case"rgba":if(4!==s.length)return void ge(t,0,0,0,1);u=me(s.pop());case"rgb":return 3!==s.length?void ge(t,0,0,0,1):(ge(t,pe(s[0]),pe(s[1]),pe(s[2]),u),xe(e,t),t);case"hsla":return 4!==s.length?void ge(t,0,0,0,1):(s[3]=me(s[3]),Ee(s,t),xe(e,t),t);case"hsl":return 3!==s.length?void ge(t,0,0,0,1):(Ee(s,t),xe(e,t),t);default:return}}ge(t,0,0,0,1)}else{if(4===n.length){var l=parseInt(n.substr(1),16);return l>=0&&l<=4095?(ge(t,(3840&l)>>4|(3840&l)>>8,240&l|(240&l)>>4,15&l|(15&l)<<4,1),xe(e,t),t):void ge(t,0,0,0,1)}if(7===n.length){var l=parseInt(n.substr(1),16);return l>=0&&l<=16777215?(ge(t,(16711680&l)>>16,(65280&l)>>8,255&l,1),xe(e,t),t):void ge(t,0,0,0,1)}}}}function Ee(e,t){var r=(parseFloat(e[0])%360+360)%360/360,n=me(e[1]),i=me(e[2]),a=i<=.5?i*(n+1):i+n-i*n,o=2*i-a;return t=t||[],ge(t,de(255*ve(o,a,r+1/3)),de(255*ve(o,a,r)),de(255*ve(o,a,r-1/3)),1),4===e.length&&(t[3]=e[3]),t}function be(e,t){if(e&&e.length){var r=e[0]+","+e[1]+","+e[2];return"rgba"!==t&&"hsva"!==t&&"hsla"!==t||(r+=","+e[3]),t+"("+r+")"}}function Se(e){return!e||"none"===e}function Ae(e){return e instanceof HTMLCanvasElement||e instanceof HTMLImageElement||e instanceof Image}function Ne(e){return Math.pow(2,Math.round(Math.log(e)/Math.LN2))}function we(e){if((e.wrapS===Wt.REPEAT||e.wrapT===Wt.REPEAT)&&e.image){var t=Ne(e.width),r=Ne(e.height);if(t!==e.width||r!==e.height){var n=document.createElement("canvas");n.width=t,n.height=r;n.getContext("2d").drawImage(e.image,0,0,t,r),n.srcImage=e.image,e.image=n,e.dirty()}}}function Me(){this._sourceTexture=new Lr({type:Wt.HALF_FLOAT}),this._depthTexture=new Lr({format:Wt.DEPTH_COMPONENT,type:Wt.UNSIGNED_INT}),this._framebuffer=new $n,this._framebuffer.attach(this._sourceTexture),this._framebuffer.attach(this._depthTexture,$n.DEPTH_ATTACHMENT),this._gBufferPass=new ki({enableTargetTexture3:!1});var e=new Ii;this._compositor=e.parse(aa);var t=this._compositor.getNodeByName("source");t.texture=this._sourceTexture;var r=this._compositor.getNodeByName("coc");this._sourceNode=t,this._cocNode=r,this._compositeNode=this._compositor.getNodeByName("composite"),this._fxaaNode=this._compositor.getNodeByName("FXAA"),this._dofBlurNodes=["dof_far_blur","dof_near_blur","dof_coc_blur"].map(function(e){return this._compositor.getNodeByName(e)},this),this._dofBlurKernel=null,this._dofBlurKernelSize=new Float32Array(0),this._finalNodesChain=sa.map(function(e){return this._compositor.getNodeByName(e)},this);var n={normalTexture:this._gBufferPass.getTargetTexture1(),depthTexture:this._gBufferPass.getTargetTexture2()};this._ssaoPass=new ie(n),this._ssrPass=new ae(n)}function Re(){for(var e=[],t=0;t<30;t++)e.push([ee(t,2),ee(t,3)]);this._haltonSequence=e,this._frame=0,this._sourceTex=new Lr,this._sourceFb=new $n,this._sourceFb.attach(this._sourceTex),this._prevFrameTex=new Lr,this._outputTex=new Lr;var r=this._blendPass=new yi({fragment:kt.source("qtek.compositor.blend")});r.material.shader.disableTexturesAll(),r.material.shader.enableTexture(["texture1","texture2"]),this._blendFb=new $n({depthBuffer:!1}),this._outputPass=new yi({fragment:kt.source("qtek.compositor.output"),blendWithPrevious:!0}),this._outputPass.material.shader.define("fragment","OUTPUT_ALPHA"),this._outputPass.material.blend=function(e){e.blendEquationSeparate(e.FUNC_ADD,e.FUNC_ADD),e.blendFuncSeparate(e.ONE,e.ONE_MINUS_SRC_ALPHA,e.ONE,e.ONE_MINUS_SRC_ALPHA)}}function Ce(e,t,r){this.renderer=e,r=r||"perspective",this.scene=new fr,this.rootNode=this.scene,this.viewport={x:0,y:0,width:0,height:0},this.preZ=!1,this.setProjection(r),this._compositor=new Me,this._temporalSS=new Re,t&&(this._shadowMapPass=new Ai({lightFrustumBias:20}));for(var n=[],i=0,a=0;a<30;a++){for(var o=[],s=0;s<6;s++)o.push(4*ee(i,2)-2),o.push(4*ee(i,3)-2),i++;n.push(o)}this._pcfKernels=n,this._enableTemporalSS="auto",this.scene.on("beforerender",function(e,t,r){this.needsTemporalSS()&&this._temporalSS.jitterProjection(e,r)},this)}function Le(e){this.setScene(e)}function De(e){if(null==e||"object"!=typeof e)return e;var t=e,r=da.call(e);if("[object Array]"===r){t=[];for(var n=0,i=e.length;n=0&&i[h]>1e-6&&(pa.transformMat4(s,r,a[n[h]]),pa.scaleAndAdd(o,o,s,i[h]));pa.min(p,p,o),pa.max(m,m,o)}t.min.setArray(p),t.max.setArray(m)}function He(e,t){t=t||new pt;var r=new pt;return e.traverse(function(e){e.geometry&&(e.isSkinnedMesh()?(Ue(e,r),e.geometry.boundingBox.copy(r)):(r.copy(e.geometry.boundingBox),r.applyTransform(e.worldTransform)),t.union(r))}),t}function ze(e){var t=e[1][0]-e[0][0],r=e[1][1]-e[0][1];return Math.sqrt(t*t+r*r)}function Ge(e){return[(e[0][0]+e[1][0])/2,(e[0][1]+e[1][1])/2]}function We(e){return Array.isArray(e)||(e=[e,e]),e}function qe(e,t){t=De(t),Pe(t,ca),this.init(e,t)}var Ve={extend:t,derive:t},je={trigger:function(e){if(this.hasOwnProperty("__handlers__")&&this.__handlers__.hasOwnProperty(e)){var t=this.__handlers__[e],r=t.length,n=-1,i=arguments;switch(i.length){case 1:for(;++n0&&(i=1/Math.sqrt(i),e[0]=t[0]*i,e[1]=t[1]*i),e},o.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]},o.cross=function(e,t,r){var n=t[0]*r[1]-t[1]*r[0];return e[0]=e[1]=0,e[2]=n,e},o.lerp=function(e,t,r,n){var i=t[0],a=t[1];return e[0]=i+n*(r[0]-i),e[1]=a+n*(r[1]-a),e},o.random=function(e,t){t=t||1;var r=2*n()*Math.PI;return e[0]=Math.cos(r)*t,e[1]=Math.sin(r)*t,e},o.transformMat2=function(e,t,r){var n=t[0],i=t[1];return e[0]=r[0]*n+r[2]*i,e[1]=r[1]*n+r[3]*i,e},o.transformMat2d=function(e,t,r){var n=t[0],i=t[1];return e[0]=r[0]*n+r[2]*i+r[4],e[1]=r[1]*n+r[3]*i+r[5],e},o.transformMat3=function(e,t,r){var n=t[0],i=t[1];return e[0]=r[0]*n+r[3]*i+r[6],e[1]=r[1]*n+r[4]*i+r[7],e},o.transformMat4=function(e,t,r){var n=t[0],i=t[1];return e[0]=r[0]*n+r[4]*i+r[12],e[1]=r[1]*n+r[5]*i+r[13],e},o.forEach=function(){var e=o.create();return function(t,r,n,i,a,o){var s,u;for(r||(r=2),n||(n=0),u=i?Math.min(i*r+n,t.length):t.length,s=n;s0&&(a=1/Math.sqrt(a),e[0]=t[0]*a,e[1]=t[1]*a,e[2]=t[2]*a),e},s.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]},s.cross=function(e,t,r){var n=t[0],i=t[1],a=t[2],o=r[0],s=r[1],u=r[2];return e[0]=i*u-a*s,e[1]=a*o-n*u,e[2]=n*s-i*o,e},s.lerp=function(e,t,r,n){var i=t[0],a=t[1],o=t[2];return e[0]=i+n*(r[0]-i),e[1]=a+n*(r[1]-a),e[2]=o+n*(r[2]-o),e},s.random=function(e,t){t=t||1;var r=2*n()*Math.PI,i=2*n()-1,a=Math.sqrt(1-i*i)*t;return e[0]=Math.cos(r)*a,e[1]=Math.sin(r)*a,e[2]=i*t,e},s.transformMat4=function(e,t,r){var n=t[0],i=t[1],a=t[2],o=r[3]*n+r[7]*i+r[11]*a+r[15];return o=o||1,e[0]=(r[0]*n+r[4]*i+r[8]*a+r[12])/o,e[1]=(r[1]*n+r[5]*i+r[9]*a+r[13])/o,e[2]=(r[2]*n+r[6]*i+r[10]*a+r[14])/o,e},s.transformMat3=function(e,t,r){var n=t[0],i=t[1],a=t[2];return e[0]=n*r[0]+i*r[3]+a*r[6],e[1]=n*r[1]+i*r[4]+a*r[7],e[2]=n*r[2]+i*r[5]+a*r[8],e},s.transformQuat=function(e,t,r){var n=t[0],i=t[1],a=t[2],o=r[0],s=r[1],u=r[2],l=r[3],c=l*n+s*a-u*i,h=l*i+u*n-o*a,f=l*a+o*i-s*n,d=-o*n-s*i-u*a;return e[0]=c*l+d*-o+h*-u-f*-s,e[1]=h*l+d*-s+f*-o-c*-u,e[2]=f*l+d*-u+c*-s-h*-o,e},s.rotateX=function(e,t,r,n){var i=[],a=[];return i[0]=t[0]-r[0],i[1]=t[1]-r[1],i[2]=t[2]-r[2],a[0]=i[0],a[1]=i[1]*Math.cos(n)-i[2]*Math.sin(n),a[2]=i[1]*Math.sin(n)+i[2]*Math.cos(n),e[0]=a[0]+r[0],e[1]=a[1]+r[1],e[2]=a[2]+r[2],e},s.rotateY=function(e,t,r,n){var i=[],a=[];return i[0]=t[0]-r[0],i[1]=t[1]-r[1],i[2]=t[2]-r[2],a[0]=i[2]*Math.sin(n)+i[0]*Math.cos(n),a[1]=i[1],a[2]=i[2]*Math.cos(n)-i[0]*Math.sin(n),e[0]=a[0]+r[0],e[1]=a[1]+r[1],e[2]=a[2]+r[2],e},s.rotateZ=function(e,t,r,n){var i=[],a=[];return i[0]=t[0]-r[0],i[1]=t[1]-r[1],i[2]=t[2]-r[2],a[0]=i[0]*Math.cos(n)-i[1]*Math.sin(n),a[1]=i[0]*Math.sin(n)+i[1]*Math.cos(n),a[2]=i[2],e[0]=a[0]+r[0],e[1]=a[1]+r[1],e[2]=a[2]+r[2],e},s.forEach=function(){var e=s.create();return function(t,r,n,i,a,o){var s,u;for(r||(r=3),n||(n=0),u=i?Math.min(i*r+n,t.length):t.length,s=n;s1?0:Math.acos(i)},s.str=function(e){return"vec3("+e[0]+", "+e[1]+", "+e[2]+")"},void 0!==e&&(e.vec3=s);var u={};u.create=function(){var e=new r(4);return e[0]=0,e[1]=0,e[2]=0,e[3]=0,e},u.clone=function(e){var t=new r(4);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},u.fromValues=function(e,t,n,i){var a=new r(4);return a[0]=e,a[1]=t,a[2]=n,a[3]=i,a},u.copy=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e},u.set=function(e,t,r,n,i){return e[0]=t,e[1]=r,e[2]=n,e[3]=i,e},u.add=function(e,t,r){return e[0]=t[0]+r[0],e[1]=t[1]+r[1],e[2]=t[2]+r[2],e[3]=t[3]+r[3],e},u.subtract=function(e,t,r){return e[0]=t[0]-r[0],e[1]=t[1]-r[1],e[2]=t[2]-r[2],e[3]=t[3]-r[3],e},u.sub=u.subtract,u.multiply=function(e,t,r){return e[0]=t[0]*r[0],e[1]=t[1]*r[1],e[2]=t[2]*r[2],e[3]=t[3]*r[3],e},u.mul=u.multiply,u.divide=function(e,t,r){return e[0]=t[0]/r[0],e[1]=t[1]/r[1],e[2]=t[2]/r[2],e[3]=t[3]/r[3],e},u.div=u.divide,u.min=function(e,t,r){return e[0]=Math.min(t[0],r[0]),e[1]=Math.min(t[1],r[1]),e[2]=Math.min(t[2],r[2]),e[3]=Math.min(t[3],r[3]),e},u.max=function(e,t,r){return e[0]=Math.max(t[0],r[0]),e[1]=Math.max(t[1],r[1]),e[2]=Math.max(t[2],r[2]),e[3]=Math.max(t[3],r[3]),e},u.scale=function(e,t,r){return e[0]=t[0]*r,e[1]=t[1]*r,e[2]=t[2]*r,e[3]=t[3]*r,e},u.scaleAndAdd=function(e,t,r,n){return e[0]=t[0]+r[0]*n,e[1]=t[1]+r[1]*n,e[2]=t[2]+r[2]*n,e[3]=t[3]+r[3]*n,e},u.distance=function(e,t){var r=t[0]-e[0],n=t[1]-e[1],i=t[2]-e[2],a=t[3]-e[3];return Math.sqrt(r*r+n*n+i*i+a*a)},u.dist=u.distance,u.squaredDistance=function(e,t){var r=t[0]-e[0],n=t[1]-e[1],i=t[2]-e[2],a=t[3]-e[3];return r*r+n*n+i*i+a*a},u.sqrDist=u.squaredDistance,u.length=function(e){var t=e[0],r=e[1],n=e[2],i=e[3];return Math.sqrt(t*t+r*r+n*n+i*i)},u.len=u.length,u.squaredLength=function(e){var t=e[0],r=e[1],n=e[2],i=e[3];return t*t+r*r+n*n+i*i},u.sqrLen=u.squaredLength,u.negate=function(e,t){return e[0]=-t[0],e[1]=-t[1],e[2]=-t[2],e[3]=-t[3],e},u.inverse=function(e,t){return e[0]=1/t[0],e[1]=1/t[1],e[2]=1/t[2],e[3]=1/t[3],e},u.normalize=function(e,t){var r=t[0],n=t[1],i=t[2],a=t[3],o=r*r+n*n+i*i+a*a;return o>0&&(o=1/Math.sqrt(o),e[0]=t[0]*o,e[1]=t[1]*o,e[2]=t[2]*o,e[3]=t[3]*o),e},u.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]+e[3]*t[3]},u.lerp=function(e,t,r,n){var i=t[0],a=t[1],o=t[2],s=t[3];return e[0]=i+n*(r[0]-i),e[1]=a+n*(r[1]-a),e[2]=o+n*(r[2]-o),e[3]=s+n*(r[3]-s),e},u.random=function(e,t){return t=t||1,e[0]=n(),e[1]=n(),e[2]=n(),e[3]=n(),u.normalize(e,e),u.scale(e,e,t),e},u.transformMat4=function(e,t,r){var n=t[0],i=t[1],a=t[2],o=t[3];return e[0]=r[0]*n+r[4]*i+r[8]*a+r[12]*o,e[1]=r[1]*n+r[5]*i+r[9]*a+r[13]*o,e[2]=r[2]*n+r[6]*i+r[10]*a+r[14]*o,e[3]=r[3]*n+r[7]*i+r[11]*a+r[15]*o,e},u.transformQuat=function(e,t,r){var n=t[0],i=t[1],a=t[2],o=r[0],s=r[1],u=r[2],l=r[3],c=l*n+s*a-u*i,h=l*i+u*n-o*a,f=l*a+o*i-s*n,d=-o*n-s*i-u*a;return e[0]=c*l+d*-o+h*-u-f*-s,e[1]=h*l+d*-s+f*-o-c*-u,e[2]=f*l+d*-u+c*-s-h*-o,e},u.forEach=function(){var e=u.create();return function(t,r,n,i,a,o){var s,u;for(r||(r=4),n||(n=0),u=i?Math.min(i*r+n,t.length):t.length,s=n;s.999999?(n[0]=0,n[1]=0,n[2]=0,n[3]=1,n):(s.cross(e,i,a),n[0]=e[0],n[1]=e[1],n[2]=e[2],n[3]=1+o,d.normalize(n,n))}}(),d.setAxes=function(){var e=h.create();return function(t,r,n,i){return e[0]=n[0],e[3]=n[1],e[6]=n[2],e[1]=i[0],e[4]=i[1],e[7]=i[2],e[2]=-r[0],e[5]=-r[1],e[8]=-r[2],d.normalize(t,d.fromMat3(t,e))}}(),d.clone=u.clone,d.fromValues=u.fromValues,d.copy=u.copy,d.set=u.set,d.identity=function(e){return e[0]=0,e[1]=0,e[2]=0,e[3]=1,e},d.setAxisAngle=function(e,t,r){r*=.5;var n=Math.sin(r);return e[0]=n*t[0],e[1]=n*t[1],e[2]=n*t[2],e[3]=Math.cos(r),e},d.add=u.add,d.multiply=function(e,t,r){var n=t[0],i=t[1],a=t[2],o=t[3],s=r[0],u=r[1],l=r[2],c=r[3];return e[0]=n*c+o*s+i*l-a*u,e[1]=i*c+o*u+a*s-n*l,e[2]=a*c+o*l+n*u-i*s,e[3]=o*c-n*s-i*u-a*l,e},d.mul=d.multiply,d.scale=u.scale,d.rotateX=function(e,t,r){r*=.5;var n=t[0],i=t[1],a=t[2],o=t[3],s=Math.sin(r),u=Math.cos(r);return e[0]=n*u+o*s,e[1]=i*u+a*s,e[2]=a*u-i*s,e[3]=o*u-n*s,e},d.rotateY=function(e,t,r){r*=.5;var n=t[0],i=t[1],a=t[2],o=t[3],s=Math.sin(r),u=Math.cos(r);return e[0]=n*u-a*s,e[1]=i*u+o*s,e[2]=a*u+n*s,e[3]=o*u-i*s,e},d.rotateZ=function(e,t,r){r*=.5;var n=t[0],i=t[1],a=t[2],o=t[3],s=Math.sin(r),u=Math.cos(r);return e[0]=n*u+i*s,e[1]=i*u-n*s,e[2]=a*u+o*s,e[3]=o*u-a*s,e},d.calculateW=function(e,t){var r=t[0],n=t[1],i=t[2];return e[0]=r,e[1]=n,e[2]=i,e[3]=Math.sqrt(Math.abs(1-r*r-n*n-i*i)),e},d.dot=u.dot,d.lerp=u.lerp,d.slerp=function(e,t,r,n){var i,a,o,s,u,l=t[0],c=t[1],h=t[2],f=t[3],d=r[0],_=r[1],p=r[2],m=r[3];return a=l*d+c*_+h*p+f*m,a<0&&(a=-a,d=-d,_=-_,p=-p,m=-m),1-a>1e-6?(i=Math.acos(a),o=Math.sin(i),s=Math.sin((1-n)*i)/o,u=Math.sin(n*i)/o):(s=1-n,u=n),e[0]=s*l+u*d,e[1]=s*c+u*_,e[2]=s*h+u*p,e[3]=s*f+u*m,e},d.invert=function(e,t){var r=t[0],n=t[1],i=t[2],a=t[3],o=r*r+n*n+i*i+a*a,s=o?1/o:0;return e[0]=-r*s,e[1]=-n*s,e[2]=-i*s,e[3]=a*s,e},d.conjugate=function(e,t){return e[0]=-t[0],e[1]=-t[1],e[2]=-t[2],e[3]=t[3],e},d.length=u.length,d.len=d.length,d.squaredLength=u.squaredLength,d.sqrLen=d.squaredLength,d.normalize=u.normalize,d.fromMat3=function(e,t){var r,n=t[0]+t[4]+t[8];if(n>0)r=Math.sqrt(n+1),e[3]=.5*r,r=.5/r,e[0]=(t[5]-t[7])*r,e[1]=(t[6]-t[2])*r,e[2]=(t[1]-t[3])*r;else{var i=0;t[4]>t[0]&&(i=1),t[8]>t[3*i+i]&&(i=2);var a=(i+1)%3,o=(i+2)%3;r=Math.sqrt(t[3*i+i]-t[3*a+a]-t[3*o+o]+1),e[i]=.5*r,r=.5/r,e[3]=(t[3*a+o]-t[3*o+a])*r,e[a]=(t[3*a+i]+t[3*i+a])*r,e[o]=(t[3*o+i]+t[3*i+o])*r}return e},d.str=function(e){return"quat("+e[0]+", "+e[1]+", "+e[2]+", "+e[3]+")"},void 0!==e&&(e.quat=d)}(r.exports)}()})),at=it.vec3,ot=function(e,t,r){e=e||0,t=t||0,r=r||0,this._array=at.fromValues(e,t,r),this._dirty=!0};ot.prototype={constructor:ot,add:function(e){return at.add(this._array,this._array,e._array),this._dirty=!0,this},set:function(e,t,r){return this._array[0]=e,this._array[1]=t,this._array[2]=r,this._dirty=!0,this},setArray:function(e){return this._array[0]=e[0],this._array[1]=e[1],this._array[2]=e[2],this._dirty=!0,this},clone:function(){return new ot(this.x,this.y,this.z)},copy:function(e){return at.copy(this._array,e._array),this._dirty=!0,this},cross:function(e,t){return at.cross(this._array,e._array,t._array),this._dirty=!0,this},dist:function(e){return at.dist(this._array,e._array)},distance:function(e){return at.distance(this._array,e._array)},div:function(e){return at.div(this._array,this._array,e._array),this._dirty=!0,this},divide:function(e){return at.divide(this._array,this._array,e._array),this._dirty=!0,this},dot:function(e){return at.dot(this._array,e._array)},len:function(){return at.len(this._array)},length:function(){return at.length(this._array)},lerp:function(e,t,r){return at.lerp(this._array,e._array,t._array,r),this._dirty=!0,this},min:function(e){return at.min(this._array,this._array,e._array),this._dirty=!0,this},max:function(e){return at.max(this._array,this._array,e._array),this._dirty=!0,this},mul:function(e){return at.mul(this._array,this._array,e._array),this._dirty=!0,this},multiply:function(e){return at.multiply(this._array,this._array,e._array),this._dirty=!0,this},negate:function(){return at.negate(this._array,this._array),this._dirty=!0,this},normalize:function(){return at.normalize(this._array,this._array),this._dirty=!0,this},random:function(e){return at.random(this._array,e),this._dirty=!0,this},scale:function(e){return at.scale(this._array,this._array,e),this._dirty=!0,this},scaleAndAdd:function(e,t){return at.scaleAndAdd(this._array,this._array,e._array,t),this._dirty=!0,this},sqrDist:function(e){return at.sqrDist(this._array,e._array)},squaredDistance:function(e){return at.squaredDistance(this._array,e._array)},sqrLen:function(){return at.sqrLen(this._array)},squaredLength:function(){return at.squaredLength(this._array)},sub:function(e){return at.sub(this._array,this._array,e._array),this._dirty=!0,this},subtract:function(e){return at.subtract(this._array,this._array,e._array),this._dirty=!0,this},transformMat3:function(e){return at.transformMat3(this._array,this._array,e._array),this._dirty=!0,this},transformMat4:function(e){return at.transformMat4(this._array,this._array,e._array),this._dirty=!0,this},transformQuat:function(e){return at.transformQuat(this._array,this._array,e._array),this._dirty=!0,this}, -applyProjection:function(e){var t=this._array;if(e=e._array,0===e[15]){var r=-1/t[2];t[0]=e[0]*t[0]*r,t[1]=e[5]*t[1]*r,t[2]=(e[10]*t[2]+e[14])*r}else t[0]=e[0]*t[0]+e[12],t[1]=e[5]*t[1]+e[13],t[2]=e[10]*t[2]+e[14];return this._dirty=!0,this},eulerFromQuat:function(e,t){ot.eulerFromQuat(this,e,t)},eulerFromMat3:function(e,t){ot.eulerFromMat3(this,e,t)},toString:function(){return"["+Array.prototype.join.call(this._array,",")+"]"},toArray:function(){return Array.prototype.slice.call(this._array)}};var st=Object.defineProperty;if(st){var ut=ot.prototype;st(ut,"x",{get:function(){return this._array[0]},set:function(e){this._array[0]=e,this._dirty=!0}}),st(ut,"y",{get:function(){return this._array[1]},set:function(e){this._array[1]=e,this._dirty=!0}}),st(ut,"z",{get:function(){return this._array[2]},set:function(e){this._array[2]=e,this._dirty=!0}})}ot.add=function(e,t,r){return at.add(e._array,t._array,r._array),e._dirty=!0,e},ot.set=function(e,t,r,n){at.set(e._array,t,r,n),e._dirty=!0},ot.copy=function(e,t){return at.copy(e._array,t._array),e._dirty=!0,e},ot.cross=function(e,t,r){return at.cross(e._array,t._array,r._array),e._dirty=!0,e},ot.dist=function(e,t){return at.distance(e._array,t._array)},ot.distance=ot.dist,ot.div=function(e,t,r){return at.divide(e._array,t._array,r._array),e._dirty=!0,e},ot.divide=ot.div,ot.dot=function(e,t){return at.dot(e._array,t._array)},ot.len=function(e){return at.length(e._array)},ot.lerp=function(e,t,r,n){return at.lerp(e._array,t._array,r._array,n),e._dirty=!0,e},ot.min=function(e,t,r){return at.min(e._array,t._array,r._array),e._dirty=!0,e},ot.max=function(e,t,r){return at.max(e._array,t._array,r._array),e._dirty=!0,e},ot.mul=function(e,t,r){return at.multiply(e._array,t._array,r._array),e._dirty=!0,e},ot.multiply=ot.mul,ot.negate=function(e,t){return at.negate(e._array,t._array),e._dirty=!0,e},ot.normalize=function(e,t){return at.normalize(e._array,t._array),e._dirty=!0,e},ot.random=function(e,t){return at.random(e._array,t),e._dirty=!0,e},ot.scale=function(e,t,r){return at.scale(e._array,t._array,r),e._dirty=!0,e},ot.scaleAndAdd=function(e,t,r,n){return at.scaleAndAdd(e._array,t._array,r._array,n),e._dirty=!0,e},ot.sqrDist=function(e,t){return at.sqrDist(e._array,t._array)},ot.squaredDistance=ot.sqrDist,ot.sqrLen=function(e){return at.sqrLen(e._array)},ot.squaredLength=ot.sqrLen,ot.sub=function(e,t,r){return at.subtract(e._array,t._array,r._array),e._dirty=!0,e},ot.subtract=ot.sub,ot.transformMat3=function(e,t,r){return at.transformMat3(e._array,t._array,r._array),e._dirty=!0,e},ot.transformMat4=function(e,t,r){return at.transformMat4(e._array,t._array,r._array),e._dirty=!0,e},ot.transformQuat=function(e,t,r){return at.transformQuat(e._array,t._array,r._array),e._dirty=!0,e};var lt=Math.atan2,ct=Math.asin,ht=Math.abs;ot.eulerFromQuat=function(e,t,r){e._dirty=!0,t=t._array;var n=e._array,i=t[0],a=t[1],s=t[2],u=t[3],l=i*i,c=a*a,h=s*s,f=u*u,r=(r||"XYZ").toUpperCase();switch(r){case"XYZ":n[0]=lt(2*(i*u-a*s),f-l-c+h),n[1]=ct(o(2*(i*s+a*u),-1,1)),n[2]=lt(2*(s*u-i*a),f+l-c-h);break;case"YXZ":n[0]=ct(o(2*(i*u-a*s),-1,1)),n[1]=lt(2*(i*s+a*u),f-l-c+h),n[2]=lt(2*(i*a+s*u),f-l+c-h);break;case"ZXY":n[0]=ct(o(2*(i*u+a*s),-1,1)),n[1]=lt(2*(a*u-s*i),f-l-c+h),n[2]=lt(2*(s*u-i*a),f-l+c-h);break;case"ZYX":n[0]=lt(2*(i*u+s*a),f-l-c+h),n[1]=ct(o(2*(a*u-i*s),-1,1)),n[2]=lt(2*(i*a+s*u),f+l-c-h);break;case"YZX":n[0]=lt(2*(i*u-s*a),f-l+c-h),n[1]=lt(2*(a*u-i*s),f+l-c-h),n[2]=ct(o(2*(i*a+s*u),-1,1));break;case"XZY":n[0]=lt(2*(i*u+a*s),f-l+c-h),n[1]=lt(2*(i*s+a*u),f+l-c-h),n[2]=ct(o(2*(s*u-i*a),-1,1));break;default:console.warn("Unkown order: "+r)}return e},ot.eulerFromMat3=function(e,t,r){var n=t._array,i=n[0],a=n[3],s=n[6],u=n[1],l=n[4],c=n[7],h=n[2],f=n[5],d=n[8],_=e._array,r=(r||"XYZ").toUpperCase();switch(r){case"XYZ":_[1]=ct(o(s,-1,1)),ht(s)<.99999?(_[0]=lt(-c,d),_[2]=lt(-a,i)):(_[0]=lt(f,l),_[2]=0);break;case"YXZ":_[0]=ct(-o(c,-1,1)),ht(c)<.99999?(_[1]=lt(s,d),_[2]=lt(u,l)):(_[1]=lt(-h,i),_[2]=0);break;case"ZXY":_[0]=ct(o(f,-1,1)),ht(f)<.99999?(_[1]=lt(-h,d),_[2]=lt(-a,l)):(_[1]=0,_[2]=lt(u,i));break;case"ZYX":_[1]=ct(-o(h,-1,1)),ht(h)<.99999?(_[0]=lt(f,d),_[2]=lt(u,i)):(_[0]=0,_[2]=lt(-a,l));break;case"YZX":_[2]=ct(o(u,-1,1)),ht(u)<.99999?(_[0]=lt(-c,l),_[1]=lt(-h,i)):(_[0]=0,_[1]=lt(s,d));break;case"XZY":_[2]=ct(-o(a,-1,1)),ht(a)<.99999?(_[0]=lt(f,l),_[1]=lt(s,i)):(_[0]=lt(-c,d),_[1]=0);break;default:console.warn("Unkown order: "+r)}return e._dirty=!0,e},ot.POSITIVE_X=new ot(1,0,0),ot.NEGATIVE_X=new ot(-1,0,0),ot.POSITIVE_Y=new ot(0,1,0),ot.NEGATIVE_Y=new ot(0,-1,0),ot.POSITIVE_Z=new ot(0,0,1),ot.NEGATIVE_Z=new ot(0,0,-1),ot.UP=new ot(0,1,0),ot.ZERO=new ot(0,0,0);var ft=it.vec3,dt=ft.copy,_t=ft.set,pt=function(e,t){this.min=e||new ot(1/0,1/0,1/0),this.max=t||new ot(-1/0,-1/0,-1/0)};pt.prototype={constructor:pt,updateFromVertices:function(e){if(e.length>0){var t=this.min,r=this.max,n=t._array,i=r._array;dt(n,e[0]),dt(i,e[0]);for(var a=1;ai[0]&&(i[0]=o[0]),o[1]>i[1]&&(i[1]=o[1]),o[2]>i[2]&&(i[2]=o[2])}t._dirty=!0,r._dirty=!0}},union:function(e){var t=this.min,r=this.max;return ft.min(t._array,t._array,e.min._array),ft.max(r._array,r._array,e.max._array),t._dirty=!0,r._dirty=!0,this},intersection:function(e){var t=this.min,r=this.max;return ft.max(t._array,t._array,e.min._array),ft.min(r._array,r._array,e.max._array),t._dirty=!0,r._dirty=!0,this},intersectBoundingBox:function(e){var t=this.min._array,r=this.max._array,n=e.min._array,i=e.max._array;return!(t[0]>i[0]||t[1]>i[1]||t[2]>i[2]||r[0]=i[0]&&r[1]>=i[1]&&r[2]>=i[2]},containPoint:function(e){var t=this.min._array,r=this.max._array,n=e._array;return t[0]<=n[0]&&t[1]<=n[1]&&t[2]<=n[2]&&r[0]>=n[0]&&r[1]>=n[1]&&r[2]>=n[2]},isFinite:function(){var e=this.min._array,t=this.max._array;return isFinite(e[0])&&isFinite(e[1])&&isFinite(e[2])&&isFinite(t[0])&&isFinite(t[1])&&isFinite(t[2])},applyTransform:function(){var e=ft.create(),t=ft.create(),r=ft.create(),n=ft.create(),i=ft.create(),a=ft.create();return function(o){var s=this.min._array,u=this.max._array,l=o._array;return e[0]=l[0]*s[0],e[1]=l[1]*s[0],e[2]=l[2]*s[0],t[0]=l[0]*u[0],t[1]=l[1]*u[0],t[2]=l[2]*u[0],r[0]=l[4]*s[1],r[1]=l[5]*s[1],r[2]=l[6]*s[1],n[0]=l[4]*u[1],n[1]=l[5]*u[1],n[2]=l[6]*u[1],i[0]=l[8]*s[2],i[1]=l[9]*s[2],i[2]=l[10]*s[2],a[0]=l[8]*u[2],a[1]=l[9]*u[2],a[2]=l[10]*u[2],s[0]=Math.min(e[0],t[0])+Math.min(r[0],n[0])+Math.min(i[0],a[0])+l[12],s[1]=Math.min(e[1],t[1])+Math.min(r[1],n[1])+Math.min(i[1],a[1])+l[13],s[2]=Math.min(e[2],t[2])+Math.min(r[2],n[2])+Math.min(i[2],a[2])+l[14],u[0]=Math.max(e[0],t[0])+Math.max(r[0],n[0])+Math.max(i[0],a[0])+l[12],u[1]=Math.max(e[1],t[1])+Math.max(r[1],n[1])+Math.max(i[1],a[1])+l[13],u[2]=Math.max(e[2],t[2])+Math.max(r[2],n[2])+Math.max(i[2],a[2])+l[14],this.min._dirty=!0,this.max._dirty=!0,this}}(),applyProjection:function(e){var t=this.min._array,r=this.max._array,n=e._array,i=t[0],a=t[1],o=t[2],s=r[0],u=r[1],l=t[2],c=r[0],h=r[1],f=r[2];if(1===n[15])t[0]=n[0]*i+n[12],t[1]=n[5]*a+n[13],r[2]=n[10]*o+n[14],r[0]=n[0]*c+n[12],r[1]=n[5]*h+n[13],t[2]=n[10]*f+n[14];else{var d=-1/o;t[0]=n[0]*i*d,t[1]=n[5]*a*d,r[2]=(n[10]*o+n[14])*d,d=-1/l,r[0]=n[0]*s*d,r[1]=n[5]*u*d,d=-1/f,t[2]=(n[10]*f+n[14])*d}return this.min._dirty=!0,this.max._dirty=!0,this},updateVertices:function(){var e=this.vertices;if(!e){for(var e=[],t=0;t<8;t++)e[t]=ft.fromValues(0,0,0);this.vertices=e}var r=this.min._array,n=this.max._array;return _t(e[0],r[0],r[1],r[2]),_t(e[1],r[0],n[1],r[2]),_t(e[2],n[0],r[1],r[2]),_t(e[3],n[0],n[1],r[2]),_t(e[4],r[0],r[1],n[2]),_t(e[5],r[0],n[1],n[2]),_t(e[6],n[0],r[1],n[2]),_t(e[7],n[0],n[1],n[2]),this},copy:function(e){var t=this.min,r=this.max;return dt(t._array,e.min._array),dt(r._array,e.max._array),t._dirty=!0,r._dirty=!0,this},clone:function(){var e=new pt;return e.copy(this),e}};var mt=it.mat4,vt=it.vec3,gt=it.mat3,yt=it.quat,xt=function(){this._axisX=new ot,this._axisY=new ot,this._axisZ=new ot,this._array=mt.create(),this._dirty=!0};xt.prototype={constructor:xt,setArray:function(e){for(var t=0;t0&&n.push("#define "+i.toUpperCase()+"_COUNT "+a)}for(var o in r){r[o].enabled&&n.push("#define "+o.toUpperCase()+"_ENABLED")}for(var o in e){var s=e[o];null===s?n.push("#define "+o):n.push("#define "+o+" "+s.toString())}return n.join("\n")},_unrollLoop:function(e,t){function r(e,r,i,a){var o="";isNaN(r)&&(r=r in t?t[r]:n[r]),isNaN(i)&&(i=i in t?t[i]:n[i]);for(var s=parseInt(r);s=0)r.attribSemantics[u]={symbol:a,type:c},h=!1;else if(Ot.indexOf(u)>=0){var f=!1,d=u;u.match(/TRANSPOSE$/)&&(f=!0,d=u.slice(0,-9)),r.matrixSemantics[u]={symbol:a,type:c,isTranspose:f,semanticNoTranspose:d},h=!1}else if(It.indexOf(u)>=0)r.uniformSemantics[u]={symbol:a,type:c},h=!1;else if("unconfigurable"===u)h=!1;else{if(!(l=r._parseDefaultValue(i,u)))throw new Error('Unkown semantic "'+u+'"');u=""}h&&(t[a]={type:c,value:o?Dt.array:l||Dt[i],semantic:u||null})}return["uniform",i,a,o].join(" ")+";\n"}}var t={},r=this,n="vertex";this._uniformList=[],this._vertexProcessedWithoutDefine=this._vertexProcessedWithoutDefine.replace(wt,e),n="fragment",this._fragmentProcessedWithoutDefine=this._fragmentProcessedWithoutDefine.replace(wt,e),r.matrixSemanticKeys=Object.keys(this.matrixSemantics),this.uniformTemplates=t},_parseDefaultValue:function(e,t){var r=/\[\s*(.*)\s*\]/;{if("vec2"!==e&&"vec3"!==e&&"vec4"!==e)return"bool"===e?function(){return"true"===t.toLowerCase()}:"float"===e?function(){return parseFloat(t)}:"int"===e?function(){return parseInt(t)}:void 0;var n=r.exec(t)[1];if(n){var i=n.split(/\s*,\s*/);return function(){return new nt.Float32Array(i)}}}},createUniforms:function(){var e={};for(var t in this.uniformTemplates){var r=this.uniformTemplates[t];e[t]={type:r.type,value:r.value()}}return e},attached:function(){this._attacheMaterialNumber++},detached:function(){this._attacheMaterialNumber--},isAttachedToAny:function(){return 0!==this._attacheMaterialNumber},_parseAttributes:function(){function e(e,n,i,a,o){if(n&&i){var s=1;switch(n){case"vec4":s=4;break;case"vec3":s=3;break;case"vec2":s=2;break;case"float":s=1}if(t[i]={type:"float",size:s,semantic:o||null},o){if(Pt.indexOf(o)<0)throw new Error('Unkown semantic "'+o+'"');r.attribSemantics[o]={symbol:i,type:n}}}return["attribute",n,i].join(" ")+";\n"}var t={},r=this;this._vertexProcessedWithoutDefine=this._vertexProcessedWithoutDefine.replace(Mt,e),this.attributeTemplates=t},_parseDefines:function(){function e(e,n,i){var a="vertex"===r?t.vertexDefines:t.fragmentDefines;return a[n]||(a[n]="false"!=i&&("true"==i||(i?isNaN(parseFloat(i))?i:parseFloat(i):null))),""}var t=this,r="vertex";this._vertexProcessedWithoutDefine=this._vertexProcessedWithoutDefine.replace(Rt,e),r="fragment",this._fragmentProcessedWithoutDefine=this._fragmentProcessedWithoutDefine.replace(Rt,e)},_buildProgram:function(e,t,r){var n=this._cache;n.get("program")&&e.deleteProgram(n.get("program"));var i=e.createProgram(),a=e.createShader(e.VERTEX_SHADER);e.shaderSource(a,t),e.compileShader(a);var o=e.createShader(e.FRAGMENT_SHADER);e.shaderSource(o,r),e.compileShader(o);var s=u(e,a,t);if(s)return s;if(s=u(e,o,r))return s;if(e.attachShader(i,a),e.attachShader(i,o),this.attribSemantics.POSITION)e.bindAttribLocation(i,0,this.attribSemantics.POSITION.symbol);else{var l=Object.keys(this.attributeTemplates);e.bindAttribLocation(i,0,l[0])}if(e.linkProgram(i),!e.getProgramParameter(i,e.LINK_STATUS))return"Could not link program\nVALIDATE_STATUS: "+e.getProgramParameter(i,e.VALIDATE_STATUS)+", gl error ["+e.getError()+"]";for(var c=0;c>t;return e+1},dispose:function(e){var t=this._cache;t.use(e.__GUID__);var r=t.get("webgl_texture");r&&e.gl.deleteTexture(r),t.deleteContext(e.__GUID__)},isRenderable:function(){},isPowerOfTwo:function(){}});Object.defineProperty(Wt.prototype,"width",{get:function(){return this._width},set:function(e){this._width=e}}),Object.defineProperty(Wt.prototype,"height",{get:function(){return this._height},set:function(e){this._height=e}}),Wt.BYTE=et.BYTE,Wt.UNSIGNED_BYTE=et.UNSIGNED_BYTE,Wt.SHORT=et.SHORT,Wt.UNSIGNED_SHORT=et.UNSIGNED_SHORT,Wt.INT=et.INT,Wt.UNSIGNED_INT=et.UNSIGNED_INT,Wt.FLOAT=et.FLOAT,Wt.HALF_FLOAT=36193,Wt.UNSIGNED_INT_24_8_WEBGL=34042,Wt.DEPTH_COMPONENT=et.DEPTH_COMPONENT,Wt.DEPTH_STENCIL=et.DEPTH_STENCIL,Wt.ALPHA=et.ALPHA,Wt.RGB=et.RGB,Wt.RGBA=et.RGBA,Wt.LUMINANCE=et.LUMINANCE,Wt.LUMINANCE_ALPHA=et.LUMINANCE_ALPHA,Wt.SRGB=35904,Wt.SRGB_ALPHA=35906,Wt.COMPRESSED_RGB_S3TC_DXT1_EXT=33776,Wt.COMPRESSED_RGBA_S3TC_DXT1_EXT=33777,Wt.COMPRESSED_RGBA_S3TC_DXT3_EXT=33778,Wt.COMPRESSED_RGBA_S3TC_DXT5_EXT=33779,Wt.NEAREST=et.NEAREST,Wt.LINEAR=et.LINEAR,Wt.NEAREST_MIPMAP_NEAREST=et.NEAREST_MIPMAP_NEAREST,Wt.LINEAR_MIPMAP_NEAREST=et.LINEAR_MIPMAP_NEAREST,Wt.NEAREST_MIPMAP_LINEAR=et.NEAREST_MIPMAP_LINEAR,Wt.LINEAR_MIPMAP_LINEAR=et.LINEAR_MIPMAP_LINEAR,Wt.REPEAT=et.REPEAT,Wt.CLAMP_TO_EDGE=et.CLAMP_TO_EDGE, -Wt.MIRRORED_REPEAT=et.MIRRORED_REPEAT;var qt=Qe.extend({name:"",depthTest:!0,depthMask:!0,transparent:!1,blend:null,_enabledUniforms:null},function(){this.name||(this.name="MATERIAL_"+this.__GUID__),this.shader&&this.attachShader(this.shader),this.uniforms||(this.uniforms={})},{bind:function(e,t,r,n){for(var i=e.gl,t=t||this.shader,a=t.currentTextureSlot(),o=0;o=0},set:function(e,t){if("object"==typeof e)for(var r in e){var n=e[r];this.set(r,n)}else{var i=this.uniforms[e];i&&(void 0===t&&(console.warn('Uniform value "'+e+'" is undefined'),t=null),i.value=t)}},get:function(e){var t=this.uniforms[e];if(t)return t.value},attachShader:function(e,t){this.shader&&this.shader.detached();var r=this.uniforms;this.uniforms=e.createUniforms(),this.shader=e;var n=this.uniforms;if(this._enabledUniforms=Object.keys(n),this._enabledUniforms.sort(),t)for(var i in r)n[i]&&(n[i].value=r[i].value);e.attached()},detachShader:function(){this.shader.detached(),this.shader=null,this.uniforms={}},clone:function(){var e=new this.constructor({name:this.name,shader:this.shader});for(var t in this.uniforms)e.uniforms[t].value=this.uniforms[t].value;return e.depthTest=this.depthTest,e.depthMask=this.depthMask,e.transparent=this.transparent,e.blend=this.blend,e},dispose:function(e,t){if(t)for(var r in this.uniforms){var n=this.uniforms[r].value;if(n)if(n instanceof Wt)n.dispose(e);else if(Array.isArray(n))for(var i=0;i0&&this.setViewport(this._viewportStack.pop())},saveClear:function(){this._clearStack.push({clearBit:this.clearBit,clearColor:this.clearColor})},restoreClear:function(){if(this._clearStack.length>0){var e=this._clearStack.pop();this.clearColor=e.clearColor,this.clearBit=e.clearBit}},bindSceneRendering:function(e){this._sceneRendering=e},beforeRenderObject:function(){},afterRenderObject:function(){},render:function(e,t,r,n){var i=this.gl;this._sceneRendering=e;var a=this.clearColor;if(this.clearBit){i.colorMask(!0,!0,!0,!0),i.depthMask(!0);var o=this.viewport,s=!1,u=o.devicePixelRatio;(o.width!==this._width||o.height!==this._height||u&&u!==this.devicePixelRatio||o.x||o.y)&&(s=!0,i.enable(i.SCISSOR_TEST),i.scissor(o.x*u,o.y*u,o.width*u,o.height*u)),i.clearColor(a[0],a[1],a[2],a[3]),i.clear(this.clearBit),s&&i.disable(i.SCISSOR_TEST)}r||e.update(!1),t.getScene()||t.update(!0);for(var l=e.opaqueQueue,c=e.transparentQueue,h=e.material,f=0;f0)for(var _=$t(),p=Jt.create(),f=0;f0&&e.min._array[2]<0&&(e.max._array[2]=-1e-20),e.applyProjection(t);var u=e.min._array,l=e.max._array;if(l[0]<-1||u[0]>1||l[1]<-1||u[1]>1||l[2]<-1||u[2]>1)return!0}return!1}}(),disposeScene:function(e){this.disposeNode(e,!0,!0),e.dispose()},disposeNode:function(e,t,r){var n={};e.getParent()&&e.getParent().remove(e),e.traverse(function(e){e.geometry&&t&&e.geometry.dispose(this),e.material&&(n[e.material.__GUID__]=e.material),e.dispose&&e.dispose(this)},this);for(var i in n){n[i].dispose(this,r)}},disposeShader:function(e){e.dispose(this)},disposeGeometry:function(e){e.dispose(this)},disposeTexture:function(e){e.dispose(this)},disposeFrameBuffer:function(e){e.dispose(this)},dispose:function(){},screenToNDC:function(e,t,r){r||(r=new jt),t=this._height-t;var n=this.viewport,i=r._array;return i[0]=(e-n.x)/n.width,i[0]=2*i[0]-1,i[1]=(t-n.y)/n.height,i[1]=2*i[1]-1,r}});tr.opaqueSortFunc=tr.prototype.opaqueSortFunc=function(e,t){return e.renderOrder===t.renderOrder?e.material.shader===t.material.shader?e.material===t.material?e.geometry.__GUID__-t.geometry.__GUID__:e.material.__GUID__-t.material.__GUID__:e.material.shader.__GUID__-t.material.shader.__GUID__:e.renderOrder-t.renderOrder},tr.transparentSortFunc=tr.prototype.transparentSortFunc=function(e,t){return e.renderOrder===t.renderOrder?e.__depth===t.__depth?e.material.shader===t.material.shader?e.material===t.material?e.geometry.__GUID__-t.geometry.__GUID__:e.material.__GUID__-t.material.__GUID__:e.material.shader.__GUID__-t.material.shader.__GUID__:e.__depth-t.__depth:e.renderOrder-t.renderOrder};var rr={IDENTITY:$t(),WORLD:$t(),VIEW:$t(),PROJECTION:$t(),WORLDVIEW:$t(),VIEWPROJECTION:$t(),WORLDVIEWPROJECTION:$t(),WORLDINVERSE:$t(),VIEWINVERSE:$t(),PROJECTIONINVERSE:$t(),WORLDVIEWINVERSE:$t(),VIEWPROJECTIONINVERSE:$t(),WORLDVIEWPROJECTIONINVERSE:$t(),WORLDTRANSPOSE:$t(),VIEWTRANSPOSE:$t(),PROJECTIONTRANSPOSE:$t(),WORLDVIEWTRANSPOSE:$t(),VIEWPROJECTIONTRANSPOSE:$t(),WORLDVIEWPROJECTIONTRANSPOSE:$t(),WORLDINVERSETRANSPOSE:$t(),VIEWINVERSETRANSPOSE:$t(),PROJECTIONINVERSETRANSPOSE:$t(),WORLDVIEWINVERSETRANSPOSE:$t(),VIEWPROJECTIONINVERSETRANSPOSE:$t(),WORLDVIEWPROJECTIONINVERSETRANSPOSE:$t()};tr.COLOR_BUFFER_BIT=et.COLOR_BUFFER_BIT,tr.DEPTH_BUFFER_BIT=et.DEPTH_BUFFER_BIT,tr.STENCIL_BUFFER_BIT=et.STENCIL_BUFFER_BIT;var nr={get:f},ir=it.quat,ar=function(e,t,r,n){e=e||0,t=t||0,r=r||0,n=void 0===n?1:n,this._array=ir.fromValues(e,t,r,n),this._dirty=!0};ar.prototype={constructor:ar,add:function(e){return ir.add(this._array,this._array,e._array),this._dirty=!0,this},calculateW:function(){return ir.calculateW(this._array,this._array),this._dirty=!0,this},set:function(e,t,r,n){return this._array[0]=e,this._array[1]=t,this._array[2]=r,this._array[3]=n,this._dirty=!0,this},setArray:function(e){return this._array[0]=e[0],this._array[1]=e[1],this._array[2]=e[2],this._array[3]=e[3],this._dirty=!0,this},clone:function(){return new ar(this.x,this.y,this.z,this.w)},conjugate:function(){return ir.conjugate(this._array,this._array),this._dirty=!0,this},copy:function(e){return ir.copy(this._array,e._array),this._dirty=!0,this},dot:function(e){return ir.dot(this._array,e._array)},fromMat3:function(e){return ir.fromMat3(this._array,e._array),this._dirty=!0,this},fromMat4:function(){var e=it.mat3,t=e.create();return function(r){return e.fromMat4(t,r._array),e.transpose(t,t),ir.fromMat3(this._array,t),this._dirty=!0,this}}(),identity:function(){return ir.identity(this._array),this._dirty=!0,this},invert:function(){return ir.invert(this._array,this._array),this._dirty=!0,this},len:function(){return ir.len(this._array)},length:function(){return ir.length(this._array)},lerp:function(e,t,r){return ir.lerp(this._array,e._array,t._array,r),this._dirty=!0,this},mul:function(e){return ir.mul(this._array,this._array,e._array),this._dirty=!0,this},mulLeft:function(e){return ir.multiply(this._array,e._array,this._array),this._dirty=!0,this},multiply:function(e){return ir.multiply(this._array,this._array,e._array),this._dirty=!0,this},multiplyLeft:function(e){return ir.multiply(this._array,e._array,this._array),this._dirty=!0,this},normalize:function(){return ir.normalize(this._array,this._array),this._dirty=!0,this},rotateX:function(e){return ir.rotateX(this._array,this._array,e),this._dirty=!0,this},rotateY:function(e){return ir.rotateY(this._array,this._array,e),this._dirty=!0,this},rotateZ:function(e){return ir.rotateZ(this._array,this._array,e),this._dirty=!0,this},rotationTo:function(e,t){return ir.rotationTo(this._array,e._array,t._array),this._dirty=!0,this},setAxes:function(e,t,r){return ir.setAxes(this._array,e._array,t._array,r._array),this._dirty=!0,this},setAxisAngle:function(e,t){return ir.setAxisAngle(this._array,e._array,t),this._dirty=!0,this},slerp:function(e,t,r){return ir.slerp(this._array,e._array,t._array,r),this._dirty=!0,this},sqrLen:function(){return ir.sqrLen(this._array)},squaredLength:function(){return ir.squaredLength(this._array)},fromEuler:function(e,t){return ar.fromEuler(this,e,t)},toString:function(){return"["+Array.prototype.join.call(this._array,",")+"]"},toArray:function(){return Array.prototype.slice.call(this._array)}};var or=Object.defineProperty;if(or){var sr=ar.prototype;or(sr,"x",{get:function(){return this._array[0]},set:function(e){this._array[0]=e,this._dirty=!0}}),or(sr,"y",{get:function(){return this._array[1]},set:function(e){this._array[1]=e,this._dirty=!0}}),or(sr,"z",{get:function(){return this._array[2]},set:function(e){this._array[2]=e,this._dirty=!0}}),or(sr,"w",{get:function(){return this._array[3]},set:function(e){this._array[3]=e,this._dirty=!0}})}ar.add=function(e,t,r){return ir.add(e._array,t._array,r._array),e._dirty=!0,e},ar.set=function(e,t,r,n,i){ir.set(e._array,t,r,n,i),e._dirty=!0},ar.copy=function(e,t){return ir.copy(e._array,t._array),e._dirty=!0,e},ar.calculateW=function(e,t){return ir.calculateW(e._array,t._array),e._dirty=!0,e},ar.conjugate=function(e,t){return ir.conjugate(e._array,t._array),e._dirty=!0,e},ar.identity=function(e){return ir.identity(e._array),e._dirty=!0,e},ar.invert=function(e,t){return ir.invert(e._array,t._array),e._dirty=!0,e},ar.dot=function(e,t){return ir.dot(e._array,t._array)},ar.len=function(e){return ir.length(e._array)},ar.lerp=function(e,t,r,n){return ir.lerp(e._array,t._array,r._array,n),e._dirty=!0,e},ar.slerp=function(e,t,r,n){return ir.slerp(e._array,t._array,r._array,n),e._dirty=!0,e},ar.mul=function(e,t,r){return ir.multiply(e._array,t._array,r._array),e._dirty=!0,e},ar.multiply=ar.mul,ar.rotateX=function(e,t,r){return ir.rotateX(e._array,t._array,r),e._dirty=!0,e},ar.rotateY=function(e,t,r){return ir.rotateY(e._array,t._array,r),e._dirty=!0,e},ar.rotateZ=function(e,t,r){return ir.rotateZ(e._array,t._array,r),e._dirty=!0,e},ar.setAxisAngle=function(e,t,r){return ir.setAxisAngle(e._array,t._array,r),e._dirty=!0,e},ar.normalize=function(e,t){return ir.normalize(e._array,t._array),e._dirty=!0,e},ar.sqrLen=function(e){return ir.sqrLen(e._array)},ar.squaredLength=ar.sqrLen,ar.fromMat3=function(e,t){return ir.fromMat3(e._array,t._array),e._dirty=!0,e},ar.setAxes=function(e,t,r,n){return ir.setAxes(e._array,t._array,r._array,n._array),e._dirty=!0,e},ar.rotationTo=function(e,t,r){return ir.rotationTo(e._array,t._array,r._array),e._dirty=!0,e},ar.fromEuler=function(e,t,r){e._dirty=!0,t=t._array;var n=e._array,i=Math.cos(t[0]/2),a=Math.cos(t[1]/2),o=Math.cos(t[2]/2),s=Math.sin(t[0]/2),u=Math.sin(t[1]/2),l=Math.sin(t[2]/2),r=(r||"XYZ").toUpperCase();switch(r){case"XYZ":n[0]=s*a*o+i*u*l,n[1]=i*u*o-s*a*l,n[2]=i*a*l+s*u*o,n[3]=i*a*o-s*u*l;break;case"YXZ":n[0]=s*a*o+i*u*l,n[1]=i*u*o-s*a*l,n[2]=i*a*l-s*u*o,n[3]=i*a*o+s*u*l;break;case"ZXY":n[0]=s*a*o-i*u*l,n[1]=i*u*o+s*a*l,n[2]=i*a*l+s*u*o,n[3]=i*a*o-s*u*l;break;case"ZYX":n[0]=s*a*o-i*u*l,n[1]=i*u*o+s*a*l,n[2]=i*a*l-s*u*o,n[3]=i*a*o+s*u*l;break;case"YZX":n[0]=s*a*o+i*u*l,n[1]=i*u*o+s*a*l,n[2]=i*a*l-s*u*o,n[3]=i*a*o-s*u*l;break;case"XZY":n[0]=s*a*o-i*u*l,n[1]=i*u*o-s*a*l,n[2]=i*a*l+s*u*o,n[3]=i*a*o+s*u*l}};var ur=it.mat4,lr=0,cr=Qe.extend({name:"",position:null,rotation:null,scale:null,worldTransform:null,localTransform:null,autoUpdateLocalTransform:!0,_parent:null,_scene:null,_needsUpdateWorldTransform:!0,_inIterating:!1,__depth:0},function(){this.name||(this.name=(this.type||"NODE")+"_"+lr++),this.position||(this.position=new ot),this.rotation||(this.rotation=new ar),this.scale||(this.scale=new ot(1,1,1)),this.worldTransform=new xt,this.localTransform=new xt,this._children=[]},{target:null,invisible:!1,isSkinnedMesh:function(){return!1},isRenderable:function(){return!1},setName:function(e){var t=this._scene;if(t){var r=t._nodeRepository;delete r[this.name],r[e]=this}this.name=e},add:function(e){this._inIterating&&console.warn("Add operation can cause unpredictable error when in iterating");var t=e._parent;if(t!==this){t&&t.remove(e),e._parent=this,this._children.push(e);var r=this._scene;r&&r!==e.scene&&e.traverse(this._addSelfToScene,this),e._needsUpdateWorldTransform=!0}},remove:function(e){this._inIterating&&console.warn("Remove operation can cause unpredictable error when in iterating");var t=this._children,r=t.indexOf(e);r<0||(t.splice(r,1),e._parent=null,this._scene&&e.traverse(this._removeSelfFromScene,this))},removeAll:function(){for(var e=this._children,t=0;t0&&this._updateRenderQueue(n)}},_updateLightUniforms:function(){var e=this.lights;e.sort(d);var t=this._lightUniforms;for(var r in t)for(var n in t[r])t[r][n].value.length=0;for(var i=0;i 0.0) {\n vec3 normalTexel = texture2D(normalMap, uv).xyz;\n if (dot(normalTexel, normalTexel) > 0.0) { N = normalTexel * 2.0 - 1.0;\n tbn[1] = -tbn[1];\n N = normalize(tbn * N);\n }\n }\n#endif\n vec3 diffuseTerm = vec3(0.0, 0.0, 0.0);\n vec3 specularTerm = vec3(0.0, 0.0, 0.0);\n float ndv = clamp(dot(N, V), 0.0, 1.0);\n vec3 fresnelTerm = F_Schlick(ndv, spec);\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {{\n diffuseTerm += ambientLightColor[_idx_];\n }}\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseTerm += calcAmbientSHLight(_idx_, N) * ambientSHLightColor[_idx_];\n }}\n#endif\n#ifdef POINT_LIGHT_COUNT\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsPoint[POINT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfPointLights(v_WorldPosition, shadowContribsPoint);\n }\n#endif\n for(int _idx_ = 0; _idx_ < POINT_LIGHT_COUNT; _idx_++)\n {{\n vec3 lightPosition = pointLightPosition[_idx_];\n vec3 lc = pointLightColor[_idx_];\n float range = pointLightRange[_idx_];\n vec3 L = lightPosition - v_WorldPosition;\n float dist = length(L);\n float attenuation = lightAttenuation(dist, range);\n L /= dist;\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n if(shadowEnabled)\n {\n shadowContrib = shadowContribsPoint[_idx_];\n }\n#endif\n vec3 li = lc * ndl * attenuation * shadowContrib;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }}\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int _idx_ = 0; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++)\n {{\n vec3 L = -normalize(directionalLightDirection[_idx_]);\n vec3 lc = directionalLightColor[_idx_];\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if(shadowEnabled)\n {\n shadowContrib = shadowContribsDir[_idx_];\n }\n#endif\n vec3 li = lc * ndl * shadowContrib;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }}\n#endif\n#ifdef SPOT_LIGHT_COUNT\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsSpot[SPOT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfSpotLights(v_WorldPosition, shadowContribsSpot);\n }\n#endif\n for(int i = 0; i < SPOT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = spotLightPosition[i];\n vec3 spotLightDirection = -normalize(spotLightDirection[i]);\n vec3 lc = spotLightColor[i];\n float range = spotLightRange[i];\n float a = spotLightUmbraAngleCosine[i];\n float b = spotLightPenumbraAngleCosine[i];\n float falloffFactor = spotLightFalloffFactor[i];\n vec3 L = lightPosition - v_WorldPosition;\n float dist = length(L);\n float attenuation = lightAttenuation(dist, range);\n L /= dist;\n float c = dot(spotLightDirection, L);\n float falloff;\n falloff = clamp((c - a) /( b - a), 0.0, 1.0);\n falloff = pow(falloff, falloffFactor);\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n if (shadowEnabled)\n {\n shadowContrib = shadowContribsSpot[i];\n }\n#endif\n vec3 li = lc * attenuation * (1.0 - falloff) * shadowContrib * ndl;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }\n#endif\n vec4 outColor = albedoColor;\n outColor.rgb *= diffuseTerm;\n outColor.rgb += specularTerm;\n#ifdef AMBIENT_CUBEMAP_LIGHT_COUNT\n vec3 L = reflect(-V, N);\n float rough2 = clamp(1.0 - g, 0.0, 1.0);\n float bias2 = rough2 * 5.0;\n vec2 brdfParam2 = texture2D(ambientCubemapLightBRDFLookup[0], vec2(rough2, ndv)).xy;\n vec3 envWeight2 = spec * brdfParam2.x + brdfParam2.y;\n vec3 envTexel2;\n for(int _idx_ = 0; _idx_ < AMBIENT_CUBEMAP_LIGHT_COUNT; _idx_++)\n {{\n envTexel2 = RGBMDecode(textureCubeLodEXT(ambientCubemapLightCubemap[_idx_], L, bias2), 51.5);\n outColor.rgb += ambientCubemapLightColor[_idx_] * envTexel2 * envWeight2;\n }}\n#endif\n#ifdef ENVIRONMENTMAP_ENABLED\n vec3 envWeight = g * fresnelTerm;\n vec3 L = reflect(-V, N);\n #ifdef PARALLAX_CORRECTED\n L = parallaxCorrect(L, v_WorldPosition, environmentBoxMin, environmentBoxMax);\n #endif\n #ifdef ENVIRONMENTMAP_PREFILTER\n float rough = clamp(1.0 - g, 0.0, 1.0);\n float bias = rough * maxMipmapLevel;\n vec3 envTexel = decodeHDR(textureCubeLodEXT(environmentMap, L, bias)).rgb;\n #ifdef BRDFLOOKUP_ENABLED\n vec2 brdfParam = texture2D(brdfLookup, vec2(rough, ndv)).xy;\n envWeight = spec * brdfParam.x + brdfParam.y;\n #endif\n #else\n vec3 envTexel = textureCube(environmentMap, L).xyz;\n #endif\n outColor.rgb += envTexel * envWeight;\n#endif\n float aoFactor = 1.0;\n#ifdef SSAOMAP_ENABLED\n aoFactor = min(texture2D(ssaoMap, (gl_FragCoord.xy - viewport.xy) / viewport.zw).r, aoFactor);\n#endif\n#ifdef AOMAP_ENABLED\n aoFactor = min(1.0 - clamp((1.0 - texture2D(aoMap, v_Texcoord2).r) * aoIntensity, 0.0, 1.0), aoFactor);\n#endif\n outColor.rgb *= aoFactor;\n vec3 lEmission = emission;\n#ifdef EMISSIVEMAP_ENABLED\n lEmission *= texture2D(emissiveMap, uv).rgb;\n#endif\n outColor.rgb += lEmission * emissionIntensity;\n#ifdef GAMMA_ENCODE\n outColor.rgb = pow(outColor.rgb, vec3(1 / 2.2));\n#endif\n if(lineWidth > 0.)\n {\n outColor.rgb = mix(outColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (outColor.a < alphaCutoff) {\n discard;\n }\n#endif\n gl_FragColor = encodeHDR(outColor);\n}\n@end\n";kt.import(dr);var _r={},pr={},mr=["diffuseMap","normalMap","roughnessMap","metalnessMap","emissiveMap","environmentMap","brdfLookup","ssaoMap","aoMap"],vr=["color","emission","emissionIntensity","alpha","roughness","metalness","uvRepeat","uvOffset","aoIntensity","alphaCutoff"],gr=["jointCount","linear","encodeRGBM","decodeRGBM","doubleSided","alphaTest","roughnessChannel","metalnessChannel"],yr=["environmentMapPrefiltered","linear","encodeRGBM","decodeRGBM","doubleSided","alphaTest","parallaxCorrected"],xr=mr.concat(yr),Tr=xr.reduce(function(e,t,r){return e[t]=4096<0},beforeRender:function(e){},afterRender:function(e,t){},getBoundingBox:function(e,t){return t=cr.prototype.getBoundingBox.call(this,e,t),this.geometry&&this.geometry.boundingBox&&t.union(this.geometry.boundingBox),t},render:function(e,t){var r=e.gl,t=t||this.material.shader,n=this.geometry,i=this.mode,a=n.vertexCount,o=n.isUseIndices(),s=e.getGLExtension("OES_element_index_uint"),u=s&&a>65535,l=u?r.UNSIGNED_INT:r.UNSIGNED_SHORT,c=e.getGLExtension("OES_vertex_array_object"),h=!n.dynamic,f=this._renderInfo;f.vertexCount=a,f.triangleCount=0,f.drawCallCount=0;var d=!1;if(br=e.__GUID__+"-"+n.__GUID__+"-"+t.__GUID__,br!==Sr?d=!0:(a>65535&&!s&&o||c&&h||n._cache.isDirty())&&(d=!0),Sr=br,d){var _=this._drawCache[br];if(!_){var p=n.getBufferChunks(e);if(!p)return;_=[];for(var m=0;m>1,e|=e>>2,e|=e>>4,e|=e>>8,e|=e>>16,++e},Rr.nearestPowerOfTwo=function(e){return Math.pow(2,Math.round(Math.log(e)/Math.LN2))};var Cr=Rr.isPowerOfTwo,Lr=Wt.extend(function(){return{image:null,pixels:null,mipmaps:[]}},{update:function(e){var t=e.gl;t.bindTexture(t.TEXTURE_2D,this._cache.get("webgl_texture")),this.updateCommon(e);var r=this.format,n=this.type;t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,this.getAvailableWrapS()),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,this.getAvailableWrapT()),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,this.getAvailableMagFilter()),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,this.getAvailableMinFilter());var i=e.getGLExtension("EXT_texture_filter_anisotropic");if(i&&this.anisotropic>1&&t.texParameterf(t.TEXTURE_2D,i.TEXTURE_MAX_ANISOTROPY_EXT,this.anisotropic),36193===n){e.getGLExtension("OES_texture_half_float")||(n=et.FLOAT)}if(this.mipmaps.length)for(var a=this.width,o=this.height,s=0;s=Wt.COMPRESSED_RGB_S3TC_DXT1_EXT?e.compressedTexImage2D(e.TEXTURE_2D,r,a,n,i,0,t.pixels):e.texImage2D(e.TEXTURE_2D,r,a,n,i,0,a,o,t.pixels)},generateMipmap:function(e){var t=e.gl;this.useMipmap&&!this.NPOT&&(t.bindTexture(t.TEXTURE_2D,this._cache.get("webgl_texture")),t.generateMipmap(t.TEXTURE_2D))},isPowerOfTwo:function(){var e,t;return this.image?(e=this.image.width,t=this.image.height):(e=this.width,t=this.height),Cr(e)&&Cr(t)},isRenderable:function(){return this.image?"CANVAS"===this.image.nodeName||"VIDEO"===this.image.nodeName||this.image.complete:!(!this.width||!this.height)},bind:function(e){e.gl.bindTexture(e.gl.TEXTURE_2D,this.getWebGLTexture(e))},unbind:function(e){e.gl.bindTexture(e.gl.TEXTURE_2D,null)},load:function(e,t){var r=new Image;t&&(r.crossOrigin=t);var n=this;return r.onload=function(){n.dirty(),n.trigger("success",n),r.onload=null},r.onerror=function(){n.trigger("error",n),r.onerror=null},r.src=e,this.image=r,this}});Object.defineProperty(Lr.prototype,"width",{get:function(){return this.image?this.image.width:this._width},set:function(e){this.image?console.warn("Texture from image can't set width"):(this._width!==e&&this.dirty(),this._width=e)}}),Object.defineProperty(Lr.prototype,"height",{get:function(){return this.image?this.image.height:this._height},set:function(e){this.image?console.warn("Texture from image can't set height"):(this._height!==e&&this.dirty(),this._height=e)}});var Dr=Mr.extend({skeleton:null,joints:null,useSkinMatricesTexture:!1},function(){this.joints||(this.joints=[])},{isSkinnedMesh:function(){return!(!this.skeleton||!this.material.shader.isDefined("vertex","SKINNING"))},render:function(e,t){var r=e.gl;if(t=t||this.material.shader,this.skeleton){this.skeleton.update();var n=this.skeleton.getSubSkinMatrices(this.__GUID__,this.joints);if(this.useSkinMatricesTexture){var i,a=this.joints.length;i=a>256?64:a>64?32:a>16?16:8;var o=this.getSkinMatricesTexture();o.width=i,o.height=i,o.pixels&&o.pixels.length===i*i*4||(o.pixels=new Float32Array(i*i*4)),o.pixels.set(n),o.dirty(),t.setUniform(r,"1f","skinMatricesTextureSize",i)}else t.setUniformOfSemantic(r,"SKIN_MATRIX",n)}return Mr.prototype.render.call(this,e,t)},getSkinMatricesTexture:function(){return this._skinMatricesTexture=this._skinMatricesTexture||new Lr({type:et.FLOAT,minFilter:et.NEAREST,magFilter:et.NEAREST,useMipmap:!1,flipY:!1}),this._skinMatricesTexture}});Dr.POINTS=et.POINTS,Dr.LINES=et.LINES,Dr.LINE_LOOP=et.LINE_LOOP,Dr.LINE_STRIP=et.LINE_STRIP,Dr.TRIANGLES=et.TRIANGLES,Dr.TRIANGLE_STRIP=et.TRIANGLE_STRIP,Dr.TRIANGLE_FAN=et.TRIANGLE_FAN,Dr.BACK=et.BACK,Dr.FRONT=et.FRONT,Dr.FRONT_AND_BACK=et.FRONT_AND_BACK,Dr.CW=et.CW,Dr.CCW=et.CCW;var Pr=Qe.extend({name:"",index:-1,node:null,rootNode:null}),Ir=it.quat,Or=it.vec3,Fr=it.mat4,kr=Qe.extend(function(){return{relativeRootNode:null,name:"",joints:[],_clips:[],_invBindPoseMatricesArray:null,_jointMatricesSubArrays:[],_skinMatricesArray:null,_skinMatricesSubArrays:[],_subSkinMatricesArray:{}}},{addClip:function(e,t){for(var r=0;r0&&this._clips.splice(t,1)},removeClipsAll:function(){this._clips=[]},getClip:function(e){if(this._clips[e])return this._clips[e].clip},getClipNumber:function(){return this._clips.length},updateJointMatrices:function(){var e=Fr.create();return function(){this._invBindPoseMatricesArray=new Float32Array(16*this.joints.length),this._skinMatricesArray=new Float32Array(16*this.joints.length);for(var t=0;tthis.distance,i=1;i<8;i++)if(Br.dot(t[i]._array,r)>this.distance!=n)return!0},intersectLine:function(){var e=Br.create();return function(t,r,n){var i=this.distanceToPoint(t),a=this.distanceToPoint(r);if(i>0&&a>0||i<0&&a<0)return null;var o=this.normal._array,s=this.distance,u=t._array;Br.sub(e,r._array,t._array),Br.normalize(e,e);var l=Br.dot(o,e);if(0===l)return null;n||(n=new ot);var c=(Br.dot(o,u)-s)/l;return Br.scaleAndAdd(n._array,u,e,-c),n._dirty=!0,n}}(),applyTransform:function(){var e=Ur.create(),t=Hr.create(),r=Hr.create();return r[3]=1,function(n){n=n._array,Br.scale(r,this.normal._array,this.distance),Hr.transformMat4(r,r,n),this.distance=Br.dot(r,this.normal._array),Ur.invert(e,n),Ur.transpose(e,e),t[3]=0,Br.copy(t,this.normal._array),Hr.transformMat4(t,t,e),Br.copy(this.normal._array,t)}}(),copy:function(e){Br.copy(this.normal._array,e.normal._array),this.normal._dirty=!0,this.distance=e.distance},clone:function(){var e=new zr;return e.copy(this),e}};var Gr=it.vec3,Wr=Gr.set,qr=Gr.copy,Vr=Gr.transformMat4,jr=Math.min,Xr=Math.max,Kr=function(){this.planes=[];for(var e=0;e<6;e++)this.planes.push(new zr);this.boundingBox=new pt,this.vertices=[];for(var e=0;e<8;e++)this.vertices[e]=Gr.fromValues(0,0,0)};Kr.prototype={setFromProjection:function(e){var t=this.planes,r=e._array,n=r[0],i=r[1],a=r[2],o=r[3],s=r[4],u=r[5],l=r[6],c=r[7],h=r[8],f=r[9],d=r[10],_=r[11],p=r[12],m=r[13],v=r[14],g=r[15];Wr(t[0].normal._array,o-n,c-s,_-h),t[0].distance=-(g-p),t[0].normalize(),Wr(t[1].normal._array,o+n,c+s,_+h),t[1].distance=-(g+p),t[1].normalize(),Wr(t[2].normal._array,o+i,c+u,_+f),t[2].distance=-(g+m),t[2].normalize(),Wr(t[3].normal._array,o-i,c-u,_-f),t[3].distance=-(g-m),t[3].normalize(),Wr(t[4].normal._array,o-a,c-l,_-d),t[4].distance=-(g-v),t[4].normalize(),Wr(t[5].normal._array,o+a,c+l,_+d),t[5].distance=-(g+v),t[5].normalize();var y=this.boundingBox;if(0===g){var x=u/n,T=-v/(d-1),E=-v/(d+1),b=-E/u,S=-T/u;y.min.set(-b*x,-b,E),y.max.set(b*x,b,T);var A=this.vertices;Wr(A[0],-b*x,-b,E),Wr(A[1],-b*x,b,E),Wr(A[2],b*x,-b,E),Wr(A[3],b*x,b,E),Wr(A[4],-S*x,-S,T),Wr(A[5],-S*x,S,T),Wr(A[6],S*x,-S,T),Wr(A[7],S*x,S,T)}else{var N=(-1-p)/n,w=(1-p)/n,M=(1-m)/u,R=(-1-m)/u,C=(-1-v)/d,L=(1-v)/d;y.min.set(Math.min(N,w),Math.min(R,M),Math.min(L,C)),y.max.set(Math.max(w,N),Math.max(M,R),Math.max(C,L));var D=y.min._array,P=y.max._array,A=this.vertices;Wr(A[0],D[0],D[1],D[2]),Wr(A[1],D[0],P[1],D[2]),Wr(A[2],P[0],D[1],D[2]),Wr(A[3],P[0],P[1],D[2]),Wr(A[4],D[0],D[1],P[2]),Wr(A[5],D[0],P[1],P[2]),Wr(A[6],P[0],D[1],P[2]),Wr(A[7],P[0],P[1],P[2])}},getTransformedBoundingBox:function(){var e=Gr.create();return function(t,r){var n=this.vertices,i=r._array,a=t.min,o=t.max,s=a._array,u=o._array,l=n[0];Vr(e,l,i),qr(s,e),qr(u,e);for(var c=1;c<8;c++)l=n[c],Vr(e,l,i),s[0]=jr(e[0],s[0]),s[1]=jr(e[1],s[1]),s[2]=jr(e[2],s[2]),u[0]=Xr(e[0],u[0]),u[1]=Xr(e[1],u[1]),u[2]=Xr(e[2],u[2]);return a._dirty=!0,o._dirty=!0,t}}()};var Yr=it.vec3,Zr=function(e,t){this.origin=e||new ot,this.direction=t||new ot};Zr.prototype={constructor:Zr,intersectPlane:function(e,t){var r=e.normal._array,n=e.distance,i=this.origin._array,a=this.direction._array,o=Yr.dot(r,a);if(0===o)return null;t||(t=new ot);var s=(Yr.dot(r,i)-n)/o;return Yr.scaleAndAdd(t._array,i,a,-s),t._dirty=!0,t},mirrorAgainstPlane:function(e){var t=Yr.dot(e.normal._array,this.direction._array);Yr.scaleAndAdd(this.direction._array,this.direction._array,e.normal._array,2*-t),this.direction._dirty=!0},distanceToPoint:function(){var e=Yr.create();return function(t){Yr.sub(e,t,this.origin._array);var r=Yr.dot(e,this.direction._array);if(r<0)return Yr.distance(this.origin._array,t);var n=Yr.lenSquared(e);return Math.sqrt(n-r*r)}}(),intersectSphere:function(){var e=Yr.create();return function(t,r,n){var i=this.origin._array,a=this.direction._array;t=t._array,Yr.sub(e,t,i);var o=Yr.dot(e,a),s=Yr.squaredLength(e),u=s-o*o,l=r*r;if(!(u>l)){var c=Math.sqrt(l-u),h=o-c,f=o+c;return n||(n=new ot),h<0?f<0?null:(Yr.scaleAndAdd(n._array,i,a,f),n):(Yr.scaleAndAdd(n._array,i,a,h),n)}}}(),intersectBoundingBox:function(e,t){var r,n,i,a,o,s,u=this.direction._array,l=this.origin._array,c=e.min._array,h=e.max._array,f=1/u[0],d=1/u[1],_=1/u[2];if(f>=0?(r=(c[0]-l[0])*f,n=(h[0]-l[0])*f):(n=(c[0]-l[0])*f,r=(h[0]-l[0])*f),d>=0?(i=(c[1]-l[1])*d,a=(h[1]-l[1])*d):(a=(c[1]-l[1])*d,i=(h[1]-l[1])*d),r>a||i>n)return null;if((i>r||r!==r)&&(r=i),(a=0?(o=(c[2]-l[2])*_,s=(h[2]-l[2])*_):(s=(c[2]-l[2])*_,o=(h[2]-l[2])*_),r>s||o>n)return null;if((o>r||r!==r)&&(r=o),(s=0?r:n;return t||(t=new ot),Yr.scaleAndAdd(t._array,l,u,p),t},intersectTriangle:function(){var e=Yr.create(),t=Yr.create(),r=Yr.create(),n=Yr.create();return function(i,a,o,s,u,l){var c=this.direction._array,h=this.origin._array;i=i._array,a=a._array,o=o._array,Yr.sub(e,a,i),Yr.sub(t,o,i),Yr.cross(n,t,c);var f=Yr.dot(e,n);if(s){if(f>-1e-5)return null}else if(f>-1e-5&&f<1e-5)return null;Yr.sub(r,h,i);var d=Yr.dot(n,r)/f;if(d<0||d>1)return null;Yr.cross(n,e,r);var _=Yr.dot(c,n)/f;if(_<0||_>1||d+_>1)return null;Yr.cross(n,e,t);var p=-Yr.dot(r,n)/f;return p<0?null:(u||(u=new ot),l&&ot.set(l,1-d-_,d,_),Yr.scaleAndAdd(u._array,h,c,p),u)}}(),applyTransform:function(e){ot.add(this.direction,this.direction,this.origin),ot.transformMat4(this.origin,this.origin,e),ot.transformMat4(this.direction,this.direction,e),ot.sub(this.direction,this.direction,this.origin),ot.normalize(this.direction,this.direction)},copy:function(e){ot.copy(this.origin,e.origin),ot.copy(this.direction,e.direction)},clone:function(){var e=new Zr;return e.copy(this),e}};var Qr=it.vec3,Jr=it.vec4,$r=cr.extend(function(){return{projectionMatrix:new xt,invProjectionMatrix:new xt,viewMatrix:new xt,frustum:new Kr}},function(){this.update(!0)},{update:function(e){cr.prototype.update.call(this,e),xt.invert(this.viewMatrix,this.worldTransform),this.updateProjectionMatrix(),xt.invert(this.invProjectionMatrix,this.projectionMatrix),this.frustum.setFromProjection(this.projectionMatrix)},setViewMatrix:function(e){xt.copy(this.viewMatrix,e),xt.invert(this.worldTransform,e),this.decomposeWorldTransform()},decomposeProjectionMatrix:function(){},setProjectionMatrix:function(e){xt.copy(this.projectionMatrix,e),xt.invert(this.invProjectionMatrix,e),this.decomposeProjectionMatrix()},updateProjectionMatrix:function(){},castRay:function(){var e=Jr.create();return function(t,r){var n=void 0!==r?r:new Zr,i=t._array[0],a=t._array[1];return Jr.set(e,i,a,-1,1),Jr.transformMat4(e,e,this.invProjectionMatrix._array),Jr.transformMat4(e,e,this.worldTransform._array),Qr.scale(n.origin._array,e,1/e[3]),Jr.set(e,i,a,1,1),Jr.transformMat4(e,e,this.invProjectionMatrix._array),Jr.transformMat4(e,e,this.worldTransform._array),Qr.scale(e,e,1/e[3]),Qr.sub(n.direction._array,e,n.origin._array),Qr.normalize(n.direction._array,n.direction._array),n.direction._dirty=!0,n.origin._dirty=!0,n}}()}),en=$r.extend({fov:50,aspect:1,near:.1,far:2e3},{updateProjectionMatrix:function(){var e=this.fov/180*Math.PI;this.projectionMatrix.perspective(e,this.aspect,this.near,this.far)},decomposeProjectionMatrix:function(){var e=this.projectionMatrix._array,t=2*Math.atan(1/e[5]);this.fov=t/Math.PI*180,this.aspect=e[5]/e[0],this.near=e[14]/(e[10]-1),this.far=e[14]/(e[10]+1)},clone:function(){var e=$r.prototype.clone.call(this);return e.fov=this.fov,e.aspect=this.aspect,e.near=this.near,e.far=this.far,e}}),tn=$r.extend({left:-1,right:1,near:-1,far:1,top:1,bottom:-1},{updateProjectionMatrix:function(){this.projectionMatrix.ortho(this.left,this.right,this.bottom,this.top,this.near,this.far)},decomposeProjectionMatrix:function(){var e=this.projectionMatrix._array;this.left=(-1-e[12])/e[0],this.right=(1-e[12])/e[0],this.top=(1-e[13])/e[5],this.bottom=(-1-e[13])/e[5],this.near=-(-1-e[14])/e[10],this.far=-(1-e[14])/e[10]},clone:function(){var e=$r.prototype.clone.call(this);return e.left=this.left,e.right=this.right,e.near=this.near,e.far=this.far,e.top=this.top,e.bottom=this.bottom,e}}),rn={linear:function(e){return e},quadraticIn:function(e){return e*e},quadraticOut:function(e){return e*(2-e)},quadraticInOut:function(e){return(e*=2)<1?.5*e*e:-.5*(--e*(e-2)-1)},cubicIn:function(e){return e*e*e},cubicOut:function(e){return--e*e*e+1},cubicInOut:function(e){return(e*=2)<1?.5*e*e*e:.5*((e-=2)*e*e+2)},quarticIn:function(e){return e*e*e*e},quarticOut:function(e){return 1- --e*e*e*e},quarticInOut:function(e){return(e*=2)<1?.5*e*e*e*e:-.5*((e-=2)*e*e*e-2)},quinticIn:function(e){return e*e*e*e*e},quinticOut:function(e){return--e*e*e*e*e+1},quinticInOut:function(e){return(e*=2)<1?.5*e*e*e*e*e:.5*((e-=2)*e*e*e*e+2)},sinusoidalIn:function(e){return 1-Math.cos(e*Math.PI/2)},sinusoidalOut:function(e){return Math.sin(e*Math.PI/2)},sinusoidalInOut:function(e){return.5*(1-Math.cos(Math.PI*e))},exponentialIn:function(e){return 0===e?0:Math.pow(1024,e-1)},exponentialOut:function(e){return 1===e?1:1-Math.pow(2,-10*e)},exponentialInOut:function(e){return 0===e?0:1===e?1:(e*=2)<1?.5*Math.pow(1024,e-1):.5*(2-Math.pow(2,-10*(e-1)))},circularIn:function(e){return 1-Math.sqrt(1-e*e)},circularOut:function(e){return Math.sqrt(1- --e*e)},circularInOut:function(e){return(e*=2)<1?-.5*(Math.sqrt(1-e*e)-1):.5*(Math.sqrt(1-(e-=2)*e)+1)},elasticIn:function(e){var t,r=.1;return 0===e?0:1===e?1:(!r||r<1?(r=1,t=.1):t=.4*Math.asin(1/r)/(2*Math.PI),-r*Math.pow(2,10*(e-=1))*Math.sin((e-t)*(2*Math.PI)/.4))},elasticOut:function(e){var t,r=.1;return 0===e?0:1===e?1:(!r||r<1?(r=1,t=.1):t=.4*Math.asin(1/r)/(2*Math.PI),r*Math.pow(2,-10*e)*Math.sin((e-t)*(2*Math.PI)/.4)+1)},elasticInOut:function(e){var t,r=.1;return 0===e?0:1===e?1:(!r||r<1?(r=1,t=.1):t=.4*Math.asin(1/r)/(2*Math.PI),(e*=2)<1?r*Math.pow(2,10*(e-=1))*Math.sin((e-t)*(2*Math.PI)/.4)*-.5:r*Math.pow(2,-10*(e-=1))*Math.sin((e-t)*(2*Math.PI)/.4)*.5+1)},backIn:function(e){var t=1.70158;return e*e*((t+1)*e-t)},backOut:function(e){var t=1.70158;return--e*e*((t+1)*e+t)+1},backInOut:function(e){var t=2.5949095;return(e*=2)<1?e*e*((t+1)*e-t)*.5:.5*((e-=2)*e*((t+1)*e+t)+2)},bounceIn:function(e){return 1-rn.bounceOut(1-e)},bounceOut:function(e){return e<1/2.75?7.5625*e*e:e<2/2.75?7.5625*(e-=1.5/2.75)*e+.75:e<2.5/2.75?7.5625*(e-=2.25/2.75)*e+.9375:7.5625*(e-=2.625/2.75)*e+.984375},bounceInOut:function(e){return e<.5?.5*rn.bounceIn(2*e):.5*rn.bounceOut(2*e-1)+.5}},nn=function(e){e=e||{},this.name=e.name||"",this.target=e.target,this.life=e.life||1e3,this.delay=e.delay||0,this.gap=e.gap||0,this.playbackRate=e.playbackRate||1,this._initialized=!1,this._elapsedTime=0,this._loop=null!=e.loop&&e.loop,this.setLoop(this._loop),null!=e.easing&&this.setEasing(e.easing),this.onframe=e.onframe||g,this.onfinish=e.onfinish||g,this.onrestart=e.onrestart||g,this._paused=!1};nn.prototype={gap:0,life:0,delay:0,setLoop:function(e){this._loop=e,e&&(this._loopRemained="number"==typeof e?e:1e8)},setEasing:function(e){"string"==typeof e&&(e=rn[e]),this.easing=e},step:function(e,t,r){if(this._initialized||(this._startTime=e+this.delay,this._initialized=!0),null!=this._currentTime&&(t=e-this._currentTime),this._currentTime=e,this._paused)return"paused";if(!(e0?(this._restartInLoop(e),this._loopRemained--,"restart"):(this._needsRemove=!0,"finish"):null}}},setTime:function(e){return this.step(e+this._startTime)},restart:function(e){var t=0;e&&(this._elapse(e),t=this._elapsedTime%this.life),e=e||Date.now(),this._startTime=e-t+this.delay,this._elapsedTime=0,this._needsRemove=!1,this._paused=!1},getElapsedTime:function(){return this._elapsedTime},_restartInLoop:function(e){this._startTime=e+this.gap,this._elapsedTime=0},_elapse:function(e,t){this._elapsedTime+=t*this.playbackRate},fire:function(e,t){var r="on"+e;this[r]&&this[r](this.target,t)},clone:function(){var e=new this.constructor;return e.name=this.name,e._loop=this._loop,e._loopRemained=this._loopRemained,e.life=this.life,e.gap=this.gap,e.delay=this.delay,e},pause:function(){this._paused=!0},resume:function(){this._paused=!1}},nn.prototype.constructor=nn;var an=it.quat,on=it.vec3,sn=function(e){e=e||{},nn.call(this,e),this.tracks=e.tracks||[]};sn.prototype=Object.create(nn.prototype),sn.prototype.constructor=sn,sn.prototype.step=function(e,t,r){var n=nn.prototype.step.call(this,e,t,!0);if("finish"!==n){var e=this.getElapsedTime();this._range&&(e=this._range[0]+e),this.setTime(e)}return r||"paused"===n||this.fire("frame"),n},sn.prototype.setRange=function(e){this.calcLifeFromTracks(),this._range=e,e&&(e[1]=Math.min(e[1],this.life),e[0]=Math.min(e[0],this.life),this.life=e[1]-e[0])},sn.prototype.setTime=function(e){for(var t=0;t=0&&this.tracks.splice(t,1)},sn.prototype.getSubClip=function(e,t,r){for(var n=new sn({name:this.name}),i=0;i=e.time)return this.keyFrames.splice(t,0,e),t}this.life=e.time,this.keyFrames.push(e)},cn.prototype.addKeyFrames=function(e){for(var t=0;ti[i.length-1].time)){if(e=a-1?a-1:this._cacheKey+1,s=o;s>=0;s--)if(i[s].time<=e&&i[s][t])r=i[s],this._cacheKey=s,this._cacheTime=e;else if(i[s][t]){n=i[s];break}}else for(var s=this._cacheKey;s=t.time[r-1])e=t.time[r-1],n=r-2;else if(e=0;a--)if(t.time[a-1]<=e&&t.time[a]>e){n=a-1;break}}else for(var a=this._cacheKey;ae){n=a;break}if(n>-1){this._cacheKey=n,this._cacheTime=e;var o=n,s=n+1,u=t.time[o],l=t.time[s],c=l-u,h=0===c?0:(e-u)/c;t.rotation&&T(this.rotation,t.rotation,t.rotation,h,4*o,4*s),t.position&&x(this.position,t.position,t.position,h,3*o,3*s),t.scale&&x(this.scale,t.scale,t.scale,h,3*o,3*s)}n==r-2&&(this._cacheKey=0,this._cacheTime=0),this.updateTarget()}},dn.prototype.updateTarget=function(){var e=this.channels;this.target&&(e.position&&this.target.position.setArray(this.position),e.rotation&&this.target.rotation.setArray(this.rotation),e.scale&&this.target.scale.setArray(this.scale))},dn.prototype.getMaxTime=function(){return this.channels.time[this.channels.time.length-1]},dn.prototype.getSubTrack=function(e,t){var r=new dn({name:this.name}),n=this.channels.time[0];e=Math.min(Math.max(e,n),this.life),t=Math.min(Math.max(t,n),this.life);var i=this._findRange(e),a=this._findRange(t),o=a[0]-i[0]+1;0===i[1]&&0===a[1]&&(o-=1),this.channels.rotation&&(r.channels.rotation=new Float32Array(4*o)),this.channels.position&&(r.channels.position=new Float32Array(3*o)),this.channels.scale&&(r.channels.scale=new Float32Array(3*o)),this.channels.time&&(r.channels.time=new Float32Array(o)),this.setTime(e);for(var s=0;s<3;s++)r.channels.rotation[s]=this.rotation[s],r.channels.position[s]=this.position[s],r.channels.scale[s]=this.scale[s];r.channels.time[0]=0,r.channels.rotation[3]=this.rotation[3];for(var s=1;se&&(n=i);var a=0;if(n>=0)var o=t.time[n],s=t.time[n+1],a=(e-o)/(s-o);return[n,a]},dn.prototype.blend1D=cn.prototype.blend1D,dn.prototype.blend2D=cn.prototype.blend2D,dn.prototype.additiveBlend=cn.prototype.additiveBlend,dn.prototype.subtractiveBlend=cn.prototype.subtractiveBlend,dn.prototype.clone=function(){var e=dn.prototype.clone.call(this);return e.channels={time:this.channels.time||null,position:this.channels.position||null,rotation:this.channels.rotation||null,scale:this.channels.scale||null},fn.copy(e.position,this.position),hn.copy(e.rotation,this.rotation),fn.copy(e.scale,this.scale),e.target=this.target,e.updateTarget(),e};var _n=it.vec3,pn=it.mat4,mn=_n.create,vn=_n.add,gn=_n.set;S.prototype.init=function(e){if(!this.value||this.value.length!=e*this.size){var t=E(this.type);this.value=new t(e*this.size)}},S.prototype.fromArray=function(e){var t,r=E(this.type);if(e[0]&&e[0].length){var n=0,i=this.size;t=new r(e.length*i);for(var a=0;aa[0]&&(a[0]=s),u>a[1]&&(a[1]=u),l>a[2]&&(a[2]=l)}r._dirty=!0,n._dirty=!0}},dirty:function(){for(var e=this.getEnabledAttributes(),t=0;t=0){t||(t=mn());var r=this.indices;return t[0]=r[3*e],t[1]=r[3*e+1],t[2]=r[3*e+2],t}},setTriangleIndices:function(e,t){var r=this.indices;r[3*e]=t[0],r[3*e+1]=t[1],r[3*e+2]=t[2]},isUseIndices:function(){return!!this.indices},initIndicesFromArray:function(e){var t,r=this.vertexCount>65535?nt.Uint32Array:nt.Uint16Array;if(e[0]&&e[0].length){var n=0;t=new r(3*e.length);for(var i=0;i=0&&(t.splice(r,1),delete this.attributes[e],!0)},getAttribute:function(e){return this.attribute[e]},getEnabledAttributes:function(){var e=this._enabledAttributes,t=this._attributeList;if(e)return e;for(var r=[],n=this.vertexCount,i=0;i65535&&(this.indices=new nt.Uint32Array(this.indices));for(var e=this.attributes,t=this.indices,r=this.getEnabledAttributes(),n={},i=0;i 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.y) * weight.y;\n}\nif (weight.z > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.z) * weight.z;\n}\nfloat weightW = 1.0-weight.x-weight.y-weight.z;\nif (weightW > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.w) * weightW;\n}\n@end\n@export qtek.util.parallax_correct\nvec3 parallaxCorrect(in vec3 dir, in vec3 pos, in vec3 boxMin, in vec3 boxMax) {\n vec3 first = (boxMax - pos) / dir;\n vec3 second = (boxMin - pos) / dir;\n vec3 further = max(first, second);\n float dist = min(further.x, min(further.y, further.z));\n vec3 fixedPos = pos + dir * dist;\n vec3 boxCenter = (boxMax + boxMin) * 0.5;\n return normalize(fixedPos - boxCenter);\n}\n@end\n@export qtek.util.clamp_sample\nvec4 clampSample(const in sampler2D texture, const in vec2 coord)\n{\n#ifdef STEREO\n float eye = step(0.5, coord.x) * 0.5;\n vec2 coordClamped = clamp(coord, vec2(eye, 0.0), vec2(0.5 + eye, 1.0));\n#else\n vec2 coordClamped = clamp(coord, vec2(0.0), vec2(1.0));\n#endif\n return texture2D(texture, coordClamped);\n}\n@end"),kt.import(xn),kt.import("\n@export qtek.lambert.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\nattribute vec3 normal : NORMAL;\nattribute vec3 barycentric;\n@import qtek.chunk.skinning_header\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nvarying vec3 v_Barycentric;\nvoid main()\n{\n vec3 skinnedPosition = position;\n vec3 skinnedNormal = normal;\n#ifdef SKINNING\n @import qtek.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4( skinnedPosition, 1.0 );\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_Normal = normalize( ( worldInverseTranspose * vec4(skinnedNormal, 0.0) ).xyz );\n v_WorldPosition = ( world * vec4( skinnedPosition, 1.0) ).xyz;\n v_Barycentric = barycentric;\n}\n@end\n@export qtek.lambert.fragment\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nuniform sampler2D diffuseMap;\nuniform sampler2D alphaMap;\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\nvarying vec3 v_Barycentric;\n#ifdef AMBIENT_LIGHT_COUNT\n@import qtek.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import qtek.header.ambient_sh_light\n#endif\n#ifdef POINT_LIGHT_COUNT\n@import qtek.header.point_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import qtek.header.directional_light\n#endif\n#ifdef SPOT_LIGHT_COUNT\n@import qtek.header.spot_light\n#endif\n@import qtek.util.calculate_attenuation\n@import qtek.util.edge_factor\n@import qtek.util.rgbm\n@import qtek.plugin.compute_shadow_map\nvoid main()\n{\n#ifdef RENDER_NORMAL\n gl_FragColor = vec4(v_Normal * 0.5 + 0.5, 1.0);\n return;\n#endif\n#ifdef RENDER_TEXCOORD\n gl_FragColor = vec4(v_Texcoord, 1.0, 1.0);\n return;\n#endif\n gl_FragColor = vec4(color, alpha);\n#ifdef DIFFUSEMAP_ENABLED\n vec4 tex = texture2D( diffuseMap, v_Texcoord );\n#ifdef SRGB_DECODE\n tex.rgb = pow(tex.rgb, vec3(2.2));\n#endif\n gl_FragColor.rgb *= tex.rgb;\n#ifdef DIFFUSEMAP_ALPHA_ALPHA\n gl_FragColor.a *= tex.a;\n#endif\n#endif\n vec3 diffuseColor = vec3(0.0, 0.0, 0.0);\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {\n diffuseColor += ambientLightColor[_idx_];\n }\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseColor += calcAmbientSHLight(_idx_, v_Normal) * ambientSHLightColor[_idx_];\n }}\n#endif\n#ifdef POINT_LIGHT_COUNT\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsPoint[POINT_LIGHT_COUNT];\n if( shadowEnabled )\n {\n computeShadowOfPointLights(v_WorldPosition, shadowContribsPoint);\n }\n#endif\n for(int i = 0; i < POINT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = pointLightPosition[i];\n vec3 lightColor = pointLightColor[i];\n float range = pointLightRange[i];\n vec3 lightDirection = lightPosition - v_WorldPosition;\n float dist = length(lightDirection);\n float attenuation = lightAttenuation(dist, range);\n lightDirection /= dist;\n float ndl = dot( v_Normal, lightDirection );\n float shadowContrib = 1.0;\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsPoint[i];\n }\n#endif\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * attenuation * shadowContrib;\n }\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++)\n {\n vec3 lightDirection = -directionalLightDirection[i];\n vec3 lightColor = directionalLightColor[i];\n float ndl = dot(v_Normal, normalize(lightDirection));\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsDir[i];\n }\n#endif\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * shadowContrib;\n }\n#endif\n#ifdef SPOT_LIGHT_COUNT\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsSpot[SPOT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfSpotLights(v_WorldPosition, shadowContribsSpot);\n }\n#endif\n for(int i = 0; i < SPOT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = -spotLightPosition[i];\n vec3 spotLightDirection = -normalize( spotLightDirection[i] );\n vec3 lightColor = spotLightColor[i];\n float range = spotLightRange[i];\n float a = spotLightUmbraAngleCosine[i];\n float b = spotLightPenumbraAngleCosine[i];\n float falloffFactor = spotLightFalloffFactor[i];\n vec3 lightDirection = lightPosition - v_WorldPosition;\n float dist = length(lightDirection);\n float attenuation = lightAttenuation(dist, range);\n lightDirection /= dist;\n float c = dot(spotLightDirection, lightDirection);\n float falloff;\n falloff = clamp((c - a) /( b - a), 0.0, 1.0);\n falloff = pow(falloff, falloffFactor);\n float ndl = dot(v_Normal, lightDirection);\n ndl = clamp(ndl, 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsSpot[i];\n }\n#endif\n diffuseColor += lightColor * ndl * attenuation * (1.0-falloff) * shadowContrib;\n }\n#endif\n gl_FragColor.rgb *= diffuseColor;\n gl_FragColor.rgb += emission;\n if(lineWidth > 0.)\n {\n gl_FragColor.rgb = mix(gl_FragColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (gl_FragColor.a < alphaCutoff) {\n discard;\n }\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n}\n@end"),kt.import(dr),kt.import("@export qtek.wireframe.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 world : WORLD;\nattribute vec3 position : POSITION;\nattribute vec3 barycentric;\n@import qtek.chunk.skinning_header\nvarying vec3 v_Barycentric;\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import qtek.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0 );\n v_Barycentric = barycentric;\n}\n@end\n@export qtek.wireframe.fragment\nuniform vec3 color : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\nuniform float lineWidth : 1.0;\nvarying vec3 v_Barycentric;\n@import qtek.util.edge_factor\nvoid main()\n{\n gl_FragColor.rgb = color;\n gl_FragColor.a = (1.0-edgeFactor(lineWidth)) * alpha;\n}\n@end"),kt.import(Tn),kt.import(Zt),Gt.template("qtek.basic",kt.source("qtek.basic.vertex"),kt.source("qtek.basic.fragment")),Gt.template("qtek.lambert",kt.source("qtek.lambert.vertex"),kt.source("qtek.lambert.fragment")),Gt.template("qtek.wireframe",kt.source("qtek.wireframe.vertex"),kt.source("qtek.wireframe.fragment")),Gt.template("qtek.skybox",kt.source("qtek.skybox.vertex"),kt.source("qtek.skybox.fragment")),Gt.template("qtek.prez",kt.source("qtek.prez.vertex"),kt.source("qtek.prez.fragment")),Gt.template("qtek.standard",kt.source("qtek.standard.vertex"),kt.source("qtek.standard.fragment")),kt.import("@export qtek.compositor.coloradjust\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float brightness : 0.0;\nuniform float contrast : 1.0;\nuniform float exposure : 0.0;\nuniform float gamma : 1.0;\nuniform float saturation : 1.0;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = clamp(tex.rgb + vec3(brightness), 0.0, 1.0);\n color = clamp( (color-vec3(0.5))*contrast+vec3(0.5), 0.0, 1.0);\n color = clamp( color * pow(2.0, exposure), 0.0, 1.0);\n color = clamp( pow(color, vec3(gamma)), 0.0, 1.0);\n float luminance = dot( color, w );\n color = mix(vec3(luminance), color, saturation);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export qtek.compositor.brightness\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float brightness : 0.0;\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = tex.rgb + vec3(brightness);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export qtek.compositor.contrast\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float contrast : 1.0;\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = (tex.rgb-vec3(0.5))*contrast+vec3(0.5);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export qtek.compositor.exposure\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float exposure : 0.0;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = tex.rgb * pow(2.0, exposure);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export qtek.compositor.gamma\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float gamma : 1.0;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = pow(tex.rgb, vec3(gamma));\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export qtek.compositor.saturation\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float saturation : 1.0;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = tex.rgb;\n float luminance = dot(color, w);\n color = mix(vec3(luminance), color, saturation);\n gl_FragColor = vec4(color, tex.a);\n}\n@end"),kt.import(En), -kt.import("@export qtek.compositor.hdr.log_lum\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\n@import qtek.util.rgbm\nvoid main()\n{\n vec4 tex = decodeHDR(texture2D(texture, v_Texcoord));\n float luminance = dot(tex.rgb, w);\n luminance = log(luminance + 0.001);\n gl_FragColor = encodeHDR(vec4(vec3(luminance), 1.0));\n}\n@end\n@export qtek.compositor.hdr.lum_adaption\nvarying vec2 v_Texcoord;\nuniform sampler2D adaptedLum;\nuniform sampler2D currentLum;\nuniform float frameTime : 0.02;\n@import qtek.util.rgbm\nvoid main()\n{\n float fAdaptedLum = decodeHDR(texture2D(adaptedLum, vec2(0.5, 0.5))).r;\n float fCurrentLum = exp(encodeHDR(texture2D(currentLum, vec2(0.5, 0.5))).r);\n fAdaptedLum += (fCurrentLum - fAdaptedLum) * (1.0 - pow(0.98, 30.0 * frameTime));\n gl_FragColor = encodeHDR(vec4(vec3(fAdaptedLum), 1.0));\n}\n@end\n@export qtek.compositor.lum\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord );\n float luminance = dot(tex.rgb, w);\n gl_FragColor = vec4(vec3(luminance), 1.0);\n}\n@end"),kt.import("\n@export qtek.compositor.lut\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform sampler2D lookup;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n float blueColor = tex.b * 63.0;\n vec2 quad1;\n quad1.y = floor(floor(blueColor) / 8.0);\n quad1.x = floor(blueColor) - (quad1.y * 8.0);\n vec2 quad2;\n quad2.y = floor(ceil(blueColor) / 8.0);\n quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n vec2 texPos1;\n texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.r);\n texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.g);\n vec2 texPos2;\n texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.r);\n texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.g);\n vec4 newColor1 = texture2D(lookup, texPos1);\n vec4 newColor2 = texture2D(lookup, texPos2);\n vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n gl_FragColor = vec4(newColor.rgb, tex.w);\n}\n@end"),kt.import("@export qtek.compositor.vignette\n#define OUTPUT_ALPHA\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float darkness: 1;\nuniform float offset: 1;\n@import qtek.util.rgbm\nvoid main()\n{\n vec4 texel = decodeHDR(texture2D(texture, v_Texcoord));\n gl_FragColor.rgb = texel.rgb;\n vec2 uv = (v_Texcoord - vec2(0.5)) * vec2(offset);\n gl_FragColor = encodeHDR(vec4(mix(texel.rgb, vec3(1.0 - darkness), dot(uv, uv)), texel.a));\n}\n@end"),kt.import(bn),kt.import(Sn),kt.import(An),kt.import(Nn),kt.import(wn),kt.import("@export qtek.compositor.dof.coc\nuniform sampler2D depth;\nuniform float zNear: 0.1;\nuniform float zFar: 2000;\nuniform float focalDist: 3;\nuniform float focalRange: 1;\nuniform float focalLength: 30;\nuniform float fstop: 2.8;\nvarying vec2 v_Texcoord;\n@import qtek.util.encode_float\nvoid main()\n{\n float z = texture2D(depth, v_Texcoord).r * 2.0 - 1.0;\n float dist = 2.0 * zNear * zFar / (zFar + zNear - z * (zFar - zNear));\n float aperture = focalLength / fstop;\n float coc;\n float uppper = focalDist + focalRange;\n float lower = focalDist - focalRange;\n if (dist <= uppper && dist >= lower) {\n coc = 0.5;\n }\n else {\n float focalAdjusted = dist > uppper ? uppper : lower;\n coc = abs(aperture * (focalLength * (dist - focalAdjusted)) / (dist * (focalAdjusted - focalLength)));\n coc = clamp(coc, 0.0, 0.4) / 0.4000001;\n if (dist < lower) {\n coc = -coc;\n }\n coc = coc * 0.5 + 0.5;\n }\n gl_FragColor = encodeFloat(coc);\n}\n@end\n@export qtek.compositor.dof.premultiply\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\n@import qtek.util.decode_float\nvoid main() {\n float fCoc = max(abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0), 0.1);\n gl_FragColor = encodeHDR(\n vec4(decodeHDR(texture2D(texture, v_Texcoord)).rgb * fCoc, 1.0)\n );\n}\n@end\n@export qtek.compositor.dof.min_coc\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform vec2 textureSize : [512.0, 512.0];\n@import qtek.util.float\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zy)));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.xw)));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zw)));\n gl_FragColor = encodeFloat(fCoc);\n}\n@end\n@export qtek.compositor.dof.max_coc\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform vec2 textureSize : [512.0, 512.0];\n@import qtek.util.float\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zy)));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.xw)));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zw)));\n gl_FragColor = encodeFloat(fCoc);\n}\n@end\n@export qtek.compositor.dof.coc_upsample\n#define HIGH_QUALITY\nuniform sampler2D coc;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import qtek.util.float\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n float s;\n s = decodeFloat(texture2D(coc, v_Texcoord - d.xy));\n s += decodeFloat(texture2D(coc, v_Texcoord - d.wy)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord - d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zw)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord )) * 4.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xw)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.wy)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n gl_FragColor = encodeFloat(s / 16.0);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n float s;\n s = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xw));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zw));\n gl_FragColor = encodeFloat(s / 4.0);\n#endif\n}\n@end\n@export qtek.compositor.dof.upsample\n#define HIGH_QUALITY\nuniform sampler2D coc;\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\n@import qtek.util.decode_float\nfloat tap(vec2 uv, inout vec4 color, float baseWeight) {\n float weight = abs(decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0) * baseWeight;\n color += decodeHDR(texture2D(texture, uv)) * weight;\n return weight;\n}\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n vec4 color = vec4(0.0);\n float baseWeight = 1.0 / 16.0;\n float w = tap(v_Texcoord - d.xy, color, baseWeight);\n w += tap(v_Texcoord - d.wy, color, baseWeight * 2.0);\n w += tap(v_Texcoord - d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.zw, color, baseWeight * 2.0);\n w += tap(v_Texcoord , color, baseWeight * 4.0);\n w += tap(v_Texcoord + d.xw, color, baseWeight * 2.0);\n w += tap(v_Texcoord + d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.wy, color, baseWeight * 2.0);\n w += tap(v_Texcoord + d.xy, color, baseWeight);\n gl_FragColor = encodeHDR(color / w);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n vec4 color = vec4(0.0);\n float baseWeight = 1.0 / 4.0;\n float w = tap(v_Texcoord + d.xy, color, baseWeight);\n w += tap(v_Texcoord + d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.xw, color, baseWeight);\n w += tap(v_Texcoord + d.zw, color, baseWeight);\n gl_FragColor = encodeHDR(color / w);\n#endif\n}\n@end\n@export qtek.compositor.dof.downsample\nuniform sampler2D texture;\nuniform sampler2D coc;\nuniform vec2 textureSize : [512, 512];\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\n@import qtek.util.decode_float\nfloat tap(vec2 uv, inout vec4 color) {\n float weight = abs(decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0) * 0.25;\n color += decodeHDR(texture2D(texture, uv)) * weight;\n return weight;\n}\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n vec4 color = vec4(0.0);\n float weight = tap(v_Texcoord + d.xy, color);\n weight += tap(v_Texcoord + d.zy, color);\n weight += tap(v_Texcoord + d.xw, color);\n weight += tap(v_Texcoord + d.zw, color);\n color /= weight;\n gl_FragColor = encodeHDR(color);\n}\n@end\n@export qtek.compositor.dof.hexagonal_blur_frag\n@import qtek.util.float\nvec4 doBlur(sampler2D targetTexture, vec2 offset) {\n#ifdef BLUR_COC\n float cocSum = 0.0;\n#else\n vec4 color = vec4(0.0);\n#endif\n float weightSum = 0.0;\n float kernelWeight = 1.0 / float(KERNEL_SIZE);\n for (int i = 0; i < KERNEL_SIZE; i++) {\n vec2 coord = v_Texcoord + offset * float(i);\n float w = kernelWeight;\n#ifdef BLUR_COC\n float fCoc = decodeFloat(texture2D(targetTexture, coord)) * 2.0 - 1.0;\n cocSum += clamp(fCoc, -1.0, 0.0) * w;\n#else\n float fCoc = decodeFloat(texture2D(coc, coord)) * 2.0 - 1.0;\n vec4 texel = texture2D(targetTexture, coord);\n #if !defined(BLUR_NEARFIELD)\n w *= abs(fCoc);\n #endif\n color += decodeHDR(texel) * w;\n#endif\n weightSum += w;\n }\n#ifdef BLUR_COC\n return encodeFloat(clamp(cocSum / weightSum, -1.0, 0.0) * 0.5 + 0.5);\n#else\n return color / weightSum;\n#endif\n}\n@end\n@export qtek.compositor.dof.hexagonal_blur_1\n#define KERNEL_SIZE 5\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import qtek.util.rgbm\n@import qtek.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n gl_FragColor = doBlur(texture, vec2(0.0, offset.y));\n#if !defined(BLUR_COC)\n gl_FragColor = encodeHDR(gl_FragColor);\n#endif\n}\n@end\n@export qtek.compositor.dof.hexagonal_blur_2\n#define KERNEL_SIZE 5\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import qtek.util.rgbm\n@import qtek.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n offset.y /= 2.0;\n gl_FragColor = doBlur(texture, -offset);\n#if !defined(BLUR_COC)\n gl_FragColor = encodeHDR(gl_FragColor);\n#endif\n}\n@end\n@export qtek.compositor.dof.hexagonal_blur_3\n#define KERNEL_SIZE 5\nuniform sampler2D texture1;\nuniform sampler2D texture2;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import qtek.util.rgbm\n@import qtek.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n offset.y /= 2.0;\n vec2 vDownRight = vec2(offset.x, -offset.y);\n vec4 texel1 = doBlur(texture1, -offset);\n vec4 texel2 = doBlur(texture1, vDownRight);\n vec4 texel3 = doBlur(texture2, vDownRight);\n#ifdef BLUR_COC\n float coc1 = decodeFloat(texel1) * 2.0 - 1.0;\n float coc2 = decodeFloat(texel2) * 2.0 - 1.0;\n float coc3 = decodeFloat(texel3) * 2.0 - 1.0;\n gl_FragColor = encodeFloat(\n ((coc1 + coc2 + coc3) / 3.0) * 0.5 + 0.5\n );\n#else\n vec4 color = (texel1 + texel2 + texel3) / 3.0;\n gl_FragColor = encodeHDR(color);\n#endif\n}\n@end\n@export qtek.compositor.dof.composite\n#define DEBUG 0\nuniform sampler2D original;\nuniform sampler2D blurred;\nuniform sampler2D nearfield;\nuniform sampler2D coc;\nuniform sampler2D nearcoc;\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\n@import qtek.util.float\nvoid main()\n{\n vec4 blurredColor = decodeHDR(texture2D(blurred, v_Texcoord));\n vec4 originalColor = decodeHDR(texture2D(original, v_Texcoord));\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord));\n fCoc = abs(fCoc * 2.0 - 1.0);\n float weight = smoothstep(0.0, 1.0, fCoc);\n#ifdef NEARFIELD_ENABLED\n vec4 nearfieldColor = decodeHDR(texture2D(nearfield, v_Texcoord));\n float fNearCoc = decodeFloat(texture2D(nearcoc, v_Texcoord));\n fNearCoc = abs(fNearCoc * 2.0 - 1.0);\n gl_FragColor = encodeHDR(\n mix(\n nearfieldColor, mix(originalColor, blurredColor, weight),\n pow(1.0 - fNearCoc, 4.0)\n )\n );\n#else\n gl_FragColor = encodeHDR(mix(originalColor, blurredColor, weight));\n#endif\n#if DEBUG == 1\n gl_FragColor = vec4(vec3(fCoc), 1.0);\n#elif DEBUG == 2\n gl_FragColor = vec4(vec3(fNearCoc), 1.0);\n#elif DEBUG == 3\n gl_FragColor = encodeHDR(blurredColor);\n#elif DEBUG == 4\n gl_FragColor = encodeHDR(nearfieldColor);\n#endif\n}\n@end"),kt.import("@export qtek.compositor.lensflare\n#define SAMPLE_NUMBER 8\nuniform sampler2D texture;\nuniform sampler2D lenscolor;\nuniform vec2 textureSize : [512, 512];\nuniform float dispersal : 0.3;\nuniform float haloWidth : 0.4;\nuniform float distortion : 1.0;\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\nvec4 textureDistorted(\n in vec2 texcoord,\n in vec2 direction,\n in vec3 distortion\n) {\n return vec4(\n decodeHDR(texture2D(texture, texcoord + direction * distortion.r)).r,\n decodeHDR(texture2D(texture, texcoord + direction * distortion.g)).g,\n decodeHDR(texture2D(texture, texcoord + direction * distortion.b)).b,\n 1.0\n );\n}\nvoid main()\n{\n vec2 texcoord = -v_Texcoord + vec2(1.0); vec2 textureOffset = 1.0 / textureSize;\n vec2 ghostVec = (vec2(0.5) - texcoord) * dispersal;\n vec2 haloVec = normalize(ghostVec) * haloWidth;\n vec3 distortion = vec3(-textureOffset.x * distortion, 0.0, textureOffset.x * distortion);\n vec4 result = vec4(0.0);\n for (int i = 0; i < SAMPLE_NUMBER; i++)\n {\n vec2 offset = fract(texcoord + ghostVec * float(i));\n float weight = length(vec2(0.5) - offset) / length(vec2(0.5));\n weight = pow(1.0 - weight, 10.0);\n result += textureDistorted(offset, normalize(ghostVec), distortion) * weight;\n }\n result *= texture2D(lenscolor, vec2(length(vec2(0.5) - texcoord)) / length(vec2(0.5)));\n float weight = length(vec2(0.5) - fract(texcoord + haloVec)) / length(vec2(0.5));\n weight = pow(1.0 - weight, 10.0);\n vec2 offset = fract(texcoord + haloVec);\n result += textureDistorted(offset, normalize(ghostVec), distortion) * weight;\n gl_FragColor = result;\n}\n@end"),kt.import(Mn),kt.import(Rn),kt.import("@export qtek.compositor.fxaa3\nuniform sampler2D texture;\nuniform vec4 viewport : VIEWPORT;\nuniform float subpixel: 0.75;\nuniform float edgeThreshold: 0.125;\nuniform float edgeThresholdMin: 0.0625;\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\nfloat FxaaLuma(vec4 rgba) { return rgba.y; }\nvec4 FxaaPixelShader(\n vec2 pos\n ,sampler2D tex\n ,vec2 fxaaQualityRcpFrame\n ,float fxaaQualitySubpix\n ,float fxaaQualityEdgeThreshold\n ,float fxaaQualityEdgeThresholdMin\n) {\n vec2 posM;\n posM.x = pos.x;\n posM.y = pos.y;\n vec4 rgbyM = decodeHDR(texture2D(texture, posM, 0.0));\n float lumaS = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 0.0, 1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaE = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 1.0, 0.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaN = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 0.0,-1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaW = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2(-1.0, 0.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float maxSM = max(lumaS, rgbyM.y);\n float minSM = min(lumaS, rgbyM.y);\n float maxESM = max(lumaE, maxSM);\n float minESM = min(lumaE, minSM);\n float maxWN = max(lumaN, lumaW);\n float minWN = min(lumaN, lumaW);\n float rangeMax = max(maxWN, maxESM);\n float rangeMin = min(minWN, minESM);\n float rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold;\n float range = rangeMax - rangeMin;\n float rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled);\n bool earlyExit = range < rangeMaxClamped;\n if(earlyExit) return rgbyM;\n float lumaNW = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2(-1.0,-1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaSE = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 1.0, 1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaNE = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 1.0,-1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaSW = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2(-1.0, 1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaNS = lumaN + lumaS;\n float lumaWE = lumaW + lumaE;\n float subpixRcpRange = 1.0/range;\n float subpixNSWE = lumaNS + lumaWE;\n float edgeHorz1 = (-2.0 * rgbyM.y) + lumaNS;\n float edgeVert1 = (-2.0 * rgbyM.y) + lumaWE;\n float lumaNESE = lumaNE + lumaSE;\n float lumaNWNE = lumaNW + lumaNE;\n float edgeHorz2 = (-2.0 * lumaE) + lumaNESE;\n float edgeVert2 = (-2.0 * lumaN) + lumaNWNE;\n float lumaNWSW = lumaNW + lumaSW;\n float lumaSWSE = lumaSW + lumaSE;\n float edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2);\n float edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2);\n float edgeHorz3 = (-2.0 * lumaW) + lumaNWSW;\n float edgeVert3 = (-2.0 * lumaS) + lumaSWSE;\n float edgeHorz = abs(edgeHorz3) + edgeHorz4;\n float edgeVert = abs(edgeVert3) + edgeVert4;\n float subpixNWSWNESE = lumaNWSW + lumaNESE;\n float lengthSign = fxaaQualityRcpFrame.x;\n bool horzSpan = edgeHorz >= edgeVert;\n float subpixA = subpixNSWE * 2.0 + subpixNWSWNESE;\n if(!horzSpan) lumaN = lumaW;\n if(!horzSpan) lumaS = lumaE;\n if(horzSpan) lengthSign = fxaaQualityRcpFrame.y;\n float subpixB = (subpixA * (1.0/12.0)) - rgbyM.y;\n float gradientN = lumaN - rgbyM.y;\n float gradientS = lumaS - rgbyM.y;\n float lumaNN = lumaN + rgbyM.y;\n float lumaSS = lumaS + rgbyM.y;\n bool pairN = abs(gradientN) >= abs(gradientS);\n float gradient = max(abs(gradientN), abs(gradientS));\n if(pairN) lengthSign = -lengthSign;\n float subpixC = clamp(abs(subpixB) * subpixRcpRange, 0.0, 1.0);\n vec2 posB;\n posB.x = posM.x;\n posB.y = posM.y;\n vec2 offNP;\n offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;\n offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;\n if(!horzSpan) posB.x += lengthSign * 0.5;\n if( horzSpan) posB.y += lengthSign * 0.5;\n vec2 posN;\n posN.x = posB.x - offNP.x * 1.0;\n posN.y = posB.y - offNP.y * 1.0;\n vec2 posP;\n posP.x = posB.x + offNP.x * 1.0;\n posP.y = posB.y + offNP.y * 1.0;\n float subpixD = ((-2.0)*subpixC) + 3.0;\n float lumaEndN = FxaaLuma(decodeHDR(texture2D(texture, posN, 0.0)));\n float subpixE = subpixC * subpixC;\n float lumaEndP = FxaaLuma(decodeHDR(texture2D(texture, posP, 0.0)));\n if(!pairN) lumaNN = lumaSS;\n float gradientScaled = gradient * 1.0/4.0;\n float lumaMM = rgbyM.y - lumaNN * 0.5;\n float subpixF = subpixD * subpixE;\n bool lumaMLTZero = lumaMM < 0.0;\n lumaEndN -= lumaNN * 0.5;\n lumaEndP -= lumaNN * 0.5;\n bool doneN = abs(lumaEndN) >= gradientScaled;\n bool doneP = abs(lumaEndP) >= gradientScaled;\n if(!doneN) posN.x -= offNP.x * 1.5;\n if(!doneN) posN.y -= offNP.y * 1.5;\n bool doneNP = (!doneN) || (!doneP);\n if(!doneP) posP.x += offNP.x * 1.5;\n if(!doneP) posP.y += offNP.y * 1.5;\n if(doneNP) {\n if(!doneN) lumaEndN = FxaaLuma(decodeHDR(texture2D(texture, posN.xy, 0.0)));\n if(!doneP) lumaEndP = FxaaLuma(decodeHDR(texture2D(texture, posP.xy, 0.0)));\n if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;\n if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;\n doneN = abs(lumaEndN) >= gradientScaled;\n doneP = abs(lumaEndP) >= gradientScaled;\n if(!doneN) posN.x -= offNP.x * 2.0;\n if(!doneN) posN.y -= offNP.y * 2.0;\n doneNP = (!doneN) || (!doneP);\n if(!doneP) posP.x += offNP.x * 2.0;\n if(!doneP) posP.y += offNP.y * 2.0;\n if(doneNP) {\n if(!doneN) lumaEndN = FxaaLuma(decodeHDR(texture2D(texture, posN.xy, 0.0)));\n if(!doneP) lumaEndP = FxaaLuma(decodeHDR(texture2D(texture, posP.xy, 0.0)));\n if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;\n if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;\n doneN = abs(lumaEndN) >= gradientScaled;\n doneP = abs(lumaEndP) >= gradientScaled;\n if(!doneN) posN.x -= offNP.x * 4.0;\n if(!doneN) posN.y -= offNP.y * 4.0;\n doneNP = (!doneN) || (!doneP);\n if(!doneP) posP.x += offNP.x * 4.0;\n if(!doneP) posP.y += offNP.y * 4.0;\n if(doneNP) {\n if(!doneN) lumaEndN = FxaaLuma(decodeHDR(texture2D(texture, posN.xy, 0.0)));\n if(!doneP) lumaEndP = FxaaLuma(decodeHDR(texture2D(texture, posP.xy, 0.0)));\n if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;\n if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;\n doneN = abs(lumaEndN) >= gradientScaled;\n doneP = abs(lumaEndP) >= gradientScaled;\n if(!doneN) posN.x -= offNP.x * 12.0;\n if(!doneN) posN.y -= offNP.y * 12.0;\n doneNP = (!doneN) || (!doneP);\n if(!doneP) posP.x += offNP.x * 12.0;\n if(!doneP) posP.y += offNP.y * 12.0;\n }\n }\n }\n float dstN = posM.x - posN.x;\n float dstP = posP.x - posM.x;\n if(!horzSpan) dstN = posM.y - posN.y;\n if(!horzSpan) dstP = posP.y - posM.y;\n bool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero;\n float spanLength = (dstP + dstN);\n bool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero;\n float spanLengthRcp = 1.0/spanLength;\n bool directionN = dstN < dstP;\n float dst = min(dstN, dstP);\n bool goodSpan = directionN ? goodSpanN : goodSpanP;\n float subpixG = subpixF * subpixF;\n float pixelOffset = (dst * (-spanLengthRcp)) + 0.5;\n float subpixH = subpixG * fxaaQualitySubpix;\n float pixelOffsetGood = goodSpan ? pixelOffset : 0.0;\n float pixelOffsetSubpix = max(pixelOffsetGood, subpixH);\n if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign;\n if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign;\n return vec4(decodeHDR(texture2D(texture, posM, 0.0)).xyz, rgbyM.y);\n}\nvoid main()\n{\n vec4 color = FxaaPixelShader(\n v_Texcoord,\n texture,\n vec2(1.0) / viewport.zw,\n subpixel,\n edgeThreshold,\n edgeThresholdMin\n );\n gl_FragColor = vec4(color.rgb, 1.0);\n}\n@end");var Cn={NORMAL:"normal",POSITION:"position",TEXCOORD_0:"texcoord0",TEXCOORD_1:"texcoord1",WEIGHTS_0:"weight",JOINTS_0:"joint",COLOR:"color"},Ln={5120:nt.Int8Array,5121:nt.Uint8Array,5122:nt.Int16Array,5123:nt.Uint16Array,5125:nt.Uint32Array,5126:nt.Float32Array},Dn={SCALAR:1,VEC2:2,VEC3:3,VEC4:4,MAT2:4,MAT3:9,MAT4:16},Pn=Qe.extend({rootNode:null,rootPath:null,textureRootPath:null,bufferRootPath:null,shaderName:"qtek.standard",useStandardMaterial:!1,includeCamera:!0,includeAnimation:!0,includeMesh:!0,includeTexture:!0,crossOrigin:"",textureFlipY:!1,shaderLibrary:null},function(){this.shaderLibrary||(this.shaderLibrary=Gt.createLibrary())},{load:function(e){var t=this,r=e.endsWith(".glb");null==this.rootPath&&(this.rootPath=e.slice(0,e.lastIndexOf("/"))),nr.get({url:e,onprogress:function(e,r,n){t.trigger("progress",e,r,n)},onerror:function(e){t.trigger("error",e)},responseType:r?"arraybuffer":"text",onload:function(e){r?t.parseBinary(e):t.parse(JSON.parse(e))}})},parseBinary:function(e){var t=new Uint32Array(e,0,4);if(1179937895!==t[0])return void this.trigger("error","Invalid glTF binary format: Invalid header");if(t[0]<2)return void this.trigger("error","Only glTF2.0 is supported.");for(var r,n=new DataView(e,12),i=[],a=0;a=0&&this._clips.splice(t,1)},removeAnimator:function(e){for(var t=e.getClips(),r=0;r=65535?new Uint32Array(3*f):new Uint16Array(3*f);for(var m=0,v=0,g=n.isUseIndices(),y=0;y0;){for(var x=[],T=[],E=[],b=0,m=0;m=0&&-1===T[R]&&(b65535?new Uint32Array(3*I.triangles.length):new Uint16Array(3*I.triangles.length);var K=0;G=0;for(var m=0;m=0?O[R]:-1}G++}H.indices[K++]=D[w]}H.updateBoundingBox(),C.add(z)}for(var $=e.children(),m=0;m<$.length;m++)C.add($[m]);if(C.position.copy(e.position),C.rotation.copy(e.rotation),C.scale.copy(e.scale),r&&e.getParent()){var ee=e.getParent();ee.remove(e),ee.add(C)}return C}}},Hn=function(){this._fullfilled=!1,this._rejected=!1};Hn.prototype.resolve=function(e){this._fullfilled=!0,this._rejected=!1,this.trigger("success",e)},Hn.prototype.reject=function(e){this._rejected=!0,this._fullfilled=!1,this.trigger("error",e)},Hn.prototype.isFullfilled=function(){return this._fullfilled},Hn.prototype.isRejected=function(){return this._rejected},Hn.prototype.isSettled=function(){return this._fullfilled||this._rejected},Ze.extend(Hn.prototype,je),Hn.makeRequestTask=function(e,t){if("string"==typeof e)return H(e,t);if(e.url){var r=e;return H(r.url,r.responseType)}if(Array.isArray(e)){var n=e,i=[];return n.forEach(function(e){var t,r;"string"==typeof e?t=e:Object(e)===e&&(t=e.url,r=e.responseType),i.push(H(t,r))}),i}},Hn.makeTask=function(){return new Hn},Ze.extend(Hn.prototype,je);var zn=function(){Hn.apply(this,arguments),this._tasks=[],this._fulfilledNumber=0,this._rejectedNumber=0},Gn=function(){};Gn.prototype=Hn.prototype,zn.prototype=new Gn,zn.prototype.constructor=zn,zn.prototype.all=function(e){var t=0,r=this,n=[];return this._tasks=e,this._fulfilledNumber=0,this._rejectedNumber=0,Ze.each(e,function(e,i){e&&e.once&&(t++,e.once("success",function(a){t--,r._fulfilledNumber++,e._fulfilled=!0,e._rejected=!1,n[i]=a,0===t&&r.resolve(n)}),e.once("error",function(){r._rejectedNumber++,e._fulfilled=!1,e._rejected=!0,r.reject(e)}))}),0===t?(setTimeout(function(){r.resolve(n)}),this):this},zn.prototype.allSettled=function(e){var t=0,r=this,n=[];return 0===e.length?(setTimeout(function(){r.trigger("success",n)}),this):(this._tasks=e,Ze.each(e,function(e,i){e&&e.once&&(t++,e.once("success",function(a){t--,r._fulfilledNumber++,e._fulfilled=!0,e._rejected=!1,n[i]=a,0===t&&r.resolve(n)}),e.once("error",function(a){t--,r._rejectedNumber++,e._fulfilled=!1,e._rejected=!0,n[i]=null,0===t&&r.resolve(n)}))}),this)},zn.prototype.getFulfilledNumber=function(e){if(e){for(var t=0,r=0;r=0&&x[g]>1e-4&&(qn.transformMat4(b,y,m[T[g]]),qn.scaleAndAdd(E,E,b,x[g]));S.set(v,E)}}for(var v=0;v1&&t.texParameterf(t.TEXTURE_CUBE_MAP,i.TEXTURE_MAX_ANISOTROPY_EXT,this.anisotropic),36193===n){e.getGLExtension("OES_texture_half_float")||(n=et.FLOAT)}if(this.mipmaps.length)for(var a=this.width,o=this.height,s=0;s65535?Uint32Array:Uint16Array,_=this.indices=new d(t*e*6),p=this.radius,m=this.phiStart,v=this.phiLength,g=this.thetaStart,y=this.thetaLength,p=this.radius,x=[],T=[],E=0,b=1/p;for(f=0;f<=e;f++)for(h=0;h<=t;h++)l=h/t,c=f/e,o=-p*Math.cos(m+l*v)*Math.sin(g+c*y),s=p*Math.cos(g+c*y),u=p*Math.sin(m+l*v)*Math.sin(g+c*y),x[0]=o,x[1]=s,x[2]=u,T[0]=l,T[1]=c,r.set(E,x),n.set(E,T),x[0]*=b,x[1]*=b,x[2]*=b,i.set(E,x),E++;var S,A,N,w,M=t+1,R=0;for(f=0;f=i)){a+=2;for(var o="";a20)return console.warn("Given image is not a height map"),e}var f,d,_,p;u%(4*n)==0?(f=o.data[u],_=o.data[u+4]):u%(4*n)==4*(n-1)?(f=o.data[u-4],_=o.data[u]):(f=o.data[u-4],_=o.data[u+4]),u<4*n?(d=o.data[u],p=o.data[u+4*n]):u>n*(i-1)*4?(d=o.data[u-4*n],p=o.data[u]):(d=o.data[u-4*n],p=o.data[u+4*n]),s.data[u]=f-_+127,s.data[u+1]=d-p+127,s.data[u+2]=255,s.data[u+3]=255}return a.putImageData(s,0,0),r},isHeightImage:function(e,t,r){if(!e||!e.width||!e.height)return!1;var n=document.createElement("canvas"),i=n.getContext("2d"),a=t||32;r=r||20,n.width=n.height=a,i.drawImage(e,0,0,a,a);for(var o=i.getImageData(0,0,a,a),s=0;sr)return!1}return!0},_fetchTexture:function(e,t,r){nr.get({url:e,responseType:"arraybuffer",onload:t,onerror:r})},createChessboard:function(e,t,r,n){e=e||512,t=t||64,r=r||"black",n=n||"white";var i=Math.ceil(e/t),a=document.createElement("canvas");a.width=e,a.height=e;var o=a.getContext("2d");o.fillStyle=n,o.fillRect(0,0,e,e),o.fillStyle=r;for(var s=0;s=r.COLOR_ATTACHMENT0&&a<=r.COLOR_ATTACHMENT0+8&&i.push(a);n.drawBuffersEXT(i)}}this.trigger("beforerender",this,e);var o=this.clearDepth?r.DEPTH_BUFFER_BIT:0;if(r.depthMask(!0),this.clearColor){o|=r.COLOR_BUFFER_BIT,r.colorMask(!0,!0,!0,!0);var s=this.clearColor;Array.isArray(s)&&r.clearColor(s[0],s[1],s[2],s[3])}r.clear(o),this.blendWithPrevious?(r.enable(r.BLEND),this.material.transparent=!0):(r.disable(r.BLEND),this.material.transparent=!1),this.renderQuad(e),this.trigger("afterrender",this,e),t&&this.unbind(e,t)},renderQuad:function(e){vi.material=this.material,e.renderQueue([vi],gi)},dispose:function(e){this.material.dispose(e)}}),xi=function(){this._pool={},this._allocatedTextures=[]};xi.prototype={constructor:xi,get:function(e){var t=K(e);this._pool.hasOwnProperty(t)||(this._pool[t]=[]);var r=this._pool[t];if(!r.length){var n=new Lr(e);return this._allocatedTextures.push(n),n}return r.pop()},put:function(e){var t=K(e);this._pool.hasOwnProperty(t)||(this._pool[t]=[]),this._pool[t].push(e)},clear:function(e){for(var t=0;t= shadowCascadeClipsNear[_idx_] &&\n depth <= shadowCascadeClipsFar[_idx_]\n ) {\n shadowContrib = computeShadowContrib(\n directionalLightShadowMaps[0], directionalLightMatrices[_idx_], position,\n directionalLightShadowMapSizes[0],\n vec2(1.0 / float(SHADOW_CASCADE), 1.0),\n vec2(float(_idx_) / float(SHADOW_CASCADE), 0.0)\n );\n shadowContribs[0] = shadowContrib;\n }\n }}\n for(int _idx_ = DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#else\nvoid computeShadowOfDirectionalLights(vec3 position, inout float shadowContribs[DIRECTIONAL_LIGHT_COUNT]){\n float shadowContrib;\n for(int _idx_ = 0; _idx_ < DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n shadowContrib = computeShadowContrib(\n directionalLightShadowMaps[_idx_], directionalLightMatrices[_idx_], position,\n directionalLightShadowMapSizes[_idx_]\n );\n shadowContribs[_idx_] = shadowContrib;\n }}\n for(int _idx_ = DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#endif\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\nvoid computeShadowOfPointLights(vec3 position, inout float shadowContribs[POINT_LIGHT_COUNT] ){\n vec3 lightPosition;\n vec3 direction;\n for(int _idx_ = 0; _idx_ < POINT_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n lightPosition = pointLightPosition[_idx_];\n direction = position - lightPosition;\n shadowContribs[_idx_] = computeShadowContribOmni(pointLightShadowMaps[_idx_], direction, pointLightRange[_idx_]);\n }}\n for(int _idx_ = POINT_LIGHT_SHADOWMAP_COUNT; _idx_ < POINT_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#endif\n@end");var Ai=Qe.extend(function(){return{softShadow:Ai.PCF,shadowBlur:1,lightFrustumBias:"auto",kernelPCF:new Float32Array([1,0,1,1,-1,1,0,1,-1,0,-1,-1,1,-1,0,-1]),precision:"mediump",_lastRenderNotCastShadow:!1,_frameBuffer:new $n,_textures:{},_shadowMapNumber:{POINT_LIGHT:0,DIRECTIONAL_LIGHT:0,SPOT_LIGHT:0},_meshMaterials:{},_depthMaterials:{},_depthShaders:{},_distanceMaterials:{},_opaqueCasters:[],_receivers:[],_lightsCastShadow:[],_lightCameras:{},_texturePool:new xi}},function(){this._gaussianPassH=new yi({fragment:kt.source("qtek.compositor.gaussian_blur")}),this._gaussianPassV=new yi({fragment:kt.source("qtek.compositor.gaussian_blur")}),this._gaussianPassH.setUniform("blurSize",this.shadowBlur),this._gaussianPassH.setUniform("blurDir",0),this._gaussianPassV.setUniform("blurSize",this.shadowBlur),this._gaussianPassV.setUniform("blurDir",1),this._outputDepthPass=new yi({fragment:kt.source("qtek.sm.debug_depth")})},{render:function(e,t,r,n){this.trigger("beforerender",this,e,t,r),this._renderShadowPass(e,t,r,n),this.trigger("afterrender",this,e,t,r)},renderDebug:function(e,t){e.saveClear();var r=e.viewport,n=0,i=t||r.width/4,a=i;this.softShadow===Ai.VSM?this._outputDepthPass.material.shader.define("fragment","USE_VSM"):this._outputDepthPass.material.shader.undefine("fragment","USE_VSM");for(var o in this._textures){var s=this._textures[o];e.setViewport(n,0,i*s.width/s.height,a),this._outputDepthPass.setUniform("depthMap",s),this._outputDepthPass.render(e),n+=i*s.width/s.height}e.setViewport(r),e.restoreClear()},_bindDepthMaterial:function(e,t,r){for(var n=0;n0&&(h.define("vertex","SKINNING"),h.define("vertex","JOINT_COUNT",l)),s&&h.define("both","SHADOW_TRANSPARENT"),o.useSkinMatricesTexture&&h.define("vertex","USE_SKIN_MATRICES_TEXTURE"),this._depthShaders[a]=h),c||(c=new qt({shader:h}),this._depthMaterials[i]=c),o.material=c,this.softShadow===Ai.VSM?h.define("fragment","USE_VSM"):h.undefine("fragment","USE_VSM"),c.setUniform("bias",t),c.setUniform("slopeScale",r),s&&c.set("shadowTransparentMap",u))}},_bindDistanceMaterial:function(e,t){for(var r=t.getWorldPosition()._array,n=0;n0&&(o.shader.define("vertex","SKINNING"),o.shader.define("vertex","JOINT_COUNT",a)),this._distanceMaterials[a]=o),i.material=o,this.softShadow===Ai.VSM?o.shader.define("fragment","USE_VSM"):o.shader.undefine("fragment","USE_VSM")),o.set("lightPosition",r),o.set("range",t.range)}},saveMaterial:function(e){for(var t=0;t1&&(d=p,p.shadowCascade>4)){console.warn("Support at most 4 cascade");continue}this.renderDirectionalLightShadow(e,t,r,p,this._opaqueCasters,h,c,l)}else p instanceof di?this.renderSpotLightShadow(e,p,this._opaqueCasters,u,s):p instanceof pi&&this.renderPointLightShadow(e,p,this._opaqueCasters,f);this._shadowMapNumber[p.type]++}this.restoreMaterial(this._opaqueCasters);var m=h.slice(),v=h.slice();m.pop(),v.shift(),m.reverse(),v.reverse(),c.reverse();for(var g=s.map(i),y=l.map(i),x={},_=0;_0?(b.fragmentDefines[w]=N,S=!0):b.isDefined("fragment",w)&&(b.undefine("fragment",w),S=!0))}S&&b.dirty(),d?b.define("fragment","SHADOW_CASCADE",d.shadowCascade):b.undefine("fragment","SHADOW_CASCADE"),x[b.__GUID__]=!0}s.length>0&&(E.setUniform("spotLightShadowMaps",s),E.setUniform("spotLightMatrices",u),E.setUniform("spotLightShadowMapSizes",g)),l.length>0&&(E.setUniform("directionalLightShadowMaps",l),d&&(E.setUniform("shadowCascadeClipsNear",m),E.setUniform("shadowCascadeClipsFar",v)),E.setUniform("directionalLightMatrices",c),E.setUniform("directionalLightShadowMapSizes",y)),f.length>0&&E.setUniform("pointLightShadowMaps",f)}}},renderDirectionalLightShadow:function(){var e=new Kr,t=new xt,r=new pt,n=new xt,i=new xt,a=new xt,o=new xt;return function(s,u,l,c,h,f,d,_){var p=c.shadowBias;if(this._bindDepthMaterial(h,p,c.shadowSlopeScale),h.sort(tr.opaqueSortFunc),!u.viewBoundingBoxLastFrame.isFinite()){var m=u.getBoundingBox();u.viewBoundingBoxLastFrame.copy(m).applyTransform(l.viewMatrix)}var v=Math.min(-u.viewBoundingBoxLastFrame.min.z,l.far),g=Math.max(-u.viewBoundingBoxLastFrame.max.z,l.near),y=this._getDirectionalLightCamera(c,u,l),x=a._array;o.copy(y.projectionMatrix),bi.invert(i._array,y.worldTransform._array),bi.multiply(i._array,i._array,l.worldTransform._array),bi.multiply(x,o._array,i._array);for(var T=[],E=l instanceof en,b=(l.near+l.far)/(l.near-l.far),S=2*l.near*l.far/(l.near-l.far),A=0;A<=c.shadowCascade;A++){var N=g*Math.pow(v/g,A/c.shadowCascade),w=g+(v-g)*A/c.shadowCascade,M=N*c.cascadeSplitLogFactor+w*(1-c.cascadeSplitLogFactor);T.push(M),f.push(-(-M*b+S)/-M)}var R=this._getTexture(c,c.shadowCascade);_.push(R);var C=s.viewport,L=s.gl;this._frameBuffer.attach(R),this._frameBuffer.bind(s),L.clear(L.COLOR_BUFFER_BIT|L.DEPTH_BUFFER_BIT);for(var A=0;A0){var t=this.outputs[e];t.keepLastFrame?(this._prevOutputTextures[e]&&this._compositor.releaseTexture(this._prevOutputTextures[e]),this._prevOutputTextures[e]=this._outputTextures[e]):this._compositor.releaseTexture(this._outputTextures[e])}}}),wi=Qe.extend(function(){return{nodes:[]}},{dirty:function(){this._dirty=!0},addNode:function(e){this.nodes.indexOf(e)>=0||(this.nodes.push(e),this._dirty=!0)},removeNode:function(e){"string"==typeof e&&(e=this.getNodeByName(e));var t=this.nodes.indexOf(e);t>=0&&(this.nodes.splice(t,1),this._dirty=!0)},getNodeByName:function(e){for(var t=0;t=t.COLOR_ATTACHMENT0&&u<=t.COLOR_ATTACHMENT0+8&&c.push(u);l.drawBuffersEXT(c)}e.saveClear(),e.clearBit=et.DEPTH_BUFFER_BIT|et.COLOR_BUFFER_BIT,r=e.render(this.scene,this.camera,!this.autoUpdateScene,this.preZ),e.restoreClear(),n.unbind(e)}else r=e.render(this.scene,this.camera,!this.autoUpdateScene,this.preZ);this.trigger("afterrender",r),this._rendering=!1,this._rendered=!0}}),Ci=Ni.extend(function(){return{texture:null,outputs:{color:{}}}},function(){},{getOutput:function(e,t){return this.texture},beforeFrame:function(){},afterFrame:function(){}}),Li=Ni.extend(function(){return{name:"",inputs:{},outputs:null,shader:"",inputLinks:{},outputLinks:{},pass:null,_prevOutputTextures:{},_outputTextures:{},_outputReferences:{},_rendering:!1,_rendered:!1,_compositor:null}},function(){var e=new yi({fragment:this.shader});this.pass=e},{render:function(e,t){this.trigger("beforerender",e),this._rendering=!0;var r=e.gl;for(var n in this.inputLinks){var i=this.inputLinks[n],a=i.node.getOutput(e,i.pin);this.pass.setUniform(n,a)}if(this.outputs){this.pass.outputs={};var o={};for(var s in this.outputs){var u=this.updateParameter(s,e);isNaN(u.width)&&this.updateParameter(s,e);var l=this.outputs[s],c=this._compositor.allocateTexture(u);this._outputTextures[s]=c;var h=l.attachment||r.COLOR_ATTACHMENT0;"string"==typeof h&&(h=r[h]),o[h]=c}this._compositor.getFrameBuffer().bind(e);for(var h in o)this._compositor.getFrameBuffer().attach(o[h],h);this.pass.render(e),this._compositor.getFrameBuffer().updateMipmap(e.gl)}else this.pass.outputs=null,this._compositor.getFrameBuffer().unbind(e),this.pass.render(e,t);for(var n in this.inputLinks){var i=this.inputLinks[n];i.node.removeReference(i.pin)}this._rendering=!1,this._rendered=!0,this.trigger("afterrender",e)},updateParameter:function(e,t){var r=this.outputs[e],n=r.parameters,i=r._parametersCopy;if(i||(i=r._parametersCopy={}),n)for(var a in n)"width"!==a&&"height"!==a&&(i[a]=n[a]);var o,s;return o=n.width instanceof Function?n.width.call(this,t):n.width,s=n.height instanceof Function?n.height.call(this,t):n.height,i.width===o&&i.height===s||this._outputTextures[e]&&this._outputTextures[e].dispose(t),i.width=o,i.height=s,i},setParameter:function(e,t){this.pass.setUniform(e,t)},getParameter:function(e){return this.pass.getUniform(e)},setParameters:function(e){for(var t in e)this.setParameter(t,e[t])},setShader:function(e){var t=this.pass.material;t.shader.setFragment(e),t.attachShader(t.shader,!0)},shaderDefine:function(e,t){this.pass.material.shader.define("fragment",e,t)},shaderUndefine:function(e){this.pass.material.shader.undefine("fragment",e)},removeReference:function(e){if(0===--this._outputReferences[e]){this.outputs[e].keepLastFrame?(this._prevOutputTextures[e]&&this._compositor.releaseTexture(this._prevOutputTextures[e]),this._prevOutputTextures[e]=this._outputTextures[e]):this._compositor.releaseTexture(this._outputTextures[e])}},link:function(e,t,r){this.inputLinks[e]={node:t,pin:r},t.outputLinks[r]||(t.outputLinks[r]=[]),t.outputLinks[r].push({node:this,pin:e}),this.pass.material.shader.enableTexture(e)},clear:function(){Ni.prototype.clear.call(this),this.pass.material.shader.disableTexturesAll()},updateReference:function(e){if(!this._rendering){this._rendering=!0;for(var t in this.inputLinks){var r=this.inputLinks[t];r.node.updateReference(r.pin)}this._rendering=!1}e&&this._outputReferences[e]++},beforeFrame:function(){this._rendered=!1;for(var e in this.outputLinks)this._outputReferences[e]=0},afterFrame:function(){for(var e in this.outputLinks)if(this._outputReferences[e]>0){var t=this.outputs[e];t.keepLastFrame?(this._prevOutputTextures[e]&&this._compositor.releaseTexture(this._prevOutputTextures[e]),this._prevOutputTextures[e]=this._outputTextures[e]):this._compositor.releaseTexture(this._outputTextures[e])}}}),Di=/#source\((.*?)\)/,Pi=/#url\((.*?)\)/,Ii=Qe.extend({rootPath:"",textureRootPath:"",shaderRootPath:"",scene:null,camera:null},{load:function(e){var t=this;this.rootPath||(this.rootPath=e.slice(0,e.lastIndexOf("/"))),nr.get({url:e,onprogress:function(e,r,n){t.trigger("progress",e,r,n)},onerror:function(e){t.trigger("error",e)},responseType:"text",onload:function(e){t.parse(JSON.parse(e))}})},parse:function(e){var t=this,r=new Mi,n={textures:{},shaders:{},parameters:{}},i=function(i,a){for(var o=0;o 0.99999) {\n gl_FragColor = vec4(1.0);\n return;\n }\n mat3 kernelBasis;\n#endif\n\n float z = depthTexel.r * 2.0 - 1.0;\n\n vec4 projectedPos = vec4(v_Texcoord * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * projectedPos;\n\n vec3 position = p4.xyz / p4.w;\n\n float ao = ssaoEstimator(position, N, kernelBasis);\n ao = clamp(1.0 - (1.0 - ao) * intensity, 0.0, 1.0);\n gl_FragColor = vec4(vec3(ao), 1.0);\n}\n\n@end\n\n\n@export ecgl.ssao.blur\n#define SHADER_NAME SSAO_BLUR\n\nuniform sampler2D ssaoTexture;\n\n#ifdef NORMALTEX_ENABLED\nuniform sampler2D normalTex;\n#endif\n\nvarying vec2 v_Texcoord;\n\nuniform vec2 textureSize;\nuniform float blurSize : 1.0;\n\nuniform int direction: 0.0;\n\n#ifdef DEPTHTEX_ENABLED\nuniform sampler2D depthTex;\nuniform mat4 projection;\nuniform float depthRange : 0.05;\n\nfloat getLinearDepth(vec2 coord)\n{\n float depth = texture2D(depthTex, coord).r * 2.0 - 1.0;\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n}\n#endif\n\nvoid main()\n{\n @import qtek.compositor.kernel.gaussian_9\n\n vec2 off = vec2(0.0);\n if (direction == 0) {\n off[0] = blurSize / textureSize.x;\n }\n else {\n off[1] = blurSize / textureSize.y;\n }\n\n vec2 coord = v_Texcoord;\n\n float sum = 0.0;\n float weightAll = 0.0;\n\n#ifdef NORMALTEX_ENABLED\n vec3 centerNormal = texture2D(normalTex, v_Texcoord).rgb * 2.0 - 1.0;\n#endif\n#if defined(DEPTHTEX_ENABLED)\n float centerDepth = getLinearDepth(v_Texcoord);\n#endif\n\n for (int i = 0; i < 9; i++) {\n vec2 coord = clamp(v_Texcoord + vec2(float(i) - 4.0) * off, vec2(0.0), vec2(1.0));\n\n float w = gaussianKernel[i];\n#ifdef NORMALTEX_ENABLED\n vec3 normal = texture2D(normalTex, coord).rgb * 2.0 - 1.0;\n w *= clamp(dot(normal, centerNormal), 0.0, 1.0);\n#endif\n#ifdef DEPTHTEX_ENABLED\n float d = getLinearDepth(coord);\n w *= (1.0 - smoothstep(abs(centerDepth - d) / depthRange, 0.0, 1.0));\n#endif\n\n weightAll += w;\n sum += texture2D(ssaoTexture, coord).r * w;\n }\n\n gl_FragColor = vec4(vec3(sum / weightAll), 1.0);\n}\n\n@end\n"),ie.prototype.setDepthTexture=function(e){this._depthTex=e},ie.prototype.setNormalTexture=function(e){this._normalTex=e,this._ssaoPass.material.shader[e?"enableTexture":"disableTexture"]("normalTex"),this.setKernelSize(this._kernelSize)},ie.prototype.update=function(e,t,r){var n=e.getWidth(),i=e.getHeight(),a=this._ssaoPass,o=this._blurPass;a.setUniform("kernel",this._kernels[r%this._kernels.length]),a.setUniform("depthTex",this._depthTex),null!=this._normalTex&&a.setUniform("normalTex",this._normalTex),a.setUniform("depthTexSize",[this._depthTex.width,this._depthTex.height]);var s=new xt;xt.transpose(s,t.worldTransform),a.setUniform("projection",t.projectionMatrix._array),a.setUniform("projectionInv",t.invProjectionMatrix._array),a.setUniform("viewInverseTranspose",s._array);var u=this._ssaoTexture,l=this._blurTexture;u.width=n,u.height=i,l.width=n,l.height=i,this._framebuffer.attach(u),this._framebuffer.bind(e),e.gl.clearColor(1,1,1,1),e.gl.clear(e.gl.COLOR_BUFFER_BIT),a.render(e),o.setUniform("textureSize",[n,i]),o.setUniform("projection",t.projectionMatrix._array),this._framebuffer.attach(l),o.setUniform("direction",0),o.setUniform("ssaoTexture",u),o.render(e),this._framebuffer.attach(u),o.setUniform("direction",1),o.setUniform("ssaoTexture",l),o.render(e),this._framebuffer.unbind(e);var c=e.clearColor;e.gl.clearColor(c[0],c[1],c[2],c[3])},ie.prototype.getTargetTexture=function(){return this._ssaoTexture},ie.prototype.setParameter=function(e,t){"noiseTexSize"===e?this.setNoiseSize(t):"kernelSize"===e?this.setKernelSize(t):"intensity"===e?this._ssaoPass.material.set("intensity",t):this._ssaoPass.setUniform(e,t)},ie.prototype.setKernelSize=function(e){this._kernelSize=e,this._ssaoPass.material.shader.define("fragment","KERNEL_SIZE",e),this._kernels=this._kernels||[];for(var t=0;t<30;t++)this._kernels[t]=ne(e,t*e,!!this._normalTex)},ie.prototype.setNoiseSize=function(e){var t=this._ssaoPass.getUniform("noiseTex");t?(t.data=te(e),t.width=t.height=e,t.dirty()):(t=re(e),this._ssaoPass.setUniform("noiseTex",re(e))),this._ssaoPass.setUniform("noiseTexSize",[e,e])},ie.prototype.dispose=function(e){this._blurTexture.dispose(e),this._ssaoTexture.dispose(e)};kt.import("@export ecgl.ssr.main\n\n#define MAX_ITERATION 20;\n\nuniform sampler2D sourceTexture;\nuniform sampler2D gBufferTexture1;\nuniform sampler2D gBufferTexture2;\n\nuniform mat4 projection;\nuniform mat4 projectionInv;\nuniform mat4 viewInverseTranspose;\n\nuniform float maxRayDistance: 50;\n\nuniform float pixelStride: 16;\nuniform float pixelStrideZCutoff: 50; \nuniform float screenEdgeFadeStart: 0.9; \nuniform float eyeFadeStart : 0.2; uniform float eyeFadeEnd: 0.8; \nuniform float minGlossiness: 0.2; uniform float zThicknessThreshold: 10;\n\nuniform float nearZ;\nuniform vec2 viewportSize : VIEWPORT_SIZE;\n\nuniform float jitterOffset: 0;\n\nvarying vec2 v_Texcoord;\n\n#ifdef DEPTH_DECODE\n@import qtek.util.decode_float\n#endif\n\nfloat fetchDepth(sampler2D depthTexture, vec2 uv)\n{\n vec4 depthTexel = texture2D(depthTexture, uv);\n return depthTexel.r * 2.0 - 1.0;\n}\n\nfloat linearDepth(float depth)\n{\n if (projection[3][3] == 0.0) {\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n }\n else {\n return (depth - projection[3][2]) / projection[2][2];\n }\n}\n\nbool rayIntersectDepth(float rayZNear, float rayZFar, vec2 hitPixel)\n{\n if (rayZFar > rayZNear)\n {\n float t = rayZFar; rayZFar = rayZNear; rayZNear = t;\n }\n float cameraZ = linearDepth(fetchDepth(gBufferTexture2, hitPixel));\n return rayZFar <= cameraZ && rayZNear >= cameraZ - zThicknessThreshold;\n}\n\n\nbool traceScreenSpaceRay(\n vec3 rayOrigin, vec3 rayDir, float jitter,\n out vec2 hitPixel, out vec3 hitPoint, out float iterationCount\n)\n{\n float rayLength = ((rayOrigin.z + rayDir.z * maxRayDistance) > -nearZ)\n ? (-nearZ - rayOrigin.z) / rayDir.z : maxRayDistance;\n\n vec3 rayEnd = rayOrigin + rayDir * rayLength;\n\n vec4 H0 = projection * vec4(rayOrigin, 1.0);\n vec4 H1 = projection * vec4(rayEnd, 1.0);\n\n float k0 = 1.0 / H0.w, k1 = 1.0 / H1.w;\n\n vec3 Q0 = rayOrigin * k0, Q1 = rayEnd * k1;\n\n vec2 P0 = (H0.xy * k0 * 0.5 + 0.5) * viewportSize;\n vec2 P1 = (H1.xy * k1 * 0.5 + 0.5) * viewportSize;\n\n P1 += dot(P1 - P0, P1 - P0) < 0.0001 ? 0.01 : 0.0;\n vec2 delta = P1 - P0;\n\n bool permute = false;\n if (abs(delta.x) < abs(delta.y)) {\n permute = true;\n delta = delta.yx;\n P0 = P0.yx;\n P1 = P1.yx;\n }\n float stepDir = sign(delta.x);\n float invdx = stepDir / delta.x;\n\n vec3 dQ = (Q1 - Q0) * invdx;\n float dk = (k1 - k0) * invdx;\n\n vec2 dP = vec2(stepDir, delta.y * invdx);\n\n float strideScaler = 1.0 - min(1.0, -rayOrigin.z / pixelStrideZCutoff);\n float pixStride = 1.0 + strideScaler * pixelStride;\n\n dP *= pixStride; dQ *= pixStride; dk *= pixStride;\n\n vec4 pqk = vec4(P0, Q0.z, k0);\n vec4 dPQK = vec4(dP, dQ.z, dk);\n\n pqk += dPQK * jitter;\n float rayZFar = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);\n float rayZNear;\n\n bool intersect = false;\n\n vec2 texelSize = 1.0 / viewportSize;\n\n iterationCount = 0.0;\n\n for (int i = 0; i < MAX_ITERATION; i++)\n {\n pqk += dPQK;\n\n rayZNear = rayZFar;\n rayZFar = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);\n\n hitPixel = permute ? pqk.yx : pqk.xy;\n hitPixel *= texelSize;\n\n intersect = rayIntersectDepth(rayZNear, rayZFar, hitPixel);\n\n iterationCount += 1.0;\n\n if (intersect) {\n break;\n }\n }\n\n\n Q0.xy += dQ.xy * iterationCount;\n Q0.z = pqk.z;\n hitPoint = Q0 / pqk.w;\n\n return intersect;\n}\n\nfloat calculateAlpha(\n float iterationCount, float reflectivity,\n vec2 hitPixel, vec3 hitPoint, float dist, vec3 rayDir\n)\n{\n float alpha = clamp(reflectivity, 0.0, 1.0);\n alpha *= 1.0 - (iterationCount / float(MAX_ITERATION));\n vec2 hitPixelNDC = hitPixel * 2.0 - 1.0;\n float maxDimension = min(1.0, max(abs(hitPixelNDC.x), abs(hitPixelNDC.y)));\n alpha *= 1.0 - max(0.0, maxDimension - screenEdgeFadeStart) / (1.0 - screenEdgeFadeStart);\n\n float _eyeFadeStart = eyeFadeStart;\n float _eyeFadeEnd = eyeFadeEnd;\n if (_eyeFadeStart > _eyeFadeEnd) {\n float tmp = _eyeFadeEnd;\n _eyeFadeEnd = _eyeFadeStart;\n _eyeFadeStart = tmp;\n }\n\n float eyeDir = clamp(rayDir.z, _eyeFadeStart, _eyeFadeEnd);\n alpha *= 1.0 - (eyeDir - _eyeFadeStart) / (_eyeFadeEnd - _eyeFadeStart);\n\n alpha *= 1.0 - clamp(dist / maxRayDistance, 0.0, 1.0);\n\n return alpha;\n}\n\n@import qtek.util.rand\n\n@import qtek.util.rgbm\n\nvoid main()\n{\n vec4 normalAndGloss = texture2D(gBufferTexture1, v_Texcoord);\n\n if (dot(normalAndGloss.rgb, vec3(1.0)) == 0.0) {\n discard;\n }\n\n float g = normalAndGloss.a;\n if (g <= minGlossiness) {\n discard;\n }\n\n float reflectivity = (g - minGlossiness) / (1.0 - minGlossiness);\n\n vec3 N = normalAndGloss.rgb * 2.0 - 1.0;\n N = normalize((viewInverseTranspose * vec4(N, 0.0)).xyz);\n\n vec4 projectedPos = vec4(v_Texcoord * 2.0 - 1.0, fetchDepth(gBufferTexture2, v_Texcoord), 1.0);\n vec4 pos = projectionInv * projectedPos;\n vec3 rayOrigin = pos.xyz / pos.w;\n\n vec3 rayDir = normalize(reflect(normalize(rayOrigin), N));\n vec2 hitPixel;\n vec3 hitPoint;\n float iterationCount;\n\n vec2 uv2 = v_Texcoord * viewportSize;\n float jitter = rand(fract(v_Texcoord + jitterOffset));\n\n bool intersect = traceScreenSpaceRay(rayOrigin, rayDir, jitter, hitPixel, hitPoint, iterationCount);\n\n float dist = distance(rayOrigin, hitPoint);\n\n float alpha = calculateAlpha(iterationCount, reflectivity, hitPixel, hitPoint, dist, rayDir) * float(intersect);\n\n vec3 hitNormal = texture2D(gBufferTexture1, hitPixel).rgb * 2.0 - 1.0;\n hitNormal = normalize((viewInverseTranspose * vec4(hitNormal, 0.0)).xyz);\n\n if (dot(hitNormal, rayDir) >= 0.0) {\n discard;\n }\n\n \n if (!intersect) {\n discard;\n }\n vec4 color = decodeHDR(texture2D(sourceTexture, hitPixel));\n gl_FragColor = encodeHDR(vec4(color.rgb * alpha, color.a));\n}\n@end\n\n@export ecgl.ssr.blur\n\nuniform sampler2D texture;\nuniform sampler2D gBufferTexture1;\n\nvarying vec2 v_Texcoord;\n\nuniform vec2 textureSize;\nuniform float blurSize : 4.0;\n\n#ifdef BLEND\n #ifdef SSAOTEX_ENABLED\nuniform sampler2D ssaoTex;\n #endif\nuniform sampler2D sourceTexture;\n#endif\n\n@import qtek.util.rgbm\n\n\nvoid main()\n{\n @import qtek.compositor.kernel.gaussian_13\n\n vec4 centerNTexel = texture2D(gBufferTexture1, v_Texcoord);\n float g = centerNTexel.a;\n float maxBlurSize = clamp(1.0 - g + 0.1, 0.0, 1.0) * blurSize;\n#ifdef VERTICAL\n vec2 off = vec2(0.0, maxBlurSize / textureSize.y);\n#else\n vec2 off = vec2(maxBlurSize / textureSize.x, 0.0);\n#endif\n\n vec2 coord = v_Texcoord;\n\n vec4 sum = vec4(0.0);\n float weightAll = 0.0;\n\n vec3 cN = centerNTexel.rgb * 2.0 - 1.0;\n for (int i = 0; i < 13; i++) {\n vec2 coord = clamp((float(i) - 6.0) * off + v_Texcoord, vec2(0.0), vec2(1.0));\n float w = gaussianKernel[i] * clamp(dot(cN, texture2D(gBufferTexture1, coord).rgb * 2.0 - 1.0), 0.0, 1.0);\n weightAll += w;\n sum += decodeHDR(texture2D(texture, coord)) * w;\n }\n\n#ifdef BLEND\n\n float aoFactor = 1.0;\n #ifdef SSAOTEX_ENABLED\n aoFactor = texture2D(ssaoTex, v_Texcoord).r;\n #endif\n gl_FragColor = encodeHDR(\n sum / weightAll * aoFactor + decodeHDR(texture2D(sourceTexture, v_Texcoord))\n );\n#else\n gl_FragColor = encodeHDR(sum / weightAll);\n#endif\n}\n\n@end"),ae.prototype.update=function(e,t,r,n){var i=e.getWidth(),a=e.getHeight(),o=this._texture1,s=this._texture2;o.width=s.width=i,o.height=s.height=a;var u=this._frameBuffer,l=this._ssrPass,c=this._blurPass1,h=this._blurPass2,f=new xt;xt.transpose(f,t.worldTransform),l.setUniform("sourceTexture",r),l.setUniform("projection",t.projectionMatrix._array),l.setUniform("projectionInv",t.invProjectionMatrix._array),l.setUniform("viewInverseTranspose",f._array),l.setUniform("nearZ",t.near),l.setUniform("jitterOffset",n/30);var d=[i,a];c.setUniform("textureSize",d),h.setUniform("textureSize",d),h.setUniform("sourceTexture",r),u.attach(s),u.bind(e),l.render(e),u.attach(o),c.setUniform("texture",s),c.render(e),u.attach(s),h.setUniform("texture",o),h.render(e),u.unbind(e)},ae.prototype.getTargetTexture=function(){return this._texture2},ae.prototype.setParameter=function(e,t){"maxIteration"===e?this._ssrPass.material.shader.define("fragment","MAX_ITERATION",t):this._ssrPass.setUniform(e,t)},ae.prototype.setSSAOTexture=function(e){var t=this._blurPass2;e?(t.material.shader.enableTexture("ssaoTex"),t.material.set("ssaoTex",e)):t.material.shader.disableTexture("ssaoTex")},ae.prototype.dispose=function(e){this._texture1.dispose(e),this._texture2.dispose(e),this._frameBuffer.dispose(e)};var Oi=[0,0,-.321585265978,-.154972575841,.458126042375,.188473391593,.842080129861,.527766490688,.147304551086,-.659453822776,-.331943915203,-.940619700594,.0479226680259,.54812163202,.701581552186,-.709825561388,-.295436780218,.940589268233,-.901489676764,.237713156085,.973570876096,-.109899459384,-.866792314779,-.451805525005,.330975007087,.800048655954,-.344275183665,.381779221166,-.386139432542,-.437418421534,-.576478634965,-.0148463392551,.385798197415,-.262426961053,-.666302061145,.682427250835,-.628010632582,-.732836215494,.10163141741,-.987658134403,.711995289051,-.320024291314,.0296005138058,.950296523438,.0130612307608,-.351024443122,-.879596633704,-.10478487883,.435712737232,.504254490347,.779203817497,.206477676721,.388264289969,-.896736162545,-.153106280781,-.629203242522,-.245517550697,.657969239148,.126830499058,.26862328493,-.634888119007,-.302301223431,.617074219636,.779817204925],Fi="@export qtek.deferred.gbuffer.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat;\nuniform vec2 uvOffset;\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\n#ifdef FIRST_PASS\nattribute vec3 normal : NORMAL;\n#endif\n@import qtek.chunk.skinning_header\n#ifdef FIRST_PASS\nvarying vec3 v_Normal;\nattribute vec4 tangent : TANGENT;\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\nvarying vec3 v_WorldPosition;\n#endif\nvarying vec2 v_Texcoord;\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef FIRST_PASS\n vec3 skinnedNormal = normal;\n vec3 skinnedTangent = tangent.xyz;\n bool hasTangent = dot(tangent, tangent) > 0.0;\n#endif\n#ifdef SKINNING\n @import qtek.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n #ifdef FIRST_PASS\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n if (hasTangent) {\n skinnedTangent = (skinMatrixWS * vec4(tangent.xyz, 0.0)).xyz;\n }\n #endif\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n#ifdef FIRST_PASS\n v_Normal = normalize((worldInverseTranspose * vec4(skinnedNormal, 0.0)).xyz);\n if (hasTangent) {\n v_Tangent = normalize((worldInverseTranspose * vec4(skinnedTangent, 0.0)).xyz);\n v_Bitangent = normalize(cross(v_Normal, v_Tangent) * tangent.w);\n }\n v_WorldPosition = (world * vec4(skinnedPosition, 1.0)).xyz;\n#endif\n}\n@end\n@export qtek.deferred.gbuffer1.fragment\nuniform mat4 viewInverse : VIEWINVERSE;\nuniform float glossiness;\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nuniform sampler2D normalMap;\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\nuniform sampler2D roughGlossMap;\nuniform bool useRoughGlossMap;\nuniform bool useRoughness;\nuniform bool doubleSided;\nuniform int roughGlossChannel: 0;\nfloat indexingTexel(in vec4 texel, in int idx) {\n if (idx == 3) return texel.a;\n else if (idx == 1) return texel.g;\n else if (idx == 2) return texel.b;\n else return texel.r;\n}\nvoid main()\n{\n vec3 N = v_Normal;\n if (doubleSided) {\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = eyePos - v_WorldPosition;\n if (dot(N, V) < 0.0) {\n N = -N;\n }\n }\n if (dot(v_Tangent, v_Tangent) > 0.0) {\n vec3 normalTexel = texture2D(normalMap, v_Texcoord).xyz;\n if (dot(normalTexel, normalTexel) > 0.0) { N = normalTexel * 2.0 - 1.0;\n mat3 tbn = mat3(v_Tangent, v_Bitangent, v_Normal);\n N = normalize(tbn * N);\n }\n }\n gl_FragColor.rgb = (N + 1.0) * 0.5;\n float g = glossiness;\n if (useRoughGlossMap) {\n float g2 = indexingTexel(texture2D(roughGlossMap, v_Texcoord), roughGlossChannel);\n if (useRoughness) {\n g2 = 1.0 - g2;\n }\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n }\n gl_FragColor.a = g;\n}\n@end\n@export qtek.deferred.gbuffer2.fragment\nuniform sampler2D diffuseMap;\nuniform sampler2D metalnessMap;\nuniform vec3 color;\nuniform float metalness;\nuniform bool useMetalnessMap;\nuniform bool linear;\nvarying vec2 v_Texcoord;\n@import qtek.util.srgb\nvoid main ()\n{\n float m = metalness;\n if (useMetalnessMap) {\n vec4 metalnessTexel = texture2D(metalnessMap, v_Texcoord);\n m = clamp(metalnessTexel.r + (m * 2.0 - 1.0), 0.0, 1.0);\n }\n vec4 texel = texture2D(diffuseMap, v_Texcoord);\n if (linear) {\n texel = sRGBToLinear(texel);\n }\n gl_FragColor.rgb = texel.rgb * color;\n gl_FragColor.a = m;\n}\n@end\n@export qtek.deferred.gbuffer.debug\n@import qtek.deferred.chunk.light_head\nuniform int debug: 0;\nvoid main ()\n{\n @import qtek.deferred.chunk.gbuffer_read\n if (debug == 0) {\n gl_FragColor = vec4(N, 1.0);\n }\n else if (debug == 1) {\n gl_FragColor = vec4(vec3(z), 1.0);\n }\n else if (debug == 2) {\n gl_FragColor = vec4(position, 1.0);\n }\n else if (debug == 3) {\n gl_FragColor = vec4(vec3(glossiness), 1.0);\n }\n else if (debug == 4) {\n gl_FragColor = vec4(vec3(metalness), 1.0);\n }\n else {\n gl_FragColor = vec4(albedo, 1.0);\n }\n}\n@end";kt.import(Fi),kt.import("@export qtek.deferred.chunk.light_head\nuniform sampler2D gBufferTexture1;\nuniform sampler2D gBufferTexture2;\nuniform sampler2D gBufferTexture3;\nuniform vec2 windowSize: WINDOW_SIZE;\nuniform vec4 viewport: VIEWPORT;\nuniform mat4 viewProjectionInv;\n#ifdef DEPTH_ENCODED\n@import qtek.util.decode_float\n#endif\n@end\n@export qtek.deferred.chunk.gbuffer_read\n vec2 uv = gl_FragCoord.xy / windowSize;\n vec2 uv2 = (gl_FragCoord.xy - viewport.xy) / viewport.zw;\n vec4 texel1 = texture2D(gBufferTexture1, uv);\n vec4 texel3 = texture2D(gBufferTexture3, uv);\n if (dot(texel1.rgb, vec3(1.0)) == 0.0) {\n discard;\n }\n float glossiness = texel1.a;\n float metalness = texel3.a;\n vec3 N = texel1.rgb * 2.0 - 1.0;\n float z = texture2D(gBufferTexture2, uv).r * 2.0 - 1.0;\n vec2 xy = uv2 * 2.0 - 1.0;\n vec4 projectedPos = vec4(xy, z, 1.0);\n vec4 p4 = viewProjectionInv * projectedPos;\n vec3 position = p4.xyz / p4.w;\n vec3 albedo = texel3.rgb;\n vec3 diffuseColor = albedo * (1.0 - metalness);\n vec3 specularColor = mix(vec3(0.04), albedo, metalness);\n@end\n@export qtek.deferred.chunk.light_equation\nfloat D_Phong(in float g, in float ndh) {\n float a = pow(8192.0, g);\n return (a + 2.0) / 8.0 * pow(ndh, a);\n}\nfloat D_GGX(in float g, in float ndh) {\n float r = 1.0 - g;\n float a = r * r;\n float tmp = ndh * ndh * (a - 1.0) + 1.0;\n return a / (3.1415926 * tmp * tmp);\n}\nvec3 F_Schlick(in float ndv, vec3 spec) {\n return spec + (1.0 - spec) * pow(1.0 - ndv, 5.0);\n}\nvec3 lightEquation(\n in vec3 lightColor, in vec3 diffuseColor, in vec3 specularColor,\n in float ndl, in float ndh, in float ndv, in float g\n)\n{\n return ndl * lightColor\n * (diffuseColor + D_Phong(g, ndh) * F_Schlick(ndv, specularColor));\n}\n@end");var ki=Qe.extend(function(){return{enableTargetTexture1:!0,enableTargetTexture2:!0,enableTargetTexture3:!0,_renderQueue:[],_gBufferTex1:new Lr({minFilter:Wt.NEAREST,magFilter:Wt.NEAREST,type:Wt.HALF_FLOAT}),_gBufferTex2:new Lr({minFilter:Wt.NEAREST,magFilter:Wt.NEAREST,format:Wt.DEPTH_STENCIL,type:Wt.UNSIGNED_INT_24_8_WEBGL}),_gBufferTex3:new Lr({minFilter:Wt.NEAREST,magFilter:Wt.NEAREST}),_defaultNormalMap:new Lr({image:oe("#000")}),_defaultRoughnessMap:new Lr({image:oe("#fff")}),_defaultMetalnessMap:new Lr({image:oe("#fff")}),_defaultDiffuseMap:new Lr({image:oe("#fff")}),_frameBuffer:new $n,_gBufferMaterials:{},_debugPass:new yi({fragment:kt.source("qtek.deferred.gbuffer.debug")})}},{resize:function(e,t){this._gBufferTex1.width===e&&this._gBufferTex1.height===t||(this._gBufferTex1.width=e,this._gBufferTex1.height=t,this._gBufferTex2.width=e,this._gBufferTex2.height=t,this._gBufferTex3.width=e,this._gBufferTex3.height=t)},setViewport:function(e,t,r,n,i){var a;a="object"==typeof e?e:{x:e,y:t,width:r,height:n,devicePixelRatio:i||1},this._frameBuffer.viewport=a},getViewport:function(){return this._frameBuffer.viewport?this._frameBuffer.viewport:{x:0,y:0,width:this._gBufferTex1.width,height:this._gBufferTex1.height,devicePixelRatio:1}},update:function(e,t,r){for(var n=e.gl,i=this._frameBuffer,a=i.viewport,o=t.opaqueQueue,s=t.transparentQueue,u=e.beforeRenderObject,l=0;l0&&(n.shader.define("vertex","SKINNING"),n.shader.define("vertex","JOINT_COUNT",e),i.shader.define("vertex","SKINNING"),i.shader.define("vertex","JOINT_COUNT",e)),r={material1:n,material2:i},t[e]=r}return r.used=!0,r},_resetGBufferMaterials:function(){for(var e in this._gBufferMaterials)this._gBufferMaterials[e].used=!1},_cleanGBufferMaterials:function(e){for(var t in this._gBufferMaterials){var r=this._gBufferMaterials[t];r.used||(r.material1.dispose(e),r.material2.dispose(e))}},_replaceGBufferMat:function(e,t){for(var r=0;r=this._maxSize&&a>0){var s=r.head;r.remove(s),delete n[s.key],i=s.value,this._lastRemovedEntry=s}o?o.value=t:o=new Hi(t),o.key=e,r.insertEntry(o),n[e]=o}return i},Gi.get=function(e){var t=this._map[e],r=this._list;if(null!=t)return t!==r.tail&&(r.remove(t),r.insertEntry(t)),t.value},Gi.clear=function(){this._list.clear(),this._map={}};var Wi=new xt,qi=yn.extend({dynamic:!1,widthSegments:1,heightSegments:1,depthSegments:1,inside:!1},function(){this.build()},{build:function(){var e={px:ce("px",this.depthSegments,this.heightSegments),nx:ce("nx",this.depthSegments,this.heightSegments),py:ce("py",this.widthSegments,this.depthSegments),ny:ce("ny",this.widthSegments,this.depthSegments),pz:ce("pz",this.widthSegments,this.heightSegments),nz:ce("nz",this.widthSegments,this.heightSegments)},t=["position","texcoord0","normal"],r=0,n=0;for(var i in e)r+=e[i].vertexCount,n+=e[i].indices.length;for(var a=0;a 0.0) {\n prefilteredColor += decodeHDR(textureCube(environmentMap, L)).rgb * NoL;\n totalWeight += NoL;\n }\n }\n gl_FragColor = encodeHDR(vec4(prefilteredColor / totalWeight, 1.0));\n}\n"})});h.set("normalDistribution",n),r.encodeRGBM&&h.shader.define("fragment","RGBM_ENCODE"),r.decodeRGBM&&h.shader.define("fragment","RGBM_DECODE");var f,d=new fr;if(t instanceof Lr){var _=new Kn({width:a,height:o,type:s===Wt.FLOAT?Wt.HALF_FLOAT:s});fi.panoramaToCubeMap(e,t,_,{encodeRGBM:r.decodeRGBM}),t=_}f=new Vi({scene:d,material:h}),f.material.set("environmentMap",t);var p=new ti({texture:u});r.encodeRGBM&&(s=u.type=Wt.UNSIGNED_BYTE);for(var m=new Lr({width:a,height:o,type:s}),v=new $n({depthBuffer:!1}),g=nt[s===Wt.UNSIGNED_BYTE?"Uint8Array":"Float32Array"],y=0;y 0.0) {\n float G = G_Smith(roughness, NoV, NoL);\n float G_Vis = G * VoH / (NoH * NoV);\n float Fc = pow(1.0 - VoH, 5.0);\n A += (1.0 - Fc) * G_Vis;\n B += Fc * G_Vis;\n }\n }\n gl_FragColor = vec4(vec2(A, B) / fSampleNumber, 0.0, 1.0);\n}\n"}),i=new Lr({width:512,height:256,type:Wt.HALF_FLOAT,minFilter:Wt.NEAREST,magFilter:Wt.NEAREST,useMipmap:!1});return n.setUniform("normalDistribution",t),n.setUniform("viewportSize",[512,256]),n.attachOutput(i),n.render(e,r),r.dispose(e),i},ji.generateNormalDistribution=function(e,t){for(var e=e||256,t=t||1024,r=new Lr({width:e,height:t,type:Wt.FLOAT,minFilter:Wt.NEAREST,magFilter:Wt.NEAREST,useMipmap:!1}),n=new Float32Array(t*e*4),i=0;i>>16)>>>0;o=((1431655765&o)<<1|(2863311530&o)>>>1)>>>0,o=((858993459&o)<<2|(3435973836&o)>>>2)>>>0,o=((252645135&o)<<4|(4042322160&o)>>>4)>>>0,o=(((16711935&o)<<8|(4278255360&o)>>>8)>>>0)/4294967296;for(var s=0;s3?t[3]=e[3]:t[3]=1,t):(t=Te(e||"#000",t)||[0,0,0,0],t[0]/=255,t[1]/=255,t[2]/=255,t)},na.stringifyColor=function(e,t){return e=e.slice(),e[0]=Math.round(255*e[0]),e[1]=Math.round(255*e[1]),e[2]=Math.round(255*e[2]),"hex"===t?"#"+((1<<24)+(e[0]<<16)+(e[1]<<8)+e[2]).toString(16).slice(1):be(e,t)},na.directionFromAlphaBeta=function(e,t){var r=e/180*Math.PI+Math.PI/2,n=-t/180*Math.PI+Math.PI/2,i=[],a=Math.sin(r);return i[0]=a*Math.cos(n),i[1]=-Math.cos(r),i[2]=a*Math.sin(n),i},na.convertTextureToPowerOfTwo=we;var aa={type:"compositor",nodes:[{name:"source",type:"texture",outputs:{color:{}}},{name:"source_half",shader:"#source(qtek.compositor.downsample)",inputs:{texture:"source"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0, height * 1.0] )"}},{name:"bright",shader:"#source(qtek.compositor.bright)",inputs:{texture:"source_half"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{threshold:2,scale:4,textureSize:"expr([width * 1.0 / 2, height / 2])"}},{name:"bright_downsample_4",shader:"#source(qtek.compositor.downsample)",inputs:{texture:"bright"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 4)",height:"expr(height * 1.0 / 4)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0 / 2, height / 2] )"}},{name:"bright_downsample_8",shader:"#source(qtek.compositor.downsample)",inputs:{texture:"bright_downsample_4"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 8)",height:"expr(height * 1.0 / 8)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0 / 4, height / 4] )"}},{name:"bright_downsample_16",shader:"#source(qtek.compositor.downsample)",inputs:{texture:"bright_downsample_8"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 16)",height:"expr(height * 1.0 / 16)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0 / 8, height / 8] )"}},{name:"bright_downsample_32",shader:"#source(qtek.compositor.downsample)",inputs:{texture:"bright_downsample_16"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 32)",height:"expr(height * 1.0 / 32)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0 / 16, height / 16] )"}},{name:"bright_upsample_16_blur_h",shader:"#source(qtek.compositor.gaussian_blur)",inputs:{texture:"bright_downsample_32"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 16)",height:"expr(height * 1.0 / 16)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 32, height / 32] )"}},{name:"bright_upsample_16_blur_v",shader:"#source(qtek.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_16_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 16)",height:"expr(height * 1.0 / 16)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 32, height * 1.0 / 32] )"}},{name:"bright_upsample_8_blur_h",shader:"#source(qtek.compositor.gaussian_blur)",inputs:{texture:"bright_downsample_16"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 8)",height:"expr(height * 1.0 / 8)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 16, height * 1.0 / 16] )"}},{name:"bright_upsample_8_blur_v",shader:"#source(qtek.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_8_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 8)",height:"expr(height * 1.0 / 8)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 16, height * 1.0 / 16] )"}},{name:"bright_upsample_8_blend",shader:"#source(qtek.compositor.blend)",inputs:{texture1:"bright_upsample_8_blur_v",texture2:"bright_upsample_16_blur_v"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 8)",height:"expr(height * 1.0 / 8)",type:"HALF_FLOAT"}}},parameters:{weight1:.3,weight2:.7}},{name:"bright_upsample_4_blur_h",shader:"#source(qtek.compositor.gaussian_blur)",inputs:{texture:"bright_downsample_8"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 4)",height:"expr(height * 1.0 / 4)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 8, height * 1.0 / 8] )"}},{name:"bright_upsample_4_blur_v",shader:"#source(qtek.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_4_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 4)",height:"expr(height * 1.0 / 4)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 8, height * 1.0 / 8] )"}},{name:"bright_upsample_4_blend",shader:"#source(qtek.compositor.blend)",inputs:{texture1:"bright_upsample_4_blur_v",texture2:"bright_upsample_8_blend"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 4)",height:"expr(height * 1.0 / 4)",type:"HALF_FLOAT"}}},parameters:{weight1:.3,weight2:.7}},{name:"bright_upsample_2_blur_h",shader:"#source(qtek.compositor.gaussian_blur)",inputs:{texture:"bright_downsample_4"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 4, height * 1.0 / 4] )"}},{name:"bright_upsample_2_blur_v",shader:"#source(qtek.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_2_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 4, height * 1.0 / 4] )"}},{name:"bright_upsample_2_blend",shader:"#source(qtek.compositor.blend)",inputs:{texture1:"bright_upsample_2_blur_v",texture2:"bright_upsample_4_blend"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{weight1:.3,weight2:.7}},{name:"bright_upsample_full_blur_h",shader:"#source(qtek.compositor.gaussian_blur)",inputs:{texture:"bright"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 2, height * 1.0 / 2] )"}},{name:"bright_upsample_full_blur_v",shader:"#source(qtek.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_full_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 2, height * 1.0 / 2] )"}},{name:"bloom_composite",shader:"#source(qtek.compositor.blend)",inputs:{texture1:"bright_upsample_full_blur_v",texture2:"bright_upsample_2_blend"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{weight1:.3,weight2:.7}},{name:"coc",shader:"#source(ecgl.dof.coc)",outputs:{color:{parameters:{minFilter:"NEAREST",magFilter:"NEAREST",width:"expr(width * 1.0)",height:"expr(height * 1.0)"}}},parameters:{focalDist:50,focalRange:30}},{name:"dof_far_blur",shader:"#source(ecgl.dof.diskBlur)",inputs:{texture:"source",coc:"coc"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0, height * 1.0] )"}},{name:"dof_near_blur",shader:"#source(ecgl.dof.diskBlur)",inputs:{texture:"source",coc:"coc"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0, height * 1.0] )"},defines:{BLUR_NEARFIELD:null}},{name:"dof_coc_blur",shader:"#source(ecgl.dof.diskBlur)",inputs:{texture:"coc"},outputs:{color:{parameters:{minFilter:"NEAREST",magFilter:"NEAREST",width:"expr(width * 1.0)",height:"expr(height * 1.0)"}}},parameters:{textureSize:"expr( [width * 1.0, height * 1.0] )"},defines:{BLUR_COC:null}},{name:"dof_composite",shader:"#source(ecgl.dof.composite)",inputs:{original:"source",blurred:"dof_far_blur",nearfield:"dof_near_blur",coc:"coc",nearcoc:"dof_coc_blur"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}}},{name:"composite",shader:"#source(qtek.compositor.hdr.composite)",inputs:{texture:"source",bloom:"bloom_composite"},defines:{}},{name:"FXAA",shader:"#source(qtek.compositor.fxaa)",inputs:{texture:"composite"}}]};kt.import(En),kt.import(bn),kt.import(Sn),kt.import(An),kt.import(Nn),kt.import(wn),kt.import(Mn),kt.import(Rn),kt.import(Fi), -kt.import("@export ecgl.dof.coc\n\nuniform sampler2D depth;\n\nuniform float zNear: 0.1;\nuniform float zFar: 2000;\n\nuniform float focalDistance: 3;\nuniform float focalRange: 1;\nuniform float focalLength: 30;\nuniform float fstop: 2.8;\n\nvarying vec2 v_Texcoord;\n\n@import qtek.util.encode_float\n\nvoid main()\n{\n float z = texture2D(depth, v_Texcoord).r * 2.0 - 1.0;\n\n float dist = 2.0 * zNear * zFar / (zFar + zNear - z * (zFar - zNear));\n\n float aperture = focalLength / fstop;\n\n float coc;\n\n float uppper = focalDistance + focalRange;\n float lower = focalDistance - focalRange;\n if (dist <= uppper && dist >= lower) {\n coc = 0.5;\n }\n else {\n float focalAdjusted = dist > uppper ? uppper : lower;\n\n coc = abs(aperture * (focalLength * (dist - focalAdjusted)) / (dist * (focalAdjusted - focalLength)));\n coc = clamp(coc, 0.0, 2.0) / 2.00001;\n\n if (dist < lower) {\n coc = -coc;\n }\n coc = coc * 0.5 + 0.5;\n }\n\n gl_FragColor = encodeFloat(coc);\n}\n@end\n\n\n@export ecgl.dof.composite\n\n#define DEBUG 0\n\nuniform sampler2D original;\nuniform sampler2D blurred;\nuniform sampler2D nearfield;\nuniform sampler2D coc;\nuniform sampler2D nearcoc;\nvarying vec2 v_Texcoord;\n\n@import qtek.util.rgbm\n@import qtek.util.float\n\nvoid main()\n{\n vec4 blurredColor = decodeHDR(texture2D(blurred, v_Texcoord));\n vec4 originalColor = decodeHDR(texture2D(original, v_Texcoord));\n\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord));\n\n fCoc = abs(fCoc * 2.0 - 1.0);\n\n float weight = smoothstep(0.0, 1.0, fCoc);\n \n#ifdef NEARFIELD_ENABLED\n vec4 nearfieldColor = decodeHDR(texture2D(nearfield, v_Texcoord));\n float fNearCoc = decodeFloat(texture2D(nearcoc, v_Texcoord));\n fNearCoc = abs(fNearCoc * 2.0 - 1.0);\n\n gl_FragColor = encodeHDR(\n mix(\n nearfieldColor, mix(originalColor, blurredColor, weight),\n pow(1.0 - fNearCoc, 4.0)\n )\n );\n#else\n gl_FragColor = encodeHDR(mix(originalColor, blurredColor, weight));\n#endif\n\n}\n\n@end\n\n\n\n@export ecgl.dof.diskBlur\n\n#define POISSON_KERNEL_SIZE 16;\n\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\n\nuniform float blurRadius : 10.0;\nuniform vec2 textureSize : [512.0, 512.0];\n\nuniform vec2 poissonKernel[POISSON_KERNEL_SIZE];\n\nuniform float percent;\n\nfloat nrand(const in vec2 n) {\n return fract(sin(dot(n.xy ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\n@import qtek.util.rgbm\n@import qtek.util.float\n\n\nvoid main()\n{\n vec2 offset = blurRadius / textureSize;\n\n float rnd = 6.28318 * nrand(v_Texcoord + 0.07 * percent );\n float cosa = cos(rnd);\n float sina = sin(rnd);\n vec4 basis = vec4(cosa, -sina, sina, cosa);\n\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n\n#ifdef BLUR_COC\n float cocSum = 0.0;\n#else\n vec4 color = vec4(0.0);\n#endif\n\n\n float weightSum = 0.0;\n\n for (int i = 0; i < POISSON_KERNEL_SIZE; i++) {\n vec2 ofs = poissonKernel[i];\n\n ofs = vec2(dot(ofs, basis.xy), dot(ofs, basis.zw));\n\n vec2 uv = v_Texcoord + ofs * offset;\n vec4 texel = texture2D(texture, uv);\n\n float w = 1.0;\n#ifdef BLUR_COC\n float fCoc = decodeFloat(texel) * 2.0 - 1.0;\n cocSum += clamp(fCoc, -1.0, 0.0) * w;\n#else\n texel = decodeHDR(texel);\n #if !defined(BLUR_NEARFIELD)\n float fCoc = decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0;\n w *= abs(fCoc);\n #endif\n color += texel * w;\n#endif\n\n weightSum += w;\n }\n\n#ifdef BLUR_COC\n gl_FragColor = encodeFloat(clamp(cocSum / weightSum, -1.0, 0.0) * 0.5 + 0.5);\n#else\n color /= weightSum;\n gl_FragColor = encodeHDR(color);\n#endif\n}\n\n@end"),kt.import("@export ecgl.edge\n\nuniform sampler2D texture;\n\nuniform sampler2D normalTexture;\nuniform sampler2D depthTexture;\n\nuniform mat4 projectionInv;\n\nuniform vec2 textureSize;\n\nuniform vec4 edgeColor: [0,0,0,0.8];\n\nvarying vec2 v_Texcoord;\n\nvec3 packColor(vec2 coord) {\n float z = texture2D(depthTexture, coord).r * 2.0 - 1.0;\n vec4 p = vec4(v_Texcoord * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * p;\n\n return vec3(\n texture2D(normalTexture, coord).rg,\n -p4.z / p4.w / 5.0\n );\n}\n\nvoid main() {\n vec2 cc = v_Texcoord;\n vec3 center = packColor(cc);\n\n float size = clamp(1.0 - (center.z - 10.0) / 100.0, 0.0, 1.0) * 0.5;\n float dx = size / textureSize.x;\n float dy = size / textureSize.y;\n\n vec2 coord;\n vec3 topLeft = packColor(cc+vec2(-dx, -dy));\n vec3 top = packColor(cc+vec2(0.0, -dy));\n vec3 topRight = packColor(cc+vec2(dx, -dy));\n vec3 left = packColor(cc+vec2(-dx, 0.0));\n vec3 right = packColor(cc+vec2(dx, 0.0));\n vec3 bottomLeft = packColor(cc+vec2(-dx, dy));\n vec3 bottom = packColor(cc+vec2(0.0, dy));\n vec3 bottomRight = packColor(cc+vec2(dx, dy));\n\n vec3 v = -topLeft-2.0*top-topRight+bottomLeft+2.0*bottom+bottomRight;\n vec3 h = -bottomLeft-2.0*left-topLeft+bottomRight+2.0*right+topRight;\n\n float edge = sqrt(dot(h, h) + dot(v, v));\n\n edge = smoothstep(0.8, 1.0, edge);\n\n gl_FragColor = mix(texture2D(texture, v_Texcoord), vec4(edgeColor.rgb, 1.0), edgeColor.a * edge);\n}\n@end");var oa={color:{parameters:{width:function(e){return e.getWidth()},height:function(e){return e.getHeight()}}}},sa=["composite","FXAA"];Me.prototype.resize=function(e,t,r){r=r||1,e*=r,t*=r;var n=this._sourceTexture,i=this._depthTexture;n.width=e,n.height=t,i.width=e,i.height=t,this._gBufferPass.resize(e,t)},Me.prototype._ifRenderNormalPass=function(){return this._enableSSAO||this._enableEdge||this._enableSSR},Me.prototype._getPrevNode=function(e){for(var t=sa.indexOf(e.name)-1,r=this._finalNodesChain[t];r&&!this._compositor.getNodeByName(r.name);)t-=1,r=this._finalNodesChain[t];return r},Me.prototype._getNextNode=function(e){for(var t=sa.indexOf(e.name)+1,r=this._finalNodesChain[t];r&&!this._compositor.getNodeByName(r.name);)t+=1,r=this._finalNodesChain[t];return r},Me.prototype._addChainNode=function(e){var t=this._getPrevNode(e),r=this._getNextNode(e);t&&(t.outputs=oa,e.inputs.texture=t.name,r?(e.outputs=oa,r.inputs.texture=e.name):e.outputs=null,this._compositor.addNode(e))},Me.prototype._removeChainNode=function(e){var t=this._getPrevNode(e),r=this._getNextNode(e);t&&(r?(t.outputs=oa,r.inputs.texture=t.name):t.outputs=null,this._compositor.removeNode(e))},Me.prototype.updateNormal=function(e,t,r,n){this._ifRenderNormalPass()&&this._gBufferPass.update(e,t,r)},Me.prototype.updateSSAO=function(e,t,r,n){this._ssaoPass.update(e,r,n)},Me.prototype.enableSSAO=function(){this._enableSSAO=!0},Me.prototype.disableSSAO=function(){this._enableSSAO=!1},Me.prototype.enableSSR=function(){this._enableSSR=!0},Me.prototype.disableSSR=function(){this._enableSSR=!1},Me.prototype.getSSAOTexture=function(e,t,r,n){return this._ssaoPass.getTargetTexture()},Me.prototype.getSourceFrameBuffer=function(){return this._framebuffer},Me.prototype.getSourceTexture=function(){return this._sourceTexture},Me.prototype.disableFXAA=function(){this._removeChainNode(this._fxaaNode)},Me.prototype.enableFXAA=function(){this._addChainNode(this._fxaaNode)},Me.prototype.enableBloom=function(){this._compositeNode.inputs.bloom="bloom_composite",this._compositor.dirty()},Me.prototype.disableBloom=function(){this._compositeNode.inputs.bloom=null,this._compositor.dirty()},Me.prototype.enableDOF=function(){this._compositeNode.inputs.texture="dof_composite",this._compositor.dirty()},Me.prototype.disableDOF=function(){this._compositeNode.inputs.texture="source",this._compositor.dirty()},Me.prototype.enableColorCorrection=function(){this._compositeNode.shaderDefine("COLOR_CORRECTION"),this._enableColorCorrection=!0},Me.prototype.disableColorCorrection=function(){this._compositeNode.shaderUndefine("COLOR_CORRECTION"),this._enableColorCorrection=!1},Me.prototype.enableEdge=function(){this._enableEdge=!0},Me.prototype.disableEdge=function(){this._enableEdge=!1},Me.prototype.setBloomIntensity=function(e){null!=e&&this._compositeNode.setParameter("bloomIntensity",e)},Me.prototype.setSSAOParameter=function(e,t){if(null!=t)switch(e){case"quality":var r={low:6,medium:12,high:32,ultra:62}[t]||12;this._ssaoPass.setParameter("kernelSize",r);break;case"radius":this._ssaoPass.setParameter(e,t),this._ssaoPass.setParameter("bias",t/50);break;case"intensity":this._ssaoPass.setParameter(e,t)}},Me.prototype.setDOFParameter=function(e,t){if(null!=t)switch(e){case"focalDistance":case"focalRange":case"fstop":this._cocNode.setParameter(e,t);break;case"blurRadius":for(var r=0;r=this._haltonSequence.length},render:function(e){var t=this._blendPass;0===this._frame?(t.setUniform("weight1",0),t.setUniform("weight2",1)):(t.setUniform("weight1",.9),t.setUniform("weight2",.1)),t.setUniform("texture1",this._prevFrameTex),t.setUniform("texture2",this._sourceTex),this._blendFb.attach(this._outputTex),this._blendFb.bind(e),t.render(e),this._blendFb.unbind(e),this._outputPass.setUniform("texture",this._outputTex),this._outputPass.render(e);var r=this._prevFrameTex;this._prevFrameTex=this._outputTex,this._outputTex=r,this._frame++},dispose:function(e){this._sourceFb.dispose(e),this._blendFb.dispose(e),this._prevFrameTex.dispose(e),this._outputTex.dispose(e),this._sourceTex.dispose(e),this._outputPass.dispose(e),this._blendPass.dispose(e)}},Ce.prototype.setProjection=function(e){var t=this.camera;t&&t.update(),"perspective"===e?this.camera instanceof en||(this.camera=new en,t&&this.camera.setLocalTransform(t.localTransform)):this.camera instanceof tn||(this.camera=new tn,t&&this.camera.setLocalTransform(t.localTransform)),this.camera.near=.1,this.camera.far=2e3},Ce.prototype.setViewport=function(e,t,r,n,i){this.camera instanceof en&&(this.camera.aspect=r/n),i=i||1,this.viewport.x=e,this.viewport.y=t,this.viewport.width=r,this.viewport.height=n,this.viewport.devicePixelRatio=i,this._compositor.resize(r*i,n*i),this._temporalSS.resize(r*i,n*i)},Ce.prototype.containPoint=function(e,t){var r=this.viewport;return t=this.layer.renderer.getHeight()-t,e>=r.x&&t>=r.y&&e<=r.x+r.width&&t<=r.y+r.height};var ua=new jt;Ce.prototype.castRay=function(e,t,r){var n=this.layer.renderer,i=n.viewport;return n.viewport=this.viewport,n.screenToNDC(e,t,ua),this.camera.castRay(ua,r),n.viewport=i,r},Ce.prototype.prepareRender=function(){this.scene.update(),this.camera.update(),this._frame=0,this._temporalSS.resetFrame()},Ce.prototype.render=function(e){this._doRender(e,this._frame),this._frame++},Ce.prototype.needsAccumulate=function(){return this.needsTemporalSS()||this._needsSortProgressively},Ce.prototype.needsTemporalSS=function(){var e=this._enableTemporalSS;return"auto"==e&&(e=this._enablePostEffect),e},Ce.prototype.hasDOF=function(){return this._enableDOF},Ce.prototype.isAccumulateFinished=function(){return this.needsTemporalSS()?this._temporalSS.isFinished():this._frame>30},Ce.prototype._doRender=function(e,t){var r=this.scene,n=this.camera,i=this.renderer;if(t=t||0,!e&&this._shadowMapPass&&(this._shadowMapPass.kernelPCF=this._pcfKernels[0],this._shadowMapPass.render(i,r,n,!0)),this._updateShadowPCFKernel(t),i.gl.clearColor(0,0,0,0),this._enablePostEffect&&(this.needsTemporalSS()&&this._temporalSS.jitterProjection(i,n),this._compositor.updateNormal(i,r,n,this._temporalSS.getFrame())),this._updateSSAO(i,r,n,this._temporalSS.getFrame()),this._enablePostEffect){var a=this._compositor.getSourceFrameBuffer();a.bind(i),i.gl.clear(i.gl.DEPTH_BUFFER_BIT|i.gl.COLOR_BUFFER_BIT),i.render(r,n,!0,this.preZ),this.afterRenderScene(i,r,n),a.unbind(i),this.needsTemporalSS()&&e?(this._compositor.composite(i,n,this._temporalSS.getSourceFrameBuffer(),this._temporalSS.getFrame()),i.setViewport(this.viewport),this._temporalSS.render(i)):(i.setViewport(this.viewport),this._compositor.composite(i,n,null,0))}else if(this.needsTemporalSS()&&e){var a=this._temporalSS.getSourceFrameBuffer();a.bind(i),i.saveClear(),i.clearBit=i.gl.DEPTH_BUFFER_BIT|i.gl.COLOR_BUFFER_BIT,i.render(r,n,!0,this.preZ),this.afterRenderScene(i,r,n),i.restoreClear(),a.unbind(i),i.setViewport(this.viewport),this._temporalSS.render(i)}else i.setViewport(this.viewport),i.render(r,n,!0,this.preZ),this.afterRenderScene(i,r,n);this.afterRenderAll(i,r,n)},Ce.prototype.afterRenderScene=function(e,t,r){},Ce.prototype.afterRenderAll=function(e,t,r){},Ce.prototype._updateSSAO=function(e,t,r,n){function i(e){for(var t=0;tthis.camera.far||e1&&n&&n.length>1){var a=ze(n)/ze(i);!isFinite(a)&&(a=1),t.pinchScale=a;var o=Ge(n);return t.pinchX=o[0],t.pinchY=o[1],{type:"pinch",target:e[0].target,event:t}}}}},ga=Qe.extend(function(){return{animation:null,domElement:null,target:null,_center:new ot,minDistance:.1,maxDistance:1e3,minAlpha:-90,maxAlpha:90,minBeta:-1/0,maxBeta:1/0,autoRotateAfterStill:0,autoRotateDirection:"cw",autoRotateSpeed:60,_mode:"rotate",damping:.8,rotateSensitivity:1,zoomSensitivity:1,panSensitivity:1,_needsUpdate:!1,_rotating:!1,_phi:0,_theta:0,_mouseX:0,_mouseY:0,_rotateVelocity:new jt,_panVelocity:new jt,_distance:20,_zoomSpeed:0,_stillTimeout:0,_animators:[],_gestureMgr:new ma}},function(){this._mouseDownHandler=this._mouseDownHandler.bind(this),this._mouseWheelHandler=this._mouseWheelHandler.bind(this),this._mouseMoveHandler=this._mouseMoveHandler.bind(this),this._mouseUpHandler=this._mouseUpHandler.bind(this),this._pinchHandler=this._pinchHandler.bind(this),this.update=this.update.bind(this),this.init()},{init:function(){var e=this.domElement;e.addEventListener("touchstart",this._mouseDownHandler),e.addEventListener("mousedown",this._mouseDownHandler),e.addEventListener("mousewheel",this._mouseWheelHandler),this.animation&&this.animation.on("frame",this.update)},dispose:function(){var e=this.domElement;e.removeEventListener("touchstart",this._mouseDownHandler),e.removeEventListener("touchmove",this._mouseMoveHandler),e.removeEventListener("touchend",this._mouseUpHandler),e.removeEventListener("mousedown",this._mouseDownHandler),e.removeEventListener("mousemove",this._mouseMoveHandler),e.removeEventListener("mouseup",this._mouseUpHandler),e.removeEventListener("mousewheel",this._mouseWheelHandler),this.animation&&this.animation.off("frame",this.update),this.stopAllAnimation()},getDistance:function(){return this._distance},setDistance:function(e){this._distance=e,this._needsUpdate=!0},getAlpha:function(){return this._theta/Math.PI*180},getBeta:function(){return-this._phi/Math.PI*180},getCenter:function(){return this._center.toArray()},setAlpha:function(e){e=Math.max(Math.min(this.maxAlpha,e),this.minAlpha),this._theta=e/180*Math.PI,this._needsUpdate=!0},setBeta:function(e){e=Math.max(Math.min(this.maxBeta,e),this.minBeta),this._phi=-e/180*Math.PI,this._needsUpdate=!0},setCenter:function(e){this._center.setArray(e)},setOption:function(e){e=e||{},["autoRotate","autoRotateAfterStill","autoRotateDirection","autoRotateSpeed","damping","minDistance","maxDistance","minAlpha","maxAlpha","minBeta","maxBeta","rotateSensitivity","zoomSensitivity","panSensitivity"].forEach(function(t){null!=e[t]&&(this[t]=e[t])},this),null!=e.distance&&this.setDistance(e.distance),null!=e.alpha&&this.setAlpha(e.alpha),null!=e.beta&&this.setBeta(e.beta),e.center&&this.setCenter(e.center)},animateTo:function(e){var t=this,r={},n={},i=this.animation;if(i)return null!=e.distance&&(r.distance=this.getDistance(),n.distance=e.distance),null!=e.alpha&&(r.alpha=this.getAlpha(),n.alpha=e.alpha),null!=e.beta&&(r.beta=this.getBeta(),n.beta=e.beta),null!=e.center&&(r.center=this.getCenter(),n.center=e.center),this._addAnimator(i.animate(r).when(e.duration||1e3,n).during(function(){null!=r.alpha&&t.setAlpha(r.alpha),null!=r.beta&&t.setBeta(r.beta),null!=r.distance&&t.setDistance(r.distance),null!=r.center&&t.setCenter(r.center),t._needsUpdate=!0}).done(e.done)).start(e.easing||"linear")},stopAllAnimation:function(){for(var e=0;e0},update:function(e){if(e=e||16,this._rotating){var t=("cw"===this.autoRotateDirection?1:-1)*this.autoRotateSpeed/180*Math.PI;this._phi-=t*e/1e3,this._needsUpdate=!0}else this._rotateVelocity.len()>0&&(this._needsUpdate=!0);(Math.abs(this._zoomSpeed)>.01||this._panVelocity.len()>0)&&(this._needsUpdate=!0),this._needsUpdate&&(this._updateDistance(Math.min(e,50)),this._updatePan(Math.min(e,50)),this._updateRotate(Math.min(e,50)),this._updateTransform(),this.target.update(),this.trigger("update"),this._needsUpdate=!1)},_updateRotate:function(e){var t=this._rotateVelocity;this._phi=t.y*e/20+this._phi,this._theta=t.x*e/20+this._theta,this.setAlpha(this.getAlpha()),this.setBeta(this.getBeta()),this._vectorDamping(t,this.damping)},_updateDistance:function(e){this._setDistance(this._distance+this._zoomSpeed*e/20),this._zoomSpeed*=this.damping},_setDistance:function(e){this._distance=Math.max(Math.min(e,this.maxDistance),this.minDistance)},_updatePan:function(e){var t=this._panVelocity,r=this._distance,n=this.target,i=n.worldTransform.y,a=n.worldTransform.x;this._center.scaleAndAdd(a,-t.x*r/200).scaleAndAdd(i,-t.y*r/200),this._vectorDamping(t,0)},_updateTransform:function(){var e=this.target,t=new ot,r=this._theta+Math.PI/2,n=this._phi+Math.PI/2,i=Math.sin(r);t.x=i*Math.cos(n),t.y=-Math.cos(r),t.z=i*Math.sin(n),e.position.copy(this._center).scaleAndAdd(t,this._distance),e.rotation.identity().rotateY(-this._phi).rotateX(-this._theta)},_startCountingStill:function(){clearTimeout(this._stillTimeout);var e=this.autoRotateAfterStill,t=this;!isNaN(e)&&e>0&&(this._stillTimeout=setTimeout(function(){t._rotating=!0},1e3*e))},_vectorDamping:function(e,t){var r=e.len();r*=t,r<1e-4&&(r=0),e.normalize().scale(r)},decomposeTransform:function(){if(this.target){var e=new ot;e.eulerFromQuat(this.target.rotation.normalize(),"ZYX"),this._theta=-e.x,this._phi=-e.y,this.setBeta(this.getBeta()),this.setAlpha(this.getAlpha()),this._setDistance(this.target.position.dist(this._center))}},_mouseDownHandler:function(e){if(!this._isAnimating()){var t=e.clientX,r=e.clientY;if(e.targetTouches){var n=e.targetTouches[0];t=n.clientX,r=n.clientY,this._mode="rotate",this._processGesture(e,"start")}var i=this.domElement;i.addEventListener("touchmove",this._mouseMoveHandler),i.addEventListener("touchend",this._mouseUpHandler),i.addEventListener("mousemove",this._mouseMoveHandler),i.addEventListener("mouseup",this._mouseUpHandler),0===e.button?this._mode="rotate":1===e.button&&(this._mode="pan"),this._rotateVelocity.set(0,0),this._rotating=!1,this.autoRotate&&this._startCountingStill(),this._mouseX=t,this._mouseY=r}},_mouseMoveHandler:function(e){if(!this._isAnimating()){var t,r=e.clientX,n=e.clientY;if(e.targetTouches){var i=e.targetTouches[0];r=i.clientX,n=i.clientY,t=this._processGesture(e,"change")}var a=We(this.panSensitivity),o=We(this.rotateSensitivity);t||("rotate"===this._mode?(this._rotateVelocity.y=(r-this._mouseX)/this.domElement.clientHeight*2*o[0],this._rotateVelocity.x=(n-this._mouseY)/this.domElement.clientWidth*2*o[1]):"pan"===this._mode&&(this._panVelocity.x=(r-this._mouseX)/this.domElement.clientWidth*a[0]*400,this._panVelocity.y=(-n+this._mouseY)/this.domElement.clientHeight*a[1]*400)),this._mouseX=r,this._mouseY=n,e.preventDefault()}},_mouseWheelHandler:function(e){if(!this._isAnimating()){var t=e.wheelDelta||-e.detail;0!==t&&this._zoomHandler(e,t>0?-1:1)}},_pinchHandler:function(e){this._isAnimating()||this._zoomHandler(e,e.pinchScale>1?-.4:.4)},_zoomHandler:function(e,t){var r=Math.max(Math.min(this._distance-this.minDistance,this.maxDistance-this._distance));this._zoomSpeed=t*Math.max(r/40*this.zoomSensitivity,.2),this._rotating=!1,this.autoRotate&&"rotate"===this._mode&&this._startCountingStill(),e.preventDefault()},_mouseUpHandler:function(e){var t=this.domElement;t.removeEventListener("touchmove",this._mouseMoveHandler),t.removeEventListener("touchend",this._mouseUpHandler),t.removeEventListener("mousemove",this._mouseMoveHandler),t.removeEventListener("mouseup",this._mouseUpHandler),this._processGesture(e,"end")},_addAnimator:function(e){var t=this._animators;return t.push(e),e.done(function(){var r=t.indexOf(e);r>=0&&t.splice(r,1)}),e},_processGesture:function(e,t){var r=this._gestureMgr;"start"===t&&r.clear();var n=r.recognize(e,null,this.domElement);if("end"===t&&r.clear(),n){var i=n.type;e.gestureEvent=i,this._pinchHandler(n.event)}return n}});Object.defineProperty(ga.prototype,"autoRotate",{get:function(){return this._autoRotate},set:function(e){this._autoRotate=e,this._rotating=e}}), -Object.defineProperty(ga.prototype,"target",{get:function(){return this._target},set:function(e){e&&e.target&&this.setCenter(e.target.toArray()),this._target=e,this.decomposeTransform()}});var ya=it.vec4,xa=function(e,t,r,n){e=e||0,t=t||0,r=r||0,n=n||0,this._array=ya.fromValues(e,t,r,n),this._dirty=!0};xa.prototype={constructor:xa,add:function(e){return ya.add(this._array,this._array,e._array),this._dirty=!0,this},set:function(e,t,r,n){return this._array[0]=e,this._array[1]=t,this._array[2]=r,this._array[3]=n,this._dirty=!0,this},setArray:function(e){return this._array[0]=e[0],this._array[1]=e[1],this._array[2]=e[2],this._array[3]=e[3],this._dirty=!0,this},clone:function(){return new xa(this.x,this.y,this.z,this.w)},copy:function(e){return ya.copy(this._array,e._array),this._dirty=!0,this},dist:function(e){return ya.dist(this._array,e._array)},distance:function(e){return ya.distance(this._array,e._array)},div:function(e){return ya.div(this._array,this._array,e._array),this._dirty=!0,this},divide:function(e){return ya.divide(this._array,this._array,e._array),this._dirty=!0,this},dot:function(e){return ya.dot(this._array,e._array)},len:function(){return ya.len(this._array)},length:function(){return ya.length(this._array)},lerp:function(e,t,r){return ya.lerp(this._array,e._array,t._array,r),this._dirty=!0,this},min:function(e){return ya.min(this._array,this._array,e._array),this._dirty=!0,this},max:function(e){return ya.max(this._array,this._array,e._array),this._dirty=!0,this},mul:function(e){return ya.mul(this._array,this._array,e._array),this._dirty=!0,this},multiply:function(e){return ya.multiply(this._array,this._array,e._array),this._dirty=!0,this},negate:function(){return ya.negate(this._array,this._array),this._dirty=!0,this},normalize:function(){return ya.normalize(this._array,this._array),this._dirty=!0,this},random:function(e){return ya.random(this._array,e),this._dirty=!0,this},scale:function(e){return ya.scale(this._array,this._array,e),this._dirty=!0,this},scaleAndAdd:function(e,t){return ya.scaleAndAdd(this._array,this._array,e._array,t),this._dirty=!0,this},sqrDist:function(e){return ya.sqrDist(this._array,e._array)},squaredDistance:function(e){return ya.squaredDistance(this._array,e._array)},sqrLen:function(){return ya.sqrLen(this._array)},squaredLength:function(){return ya.squaredLength(this._array)},sub:function(e){return ya.sub(this._array,this._array,e._array),this._dirty=!0,this},subtract:function(e){return ya.subtract(this._array,this._array,e._array),this._dirty=!0,this},transformMat4:function(e){return ya.transformMat4(this._array,this._array,e._array),this._dirty=!0,this},transformQuat:function(e){return ya.transformQuat(this._array,this._array,e._array),this._dirty=!0,this},toString:function(){return"["+Array.prototype.join.call(this._array,",")+"]"},toArray:function(){return Array.prototype.slice.call(this._array)}};var Ta=Object.defineProperty;if(Ta){var Ea=xa.prototype;Ta(Ea,"x",{get:function(){return this._array[0]},set:function(e){this._array[0]=e,this._dirty=!0}}),Ta(Ea,"y",{get:function(){return this._array[1]},set:function(e){this._array[1]=e,this._dirty=!0}}),Ta(Ea,"z",{get:function(){return this._array[2]},set:function(e){this._array[2]=e,this._dirty=!0}}),Ta(Ea,"w",{get:function(){return this._array[3]},set:function(e){this._array[3]=e,this._dirty=!0}})}xa.add=function(e,t,r){return ya.add(e._array,t._array,r._array),e._dirty=!0,e},xa.set=function(e,t,r,n,i){ya.set(e._array,t,r,n,i),e._dirty=!0},xa.copy=function(e,t){return ya.copy(e._array,t._array),e._dirty=!0,e},xa.dist=function(e,t){return ya.distance(e._array,t._array)},xa.distance=xa.dist,xa.div=function(e,t,r){return ya.divide(e._array,t._array,r._array),e._dirty=!0,e},xa.divide=xa.div,xa.dot=function(e,t){return ya.dot(e._array,t._array)},xa.len=function(e){return ya.length(e._array)},xa.lerp=function(e,t,r,n){return ya.lerp(e._array,t._array,r._array,n),e._dirty=!0,e},xa.min=function(e,t,r){return ya.min(e._array,t._array,r._array),e._dirty=!0,e},xa.max=function(e,t,r){return ya.max(e._array,t._array,r._array),e._dirty=!0,e},xa.mul=function(e,t,r){return ya.multiply(e._array,t._array,r._array),e._dirty=!0,e},xa.multiply=xa.mul,xa.negate=function(e,t){return ya.negate(e._array,t._array),e._dirty=!0,e},xa.normalize=function(e,t){return ya.normalize(e._array,t._array),e._dirty=!0,e},xa.random=function(e,t){return ya.random(e._array,t),e._dirty=!0,e},xa.scale=function(e,t,r){return ya.scale(e._array,t._array,r),e._dirty=!0,e},xa.scaleAndAdd=function(e,t,r,n){return ya.scaleAndAdd(e._array,t._array,r._array,n),e._dirty=!0,e},xa.sqrDist=function(e,t){return ya.sqrDist(e._array,t._array)},xa.squaredDistance=xa.sqrDist,xa.sqrLen=function(e){return ya.sqrLen(e._array)},xa.squaredLength=xa.sqrLen,xa.sub=function(e,t,r){return ya.subtract(e._array,t._array,r._array),e._dirty=!0,e},xa.subtract=xa.sub,xa.transformMat4=function(e,t,r){return ya.transformMat4(e._array,t._array,r._array),e._dirty=!0,e},xa.transformQuat=function(e,t,r){return ya.transformQuat(e._array,t._array,r._array),e._dirty=!0,e};var ba=Qe.extend(function(){return{dom:null,renderer:null,camera:null,_boundingBox:new pt,_hotspotRoot:null,_hotspots:[]}},function(){if(!this.dom||!this.renderer||!this.camera)throw new Error("Tip manager needs `root`, `camera`, `renderer`");var e=this._hotspotRoot=document.createElement("div");e.style.cssText="position:absolute;top:0;left:0;right:0;bottom:0;overflow:hidden;",this.dom.appendChild(e)},{setBoundingBox:function(e,t){this._boundingBox.min.setArray(e),this._boundingBox.max.setArray(t)},add:function(e,t){if("string"==typeof t){var r=document.createElement("div");r.innerHTML=t,t=r}return t.classList.add("qmv-annotation"),t.style.position="absolute",this._hotspotRoot.appendChild(t),this._hotspots.push({position:e,dom:t}),t},remove:function(e){for(var t=-1,r=0;r=0&&(this._hotspots.splice(t,1),this._hotspotRoot.removeChild(e))},update:function(){var e=new xa,t=new pt;this._hotspots.forEach(function(r){var n=r.position;e.set(n[0],n[1],n[2],1),e.transformMat4(this.camera.viewMatrix);var i=e.z;e.transformMat4(this.camera.projectionMatrix),e.scale(1/e.w);var a=.5*(e.x+1)*this.renderer.getWidth(),o=.5*(e.y+1)*this.renderer.getHeight();r.dom.style.left=a+"px",r.dom.style.top=this.renderer.getHeight()-o+"px";null==r.farAlpha||r.farAlpha,null==r.nearAlpha||r.nearAlpha;t.copy(this._boundingBox),t.applyTransform(this.camera.viewMatrix);t.max.z,t.min.z,t.max.z;r.dom.style.opacity=1,r.onupdate&&r.onupdate(a,o)},this)}});kt.import("@export qmv.ground.vertex\n@import qtek.lambert.vertex\n@end\n\n\n@export qmv.ground.fragment\n\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\nuniform float gridSize: 5;\nuniform float gridSize2: 1;\nuniform vec4 gridColor: [0, 0, 0, 1];\nuniform vec4 gridColor2: [0.3, 0.3, 0.3, 1];\n\nuniform float glossiness: 0.7;\n\n#ifdef SSAOMAP_ENABLED\nuniform sampler2D ssaoMap;\nuniform vec4 viewport : VIEWPORT;\n#endif\n\n#ifdef AMBIENT_LIGHT_COUNT\n@import qtek.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import qtek.header.ambient_sh_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import qtek.header.directional_light\n#endif\n\n@import qtek.plugin.compute_shadow_map\n\nvoid main()\n{\n gl_FragColor = color;\n\n float wx = v_WorldPosition.x;\n float wz = v_WorldPosition.z;\n float x0 = abs(fract(wx / gridSize - 0.5) - 0.5) / fwidth(wx) * gridSize / 2.0;\n float z0 = abs(fract(wz / gridSize - 0.5) - 0.5) / fwidth(wz) * gridSize / 2.0;\n\n float x1 = abs(fract(wx / gridSize2 - 0.5) - 0.5) / fwidth(wx) * gridSize2;\n float z1 = abs(fract(wz / gridSize2 - 0.5) - 0.5) / fwidth(wz) * gridSize2;\n\n float v0 = 1.0 - clamp(min(x0, z0), 0.0, 1.0);\n float v1 = 1.0 - clamp(min(x1, z1), 0.0, 1.0);\n if (v0 > 0.1) {\n gl_FragColor = mix(gl_FragColor, gridColor, v0);\n }\n else {\n gl_FragColor = mix(gl_FragColor, gridColor2, v1);\n }\n\n vec3 diffuseColor = vec3(0.0, 0.0, 0.0);\n\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {\n diffuseColor += ambientLightColor[_idx_];\n }\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseColor += calcAmbientSHLight(_idx_, v_Normal) * ambientSHLightColor[_idx_];\n }}\n#endif\n\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++)\n {\n vec3 lightDirection = -directionalLightDirection[i];\n vec3 lightColor = directionalLightColor[i];\n\n float ndl = dot(v_Normal, normalize(lightDirection));\n\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsDir[i];\n }\n#endif\n\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * shadowContrib;\n }\n#endif\n\n#ifdef SSAOMAP_ENABLED\n diffuseColor *= texture2D(ssaoMap, (gl_FragCoord.xy - viewport.xy) / viewport.zw).r;\n#endif\n\n gl_FragColor.rgb *= diffuseColor;\n\n gl_FragColor.a *= 1.0 - clamp(length(v_WorldPosition.xz) / 30.0, 0.0, 1.0);\n\n}\n\n@end");var Sa=["diffuseMap","normalMap","emissiveMap","metalnessMap","roughnessMap","specularMap","glossinessMap"];qe.prototype.init=function(e,t){t=t||{},this.root=e,this._animation=new Fn;var r=new tr({devicePixelRatio:t.devicePixelRatio||window.devicePixelRatio});e.appendChild(r.canvas),r.canvas.style.cssText="position:absolute;left:0;top:0",this._renderer=r,this._renderMain=new Ce(r,t.shadow,"perspective"),this._renderMain.afterRenderScene=function(e,t,r){this.trigger("renderscene",e,t,r)}.bind(this),this._renderMain.afterRenderAll=function(e,t,r){this.trigger("afterrender",e,t,r)}.bind(this),this._renderMain.preZ=t.preZ||!1;var n=this._cameraControl=new ga({renderer:r,animation:this._animation,domElement:e});n.target=this._renderMain.camera,n.init(),this._hotspotManager=new ba({dom:e,renderer:r,camera:this._renderMain.camera}),this._skeletons=[],this._clips=[],this._takes=[],this._materialsMap={},this._sceneHelper=new Le(this._renderMain.scene),this._sceneHelper.initLight(this._renderMain.scene),this.resize(),t.postEffect&&this.setPostEffect(t.postEffect),t.mainLight&&this.setMainLight(t.mainLight),t.secondaryLight&&this.setSecondaryLight(t.secondaryLight),t.tertiaryLight&&this.setTertiaryLight(t.tertiaryLight),t.ambientCubemapLight&&this.setAmbientCubemapLight(t.ambientCubemapLight),t.ambientLight&&this.setAmbientLight(t.ambientLight),t.environment&&this.setEnvironment(t.environment),this._createGround(),t.ground&&this.setGround(t.ground),this.setCameraControl({distance:20,minDisntance:2,maxDistance:100,center:[0,0,0]}),this._enablePicking=t.picking||!1,this._initHandlers(),n.on("update",function(){this.trigger("updatecamera",{center:n.getCenter(),alpha:n.getAlpha(),beta:n.getBeta(),distance:n.getDistance()}),this.refresh()},this),this.shaderLibrary=Gt.createLibrary()},qe.prototype._createGround=function(){var e=new Dr({isGround:!0,material:new qt({shader:new kt({vertex:kt.source("qmv.ground.vertex"),fragment:kt.source("qmv.ground.fragment")}),transparent:!0}),castShadow:!1,geometry:new Wn});e.material.set("color",[1,1,1,1]),e.scale.set(40,40,1),e.rotation.rotateX(-Math.PI/2),this._groundMesh=e,this._renderMain.scene.add(e)},qe.prototype._addModel=function(e,t,r,n){this.removeModel(),this._renderMain.scene.add(e),this._skeletons=r.slice(),this._modelNode=e,this._setAnimationClips(n),t&&t.length&&(this._nodes=t);var i={};e.traverse(function(e){if(e.material){var t=e.material;i[t.name]=i[t.name]||[],i[t.name].push(t)}},this),this._materialsMap=i,this._updateMaterialsSRGB(),this._stopAccumulating()},qe.prototype._removeAnimationClips=function(){this._clips.forEach(function(e){this._animation.removeClip(e)},this),this._clips=[],this._takes=[]},qe.prototype._setAnimationClips=function(e){function t(){r.refresh()}var r=this;e.forEach(function(e){e.tracks.forEach(function(e){e.target||(e.target=this._nodes[e.targetNodeIndex])},this),e.onframe=t,this._animation.addClip(e),this._takes.push({name:e.name,range:[0,e.life],clip:e})},this),this._clips=e.slice()},qe.prototype._initHandlers=function(){this._picking=new Vn({renderer:this._renderer,scene:this._renderMain.scene,camera:this._renderMain.camera}),this._clickHandler=this._clickHandler.bind(this),this._mouseDownHandler=this._mouseDownHandler.bind(this),this.root.addEventListener("mousedown",this._mouseDownHandler),this.root.addEventListener("click",this._clickHandler)},qe.prototype._mouseDownHandler=function(e){this._startX=e.clientX,this._startY=e.clientY},qe.prototype._clickHandler=function(e){if(this._enablePicking||this._renderMain.isDOFEnabled()){var t=e.clientX-this._startX,r=e.clientY-this._startY;if(!(Math.sqrt(t*t+r*r)>=40)){var n=this._picking.pick(e.clientX,e.clientY,!0);n&&!n.target.isGround?(this._renderMain.setDOFFocusOnPoint(n.distance),this.trigger("doffocus",n),this._selectResult=n,this.trigger("select",n),this.refresh()):(this._selectResult&&this.trigger("unselect",this._selectResult),this._selectResult=null)}}},qe.prototype.enablePicking=function(){this._enablePicking=!0},qe.prototype.disablePicking=function(){this._enablePicking=!1},qe.prototype.setModelUpAxis=function(e){var t=this._modelNode;t&&(t.position.set(0,0,0),t.scale.set(1,1,1),t.rotation.identity(),"z"===e.toLowerCase()&&t.rotation.identity().rotateX(-Math.PI/2),this.autoFitModel())},qe.prototype.setTextureFlipY=function(e){if(this._modelNode){for(var t in this._materialsMap)for(var r=0;r1||o<0){r=!0;break}}if(r)for(var n=0;n=0&&s.splice(n,1),u[e]=null}}t=t||{};var i=this._materialsMap[e],a=this,o=this._textureFlipY;if(!i||!i.length)return void console.warn("Material %s not exits",e);var s=i[0].shader.getEnabledTextures(),u={};["diffuseMap","normalMap","parallaxOcclusionMap","emissiveMap"].forEach(function(e){n(e)},this),i[0].shader.isDefined("fragment","USE_METALNESS")?["metalnessMap","roughnessMap"].forEach(function(e){n(e)},this):["specularMap","glossinessMap"].forEach(function(e){n(e)},this),(u.normalMap||u.parallaxOcclusionMap)&&this._modelNode.traverse(function(t){t.material&&t.material.name===e&&(t.geometry.attributes.tangent.value||t.geometry.generateTangents())}),i.forEach(function(e){null!=t.transparent&&(e.transparent=!!t.transparent,e.depthMask=!t.transparent),["color","emission","specularColor"].forEach(function(r){null!=t[r]&&e.set(r,na.parseColor(t[r]))}),["alpha","alphaCutoff","metalness","roughness","glossiness","emissionIntensity","uvRepeat","parallaxOcclusionScale"].forEach(function(r){null!=t[r]&&e.set(r,t[r])});for(var r in u)e.set(r,u[r]);e.attachShader(this.shaderLibrary.get("qtek."+(this._shaderName||"standard"),{fragmentDefines:e.shader.fragmentDefines,textures:s,vertexDefines:e.shader.vertexDefines,precision:e.shader.precision}),!0)},this),this.refresh()},qe.prototype.getMaterial=function(e){function t(e){var t=n.get(e);if(!t)return"";for(var r=t.image;r.srcImage;)r=r.srcImage;return r&&r.src||""}var r=this._materialsMap[e];if(!r)return void console.warn("Material %s not exits",e);var n=r[0],i={name:e};return["color","emission"].forEach(function(e){i[e]=na.stringifyColor(n.get(e),"hex")}),["alpha","alphaCutoff","emissionIntensity","uvRepeat","parallaxOcclusionScale"].forEach(function(e){i[e]=n.get(e)}),["diffuseMap","normalMap","parallaxOcclusionMap","emissiveMap"].forEach(function(e){i[e]=t(e)}),n.shader.isDefined("fragment","USE_METALNESS")?(["metalness","roughness"].forEach(function(e){i[e]=n.get(e)}),["metalnessMap","roughnessMap"].forEach(function(e){i[e]=t(e)}),i.type="pbrMetallicRoughness"):(i.specularColor=na.stringifyColor(n.get("specularColor"),"hex"),i.glossiness=n.get("glossiness"),["specularMap","glossinessMap"].forEach(function(e){i[e]=t(e)}),i.type="pbrSpecularGlossiness"),i},qe.prototype.setGround=function(e){this._groundMesh.invisible=!e.show,this.refresh()},qe.prototype.getMaterialsNames=function(){return Object.keys(this._materialsMap)},qe.prototype.setPostEffect=function(e){this._renderMain.setPostEffect(e),this._updateMaterialsSRGB(),this.refresh()},qe.prototype.start=function(){if(this._disposed)return void console.warn("Viewer already disposed");this._animation.start(),this._animation.on("frame",this._loop,this)},qe.prototype.stop=function(){this._animation.stop(),this._animation.off("frame",this._loop)},qe.prototype.addHotspot=function(e,t){return this._hotspotManager.add(e,t)},qe.prototype.setPose=function(e){this._clips.forEach(function(t){t.setTime(e)}),this._skeletons.forEach(function(e){e.update()}),this.refresh()},qe.prototype.getAnimationDuration=function(){var e=0;return this._clips.forEach(function(t){e=Math.max(t.life,e)}),e},qe.prototype.refresh=function(){this._needsRefresh=!0},qe.prototype.getRenderer=function(){return this._renderer},qe.prototype._updateMaterialsSRGB=function(){var e=this._renderMain.isLinearSpace();for(var t in this._materialsMap)for(var r=this._materialsMap[t],n=0;n} propList * @return {Object} - * @memberOf qtek.core.util + * @memberOf clay.core.util */ - extendWithPropList: function(target, source, propList) { + extendWithPropList: function (target, source, propList) { if (source) { for (var i = 0; i < propList.length; i++) { var propName = propList[i]; @@ -415,9 +415,9 @@ var util = { * @param {Object} source * @param {Array.} propList * @return {Object} - * @memberOf qtek.core.util + * @memberOf clay.core.util */ - defaultsWithPropList: function(target, source, propList) { + defaultsWithPropList: function (target, source, propList) { if (source) { for (var i = 0; i < propList.length; i++) { var propName = propList[i]; @@ -432,19 +432,21 @@ var util = { * @param {Object|Array} obj * @param {Function} iterator * @param {Object} [context] - * @memberOf qtek.core.util + * @memberOf clay.core.util */ - each: function(obj, iterator, context) { + each: function (obj, iterator, context) { if (!(obj && iterator)) { return; } if (obj.forEach && obj.forEach === nativeForEach) { obj.forEach(iterator, context); - } else if (obj.length === + obj.length) { + } + else if (obj.length === + obj.length) { for (var i = 0, len = obj.length; i < len; i++) { iterator.call(context, obj[i], i, obj); } - } else { + } + else { for (var key in obj) { if (obj.hasOwnProperty(key)) { iterator.call(context, obj[key], key, obj); @@ -454,12 +456,12 @@ var util = { }, /** - * Is object ? + * Is object * @param {} obj * @return {boolean} - * @memberOf qtek.core.util + * @memberOf clay.core.util */ - isObject: function(obj) { + isObject: function (obj) { return obj === Object(obj); }, @@ -467,9 +469,9 @@ var util = { * Is array ? * @param {} obj * @return {boolean} - * @memberOf qtek.core.util + * @memberOf clay.core.util */ - isArray: function(obj) { + isArray: function (obj) { return Array.isArray(obj); }, @@ -477,12 +479,13 @@ var util = { * Is array like, which have a length property * @param {} obj * @return {boolean} - * @memberOf qtek.core.util + * @memberOf clay.core.util */ - isArrayLike: function(obj) { + isArrayLike: function (obj) { if (!obj) { return false; - } else { + } + else { return obj.length === + obj.length; } }, @@ -490,20 +493,23 @@ var util = { /** * @param {} obj * @return {} - * @memberOf qtek.core.util + * @memberOf clay.core.util */ - clone: function(obj) { + clone: function (obj) { if (!util.isObject(obj)) { return obj; - } else if (util.isArray(obj)) { + } + else if (util.isArray(obj)) { return obj.slice(); - } else if (util.isArrayLike(obj)) { // is typed array + } + else if (util.isArrayLike(obj)) { // is typed array var ret = new obj.constructor(obj.length); for (var i = 0; i < obj.length; i++) { ret[i] = obj[i]; } return ret; - } else { + } + else { return util.extend({}, obj); } } @@ -512,14 +518,14 @@ var util = { /** * Base class of all objects * @constructor - * @alias qtek.core.Base - * @mixes qtek.core.mixin.notifier + * @alias clay.core.Base + * @mixes clay.core.mixin.notifier */ var Base = function () { /** * @type {number} */ - this.__GUID__ = util.genGUID(); + this.__uid__ = util.genGUID(); }; Base.__initializers__ = [ @@ -531,11 +537,6 @@ Base.__initializers__ = [ util.extend(Base, extendMixin); util.extend(Base.prototype, notifier); -/** - * @namespace qtek.core.glinfo - * @see http://www.khronos.org/registry/webgl/extensions/ - */ - var EXTENSION_LIST = [ 'OES_texture_float', 'OES_texture_half_float', @@ -558,7 +559,7 @@ var PARAMETER_NAMES = [ 'MAX_CUBE_MAP_TEXTURE_SIZE' ]; -function GLInfo(_gl) { +function GLInfo(_gl) { var extensions = {}; var parameters = {}; @@ -573,12 +574,6 @@ function GLInfo(_gl) { parameters[name] = _gl.getParameter(_gl[name]); } - /** - * Get extension - * @param {string} name - Extension name, vendorless - * @return {WebGLExtension} - * @memberOf qtek.core.glinfo - */ this.getExtension = function (name) { if (!(name in extensions)) { createExtension(name); @@ -586,11 +581,6 @@ function GLInfo(_gl) { return extensions[name]; }; - /** - * Get parameter - * @param {string} name Parameter name - * @return {*} - */ this.getParameter = function (name) { return parameters[name]; }; @@ -608,7 +598,7 @@ function GLInfo(_gl) { } /** - * @namespace qtek.core.glenum + * @namespace clay.core.glenum * @see http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14 */ var glenum = { @@ -1135,17 +1125,21 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -if(!GLMAT_EPSILON) { - var GLMAT_EPSILON = 0.000001; +var g = typeof window === 'undefined' ? commonjsGlobal : window; +var GLMAT_EPSILON = g.GLMAT_EPSILON; +if(GLMAT_EPSILON == null) { + GLMAT_EPSILON = 0.000001; } -if(!GLMAT_ARRAY_TYPE) { - var GLMAT_ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array; -} +// Use Array instead of Float32Array. It seems to be much faster and higher precision. +var GLMAT_ARRAY_TYPE = g.GLMAT_ARRAY_TYPE || Array; +// if(!GLMAT_ARRAY_TYPE) { +// GLMAT_ARRAY_TYPE = (typeof Float32Array !== 'undefined') ? Float32Array : Array; +// } +var GLMAT_RANDOM = g.GLMAT_RANDOM; if(!GLMAT_RANDOM) { - var GLMAT_RANDOM = Math.random; + GLMAT_RANDOM = Math.random; } /** @@ -5429,7 +5423,7 @@ var vec3$2 = glmatrix.vec3; /** * @constructor - * @alias qtek.math.Vector3 + * @alias clay.Vector3 * @param {number} x * @param {number} y * @param {number} z @@ -5441,33 +5435,35 @@ var Vector3 = function(x, y, z) { z = z || 0; /** - * Storage of Vector3, read and write of x, y, z will change the values in _array - * All methods also operate on the _array instead of x, y, z components - * @name _array + * Storage of Vector3, read and write of x, y, z will change the values in array + * All methods also operate on the array instead of x, y, z components + * @name array * @type {Float32Array} + * @memberOf clay.Vector3# */ - this._array = vec3$2.fromValues(x, y, z); + this.array = vec3$2.fromValues(x, y, z); /** * Dirty flag is used by the Node to determine * if the matrix is updated to latest * @name _dirty * @type {boolean} + * @memberOf clay.Vector3# */ this._dirty = true; }; Vector3.prototype = { - constructor : Vector3, + constructor: Vector3, /** * Add b to self - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} b + * @return {clay.Vector3} */ add: function (b) { - vec3$2.add(this._array, this._array, b._array); + vec3$2.add(this.array, this.array, b.array); this._dirty = true; return this; }, @@ -5477,12 +5473,12 @@ Vector3.prototype = { * @param {number} x * @param {number} y * @param {number} z - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ set: function (x, y, z) { - this._array[0] = x; - this._array[1] = y; - this._array[2] = z; + this.array[0] = x; + this.array[1] = y; + this.array[2] = z; this._dirty = true; return this; }, @@ -5490,12 +5486,12 @@ Vector3.prototype = { /** * Set x, y and z components from array * @param {Float32Array|number[]} arr - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ setArray: function (arr) { - this._array[0] = arr[0]; - this._array[1] = arr[1]; - this._array[2] = arr[2]; + this.array[0] = arr[0]; + this.array[1] = arr[1]; + this.array[2] = arr[2]; this._dirty = true; return this; @@ -5503,7 +5499,7 @@ Vector3.prototype = { /** * Clone a new Vector3 - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ clone: function () { return new Vector3(this.x, this.y, this.z); @@ -5511,74 +5507,74 @@ Vector3.prototype = { /** * Copy from b - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} b + * @return {clay.Vector3} */ copy: function (b) { - vec3$2.copy(this._array, b._array); + vec3$2.copy(this.array, b.array); this._dirty = true; return this; }, /** * Cross product of self and b, written to a Vector3 out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} */ cross: function (a, b) { - vec3$2.cross(this._array, a._array, b._array); + vec3$2.cross(this.array, a.array, b.array); this._dirty = true; return this; }, /** * Alias for distance - * @param {qtek.math.Vector3} b + * @param {clay.Vector3} b * @return {number} */ dist: function (b) { - return vec3$2.dist(this._array, b._array); + return vec3$2.dist(this.array, b.array); }, /** * Distance between self and b - * @param {qtek.math.Vector3} b + * @param {clay.Vector3} b * @return {number} */ distance: function (b) { - return vec3$2.distance(this._array, b._array); + return vec3$2.distance(this.array, b.array); }, /** * Alias for divide - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} b + * @return {clay.Vector3} */ div: function (b) { - vec3$2.div(this._array, this._array, b._array); + vec3$2.div(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Divide self by b - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} b + * @return {clay.Vector3} */ divide: function (b) { - vec3$2.divide(this._array, this._array, b._array); + vec3$2.divide(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Dot product of self and b - * @param {qtek.math.Vector3} b + * @param {clay.Vector3} b * @return {number} */ dot: function (b) { - return vec3$2.dot(this._array, b._array); + return vec3$2.dot(this.array, b.array); }, /** @@ -5586,7 +5582,7 @@ Vector3.prototype = { * @return {number} */ len: function () { - return vec3$2.len(this._array); + return vec3$2.len(this.array); }, /** @@ -5594,81 +5590,81 @@ Vector3.prototype = { * @return {number} */ length: function () { - return vec3$2.length(this._array); + return vec3$2.length(this.array); }, /** * Linear interpolation between a and b - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b + * @param {clay.Vector3} a + * @param {clay.Vector3} b * @param {number} t - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ lerp: function (a, b, t) { - vec3$2.lerp(this._array, a._array, b._array, t); + vec3$2.lerp(this.array, a.array, b.array, t); this._dirty = true; return this; }, /** * Minimum of self and b - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} b + * @return {clay.Vector3} */ min: function (b) { - vec3$2.min(this._array, this._array, b._array); + vec3$2.min(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Maximum of self and b - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} b + * @return {clay.Vector3} */ max: function (b) { - vec3$2.max(this._array, this._array, b._array); + vec3$2.max(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Alias for multiply - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} b + * @return {clay.Vector3} */ mul: function (b) { - vec3$2.mul(this._array, this._array, b._array); + vec3$2.mul(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Mutiply self and b - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} b + * @return {clay.Vector3} */ multiply: function (b) { - vec3$2.multiply(this._array, this._array, b._array); + vec3$2.multiply(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Negate self - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ negate: function () { - vec3$2.negate(this._array, this._array); + vec3$2.negate(this.array, this.array); this._dirty = true; return this; }, /** * Normalize self - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ normalize: function () { - vec3$2.normalize(this._array, this._array); + vec3$2.normalize(this.array, this.array); this._dirty = true; return this; }, @@ -5676,10 +5672,10 @@ Vector3.prototype = { /** * Generate random x, y, z components with a given scale * @param {number} scale - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ random: function (scale) { - vec3$2.random(this._array, scale); + vec3$2.random(this.array, scale); this._dirty = true; return this; }, @@ -5687,42 +5683,42 @@ Vector3.prototype = { /** * Scale self * @param {number} scale - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ scale: function (s) { - vec3$2.scale(this._array, this._array, s); + vec3$2.scale(this.array, this.array, s); this._dirty = true; return this; }, /** * Scale b and add to self - * @param {qtek.math.Vector3} b + * @param {clay.Vector3} b * @param {number} scale - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ scaleAndAdd: function (b, s) { - vec3$2.scaleAndAdd(this._array, this._array, b._array, s); + vec3$2.scaleAndAdd(this.array, this.array, b.array, s); this._dirty = true; return this; }, /** * Alias for squaredDistance - * @param {qtek.math.Vector3} b + * @param {clay.Vector3} b * @return {number} */ sqrDist: function (b) { - return vec3$2.sqrDist(this._array, b._array); + return vec3$2.sqrDist(this.array, b.array); }, /** * Squared distance between self and b - * @param {qtek.math.Vector3} b + * @param {clay.Vector3} b * @return {number} */ squaredDistance: function (b) { - return vec3$2.squaredDistance(this._array, b._array); + return vec3$2.squaredDistance(this.array, b.array); }, /** @@ -5730,7 +5726,7 @@ Vector3.prototype = { * @return {number} */ sqrLen: function () { - return vec3$2.sqrLen(this._array); + return vec3$2.sqrLen(this.array); }, /** @@ -5738,71 +5734,71 @@ Vector3.prototype = { * @return {number} */ squaredLength: function () { - return vec3$2.squaredLength(this._array); + return vec3$2.squaredLength(this.array); }, /** * Alias for subtract - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} b + * @return {clay.Vector3} */ sub: function (b) { - vec3$2.sub(this._array, this._array, b._array); + vec3$2.sub(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Subtract b from self - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} b + * @return {clay.Vector3} */ subtract: function (b) { - vec3$2.subtract(this._array, this._array, b._array); + vec3$2.subtract(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Transform self with a Matrix3 m - * @param {qtek.math.Matrix3} m - * @return {qtek.math.Vector3} + * @param {clay.Matrix3} m + * @return {clay.Vector3} */ transformMat3: function (m) { - vec3$2.transformMat3(this._array, this._array, m._array); + vec3$2.transformMat3(this.array, this.array, m.array); this._dirty = true; return this; }, /** * Transform self with a Matrix4 m - * @param {qtek.math.Matrix4} m - * @return {qtek.math.Vector3} + * @param {clay.Matrix4} m + * @return {clay.Vector3} */ transformMat4: function (m) { - vec3$2.transformMat4(this._array, this._array, m._array); + vec3$2.transformMat4(this.array, this.array, m.array); this._dirty = true; return this; }, /** * Transform self with a Quaternion q - * @param {qtek.math.Quaternion} q - * @return {qtek.math.Vector3} + * @param {clay.Quaternion} q + * @return {clay.Vector3} */ transformQuat: function (q) { - vec3$2.transformQuat(this._array, this._array, q._array); + vec3$2.transformQuat(this.array, this.array, q.array); this._dirty = true; return this; }, /** * Trasnform self into projection space with m - * @param {qtek.math.Matrix4} m - * @return {qtek.math.Vector3} + * @param {clay.Matrix4} m + * @return {clay.Vector3} */ applyProjection: function (m) { - var v = this._array; - m = m._array; + var v = this.array; + m = m.array; // Perspective projection if (m[15] === 0) { @@ -5830,11 +5826,11 @@ Vector3.prototype = { }, toString: function() { - return '[' + Array.prototype.join.call(this._array, ',') + ']'; + return '[' + Array.prototype.join.call(this.array, ',') + ']'; }, toArray: function () { - return Array.prototype.slice.call(this._array); + return Array.prototype.slice.call(this.array); } }; @@ -5846,15 +5842,15 @@ if (defineProperty) { /** * @name x * @type {number} - * @memberOf qtek.math.Vector3 + * @memberOf clay.Vector3 * @instance */ defineProperty(proto, 'x', { get: function () { - return this._array[0]; + return this.array[0]; }, set: function (value) { - this._array[0] = value; + this.array[0] = value; this._dirty = true; } }); @@ -5862,15 +5858,15 @@ if (defineProperty) { /** * @name y * @type {number} - * @memberOf qtek.math.Vector3 + * @memberOf clay.Vector3 * @instance */ defineProperty(proto, 'y', { get: function () { - return this._array[1]; + return this.array[1]; }, set: function (value) { - this._array[1] = value; + this.array[1] = value; this._dirty = true; } }); @@ -5878,15 +5874,15 @@ if (defineProperty) { /** * @name z * @type {number} - * @memberOf qtek.math.Vector3 + * @memberOf clay.Vector3 * @instance */ defineProperty(proto, 'z', { get: function () { - return this._array[2]; + return this.array[2]; }, set: function (value) { - this._array[2] = value; + this.array[2] = value; this._dirty = true; } }); @@ -5896,296 +5892,296 @@ if (defineProperty) { // Supply methods that are not in place /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} */ Vector3.add = function(out, a, b) { - vec3$2.add(out._array, a._array, b._array); + vec3$2.add(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector3} out + * @param {clay.Vector3} out * @param {number} x * @param {number} y * @param {number} z - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ Vector3.set = function(out, x, y, z) { - vec3$2.set(out._array, x, y, z); + vec3$2.set(out.array, x, y, z); out._dirty = true; }; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} out + * @param {clay.Vector3} b + * @return {clay.Vector3} */ Vector3.copy = function(out, b) { - vec3$2.copy(out._array, b._array); + vec3$2.copy(out.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} */ Vector3.cross = function(out, a, b) { - vec3$2.cross(out._array, a._array, b._array); + vec3$2.cross(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b + * @param {clay.Vector3} a + * @param {clay.Vector3} b * @return {number} */ Vector3.dist = function(a, b) { - return vec3$2.distance(a._array, b._array); + return vec3$2.distance(a.array, b.array); }; /** - * @method - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b + * @function + * @param {clay.Vector3} a + * @param {clay.Vector3} b * @return {number} */ Vector3.distance = Vector3.dist; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} */ Vector3.div = function(out, a, b) { - vec3$2.divide(out._array, a._array, b._array); + vec3$2.divide(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @method - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @function + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} */ Vector3.divide = Vector3.div; /** - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b + * @param {clay.Vector3} a + * @param {clay.Vector3} b * @return {number} */ Vector3.dot = function(a, b) { - return vec3$2.dot(a._array, b._array); + return vec3$2.dot(a.array, b.array); }; /** - * @param {qtek.math.Vector3} a + * @param {clay.Vector3} a * @return {number} */ Vector3.len = function(b) { - return vec3$2.length(b._array); + return vec3$2.length(b.array); }; // Vector3.length = Vector3.len; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b * @param {number} t - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ Vector3.lerp = function(out, a, b, t) { - vec3$2.lerp(out._array, a._array, b._array, t); + vec3$2.lerp(out.array, a.array, b.array, t); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} */ Vector3.min = function(out, a, b) { - vec3$2.min(out._array, a._array, b._array); + vec3$2.min(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} */ Vector3.max = function(out, a, b) { - vec3$2.max(out._array, a._array, b._array); + vec3$2.max(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} */ Vector3.mul = function(out, a, b) { - vec3$2.multiply(out._array, a._array, b._array); + vec3$2.multiply(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @method - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @function + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} */ Vector3.multiply = Vector3.mul; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @return {qtek.math.Vector3} + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @return {clay.Vector3} */ Vector3.negate = function(out, a) { - vec3$2.negate(out._array, a._array); + vec3$2.negate(out.array, a.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @return {qtek.math.Vector3} + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @return {clay.Vector3} */ Vector3.normalize = function(out, a) { - vec3$2.normalize(out._array, a._array); + vec3$2.normalize(out.array, a.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector3} out + * @param {clay.Vector3} out * @param {number} scale - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ Vector3.random = function(out, scale) { - vec3$2.random(out._array, scale); + vec3$2.random(out.array, scale); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a + * @param {clay.Vector3} out + * @param {clay.Vector3} a * @param {number} scale - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ Vector3.scale = function(out, a, scale) { - vec3$2.scale(out._array, a._array, scale); + vec3$2.scale(out.array, a.array, scale); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b * @param {number} scale - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ Vector3.scaleAndAdd = function(out, a, b, scale) { - vec3$2.scaleAndAdd(out._array, a._array, b._array, scale); + vec3$2.scaleAndAdd(out.array, a.array, b.array, scale); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b + * @param {clay.Vector3} a + * @param {clay.Vector3} b * @return {number} */ Vector3.sqrDist = function(a, b) { - return vec3$2.sqrDist(a._array, b._array); + return vec3$2.sqrDist(a.array, b.array); }; /** - * @method - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b + * @function + * @param {clay.Vector3} a + * @param {clay.Vector3} b * @return {number} */ Vector3.squaredDistance = Vector3.sqrDist; /** - * @param {qtek.math.Vector3} a + * @param {clay.Vector3} a * @return {number} */ Vector3.sqrLen = function(a) { - return vec3$2.sqrLen(a._array); + return vec3$2.sqrLen(a.array); }; /** - * @method - * @param {qtek.math.Vector3} a + * @function + * @param {clay.Vector3} a * @return {number} */ Vector3.squaredLength = Vector3.sqrLen; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} */ Vector3.sub = function(out, a, b) { - vec3$2.subtract(out._array, a._array, b._array); + vec3$2.subtract(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @method - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b - * @return {qtek.math.Vector3} + * @function + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} */ Vector3.subtract = Vector3.sub; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a + * @param {clay.Vector3} out + * @param {clay.Vector3} a * @param {Matrix3} m - * @return {qtek.math.Vector3} + * @return {clay.Vector3} */ Vector3.transformMat3 = function(out, a, m) { - vec3$2.transformMat3(out._array, a._array, m._array); + vec3$2.transformMat3(out.array, a.array, m.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Matrix4} m - * @return {qtek.math.Vector3} + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Matrix4} m + * @return {clay.Vector3} */ Vector3.transformMat4 = function(out, a, m) { - vec3$2.transformMat4(out._array, a._array, m._array); + vec3$2.transformMat4(out.array, a.array, m.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Quaternion} q - * @return {qtek.math.Vector3} + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Quaternion} q + * @return {clay.Vector3} */ Vector3.transformQuat = function(out, a, q) { - vec3$2.transformQuat(out._array, a._array, q._array); + vec3$2.transformQuat(out.array, a.array, q.array); out._dirty = true; return out; }; @@ -6203,9 +6199,9 @@ var abs = Math.abs; */ Vector3.eulerFromQuat = function (out, q, order) { out._dirty = true; - q = q._array; + q = q.array; - var target = out._array; + var target = out.array; var x = q[0], y = q[1], z = q[2], w = q[3]; var x2 = x * x; var y2 = y * y; @@ -6257,11 +6253,11 @@ Vector3.eulerFromQuat = function (out, q, order) { */ Vector3.eulerFromMat3 = function (out, m, order) { // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - var te = m._array; + var te = m.array; var m11 = te[0], m12 = te[3], m13 = te[6]; var m21 = te[1], m22 = te[4], m23 = te[7]; var m31 = te[2], m32 = te[5], m33 = te[8]; - var target = out._array; + var target = out.array; var order = (order || 'XYZ').toUpperCase(); @@ -6340,36 +6336,37 @@ Vector3.eulerFromMat3 = function (out, m, order) { return out; }; +// TODO return new. /** - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ Vector3.POSITIVE_X = new Vector3(1, 0, 0); /** - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ Vector3.NEGATIVE_X = new Vector3(-1, 0, 0); /** - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ Vector3.POSITIVE_Y = new Vector3(0, 1, 0); /** - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ Vector3.NEGATIVE_Y = new Vector3(0, -1, 0); /** - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ Vector3.POSITIVE_Z = new Vector3(0, 0, 1); /** - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ Vector3.NEGATIVE_Z = new Vector3(0, 0, -1); /** - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ Vector3.UP = new Vector3(0, 1, 0); /** - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ Vector3.ZERO = new Vector3(0, 0, 0); @@ -6381,23 +6378,25 @@ var vec3Set = vec3$1.set; /** * Axis aligned bounding box * @constructor - * @alias qtek.math.BoundingBox - * @param {qtek.math.Vector3} [min] - * @param {qtek.math.Vector3} [max] + * @alias clay.BoundingBox + * @param {clay.Vector3} [min] + * @param {clay.Vector3} [max] */ var BoundingBox = function (min, max) { /** * Minimum coords of bounding box - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ this.min = min || new Vector3(Infinity, Infinity, Infinity); /** * Maximum coords of bounding box - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ this.max = max || new Vector3(-Infinity, -Infinity, -Infinity); + + this.vertices = null; }; BoundingBox.prototype = { @@ -6411,8 +6410,8 @@ BoundingBox.prototype = { if (vertices.length > 0) { var min = this.min; var max = this.max; - var minArr = min._array; - var maxArr = max._array; + var minArr = min.array; + var maxArr = max.array; vec3Copy(minArr, vertices[0]); vec3Copy(maxArr, vertices[0]); for (var i = 1; i < vertices.length; i++) { @@ -6433,13 +6432,13 @@ BoundingBox.prototype = { /** * Union operation with another bounding box - * @param {qtek.math.BoundingBox} bbox + * @param {clay.BoundingBox} bbox */ union: function (bbox) { var min = this.min; var max = this.max; - vec3$1.min(min._array, min._array, bbox.min._array); - vec3$1.max(max._array, max._array, bbox.max._array); + vec3$1.min(min.array, min.array, bbox.min.array); + vec3$1.max(max.array, max.array, bbox.max.array); min._dirty = true; max._dirty = true; return this; @@ -6447,13 +6446,13 @@ BoundingBox.prototype = { /** * Intersection operation with another bounding box - * @param {qtek.math.BoundingBox} bbox + * @param {clay.BoundingBox} bbox */ intersection: function (bbox) { var min = this.min; var max = this.max; - vec3$1.max(min._array, min._array, bbox.min._array); - vec3$1.min(max._array, max._array, bbox.max._array); + vec3$1.max(min.array, min.array, bbox.min.array); + vec3$1.min(max.array, max.array, bbox.max.array); min._dirty = true; max._dirty = true; return this; @@ -6461,15 +6460,15 @@ BoundingBox.prototype = { /** * If intersect with another bounding box - * @param {qtek.math.BoundingBox} bbox + * @param {clay.BoundingBox} bbox * @return {boolean} */ intersectBoundingBox: function (bbox) { - var _min = this.min._array; - var _max = this.max._array; + var _min = this.min.array; + var _max = this.max.array; - var _min2 = bbox.min._array; - var _max2 = bbox.max._array; + var _min2 = bbox.min.array; + var _max2 = bbox.max.array; return ! (_min[0] > _max2[0] || _min[1] > _max2[1] || _min[2] > _max2[2] || _max[0] < _min2[0] || _max[1] < _min2[1] || _max[2] < _min2[2]); @@ -6477,16 +6476,16 @@ BoundingBox.prototype = { /** * If contain another bounding box entirely - * @param {qtek.math.BoundingBox} bbox + * @param {clay.BoundingBox} bbox * @return {boolean} */ containBoundingBox: function (bbox) { - var _min = this.min._array; - var _max = this.max._array; + var _min = this.min.array; + var _max = this.max.array; - var _min2 = bbox.min._array; - var _max2 = bbox.max._array; + var _min2 = bbox.min.array; + var _max2 = bbox.max.array; return _min[0] <= _min2[0] && _min[1] <= _min2[1] && _min[2] <= _min2[2] && _max[0] >= _max2[0] && _max[1] >= _max2[1] && _max[2] >= _max2[2]; @@ -6494,14 +6493,14 @@ BoundingBox.prototype = { /** * If contain point entirely - * @param {qtek.math.Vector3} point + * @param {clay.Vector3} point * @return {boolean} */ containPoint: function (p) { - var _min = this.min._array; - var _max = this.max._array; + var _min = this.min.array; + var _max = this.max.array; - var _p = p._array; + var _p = p.array; return _min[0] <= _p[0] && _min[1] <= _p[1] && _min[2] <= _p[2] && _max[0] >= _p[0] && _max[1] >= _p[1] && _max[2] >= _p[2]; @@ -6511,17 +6510,26 @@ BoundingBox.prototype = { * If bounding box is finite */ isFinite: function () { - var _min = this.min._array; - var _max = this.max._array; + var _min = this.min.array; + var _max = this.max.array; return isFinite(_min[0]) && isFinite(_min[1]) && isFinite(_min[2]) && isFinite(_max[0]) && isFinite(_max[1]) && isFinite(_max[2]); }, /** * Apply an affine transform matrix to the bounding box - * @param {qtek.math.Matrix4} matrix + * @param {clay.Matrix4} matrix + */ + applyTransform: function (matrix) { + this.transformFrom(this, matrix); + }, + + /** + * Get from another bounding box and an affine transform matrix. + * @param {clay.BoundingBox} source + * @param {clay.Matrix4} matrix */ - applyTransform: (function () { + transformFrom: (function () { // http://dev.theomader.com/transform-bounding-boxes/ var xa = vec3$1.create(); var xb = vec3$1.create(); @@ -6530,11 +6538,11 @@ BoundingBox.prototype = { var za = vec3$1.create(); var zb = vec3$1.create(); - return function (matrix) { - var min = this.min._array; - var max = this.max._array; + return function (source, matrix) { + var min = source.min.array; + var max = source.max.array; - var m = matrix._array; + var m = matrix.array; xa[0] = m[0] * min[0]; xa[1] = m[1] * min[0]; xa[2] = m[2] * min[0]; xb[0] = m[0] * max[0]; xb[1] = m[1] * max[0]; xb[2] = m[2] * max[0]; @@ -6545,6 +6553,8 @@ BoundingBox.prototype = { za[0] = m[8] * min[2]; za[1] = m[9] * min[2]; za[2] = m[10] * min[2]; zb[0] = m[8] * max[2]; zb[1] = m[9] * max[2]; zb[2] = m[10] * max[2]; + min = this.min.array; + max = this.max.array; min[0] = Math.min(xa[0], xb[0]) + Math.min(ya[0], yb[0]) + Math.min(za[0], zb[0]) + m[12]; min[1] = Math.min(xa[1], xb[1]) + Math.min(ya[1], yb[1]) + Math.min(za[1], zb[1]) + m[13]; min[2] = Math.min(xa[2], xb[2]) + Math.min(ya[2], yb[2]) + Math.min(za[2], zb[2]) + m[14]; @@ -6562,13 +6572,13 @@ BoundingBox.prototype = { /** * Apply a projection matrix to the bounding box - * @param {qtek.math.Matrix4} matrix + * @param {clay.Matrix4} matrix */ applyProjection: function (matrix) { - var min = this.min._array; - var max = this.max._array; + var min = this.min.array; + var max = this.max.array; - var m = matrix._array; + var m = matrix.array; // min in min z var v10 = min[0]; var v11 = min[1]; @@ -6614,7 +6624,7 @@ BoundingBox.prototype = { var vertices = this.vertices; if (!vertices) { // Cube vertices - var vertices = []; + vertices = []; for (var i = 0; i < 8; i++) { vertices[i] = vec3$1.fromValues(0, 0, 0); } @@ -6625,8 +6635,8 @@ BoundingBox.prototype = { */ this.vertices = vertices; } - var min = this.min._array; - var max = this.max._array; + var min = this.min.array; + var max = this.max.array; //--- min z // min x vec3Set(vertices[0], min[0], min[1], min[2]); @@ -6645,13 +6655,13 @@ BoundingBox.prototype = { }, /** * Copy values from another bounding box - * @param {qtek.math.BoundingBox} bbox + * @param {clay.BoundingBox} bbox */ copy: function (bbox) { var min = this.min; var max = this.max; - vec3Copy(min._array, bbox.min._array); - vec3Copy(max._array, bbox.max._array); + vec3Copy(min.array, bbox.min.array); + vec3Copy(max.array, bbox.max.array); min._dirty = true; max._dirty = true; return this; @@ -6659,7 +6669,7 @@ BoundingBox.prototype = { /** * Clone a new bounding box - * @return {qtek.math.BoundingBox} + * @return {clay.BoundingBox} */ clone: function () { var boundingBox = new BoundingBox(); @@ -6675,7 +6685,7 @@ var quat = glmatrix.quat; /** * @constructor - * @alias qtek.math.Matrix4 + * @alias clay.Matrix4 */ var Matrix4 = function() { @@ -6685,14 +6695,16 @@ var Matrix4 = function() { /** * Storage of Matrix4 - * @name _array + * @name array * @type {Float32Array} + * @memberOf clay.Matrix4# */ - this._array = mat4$1.create(); + this.array = mat4$1.create(); /** * @name _dirty * @type {boolean} + * @memberOf clay.Matrix4# */ this._dirty = true; }; @@ -6706,25 +6718,25 @@ Matrix4.prototype = { * @param {Float32Array|number[]} arr */ setArray: function (arr) { - for (var i = 0; i < this._array.length; i++) { - this._array[i] = arr[i]; + for (var i = 0; i < this.array.length; i++) { + this.array[i] = arr[i]; } this._dirty = true; return this; }, /** * Calculate the adjugate of self, in-place - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ adjoint: function() { - mat4$1.adjoint(this._array, this._array); + mat4$1.adjoint(this.array, this.array); this._dirty = true; return this; }, /** * Clone a new Matrix4 - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ clone: function() { return (new Matrix4()).copy(this); @@ -6732,11 +6744,11 @@ Matrix4.prototype = { /** * Copy from b - * @param {qtek.math.Matrix4} b - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} b + * @return {clay.Matrix4} */ copy: function(a) { - mat4$1.copy(this._array, a._array); + mat4$1.copy(this.array, a.array); this._dirty = true; return this; }, @@ -6746,28 +6758,28 @@ Matrix4.prototype = { * @return {number} */ determinant: function() { - return mat4$1.determinant(this._array); + return mat4$1.determinant(this.array); }, /** * Set upper 3x3 part from quaternion - * @param {qtek.math.Quaternion} q - * @return {qtek.math.Matrix4} + * @param {clay.Quaternion} q + * @return {clay.Matrix4} */ fromQuat: function(q) { - mat4$1.fromQuat(this._array, q._array); + mat4$1.fromQuat(this.array, q.array); this._dirty = true; return this; }, /** * Set from a quaternion rotation and a vector translation - * @param {qtek.math.Quaternion} q - * @param {qtek.math.Vector3} v - * @return {qtek.math.Matrix4} + * @param {clay.Quaternion} q + * @param {clay.Vector3} v + * @return {clay.Matrix4} */ fromRotationTranslation: function(q, v) { - mat4$1.fromRotationTranslation(this._array, q._array, v._array); + mat4$1.fromRotationTranslation(this.array, q.array, v.array); this._dirty = true; return this; }, @@ -6775,8 +6787,8 @@ Matrix4.prototype = { /** * Set from Matrix2d, it is used when converting a 2d shape to 3d space. * In 3d space it is equivalent to ranslate on xy plane and rotate about z axis - * @param {qtek.math.Matrix2d} m2d - * @return {qtek.math.Matrix4} + * @param {clay.Matrix2d} m2d + * @return {clay.Matrix4} */ fromMat2d: function(m2d) { Matrix4.fromMat2d(this, m2d); @@ -6791,87 +6803,87 @@ Matrix4.prototype = { * @param {number} top * @param {number} near * @param {number} far - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ frustum: function (left, right, bottom, top, near, far) { - mat4$1.frustum(this._array, left, right, bottom, top, near, far); + mat4$1.frustum(this.array, left, right, bottom, top, near, far); this._dirty = true; return this; }, /** * Set to a identity matrix - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ identity: function() { - mat4$1.identity(this._array); + mat4$1.identity(this.array); this._dirty = true; return this; }, /** * Invert self - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ invert: function() { - mat4$1.invert(this._array, this._array); + mat4$1.invert(this.array, this.array); this._dirty = true; return this; }, /** * Set as a matrix with the given eye position, focal point, and up axis - * @param {qtek.math.Vector3} eye - * @param {qtek.math.Vector3} center - * @param {qtek.math.Vector3} up - * @return {qtek.math.Matrix4} + * @param {clay.Vector3} eye + * @param {clay.Vector3} center + * @param {clay.Vector3} up + * @return {clay.Matrix4} */ lookAt: function(eye, center, up) { - mat4$1.lookAt(this._array, eye._array, center._array, up._array); + mat4$1.lookAt(this.array, eye.array, center.array, up.array); this._dirty = true; return this; }, /** * Alias for mutiply - * @param {qtek.math.Matrix4} b - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} b + * @return {clay.Matrix4} */ mul: function(b) { - mat4$1.mul(this._array, this._array, b._array); + mat4$1.mul(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Alias for multiplyLeft - * @param {qtek.math.Matrix4} a - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} a + * @return {clay.Matrix4} */ mulLeft: function(a) { - mat4$1.mul(this._array, a._array, this._array); + mat4$1.mul(this.array, a.array, this.array); this._dirty = true; return this; }, /** * Multiply self and b - * @param {qtek.math.Matrix4} b - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} b + * @return {clay.Matrix4} */ multiply: function(b) { - mat4$1.multiply(this._array, this._array, b._array); + mat4$1.multiply(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Multiply a and self, a is on the left - * @param {qtek.math.Matrix3} a - * @return {qtek.math.Matrix3} + * @param {clay.Matrix3} a + * @return {clay.Matrix3} */ multiplyLeft: function(a) { - mat4$1.multiply(this._array, a._array, this._array); + mat4$1.multiply(this.array, a.array, this.array); this._dirty = true; return this; }, @@ -6884,10 +6896,10 @@ Matrix4.prototype = { * @param {number} top * @param {number} near * @param {number} far - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ ortho: function(left, right, bottom, top, near, far) { - mat4$1.ortho(this._array, left, right, bottom, top, near, far); + mat4$1.ortho(this.array, left, right, bottom, top, near, far); this._dirty = true; return this; }, @@ -6897,10 +6909,10 @@ Matrix4.prototype = { * @param {number} aspect * @param {number} near * @param {number} far - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ perspective: function(fovy, aspect, near, far) { - mat4$1.perspective(this._array, fovy, aspect, near, far); + mat4$1.perspective(this.array, fovy, aspect, near, far); this._dirty = true; return this; }, @@ -6909,11 +6921,11 @@ Matrix4.prototype = { * Rotate self by rad about axis. * Equal to right-multiply a rotaion matrix * @param {number} rad - * @param {qtek.math.Vector3} axis - * @return {qtek.math.Matrix4} + * @param {clay.Vector3} axis + * @return {clay.Matrix4} */ rotate: function(rad, axis) { - mat4$1.rotate(this._array, this._array, rad, axis._array); + mat4$1.rotate(this.array, this.array, rad, axis.array); this._dirty = true; return this; }, @@ -6922,10 +6934,10 @@ Matrix4.prototype = { * Rotate self by a given radian about X axis. * Equal to right-multiply a rotaion matrix * @param {number} rad - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ rotateX: function(rad) { - mat4$1.rotateX(this._array, this._array, rad); + mat4$1.rotateX(this.array, this.array, rad); this._dirty = true; return this; }, @@ -6934,10 +6946,10 @@ Matrix4.prototype = { * Rotate self by a given radian about Y axis. * Equal to right-multiply a rotaion matrix * @param {number} rad - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ rotateY: function(rad) { - mat4$1.rotateY(this._array, this._array, rad); + mat4$1.rotateY(this.array, this.array, rad); this._dirty = true; return this; }, @@ -6946,10 +6958,10 @@ Matrix4.prototype = { * Rotate self by a given radian about Z axis. * Equal to right-multiply a rotaion matrix * @param {number} rad - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ rotateZ: function(rad) { - mat4$1.rotateZ(this._array, this._array, rad); + mat4$1.rotateZ(this.array, this.array, rad); this._dirty = true; return this; }, @@ -6957,11 +6969,11 @@ Matrix4.prototype = { /** * Scale self by s * Equal to right-multiply a scale matrix - * @param {qtek.math.Vector3} s - * @return {qtek.math.Matrix4} + * @param {clay.Vector3} s + * @return {clay.Matrix4} */ scale: function(v) { - mat4$1.scale(this._array, this._array, v._array); + mat4$1.scale(this.array, this.array, v.array); this._dirty = true; return this; }, @@ -6969,30 +6981,30 @@ Matrix4.prototype = { /** * Translate self by v. * Equal to right-multiply a translate matrix - * @param {qtek.math.Vector3} v - * @return {qtek.math.Matrix4} + * @param {clay.Vector3} v + * @return {clay.Matrix4} */ translate: function(v) { - mat4$1.translate(this._array, this._array, v._array); + mat4$1.translate(this.array, this.array, v.array); this._dirty = true; return this; }, /** * Transpose self, in-place. - * @return {qtek.math.Matrix2} + * @return {clay.Matrix2} */ transpose: function() { - mat4$1.transpose(this._array, this._array); + mat4$1.transpose(this.array, this.array); this._dirty = true; return this; }, /** * Decompose a matrix to SRT - * @param {qtek.math.Vector3} [scale] - * @param {qtek.math.Quaternion} rotation - * @param {qtek.math.Vector} position + * @param {clay.Vector3} [scale] + * @param {clay.Quaternion} rotation + * @param {clay.Vector} position * @see http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.matrix.decompose.aspx */ decomposeMatrix: (function() { @@ -7005,7 +7017,7 @@ Matrix4.prototype = { return function(scale, rotation, position) { - var el = this._array; + var el = this.array; vec3$3.set(x, el[0], el[1], el[2]); vec3$3.set(y, el[4], el[5], el[6]); vec3$3.set(z, el[8], el[9], el[10]); @@ -7044,8 +7056,8 @@ Matrix4.prototype = { m3[7] /= sz; m3[8] /= sz; - quat.fromMat3(rotation._array, m3); - quat.normalize(rotation._array, rotation._array); + quat.fromMat3(rotation.array, m3); + quat.normalize(rotation.array, rotation.array); rotation._dirty = true; position._dirty = true; @@ -7053,11 +7065,11 @@ Matrix4.prototype = { })(), toString: function() { - return '[' + Array.prototype.join.call(this._array, ',') + ']'; + return '[' + Array.prototype.join.call(this.array, ',') + ']'; }, toArray: function () { - return Array.prototype.slice.call(this._array); + return Array.prototype.slice.call(this.array); } }; @@ -7068,21 +7080,21 @@ if (defineProperty$1) { /** * Z Axis of local transform * @name z - * @type {qtek.math.Vector3} - * @memberOf qtek.math.Matrix4 + * @type {clay.Vector3} + * @memberOf clay.Matrix4 * @instance */ defineProperty$1(proto$1, 'z', { get: function () { - var el = this._array; + var el = this.array; this._axisZ.set(el[8], el[9], el[10]); return this._axisZ; }, set: function (v) { // TODO Here has a problem // If only set an item of vector will not work - var el = this._array; - v = v._array; + var el = this.array; + v = v.array; el[8] = v[0]; el[9] = v[1]; el[10] = v[2]; @@ -7094,19 +7106,19 @@ if (defineProperty$1) { /** * Y Axis of local transform * @name y - * @type {qtek.math.Vector3} - * @memberOf qtek.math.Matrix4 + * @type {clay.Vector3} + * @memberOf clay.Matrix4 * @instance */ defineProperty$1(proto$1, 'y', { get: function () { - var el = this._array; + var el = this.array; this._axisY.set(el[4], el[5], el[6]); return this._axisY; }, set: function (v) { - var el = this._array; - v = v._array; + var el = this.array; + v = v.array; el[4] = v[0]; el[5] = v[1]; el[6] = v[2]; @@ -7118,19 +7130,19 @@ if (defineProperty$1) { /** * X Axis of local transform * @name x - * @type {qtek.math.Vector3} - * @memberOf qtek.math.Matrix4 + * @type {clay.Vector3} + * @memberOf clay.Matrix4 * @instance */ defineProperty$1(proto$1, 'x', { get: function () { - var el = this._array; + var el = this.array; this._axisX.set(el[0], el[1], el[2]); return this._axisX; }, set: function (v) { - var el = this._array; - v = v._array; + var el = this.array; + v = v.array; el[0] = v[0]; el[1] = v[1]; el[2] = v[2]; @@ -7141,152 +7153,152 @@ if (defineProperty$1) { } /** - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Matrix4} a - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} out + * @param {clay.Matrix4} a + * @return {clay.Matrix4} */ Matrix4.adjoint = function(out, a) { - mat4$1.adjoint(out._array, a._array); + mat4$1.adjoint(out.array, a.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Matrix4} a - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} out + * @param {clay.Matrix4} a + * @return {clay.Matrix4} */ Matrix4.copy = function(out, a) { - mat4$1.copy(out._array, a._array); + mat4$1.copy(out.array, a.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} a + * @param {clay.Matrix4} a * @return {number} */ Matrix4.determinant = function(a) { - return mat4$1.determinant(a._array); + return mat4$1.determinant(a.array); }; /** - * @param {qtek.math.Matrix4} out - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} out + * @return {clay.Matrix4} */ Matrix4.identity = function(out) { - mat4$1.identity(out._array); + mat4$1.identity(out.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} out + * @param {clay.Matrix4} out * @param {number} left * @param {number} right * @param {number} bottom * @param {number} top * @param {number} near * @param {number} far - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ Matrix4.ortho = function(out, left, right, bottom, top, near, far) { - mat4$1.ortho(out._array, left, right, bottom, top, near, far); + mat4$1.ortho(out.array, left, right, bottom, top, near, far); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} out + * @param {clay.Matrix4} out * @param {number} fovy * @param {number} aspect * @param {number} near * @param {number} far - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ Matrix4.perspective = function(out, fovy, aspect, near, far) { - mat4$1.perspective(out._array, fovy, aspect, near, far); + mat4$1.perspective(out.array, fovy, aspect, near, far); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Vector3} eye - * @param {qtek.math.Vector3} center - * @param {qtek.math.Vector3} up - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} out + * @param {clay.Vector3} eye + * @param {clay.Vector3} center + * @param {clay.Vector3} up + * @return {clay.Matrix4} */ Matrix4.lookAt = function(out, eye, center, up) { - mat4$1.lookAt(out._array, eye._array, center._array, up._array); + mat4$1.lookAt(out.array, eye.array, center.array, up.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Matrix4} a - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} out + * @param {clay.Matrix4} a + * @return {clay.Matrix4} */ Matrix4.invert = function(out, a) { - mat4$1.invert(out._array, a._array); + mat4$1.invert(out.array, a.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Matrix4} a - * @param {qtek.math.Matrix4} b - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} out + * @param {clay.Matrix4} a + * @param {clay.Matrix4} b + * @return {clay.Matrix4} */ Matrix4.mul = function(out, a, b) { - mat4$1.mul(out._array, a._array, b._array); + mat4$1.mul(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @method - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Matrix4} a - * @param {qtek.math.Matrix4} b - * @return {qtek.math.Matrix4} + * @function + * @param {clay.Matrix4} out + * @param {clay.Matrix4} a + * @param {clay.Matrix4} b + * @return {clay.Matrix4} */ Matrix4.multiply = Matrix4.mul; /** - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Quaternion} q - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} out + * @param {clay.Quaternion} q + * @return {clay.Matrix4} */ Matrix4.fromQuat = function(out, q) { - mat4$1.fromQuat(out._array, q._array); + mat4$1.fromQuat(out.array, q.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Quaternion} q - * @param {qtek.math.Vector3} v - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} out + * @param {clay.Quaternion} q + * @param {clay.Vector3} v + * @return {clay.Matrix4} */ Matrix4.fromRotationTranslation = function(out, q, v) { - mat4$1.fromRotationTranslation(out._array, q._array, v._array); + mat4$1.fromRotationTranslation(out.array, q.array, v.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} m4 - * @param {qtek.math.Matrix2d} m2d - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} m4 + * @param {clay.Matrix2d} m2d + * @return {clay.Matrix4} */ Matrix4.fromMat2d = function(m4, m2d) { m4._dirty = true; - var m2d = m2d._array; - var m4 = m4._array; + var m2d = m2d.array; + var m4 = m4.array; m4[0] = m2d[0]; m4[4] = m2d[2]; @@ -7300,85 +7312,85 @@ Matrix4.fromMat2d = function(m4, m2d) { }; /** - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Matrix4} a + * @param {clay.Matrix4} out + * @param {clay.Matrix4} a * @param {number} rad - * @param {qtek.math.Vector3} axis - * @return {qtek.math.Matrix4} + * @param {clay.Vector3} axis + * @return {clay.Matrix4} */ Matrix4.rotate = function(out, a, rad, axis) { - mat4$1.rotate(out._array, a._array, rad, axis._array); + mat4$1.rotate(out.array, a.array, rad, axis.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Matrix4} a + * @param {clay.Matrix4} out + * @param {clay.Matrix4} a * @param {number} rad - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ Matrix4.rotateX = function(out, a, rad) { - mat4$1.rotateX(out._array, a._array, rad); + mat4$1.rotateX(out.array, a.array, rad); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Matrix4} a + * @param {clay.Matrix4} out + * @param {clay.Matrix4} a * @param {number} rad - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ Matrix4.rotateY = function(out, a, rad) { - mat4$1.rotateY(out._array, a._array, rad); + mat4$1.rotateY(out.array, a.array, rad); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Matrix4} a + * @param {clay.Matrix4} out + * @param {clay.Matrix4} a * @param {number} rad - * @return {qtek.math.Matrix4} + * @return {clay.Matrix4} */ Matrix4.rotateZ = function(out, a, rad) { - mat4$1.rotateZ(out._array, a._array, rad); + mat4$1.rotateZ(out.array, a.array, rad); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Matrix4} a - * @param {qtek.math.Vector3} v - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} out + * @param {clay.Matrix4} a + * @param {clay.Vector3} v + * @return {clay.Matrix4} */ Matrix4.scale = function(out, a, v) { - mat4$1.scale(out._array, a._array, v._array); + mat4$1.scale(out.array, a.array, v.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Matrix4} a - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} out + * @param {clay.Matrix4} a + * @return {clay.Matrix4} */ Matrix4.transpose = function(out, a) { - mat4$1.transpose(out._array, a._array); + mat4$1.transpose(out.array, a.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Matrix4} out - * @param {qtek.math.Matrix4} a - * @param {qtek.math.Vector3} v - * @return {qtek.math.Matrix4} + * @param {clay.Matrix4} out + * @param {clay.Matrix4} a + * @param {clay.Vector3} v + * @return {clay.Matrix4} */ Matrix4.translate = function(out, a, v) { - mat4$1.translate(out._array, a._array, v._array); + mat4$1.translate(out.array, a.array, v.array); out._dirty = true; return out; }; @@ -7492,2512 +7504,2089 @@ Cache.prototype = { Cache.prototype.constructor = Cache; /** - * Mainly do the parse and compile of shader string - * Support shader code chunk import and export - * Support shader semantics - * http://www.nvidia.com/object/using_sas.html - * https://github.com/KhronosGroup/collada2json/issues/45 - * - * TODO: Use etpl or other string template engine + * Base class for all textures like compressed texture, texture2d, texturecube + * TODO mapping */ -var mat2 = glmatrix.mat2; -var mat3$1 = glmatrix.mat3; -var mat4$2 = glmatrix.mat4; - -var uniformRegex = /uniform\s+(bool|float|int|vec2|vec3|vec4|ivec2|ivec3|ivec4|mat2|mat3|mat4|sampler2D|samplerCube)\s+([\w\,]+)?(\[.*?\])?\s*(:\s*([\S\s]+?))?;/g; -var attributeRegex = /attribute\s+(float|int|vec2|vec3|vec4)\s+(\w*)\s*(:\s*(\w+))?;/g; -var defineRegex = /#define\s+(\w+)?(\s+[\w-.]+)?\s*;?\s*\n/g; -var loopRegex = /for\s*?\(int\s*?_idx_\s*\=\s*([\w-]+)\;\s*_idx_\s*<\s*([\w-]+);\s*_idx_\s*\+\+\s*\)\s*\{\{([\s\S]+?)(?=\}\})\}\}/g; - -var uniformTypeMap = { - 'bool': '1i', - 'int': '1i', - 'sampler2D': 't', - 'samplerCube': 't', - 'float': '1f', - 'vec2': '2f', - 'vec3': '3f', - 'vec4': '4f', - 'ivec2': '2i', - 'ivec3': '3i', - 'ivec4': '4i', - 'mat2': 'm2', - 'mat3': 'm3', - 'mat4': 'm4' -}; - -var uniformValueConstructor = { - 'bool': function () {return true;}, - 'int': function () {return 0;}, - 'float': function () {return 0;}, - 'sampler2D': function () {return null;}, - 'samplerCube': function () {return null;}, - - 'vec2': function () {return [0, 0];}, - 'vec3': function () {return [0, 0, 0];}, - 'vec4': function () {return [0, 0, 0, 0];}, - - 'ivec2': function () {return [0, 0];}, - 'ivec3': function () {return [0, 0, 0];}, - 'ivec4': function () {return [0, 0, 0, 0];}, - - 'mat2': function () {return mat2.create();}, - 'mat3': function () {return mat3$1.create();}, - 'mat4': function () {return mat4$2.create();}, - - 'array': function () {return [];} -}; - -var attribSemantics = [ - 'POSITION', - 'NORMAL', - 'BINORMAL', - 'TANGENT', - 'TEXCOORD', - 'TEXCOORD_0', - 'TEXCOORD_1', - 'COLOR', - // Skinning - // https://github.com/KhronosGroup/glTF/blob/master/specification/README.md#semantics - 'JOINT', - 'WEIGHT' -]; -var uniformSemantics = [ - 'SKIN_MATRIX', - // Information about viewport - 'VIEWPORT_SIZE', - 'VIEWPORT', - 'DEVICEPIXELRATIO', - // Window size for window relative coordinate - // https://www.opengl.org/sdk/docs/man/html/gl_FragCoord.xhtml - 'WINDOW_SIZE', - // Infomation about camera - 'NEAR', - 'FAR', - // Time - 'TIME' -]; -var matrixSemantics = [ - 'WORLD', - 'VIEW', - 'PROJECTION', - 'WORLDVIEW', - 'VIEWPROJECTION', - 'WORLDVIEWPROJECTION', - 'WORLDINVERSE', - 'VIEWINVERSE', - 'PROJECTIONINVERSE', - 'WORLDVIEWINVERSE', - 'VIEWPROJECTIONINVERSE', - 'WORLDVIEWPROJECTIONINVERSE', - 'WORLDTRANSPOSE', - 'VIEWTRANSPOSE', - 'PROJECTIONTRANSPOSE', - 'WORLDVIEWTRANSPOSE', - 'VIEWPROJECTIONTRANSPOSE', - 'WORLDVIEWPROJECTIONTRANSPOSE', - 'WORLDINVERSETRANSPOSE', - 'VIEWINVERSETRANSPOSE', - 'PROJECTIONINVERSETRANSPOSE', - 'WORLDVIEWINVERSETRANSPOSE', - 'VIEWPROJECTIONINVERSETRANSPOSE', - 'WORLDVIEWPROJECTIONINVERSETRANSPOSE' -]; - -// Enable attribute operation is global to all programs -// Here saved the list of all enabled attribute index -// http://www.mjbshaw.com/2013/03/webgl-fixing-invalidoperation.html -var enabledAttributeList = {}; - -var SHADER_STATE_TO_ENABLE = 1; -var SHADER_STATE_KEEP_ENABLE = 2; -var SHADER_STATE_PENDING = 3; - /** * @constructor - * @extends qtek.core.Base - * @alias qtek.Shader - * @example - * // Create a phong shader - * var shader = new qtek.Shader({ - * vertex: qtek.Shader.source('qtek.phong.vertex'), - * fragment: qtek.Shader.source('qtek.phong.fragment') - * }); - * // Enable diffuse texture - * shader.enableTexture('diffuseMap'); - * // Use alpha channel in diffuse texture - * shader.define('fragment', 'DIFFUSEMAP_ALPHA_ALPHA'); + * @alias clay.Texture + * @extends clay.core.Base */ -var Shader = Base.extend(function () { - return /** @lends qtek.Shader# */ { - /** - * Vertex shader code - * @type {string} - */ - vertex: '', - - /** - * Fragment shader code - * @type {string} - */ - fragment: '', - - - // FIXME mediump is toooooo low for depth on mobile - precision: 'highp', - - // Properties follow will be generated by the program - attribSemantics: {}, - matrixSemantics: {}, - uniformSemantics: {}, - matrixSemanticKeys: [], - - uniformTemplates: {}, - attributeTemplates: {}, - - /** - * Custom defined values in the vertex shader - * @type {Object} - */ - vertexDefines: {}, - /** - * Custom defined values in the vertex shader - * @type {Object} - */ - fragmentDefines: {}, - - /** - * Enabled extensions - * @type {Array.} - */ - extensions: [ - 'OES_standard_derivatives', - 'EXT_shader_texture_lod' - ], - - /** - * Used light group. default is all zero - */ - lightGroup: 0, - - // Defines the each type light number in the scene - // AMBIENT_LIGHT - // AMBIENT_SH_LIGHT - // AMBIENT_CUBEMAP_LIGHT - // POINT_LIGHT - // SPOT_LIGHT - // AREA_LIGHT - lightNumber: {}, - - _textureSlot: 0, - - _attacheMaterialNumber: 0, - - _uniformList: [], - // { - // enabled: true - // shaderType: "vertex", - // } - _textureStatus: {}, - - _vertexProcessed: '', - _fragmentProcessed: '', - - _currentLocationsMap: {} - }; -}, function () { - - this._cache = new Cache(); - - // All context use same code - this._codeDirty = true; - - this._updateShaderString(); -}, -/** @lends qtek.Shader.prototype */ -{ +var Texture$1 = Base.extend( /** @lends clay.Texture# */ { /** - * If code is equal with given shader. - * @param {qtek.Shader} - * @return {boolean} + * Texture width, readonly when the texture source is image + * @type {number} */ - isEqual: function (otherShader) { - if (!otherShader) { - return false; - } - if (this === otherShader) { - // Still needs update and rebind if dirty. - return !this._codeDirty; - } - if (otherShader._codeDirty) { - otherShader._updateShaderString(); - } - if (this._codeDirty) { - this._updateShaderString(); - } - return !(otherShader._vertexProcessed !== this._vertexProcessed - || otherShader._fragmentProcessed !== this._fragmentProcessed); - }, + width: 512, /** - * Set vertex shader code - * @param {string} str + * Texture height, readonly when the texture source is image + * @type {number} */ - setVertex: function (str) { - this.vertex = str; - this._updateShaderString(); - this.dirty(); - }, - + height: 512, /** - * Set fragment shader code - * @param {string} str + * Texel data type. + * Possible values: + * + {@link clay.Texture.UNSIGNED_BYTE} + * + {@link clay.Texture.HALF_FLOAT} + * + {@link clay.Texture.FLOAT} + * + {@link clay.Texture.UNSIGNED_INT_24_8_WEBGL} + * + {@link clay.Texture.UNSIGNED_INT} + * @type {number} */ - setFragment: function (str) { - this.fragment = str; - this._updateShaderString(); - this.dirty(); - }, - + type: glenum.UNSIGNED_BYTE, /** - * Bind shader program - * Return true or error msg if error happened - * @param {qtek.Renderer} renderer + * Format of texel data + * Possible values: + * + {@link clay.Texture.RGBA} + * + {@link clay.Texture.DEPTH_COMPONENT} + * + {@link clay.Texture.DEPTH_STENCIL} + * @type {number} */ - bind: function (renderer) { - var cache = this._cache; - var _gl = renderer.gl; - cache.use(renderer.__GUID__, getCacheSchema); - - this._currentLocationsMap = cache.get('locations'); - - // Reset slot - this._textureSlot = 0; - - if (this._codeDirty) { - // PENDING - // var availableExts = []; - // var extensions = this.extensions; - // for (var i = 0; i < extensions.length; i++) { - // if (glInfo.getExtension(_gl, extensions[i])) { - // availableExts.push(extensions[i]); - // } - // } - this._updateShaderString(); - } - - if (cache.isDirty('program')) { - var errMsg = this._buildProgram(_gl, this._vertexProcessed, this._fragmentProcessed); - cache.fresh('program'); - - if (errMsg) { - return errMsg; - } - } - - _gl.useProgram(cache.get('program')); - }, - + format: glenum.RGBA, /** - * Mark dirty and update program in next frame + * Texture wrap. Default to be REPEAT. + * Possible values: + * + {@link clay.Texture.CLAMP_TO_EDGE} + * + {@link clay.Texture.REPEAT} + * + {@link clay.Texture.MIRRORED_REPEAT} + * @type {number} */ - dirty: function () { - var cache = this._cache; - this._codeDirty = true; - cache.dirtyAll('program'); - for (var i = 0; i < cache._caches.length; i++) { - if (cache._caches[i]) { - var context = cache._caches[i]; - context['locations'] = {}; - context['attriblocations'] = {}; - } - } - }, - - _updateShaderString: function (exts) { - - if (this.vertex !== this._vertexPrev || - this.fragment !== this._fragmentPrev - ) { - - this._parseImport(); - - this.attribSemantics = {}; - this.matrixSemantics = {}; - this._textureStatus = {}; - - this._parseUniforms(); - this._parseAttributes(); - this._parseDefines(); - - this._vertexPrev = this.vertex; - this._fragmentPrev = this.fragment; - } - - this._addDefineExtensionAndPrecision(exts); - - this._vertexProcessed = this._unrollLoop(this._vertexProcessed, this.vertexDefines); - this._fragmentProcessed = this._unrollLoop(this._fragmentProcessed, this.fragmentDefines); - - this._codeDirty = false; - }, - + wrapS: glenum.REPEAT, /** - * Add a #define macro in shader code - * @param {string} shaderType Can be vertex, fragment or both - * @param {string} symbol - * @param {number} [val] + * Texture wrap. Default to be REPEAT. + * Possible values: + * + {@link clay.Texture.CLAMP_TO_EDGE} + * + {@link clay.Texture.REPEAT} + * + {@link clay.Texture.MIRRORED_REPEAT} + * @type {number} */ - define: function (shaderType, symbol, val) { - var vertexDefines = this.vertexDefines; - var fragmentDefines = this.fragmentDefines; - if (shaderType !== 'vertex' && shaderType !== 'fragment' && shaderType !== 'both' - && arguments.length < 3 - ) { - // shaderType default to be 'both' - val = symbol; - symbol = shaderType; - shaderType = 'both'; - } - val = val != null ? val : null; - if (shaderType === 'vertex' || shaderType === 'both') { - if (vertexDefines[symbol] !== val) { - vertexDefines[symbol] = val; - // Mark as dirty - this.dirty(); - } - } - if (shaderType === 'fragment' || shaderType === 'both') { - if (fragmentDefines[symbol] !== val) { - fragmentDefines[symbol] = val; - if (shaderType !== 'both') { - this.dirty(); - } - } - } - }, - + wrapT: glenum.REPEAT, /** - * Remove a #define macro in shader code - * @param {string} shaderType Can be vertex, fragment or both - * @param {string} symbol + * Possible values: + * + {@link clay.Texture.NEAREST} + * + {@link clay.Texture.LINEAR} + * + {@link clay.Texture.NEAREST_MIPMAP_NEAREST} + * + {@link clay.Texture.LINEAR_MIPMAP_NEAREST} + * + {@link clay.Texture.NEAREST_MIPMAP_LINEAR} + * + {@link clay.Texture.LINEAR_MIPMAP_LINEAR} + * @type {number} */ - undefine: function (shaderType, symbol) { - if (shaderType !== 'vertex' && shaderType !== 'fragment' && shaderType !== 'both' - && arguments.length < 2 - ) { - // shaderType default to be 'both' - symbol = shaderType; - shaderType = 'both'; - } - if (shaderType === 'vertex' || shaderType === 'both') { - if (this.isDefined('vertex', symbol)) { - delete this.vertexDefines[symbol]; - // Mark as dirty - this.dirty(); - } - } - if (shaderType === 'fragment' || shaderType === 'both') { - if (this.isDefined('fragment', symbol)) { - delete this.fragmentDefines[symbol]; - if (shaderType !== 'both') { - this.dirty(); - } - } - } - }, - + minFilter: glenum.LINEAR_MIPMAP_LINEAR, /** - * If macro is defined in shader. - * @param {string} shaderType Can be vertex, fragment or both - * @param {string} symbol + * Possible values: + * + {@link clay.Texture.NEAREST} + * + {@link clay.Texture.LINEAR} + * @type {number} */ - isDefined: function (shaderType, symbol) { - switch (shaderType) { - case 'vertex': - return this.vertexDefines[symbol] !== undefined; - case 'fragment': - return this.fragmentDefines[symbol] !== undefined; - } - }, + magFilter: glenum.LINEAR, /** - * Get macro value defined in shader. - * @param {string} shaderType Can be vertex, fragment or both - * @param {string} symbol + * If enable mimap. + * @type {boolean} */ - getDefine: function (shaderType, symbol) { - switch(shaderType) { - case 'vertex': - return this.vertexDefines[symbol]; - case 'fragment': - return this.fragmentDefines[symbol]; - } - }, + useMipmap: true, + /** - * Enable a texture, actually it will add a #define macro in the shader code - * For example, if texture symbol is diffuseMap, it will add a line `#define DIFFUSEMAP_ENABLED` in the shader code - * @param {string} symbol + * Anisotropic filtering, enabled if value is larger than 1 + * @see https://developer.mozilla.org/en-US/docs/Web/API/EXT_texture_filter_anisotropic + * @type {number} */ - enableTexture: function (symbol) { - if (Array.isArray(symbol)) { - for (var i = 0; i < symbol.length; i++) { - this.enableTexture(symbol[i]); - } - return; - } - - var status = this._textureStatus[symbol]; - if (status) { - var isEnabled = status.enabled; - if (!isEnabled) { - status.enabled = true; - this.dirty(); - } - } - }, + anisotropic: 1, + // pixelStorei parameters, not available when texture is used as render target + // http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml /** - * Enable all textures used in the shader + * If flip in y axis for given image source + * @type {boolean} + * @default true */ - enableTexturesAll: function () { - var textureStatus = this._textureStatus; - for (var symbol in textureStatus) { - textureStatus[symbol].enabled = true; - } + flipY: true, - this.dirty(); - }, /** - * Disable a texture, it remove a #define macro in the shader - * @param {string} symbol + * A flag to indicate if texture source is sRGB */ - disableTexture: function (symbol) { - if (Array.isArray(symbol)) { - for (var i = 0; i < symbol.length; i++) { - this.disableTexture(symbol[i]); - } - return; - } - - var status = this._textureStatus[symbol]; - if (status) { - var isDisabled = ! status.enabled; - if (!isDisabled) { - status.enabled = false; - this.dirty(); - } - } - }, + sRGB: true, /** - * Disable all textures used in the shader + * @type {number} + * @default 4 */ - disableTexturesAll: function () { - var textureStatus = this._textureStatus; - for (var symbol in textureStatus) { - textureStatus[symbol].enabled = false; - } - - this.dirty(); - }, + unpackAlignment: 4, /** - * If texture of given type is enabled. - * @param {string} symbol - * @return {boolean} + * @type {boolean} + * @default false */ - isTextureEnabled: function (symbol) { - var textureStatus = this._textureStatus; - return !!textureStatus[symbol] - && textureStatus[symbol].enabled; - }, + premultiplyAlpha: false, /** - * Get all enabled textures - * @return {string[]} + * Dynamic option for texture like video + * @type {boolean} */ - getEnabledTextures: function () { - var enabledTextures = []; - var textureStatus = this._textureStatus; - for (var symbol in textureStatus) { - if (textureStatus[symbol].enabled) { - enabledTextures.push(symbol); - } + dynamic: false, + + NPOT: false, + + // PENDING + // Init it here to avoid deoptimization when it's assigned in application dynamically + __used: 0 + +}, function () { + this._cache = new Cache(); +}, +/** @lends clay.Texture.prototype */ +{ + + getWebGLTexture: function (renderer) { + var _gl = renderer.gl; + var cache = this._cache; + cache.use(renderer.__uid__); + + if (cache.miss('webgl_texture')) { + // In a new gl context, create new texture and set dirty true + cache.put('webgl_texture', _gl.createTexture()); + } + if (this.dynamic) { + this.update(renderer); + } + else if (cache.isDirty()) { + this.update(renderer); + cache.fresh(); } - return enabledTextures; - }, - hasUniform: function (symbol) { - var location = this._currentLocationsMap[symbol]; - return location !== null && location !== undefined; + return cache.get('webgl_texture'); }, - currentTextureSlot: function () { - return this._textureSlot; - }, + bind: function () {}, + unbind: function () {}, - resetTextureSlot: function (slot) { - this._textureSlot = slot || 0; + /** + * Mark texture is dirty and update in the next frame + */ + dirty: function () { + if (this._cache) { + this._cache.dirtyAll(); + } }, - takeCurrentTextureSlot: function (_gl, texture) { - var textureSlot = this._textureSlot; + update: function (renderer) {}, - this.useTextureSlot(_gl, texture, textureSlot); + // Update the common parameters of texture + updateCommon: function (renderer) { + var _gl = renderer.gl; + _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, this.flipY); + _gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha); + _gl.pixelStorei(_gl.UNPACK_ALIGNMENT, this.unpackAlignment); - this._textureSlot++; + // Use of none-power of two texture + // http://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences + if (this.format === glenum.DEPTH_COMPONENT) { + this.useMipmap = false; + } - return textureSlot; + var sRGBExt = renderer.getGLExtension('EXT_sRGB'); + // Fallback + if (this.format === Texture$1.SRGB && !sRGBExt) { + this.format = Texture$1.RGB; + } + if (this.format === Texture$1.SRGB_ALPHA && !sRGBExt) { + this.format = Texture$1.RGBA; + } + + this.NPOT = !this.isPowerOfTwo(); }, - useTextureSlot: function (renderer, texture, slot) { - if (texture) { - renderer.gl.activeTexture(renderer.gl.TEXTURE0 + slot); - // Maybe texture is not loaded yet; - if (texture.isRenderable()) { - texture.bind(renderer); - } - else { - // Bind texture to null - texture.unbind(renderer); - } - } - }, - - setUniform: function (_gl, type, symbol, value) { - var locationMap = this._currentLocationsMap; - var location = locationMap[symbol]; - // Uniform is not existed in the shader - if (location === null || location === undefined) { - return false; - } - switch (type) { - case 'm4': - // The matrix must be created by glmatrix and can pass it directly. - _gl.uniformMatrix4fv(location, false, value); - break; - case '2i': - _gl.uniform2i(location, value[0], value[1]); - break; - case '2f': - _gl.uniform2f(location, value[0], value[1]); - break; - case '3i': - _gl.uniform3i(location, value[0], value[1], value[2]); - break; - case '3f': - _gl.uniform3f(location, value[0], value[1], value[2]); - break; - case '4i': - _gl.uniform4i(location, value[0], value[1], value[2], value[3]); - break; - case '4f': - _gl.uniform4f(location, value[0], value[1], value[2], value[3]); - break; - case '1i': - _gl.uniform1i(location, value); - break; - case '1f': - _gl.uniform1f(location, value); - break; - case '1fv': - _gl.uniform1fv(location, value); - break; - case '1iv': - _gl.uniform1iv(location, value); - break; - case '2iv': - _gl.uniform2iv(location, value); - break; - case '2fv': - _gl.uniform2fv(location, value); - break; - case '3iv': - _gl.uniform3iv(location, value); - break; - case '3fv': - _gl.uniform3fv(location, value); - break; - case '4iv': - _gl.uniform4iv(location, value); - break; - case '4fv': - _gl.uniform4fv(location, value); - break; - case 'm2': - case 'm2v': - _gl.uniformMatrix2fv(location, false, value); - break; - case 'm3': - case 'm3v': - _gl.uniformMatrix3fv(location, false, value); - break; - case 'm4v': - // Raw value - if (Array.isArray(value)) { - var array = new vendor.Float32Array(value.length * 16); - var cursor = 0; - for (var i = 0; i < value.length; i++) { - var item = value[i]; - for (var j = 0; j < 16; j++) { - array[cursor++] = item[j]; - } - } - _gl.uniformMatrix4fv(location, false, array); - } - else if (value instanceof vendor.Float32Array) { // ArrayBufferView - _gl.uniformMatrix4fv(location, false, value); - } - break; + getAvailableWrapS: function () { + if (this.NPOT) { + return glenum.CLAMP_TO_EDGE; } - return true; + return this.wrapS; }, - - setUniformOfSemantic: function (_gl, semantic, val) { - var semanticInfo = this.uniformSemantics[semantic]; - if (semanticInfo) { - return this.setUniform(_gl, semanticInfo.type, semanticInfo.symbol, val); + getAvailableWrapT: function () { + if (this.NPOT) { + return glenum.CLAMP_TO_EDGE; } - return false; + return this.wrapT; }, - - // Used for creating VAO - // Enable the attributes passed in and disable the rest - // Example Usage: - // enableAttributes(renderer, ["position", "texcoords"]) - enableAttributes: function (renderer, attribList, vao) { - var _gl = renderer.gl; - var program = this._cache.get('program'); - - var locationMap = this._cache.get('attriblocations'); - - var enabledAttributeListInContext; - if (vao) { - enabledAttributeListInContext = vao.__enabledAttributeList; - } - else { - enabledAttributeListInContext = enabledAttributeList[renderer.__GUID__]; - } - if (! enabledAttributeListInContext) { - // In vertex array object context - // PENDING Each vao object needs to enable attributes again? - if (vao) { - enabledAttributeListInContext - = vao.__enabledAttributeList - = []; - } - else { - enabledAttributeListInContext - = enabledAttributeList[renderer.__GUID__] - = []; - } - } - var locationList = []; - for (var i = 0; i < attribList.length; i++) { - var symbol = attribList[i]; - if (!this.attributeTemplates[symbol]) { - locationList[i] = -1; - continue; - } - var location = locationMap[symbol]; - if (location === undefined) { - location = _gl.getAttribLocation(program, symbol); - // Attrib location is a number from 0 to ... - if (location === -1) { - locationList[i] = -1; - continue; - } - locationMap[symbol] = location; + getAvailableMinFilter: function () { + var minFilter = this.minFilter; + if (this.NPOT || !this.useMipmap) { + if (minFilter === glenum.NEAREST_MIPMAP_NEAREST || + minFilter === glenum.NEAREST_MIPMAP_LINEAR + ) { + return glenum.NEAREST; } - locationList[i] = location; - - if (!enabledAttributeListInContext[location]) { - enabledAttributeListInContext[location] = SHADER_STATE_TO_ENABLE; + else if (minFilter === glenum.LINEAR_MIPMAP_LINEAR || + minFilter === glenum.LINEAR_MIPMAP_NEAREST + ) { + return glenum.LINEAR; } else { - enabledAttributeListInContext[location] = SHADER_STATE_KEEP_ENABLE; + return minFilter; } } - - for (var i = 0; i < enabledAttributeListInContext.length; i++) { - switch(enabledAttributeListInContext[i]){ - case SHADER_STATE_TO_ENABLE: - _gl.enableVertexAttribArray(i); - enabledAttributeListInContext[i] = SHADER_STATE_PENDING; - break; - case SHADER_STATE_KEEP_ENABLE: - enabledAttributeListInContext[i] = SHADER_STATE_PENDING; - break; - // Expired - case SHADER_STATE_PENDING: - _gl.disableVertexAttribArray(i); - enabledAttributeListInContext[i] = 0; - break; - } + else { + return minFilter; } - - return locationList; - }, - - _parseImport: function () { - - this._vertexProcessedWithoutDefine = Shader.parseImport(this.vertex); - this._fragmentProcessedWithoutDefine = Shader.parseImport(this.fragment); - }, - - _addDefineExtensionAndPrecision: function (exts) { - - exts = exts || this.extensions; - // Extension declaration must before all non-preprocessor codes - // TODO vertex ? extension enum ? - var extensionStr = []; - for (var i = 0; i < exts.length; i++) { - extensionStr.push('#extension GL_' + exts[i] + ' : enable'); - } - - // Add defines - // VERTEX - var defineStr = this._getDefineStr(this.vertexDefines); - this._vertexProcessed = defineStr + '\n' + this._vertexProcessedWithoutDefine; - - // FRAGMENT - defineStr = this._getDefineStr(this.fragmentDefines); - var code = defineStr + '\n' + this._fragmentProcessedWithoutDefine; - - // Add precision - this._fragmentProcessed = extensionStr.join('\n') + '\n' - + ['precision', this.precision, 'float'].join(' ') + ';\n' - + ['precision', this.precision, 'int'].join(' ') + ';\n' - // depth texture may have precision problem on iOS device. - + ['precision', this.precision, 'sampler2D'].join(' ') + ';\n' - + code; + getAvailableMagFilter: function () { + return this.magFilter; }, - _getDefineStr: function (defines) { - - var lightNumber = this.lightNumber; - var textureStatus = this._textureStatus; - var defineStr = []; - for (var lightType in lightNumber) { - var count = lightNumber[lightType]; - if (count > 0) { - defineStr.push('#define ' + lightType.toUpperCase() + '_COUNT ' + count); - } - } - for (var symbol in textureStatus) { - var status = textureStatus[symbol]; - if (status.enabled) { - defineStr.push('#define ' + symbol.toUpperCase() + '_ENABLED'); - } - } - // Custom Defines - for (var symbol in defines) { - var value = defines[symbol]; - if (value === null) { - defineStr.push('#define ' + symbol); - } - else{ - defineStr.push('#define ' + symbol + ' ' + value.toString()); - } + nextHighestPowerOfTwo: function (x) { + --x; + for (var i = 1; i < 32; i <<= 1) { + x = x | x >> i; } - return defineStr.join('\n'); + return x + 1; }, + /** + * @param {clay.Renderer} renderer + */ + dispose: function (renderer) { - _unrollLoop: function (shaderStr, defines) { - // Loop unroll from three.js, https://github.com/mrdoob/three.js/blob/master/src/renderers/webgl/WebGLProgram.js#L175 - // In some case like shadowMap in loop use 'i' to index value much slower. - - // Loop use _idx_ and increased with _idx_++ will be unrolled - // Use {{ }} to match the pair so the if statement will not be affected - // Write like following - // for (int _idx_ = 0; _idx_ < 4; _idx_++) {{ - // vec3 color = texture2D(textures[_idx_], uv).rgb; - // }} - function replace(match, start, end, snippet) { - var unroll = ''; - // Try to treat as define - if (isNaN(start)) { - if (start in defines) { - start = defines[start]; - } - else { - start = lightNumberDefines[start]; - } - } - if (isNaN(end)) { - if (end in defines) { - end = defines[end]; - } - else { - end = lightNumberDefines[end]; - } - } - // TODO Error checking + var cache = this._cache; - for (var idx = parseInt(start); idx < parseInt(end); idx++) { - // PENDING Add scope? - unroll += '{' - + snippet - .replace(/float\s*\(\s*_idx_\s*\)/g, idx.toFixed(1)) - .replace(/_idx_/g, idx) - + '}'; - } + cache.use(renderer.__uid__); - return unroll; + var webglTexture = cache.get('webgl_texture'); + if (webglTexture){ + renderer.gl.deleteTexture(webglTexture); } + cache.deleteContext(renderer.__uid__); - var lightNumberDefines = {}; - for (var lightType in this.lightNumber) { - lightNumberDefines[lightType + '_COUNT'] = this.lightNumber[lightType]; - } - return shaderStr.replace(loopRegex, replace); }, + /** + * Test if image of texture is valid and loaded. + * @return {boolean} + */ + isRenderable: function () {}, - _parseUniforms: function () { - var uniforms = {}; - var self = this; - var shaderType = 'vertex'; - this._uniformList = []; + /** + * Test if texture size is power of two + * @return {boolean} + */ + isPowerOfTwo: function () {} +}); - this._vertexProcessedWithoutDefine = this._vertexProcessedWithoutDefine.replace(uniformRegex, _uniformParser); - shaderType = 'fragment'; - this._fragmentProcessedWithoutDefine = this._fragmentProcessedWithoutDefine.replace(uniformRegex, _uniformParser); +Object.defineProperty(Texture$1.prototype, 'width', { + get: function () { + return this._width; + }, + set: function (value) { + this._width = value; + } +}); +Object.defineProperty(Texture$1.prototype, 'height', { + get: function () { + return this._height; + }, + set: function (value) { + this._height = value; + } +}); - self.matrixSemanticKeys = Object.keys(this.matrixSemantics); +/* DataType */ - function _uniformParser(str, type, symbol, isArray, semanticWrapper, semantic) { - if (type && symbol) { - var uniformType = uniformTypeMap[type]; - var isConfigurable = true; - var defaultValueFunc; - if (uniformType) { - self._uniformList.push(symbol); - if (type === 'sampler2D' || type === 'samplerCube') { - // Texture is default disabled - self._textureStatus[symbol] = { - enabled: false, - shaderType: shaderType - }; - } - if (isArray) { - uniformType += 'v'; - } - if (semantic) { - // This case is only for SKIN_MATRIX - // TODO - if (attribSemantics.indexOf(semantic) >= 0) { - self.attribSemantics[semantic] = { - symbol: symbol, - type: uniformType - }; - isConfigurable = false; - } - else if (matrixSemantics.indexOf(semantic) >= 0) { - var isTranspose = false; - var semanticNoTranspose = semantic; - if (semantic.match(/TRANSPOSE$/)) { - isTranspose = true; - semanticNoTranspose = semantic.slice(0, -9); - } - self.matrixSemantics[semantic] = { - symbol: symbol, - type: uniformType, - isTranspose: isTranspose, - semanticNoTranspose: semanticNoTranspose - }; - isConfigurable = false; - } - else if (uniformSemantics.indexOf(semantic) >= 0) { - self.uniformSemantics[semantic] = { - symbol: symbol, - type: uniformType - }; - isConfigurable = false; - } - else { - // The uniform is not configurable, which means it will not appear - // in the material uniform properties - if (semantic === 'unconfigurable') { - isConfigurable = false; - } - else { - // Uniform have a defalut value, like - // uniform vec3 color: [1, 1, 1]; - defaultValueFunc = self._parseDefaultValue(type, semantic); - if (!defaultValueFunc) { - throw new Error('Unkown semantic "' + semantic + '"'); - } - else { - semantic = ''; - } - } - } - } - - if (isConfigurable) { - uniforms[symbol] = { - type: uniformType, - value: isArray ? uniformValueConstructor['array'] : (defaultValueFunc || uniformValueConstructor[type]), - semantic: semantic || null - }; - } - } - return ['uniform', type, symbol, isArray].join(' ') + ';\n'; - } - } - - this.uniformTemplates = uniforms; - }, - - _parseDefaultValue: function (type, str) { - var arrayRegex = /\[\s*(.*)\s*\]/; - if (type === 'vec2' || type === 'vec3' || type === 'vec4') { - var arrayStr = arrayRegex.exec(str)[1]; - if (arrayStr) { - var arr = arrayStr.split(/\s*,\s*/); - return function () { - return new vendor.Float32Array(arr); - }; - } - else { - // Invalid value - return; - } - } - else if (type === 'bool') { - return function () { - return str.toLowerCase() === 'true' ? true : false; - }; - } - else if (type === 'float') { - return function () { - return parseFloat(str); - }; - } - else if (type === 'int') { - return function () { - return parseInt(str); - }; - } - }, - - // Create a new uniform instance for material - createUniforms: function () { - var uniforms = {}; - - for (var symbol in this.uniformTemplates){ - var uniformTpl = this.uniformTemplates[symbol]; - uniforms[symbol] = { - type: uniformTpl.type, - value: uniformTpl.value() - }; - } - - return uniforms; - }, - - // Attached to material - attached: function () { - this._attacheMaterialNumber++; - }, - - // Detached to material - detached: function () { - this._attacheMaterialNumber--; - }, - - isAttachedToAny: function () { - return this._attacheMaterialNumber !== 0; - }, +/** + * @type {number} + */ +Texture$1.BYTE = glenum.BYTE; +/** + * @type {number} + */ +Texture$1.UNSIGNED_BYTE = glenum.UNSIGNED_BYTE; +/** + * @type {number} + */ +Texture$1.SHORT = glenum.SHORT; +/** + * @type {number} + */ +Texture$1.UNSIGNED_SHORT = glenum.UNSIGNED_SHORT; +/** + * @type {number} + */ +Texture$1.INT = glenum.INT; +/** + * @type {number} + */ +Texture$1.UNSIGNED_INT = glenum.UNSIGNED_INT; +/** + * @type {number} + */ +Texture$1.FLOAT = glenum.FLOAT; +/** + * @type {number} + */ +Texture$1.HALF_FLOAT = 0x8D61; - _parseAttributes: function () { - var attributes = {}; - var self = this; - this._vertexProcessedWithoutDefine = this._vertexProcessedWithoutDefine.replace( - attributeRegex, _attributeParser - ); +/** + * UNSIGNED_INT_24_8_WEBGL for WEBGL_depth_texture extension + * @type {number} + */ +Texture$1.UNSIGNED_INT_24_8_WEBGL = 34042; - function _attributeParser(str, type, symbol, semanticWrapper, semantic) { - if (type && symbol) { - var size = 1; - switch (type) { - case 'vec4': - size = 4; - break; - case 'vec3': - size = 3; - break; - case 'vec2': - size = 2; - break; - case 'float': - size = 1; - break; - } +/* PixelFormat */ +/** + * @type {number} + */ +Texture$1.DEPTH_COMPONENT = glenum.DEPTH_COMPONENT; +/** + * @type {number} + */ +Texture$1.DEPTH_STENCIL = glenum.DEPTH_STENCIL; +/** + * @type {number} + */ +Texture$1.ALPHA = glenum.ALPHA; +/** + * @type {number} + */ +Texture$1.RGB = glenum.RGB; +/** + * @type {number} + */ +Texture$1.RGBA = glenum.RGBA; +/** + * @type {number} + */ +Texture$1.LUMINANCE = glenum.LUMINANCE; +/** + * @type {number} + */ +Texture$1.LUMINANCE_ALPHA = glenum.LUMINANCE_ALPHA; - attributes[symbol] = { - // Can only be float - type: 'float', - size: size, - semantic: semantic || null - }; +/** + * @see https://www.khronos.org/registry/webgl/extensions/EXT_sRGB/ + * @type {number} + */ +Texture$1.SRGB = 0x8C40; +/** + * @see https://www.khronos.org/registry/webgl/extensions/EXT_sRGB/ + * @type {number} + */ +Texture$1.SRGB_ALPHA = 0x8C42; - if (semantic) { - if (attribSemantics.indexOf(semantic) < 0) { - throw new Error('Unkown semantic "' + semantic + '"'); - } - else { - self.attribSemantics[semantic] = { - symbol: symbol, - type: type - }; - } - } - } +/* Compressed Texture */ +Texture$1.COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0; +Texture$1.COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; +Texture$1.COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; +Texture$1.COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3; - return ['attribute', type, symbol].join(' ') + ';\n'; - } +/* TextureMagFilter */ +/** + * @type {number} + */ +Texture$1.NEAREST = glenum.NEAREST; +/** + * @type {number} + */ +Texture$1.LINEAR = glenum.LINEAR; - this.attributeTemplates = attributes; - }, +/* TextureMinFilter */ +/** + * @type {number} + */ +Texture$1.NEAREST_MIPMAP_NEAREST = glenum.NEAREST_MIPMAP_NEAREST; +/** + * @type {number} + */ +Texture$1.LINEAR_MIPMAP_NEAREST = glenum.LINEAR_MIPMAP_NEAREST; +/** + * @type {number} + */ +Texture$1.NEAREST_MIPMAP_LINEAR = glenum.NEAREST_MIPMAP_LINEAR; +/** + * @type {number} + */ +Texture$1.LINEAR_MIPMAP_LINEAR = glenum.LINEAR_MIPMAP_LINEAR; - _parseDefines: function () { - var self = this; - var shaderType = 'vertex'; - this._vertexProcessedWithoutDefine = this._vertexProcessedWithoutDefine.replace(defineRegex, _defineParser); - shaderType = 'fragment'; - this._fragmentProcessedWithoutDefine = this._fragmentProcessedWithoutDefine.replace(defineRegex, _defineParser); +/* TextureWrapMode */ +/** + * @type {number} + */ +Texture$1.REPEAT = glenum.REPEAT; +/** + * @type {number} + */ +Texture$1.CLAMP_TO_EDGE = glenum.CLAMP_TO_EDGE; +/** + * @type {number} + */ +Texture$1.MIRRORED_REPEAT = glenum.MIRRORED_REPEAT; - function _defineParser(str, symbol, value) { - var defines = shaderType === 'vertex' ? self.vertexDefines : self.fragmentDefines; - if (!defines[symbol]) { // Haven't been defined by user - if (value == 'false') { - defines[symbol] = false; - } - else if (value == 'true') { - defines[symbol] = true; - } - else { - defines[symbol] = value - // If can parse to float - ? (isNaN(parseFloat(value)) ? value : parseFloat(value)) - : null; - } - } - return ''; - } - }, +/** + * Simple double linked list. Compared with array, it has O(1) remove operation. + * @constructor + * @alias clay.core.LinkedList + */ +var LinkedList = function () { - // Return true or error msg if error happened - _buildProgram: function (_gl, vertexShaderString, fragmentShaderString) { - var cache = this._cache; - if (cache.get('program')) { - _gl.deleteProgram(cache.get('program')); - } - var program = _gl.createProgram(); + /** + * @type {clay.core.LinkedList.Entry} + */ + this.head = null; - var vertexShader = _gl.createShader(_gl.VERTEX_SHADER); - _gl.shaderSource(vertexShader, vertexShaderString); - _gl.compileShader(vertexShader); + /** + * @type {clay.core.LinkedList.Entry} + */ + this.tail = null; - var fragmentShader = _gl.createShader(_gl.FRAGMENT_SHADER); - _gl.shaderSource(fragmentShader, fragmentShaderString); - _gl.compileShader(fragmentShader); + this._length = 0; +}; - var msg = checkShaderErrorMsg(_gl, vertexShader, vertexShaderString); - if (msg) { - return msg; - } - msg = checkShaderErrorMsg(_gl, fragmentShader, fragmentShaderString); - if (msg) { - return msg; - } +/** + * Insert a new value at the tail + * @param {} val + * @return {clay.core.LinkedList.Entry} + */ +LinkedList.prototype.insert = function (val) { + var entry = new LinkedList.Entry(val); + this.insertEntry(entry); + return entry; +}; - _gl.attachShader(program, vertexShader); - _gl.attachShader(program, fragmentShader); - // Force the position bind to location 0; - if (this.attribSemantics['POSITION']) { - _gl.bindAttribLocation(program, 0, this.attribSemantics['POSITION'].symbol); +/** + * Insert a new value at idx + * @param {number} idx + * @param {} val + * @return {clay.core.LinkedList.Entry} + */ +LinkedList.prototype.insertAt = function (idx, val) { + if (idx < 0) { + return; + } + var next = this.head; + var cursor = 0; + while (next && cursor != idx) { + next = next.next; + cursor++; + } + if (next) { + var entry = new LinkedList.Entry(val); + var prev = next.prev; + if (!prev) { //next is head + this.head = entry; } else { - // Else choose an attribute and bind to location 0; - var keys = Object.keys(this.attributeTemplates); - _gl.bindAttribLocation(program, 0, keys[0]); + prev.next = entry; + entry.prev = prev; } + entry.next = next; + next.prev = entry; + } + else { + this.insert(val); + } +}; - _gl.linkProgram(program); +LinkedList.prototype.insertBeforeEntry = function (val, next) { + var entry = new LinkedList.Entry(val); + var prev = next.prev; + if (!prev) { //next is head + this.head = entry; + } + else { + prev.next = entry; + entry.prev = prev; + } + entry.next = next; + next.prev = entry; - if (!_gl.getProgramParameter(program, _gl.LINK_STATUS)) { - return 'Could not link program\n' + 'VALIDATE_STATUS: ' + _gl.getProgramParameter(program, _gl.VALIDATE_STATUS) + ', gl error [' + _gl.getError() + ']'; - } + this._length++; +}; - // Cache uniform locations - for (var i = 0; i < this._uniformList.length; i++) { - var uniformSymbol = this._uniformList[i]; - var locationMap = cache.get('locations'); - locationMap[uniformSymbol] = _gl.getUniformLocation(program, uniformSymbol); - } - - _gl.deleteShader(vertexShader); - _gl.deleteShader(fragmentShader); - - cache.put('program', program); - }, - - /** - * Clone a new shader - * @return {qtek.Shader} - */ - clone: function () { - var shader = new Shader({ - vertex: this.vertex, - fragment: this.fragment, - vertexDefines: util.clone(this.vertexDefines), - fragmentDefines: util.clone(this.fragmentDefines) - }); - for (var name in this._textureStatus) { - shader._textureStatus[name] = util.clone(this._textureStatus[name]); - } - return shader; - }, - /** - * Dispose given context - * @param {qtek.Renderer} renderer - */ - dispose: function (renderer) { - var cache = this._cache; - - cache.use(renderer.__GUID__); - var program = cache.get('program'); - if (program) { - renderer.gl.deleteProgram(program); - } - cache.deleteContext(renderer.__GUID__); - - this._locations = {}; - } -}); - -function getCacheSchema() { - return { - locations: {}, - attriblocations: {} - }; -} - -// Return true or error msg if error happened -function checkShaderErrorMsg(_gl, shader, shaderString) { - if (!_gl.getShaderParameter(shader, _gl.COMPILE_STATUS)) { - return [_gl.getShaderInfoLog(shader), addLineNumbers(shaderString)].join('\n'); +/** + * Insert an entry at the tail + * @param {clay.core.LinkedList.Entry} entry + */ +LinkedList.prototype.insertEntry = function (entry) { + if (!this.head) { + this.head = this.tail = entry; } -} - -// some util functions -function addLineNumbers(string) { - var chunks = string.split('\n'); - for (var i = 0, il = chunks.length; i < il; i ++) { - // Chrome reports shader errors on lines - // starting counting from 1 - chunks[i] = (i + 1) + ': ' + chunks[i]; + else { + this.tail.next = entry; + entry.prev = this.tail; + this.tail = entry; } - return chunks.join('\n'); -} - -var importRegex = /(@import)\s*([0-9a-zA-Z_\-\.]*)/g; -Shader.parseImport = function (shaderStr) { - shaderStr = shaderStr.replace(importRegex, function (str, importSymbol, importName) { - var str = Shader.source(importName); - if (str) { - // Recursively parse - return Shader.parseImport(str); - } - else { - console.error('Shader chunk "' + importName + '" not existed in library'); - return ''; - } - }); - return shaderStr; + this._length++; }; -var exportRegex = /(@export)\s*([0-9a-zA-Z_\-\.]*)\s*\n([\s\S]*?)@end/g; - /** - * Import shader source - * @param {string} shaderStr - * @memberOf qtek.Shader + * Remove entry. + * @param {clay.core.LinkedList.Entry} entry */ -Shader['import'] = function (shaderStr) { - shaderStr.replace(exportRegex, function (str, exportSymbol, exportName, code) { - var code = code.replace(/(^[\s\t\xa0\u3000]+)|([\u3000\xa0\s\t]+\x24)/g, ''); - if (code) { - var parts = exportName.split('.'); - var obj = Shader.codes; - var i = 0; - var key; - while (i < parts.length - 1) { - key = parts[i++]; - if (!obj[key]) { - obj[key] = {}; - } - obj = obj[key]; - } - key = parts[i]; - obj[key] = code; - } - return code; - }); +LinkedList.prototype.remove = function (entry) { + var prev = entry.prev; + var next = entry.next; + if (prev) { + prev.next = next; + } + else { + // Is head + this.head = next; + } + if (next) { + next.prev = prev; + } + else { + // Is tail + this.tail = prev; + } + entry.next = entry.prev = null; + this._length--; }; /** - * Library to store all the loaded shader codes - * @type {Object} - * @readOnly - * @memberOf qtek.Shader - */ -Shader.codes = {}; - -/** - * Get shader source - * @param {string} name - * @return {string} + * Remove entry at index. + * @param {number} idx + * @return {} */ -Shader.source = function (name) { - var parts = name.split('.'); - var obj = Shader.codes; - var i = 0; - while (obj && i < parts.length) { - var key = parts[i++]; - obj = obj[key]; +LinkedList.prototype.removeAt = function (idx) { + if (idx < 0) { + return; } - if (typeof obj !== 'string') { - // FIXME Use default instead - console.error('Shader "' + name + '" not existed in library'); - return ''; + var curr = this.head; + var cursor = 0; + while (curr && cursor != idx) { + curr = curr.next; + cursor++; + } + if (curr) { + this.remove(curr); + return curr.value; } - return obj; }; - /** - * @export{Object} library - */ -var _library = {}; - -/** - * @export qtek.shader.library~Libaray + * Get head value + * @return {} */ -function ShaderLibrary () { - this._pool = {}; -} - +LinkedList.prototype.getHead = function () { + if (this.head) { + return this.head.value; + } +}; /** - * ### Builin shaders - * + qtek.standard - * + qtek.basic - * + qtek.lambert - * + qtek.wireframe - * - * @namespace qtek.shader.library + * Get tail value + * @return {} */ +LinkedList.prototype.getTail = function () { + if (this.tail) { + return this.tail.value; + } +}; /** - * - * Get shader from library. use shader name and option as hash key. - * - * @param {string} name - * @param {Object|string|Array.} [option] - * @return {qtek.Shader} - * - * @example - * qtek.shader.library.get('qtek.standard', 'diffuseMap', 'normalMap'); - * qtek.shader.library.get('qtek.standard', ['diffuseMap', 'normalMap']); - * qtek.shader.library.get('qtek.standard', { - * textures: ['diffuseMap'], - * vertexDefines: {}, - * fragmentDefines: {} - * precision: 'mediump' - * }) + * Get value at idx + * @param {number} idx + * @return {} */ -ShaderLibrary.prototype.get = function(name, option) { - var enabledTextures = []; - var vertexDefines = {}; - var fragmentDefines = {}; - var precision; - if (typeof(option) === 'string') { - enabledTextures = Array.prototype.slice.call(arguments, 1); - } - else if (Object.prototype.toString.call(option) == '[object Object]') { - enabledTextures = option.textures || []; - vertexDefines = option.vertexDefines || {}; - fragmentDefines = option.fragmentDefines || {}; - precision = option.precision; - } - else if (Array.isArray(option)) { - enabledTextures = option; - } - var vertexDefineKeys = Object.keys(vertexDefines); - var fragmentDefineKeys = Object.keys(fragmentDefines); - enabledTextures.sort(); - vertexDefineKeys.sort(); - fragmentDefineKeys.sort(); - - var keyArr = [name]; - keyArr = keyArr.concat(enabledTextures); - for (var i = 0; i < vertexDefineKeys.length; i++) { - keyArr.push( - vertexDefineKeys[i], - vertexDefines[vertexDefineKeys[i]] - ); - } - for (var i = 0; i < fragmentDefineKeys.length; i++) { - keyArr.push( - fragmentDefineKeys[i], - fragmentDefines[fragmentDefineKeys[i]] - ); +LinkedList.prototype.getAt = function (idx) { + if (idx < 0) { + return; } - if (precision) { - keyArr.push(precision); + var curr = this.head; + var cursor = 0; + while (curr && cursor != idx) { + curr = curr.next; + cursor++; } - var key = keyArr.join('_'); + return curr.value; +}; - if (this._pool[key]) { - return this._pool[key]; - } - else { - var source = _library[name]; - if (!source) { - console.error('Shader "' + name + '"' + ' is not in the library'); - return; - } - var shader = new Shader({ - 'vertex': source.vertex, - 'fragment': source.fragment - }); - if (precision) { - shader.precision = precision; - } - for (var i = 0; i < enabledTextures.length; i++) { - shader.enableTexture(enabledTextures[i]); - } - for (var name in vertexDefines) { - shader.define('vertex', name, vertexDefines[name]); - } - for (var name in fragmentDefines) { - shader.define('fragment', name, fragmentDefines[name]); +/** + * @param {} value + * @return {number} + */ +LinkedList.prototype.indexOf = function (value) { + var curr = this.head; + var cursor = 0; + while (curr) { + if (curr.value === value) { + return cursor; } - this._pool[key] = shader; - return shader; + curr = curr.next; + cursor++; } }; /** - * Clear shaders + * @return {number} */ -ShaderLibrary.prototype.clear = function() { - this._pool = {}; +LinkedList.prototype.length = function () { + return this._length; }; /** - * @memberOf qtek.shader.library - * @param {string} name - * @param {string} vertex - Vertex shader code - * @param {string} fragment - Fragment shader code + * If list is empty */ -function template(name, vertex, fragment) { - _library[name] = { - vertex: vertex, - fragment: fragment - }; -} - -var defaultLibrary = new ShaderLibrary(); +LinkedList.prototype.isEmpty = function () { + return this._length === 0; +}; /** - * @alias qtek.shader.library + * @param {Function} cb + * @param {} context */ -var library = { - /** - * Create a new shader library. - */ - createLibrary: function () { - return new ShaderLibrary(); - }, - get: function () { - return defaultLibrary.get.apply(defaultLibrary, arguments); - }, - template: template, - clear: function () { - return defaultLibrary.clear(); +LinkedList.prototype.forEach = function (cb, context) { + var curr = this.head; + var idx = 0; + var haveContext = typeof(context) != 'undefined'; + while (curr) { + if (haveContext) { + cb.call(context, curr.value, idx); + } + else { + cb(curr.value, idx); + } + curr = curr.next; + idx++; } }; /** - * Base class for all textures like compressed texture, texture2d, texturecube - * TODO mapping + * Clear the list */ +LinkedList.prototype.clear = function () { + this.tail = this.head = null; + this._length = 0; +}; + /** * @constructor - * @alias qtek.Texture - * @extends qtek.core.Base + * @param {} val */ -var Texture = Base.extend( -/** @lends qtek.Texture# */ -{ - /** - * Texture width, readonly when the texture source is image - * @type {number} - */ - width: 512, - /** - * Texture height, readonly when the texture source is image - * @type {number} - */ - height: 512, - /** - * Texel data type. - * Possible values: - * + {@link qtek.Texture.UNSIGNED_BYTE} - * + {@link qtek.Texture.HALF_FLOAT} - * + {@link qtek.Texture.FLOAT} - * + {@link qtek.Texture.UNSIGNED_INT_24_8_WEBGL} - * + {@link qtek.Texture.UNSIGNED_INT} - * @type {number} - */ - type: glenum.UNSIGNED_BYTE, +LinkedList.Entry = function (val) { /** - * Format of texel data - * Possible values: - * + {@link qtek.Texture.RGBA} - * + {@link qtek.Texture.DEPTH_COMPONENT} - * + {@link qtek.Texture.DEPTH_STENCIL} - * @type {number} + * @type {} */ - format: glenum.RGBA, + this.value = val; + /** - * Texture wrap. Default to be REPEAT. - * Possible values: - * + {@link qtek.Texture.CLAMP_TO_EDGE} - * + {@link qtek.Texture.REPEAT} - * + {@link qtek.Texture.MIRRORED_REPEAT} - * @type {number} + * @type {clay.core.LinkedList.Entry} */ - wrapS: glenum.REPEAT, + this.next = null; + /** - * Texture wrap. Default to be REPEAT. - * Possible values: - * + {@link qtek.Texture.CLAMP_TO_EDGE} - * + {@link qtek.Texture.REPEAT} - * + {@link qtek.Texture.MIRRORED_REPEAT} - * @type {number} + * @type {clay.core.LinkedList.Entry} */ - wrapT: glenum.REPEAT, - /** - * Possible values: - * + {@link qtek.Texture.NEAREST} - * + {@link qtek.Texture.LINEAR} - * + {@link qtek.Texture.NEAREST_MIPMAP_NEAREST} - * + {@link qtek.Texture.LINEAR_MIPMAP_NEAREST} - * + {@link qtek.Texture.NEAREST_MIPMAP_LINEAR} - * + {@link qtek.Texture.LINEAR_MIPMAP_LINEAR} - * @type {number} - */ - minFilter: glenum.LINEAR_MIPMAP_LINEAR, - /** - * Possible values: - * + {@link qtek.Texture.NEAREST} - * + {@link qtek.Texture.LINEAR} - * @type {number} - */ - magFilter: glenum.LINEAR, - /** - * If enable mimap. - * @type {boolean} - */ - useMipmap: true, - - /** - * Anisotropic filtering, enabled if value is larger than 1 - * @see http://blog.tojicode.com/2012/03/anisotropic-filtering-in-webgl.html - * @type {number} - */ - anisotropic: 1, - // pixelStorei parameters, not available when texture is used as render target - // http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml - /** - * If flip in y axis for given image source - * @type {boolean} - * @default true - */ - flipY: true, - /** - * @type {number} - * @default 4 - */ - unpackAlignment: 4, - /** - * @type {boolean} - * @default false - */ - premultiplyAlpha: false, - - /** - * Dynamic option for texture like video - * @type {boolean} - */ - dynamic: false, - - NPOT: false -}, function () { - this._cache = new Cache(); -}, -/** @lends qtek.Texture.prototype */ -{ - - getWebGLTexture: function (renderer) { - var _gl = renderer.gl; - var cache = this._cache; - cache.use(renderer.__GUID__); - - if (cache.miss('webgl_texture')) { - // In a new gl context, create new texture and set dirty true - cache.put('webgl_texture', _gl.createTexture()); - } - if (this.dynamic) { - this.update(renderer); - } - else if (cache.isDirty()) { - this.update(renderer); - cache.fresh(); - } - - return cache.get('webgl_texture'); - }, - - bind: function () {}, - unbind: function () {}, - - /** - * Mark texture is dirty and update in the next frame - */ - dirty: function () { - if (this._cache) { - this._cache.dirtyAll(); - } - }, - - update: function (renderer) {}, + this.prev = null; +}; - // Update the common parameters of texture - updateCommon: function (renderer) { - var _gl = renderer.gl; - _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, this.flipY); - _gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha); - _gl.pixelStorei(_gl.UNPACK_ALIGNMENT, this.unpackAlignment); +/** + * LRU Cache + * @constructor + * @alias clay.core.LRU + */ +var LRU = function(maxSize) { - // Use of none-power of two texture - // http://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences - if (this.format === glenum.DEPTH_COMPONENT) { - this.useMipmap = false; - } + this._list = new LinkedList(); - var sRGBExt = renderer.getGLExtension('EXT_sRGB'); - // Fallback - if (this.format === Texture.SRGB && !sRGBExt) { - this.format = Texture.RGB; - } - if (this.format === Texture.SRGB_ALPHA && !sRGBExt) { - this.format = Texture.RGBA; - } + this._map = {}; - this.NPOT = !this.isPowerOfTwo(); - }, + this._maxSize = maxSize || 10; +}; - getAvailableWrapS: function () { - if (this.NPOT) { - return glenum.CLAMP_TO_EDGE; - } - return this.wrapS; - }, - getAvailableWrapT: function () { - if (this.NPOT) { - return glenum.CLAMP_TO_EDGE; - } - return this.wrapT; - }, - getAvailableMinFilter: function () { - var minFilter = this.minFilter; - if (this.NPOT || !this.useMipmap) { - if (minFilter == glenum.NEAREST_MIPMAP_NEAREST || - minFilter == glenum.NEAREST_MIPMAP_LINEAR - ) { - return glenum.NEAREST; - } - else if (minFilter == glenum.LINEAR_MIPMAP_LINEAR || - minFilter == glenum.LINEAR_MIPMAP_NEAREST - ) { - return glenum.LINEAR; - } - else { - return minFilter; - } - } - else { - return minFilter; - } - }, - getAvailableMagFilter: function () { - return this.magFilter; - }, +/** + * Set cache max size + * @param {number} size + */ +LRU.prototype.setMaxSize = function(size) { + this._maxSize = size; +}; - nextHighestPowerOfTwo: function (x) { - --x; - for (var i = 1; i < 32; i <<= 1) { - x = x | x >> i; +/** + * @param {string} key + * @param {} value + */ +LRU.prototype.put = function(key, value) { + if (typeof(this._map[key]) == 'undefined') { + var len = this._list.length(); + if (len >= this._maxSize && len > 0) { + // Remove the least recently used + var leastUsedEntry = this._list.head; + this._list.remove(leastUsedEntry); + delete this._map[leastUsedEntry.key]; } - return x + 1; - }, - /** - * @param {qtek.Renderer} renderer - */ - dispose: function (renderer) { - var cache = this._cache; - - cache.use(renderer.__GUID__); + var entry = this._list.insert(value); + entry.key = key; + this._map[key] = entry; + } +}; - var webglTexture = cache.get('webgl_texture'); - if (webglTexture){ - renderer.gl.deleteTexture(webglTexture); +/** + * @param {string} key + * @return {} + */ +LRU.prototype.get = function(key) { + var entry = this._map[key]; + if (typeof(entry) != 'undefined') { + // Put the latest used entry in the tail + if (entry !== this._list.tail) { + this._list.remove(entry); + this._list.insertEntry(entry); } - cache.deleteContext(renderer.__GUID__); - - }, - /** - * Test if image of texture is valid and loaded. - * @return {boolean} - */ - isRenderable: function () {}, - - /** - * Test if texture size is power of two - * @return {boolean} - */ - isPowerOfTwo: function () {} -}); -Object.defineProperty(Texture.prototype, 'width', { - get: function () { - return this._width; - }, - set: function (value) { - this._width = value; - } -}); -Object.defineProperty(Texture.prototype, 'height', { - get: function () { - return this._height; - }, - set: function (value) { - this._height = value; + return entry.value; } -}); - -/* DataType */ +}; /** - * @type {number} - */ -Texture.BYTE = glenum.BYTE; -/** - * @type {number} - */ -Texture.UNSIGNED_BYTE = glenum.UNSIGNED_BYTE; -/** - * @type {number} - */ -Texture.SHORT = glenum.SHORT; -/** - * @type {number} - */ -Texture.UNSIGNED_SHORT = glenum.UNSIGNED_SHORT; -/** - * @type {number} - */ -Texture.INT = glenum.INT; -/** - * @type {number} - */ -Texture.UNSIGNED_INT = glenum.UNSIGNED_INT; -/** - * @type {number} + * @param {string} key */ -Texture.FLOAT = glenum.FLOAT; -/** - * @type {number} - */ -Texture.HALF_FLOAT = 0x8D61; +LRU.prototype.remove = function(key) { + var entry = this._map[key]; + if (typeof(entry) != 'undefined') { + delete this._map[key]; + this._list.remove(entry); + } +}; /** - * UNSIGNED_INT_24_8_WEBGL for WEBGL_depth_texture extension - * @type {number} + * Clear the cache */ -Texture.UNSIGNED_INT_24_8_WEBGL = 34042; +LRU.prototype.clear = function() { + this._list.clear(); + this._map = {}; +}; -/* PixelFormat */ -/** - * @type {number} - */ -Texture.DEPTH_COMPONENT = glenum.DEPTH_COMPONENT; -/** - * @type {number} - */ -Texture.DEPTH_STENCIL = glenum.DEPTH_STENCIL; -/** - * @type {number} - */ -Texture.ALPHA = glenum.ALPHA; -/** - * @type {number} - */ -Texture.RGB = glenum.RGB; -/** - * @type {number} - */ -Texture.RGBA = glenum.RGBA; /** - * @type {number} - */ -Texture.LUMINANCE = glenum.LUMINANCE; -/** - * @type {number} + * @namespace clay.core.color */ -Texture.LUMINANCE_ALPHA = glenum.LUMINANCE_ALPHA; +var colorUtil = {}; -/** - * @see https://www.khronos.org/registry/webgl/extensions/EXT_sRGB/ - * @type {number} - */ -Texture.SRGB = 0x8C40; -/** - * @see https://www.khronos.org/registry/webgl/extensions/EXT_sRGB/ - * @type {number} - */ -Texture.SRGB_ALPHA = 0x8C42; - -/* Compressed Texture */ -Texture.COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0; -Texture.COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; -Texture.COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; -Texture.COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3; +var kCSSColorTable = { + 'transparent': [0,0,0,0], 'aliceblue': [240,248,255,1], + 'antiquewhite': [250,235,215,1], 'aqua': [0,255,255,1], + 'aquamarine': [127,255,212,1], 'azure': [240,255,255,1], + 'beige': [245,245,220,1], 'bisque': [255,228,196,1], + 'black': [0,0,0,1], 'blanchedalmond': [255,235,205,1], + 'blue': [0,0,255,1], 'blueviolet': [138,43,226,1], + 'brown': [165,42,42,1], 'burlywood': [222,184,135,1], + 'cadetblue': [95,158,160,1], 'chartreuse': [127,255,0,1], + 'chocolate': [210,105,30,1], 'coral': [255,127,80,1], + 'cornflowerblue': [100,149,237,1], 'cornsilk': [255,248,220,1], + 'crimson': [220,20,60,1], 'cyan': [0,255,255,1], + 'darkblue': [0,0,139,1], 'darkcyan': [0,139,139,1], + 'darkgoldenrod': [184,134,11,1], 'darkgray': [169,169,169,1], + 'darkgreen': [0,100,0,1], 'darkgrey': [169,169,169,1], + 'darkkhaki': [189,183,107,1], 'darkmagenta': [139,0,139,1], + 'darkolivegreen': [85,107,47,1], 'darkorange': [255,140,0,1], + 'darkorchid': [153,50,204,1], 'darkred': [139,0,0,1], + 'darksalmon': [233,150,122,1], 'darkseagreen': [143,188,143,1], + 'darkslateblue': [72,61,139,1], 'darkslategray': [47,79,79,1], + 'darkslategrey': [47,79,79,1], 'darkturquoise': [0,206,209,1], + 'darkviolet': [148,0,211,1], 'deeppink': [255,20,147,1], + 'deepskyblue': [0,191,255,1], 'dimgray': [105,105,105,1], + 'dimgrey': [105,105,105,1], 'dodgerblue': [30,144,255,1], + 'firebrick': [178,34,34,1], 'floralwhite': [255,250,240,1], + 'forestgreen': [34,139,34,1], 'fuchsia': [255,0,255,1], + 'gainsboro': [220,220,220,1], 'ghostwhite': [248,248,255,1], + 'gold': [255,215,0,1], 'goldenrod': [218,165,32,1], + 'gray': [128,128,128,1], 'green': [0,128,0,1], + 'greenyellow': [173,255,47,1], 'grey': [128,128,128,1], + 'honeydew': [240,255,240,1], 'hotpink': [255,105,180,1], + 'indianred': [205,92,92,1], 'indigo': [75,0,130,1], + 'ivory': [255,255,240,1], 'khaki': [240,230,140,1], + 'lavender': [230,230,250,1], 'lavenderblush': [255,240,245,1], + 'lawngreen': [124,252,0,1], 'lemonchiffon': [255,250,205,1], + 'lightblue': [173,216,230,1], 'lightcoral': [240,128,128,1], + 'lightcyan': [224,255,255,1], 'lightgoldenrodyellow': [250,250,210,1], + 'lightgray': [211,211,211,1], 'lightgreen': [144,238,144,1], + 'lightgrey': [211,211,211,1], 'lightpink': [255,182,193,1], + 'lightsalmon': [255,160,122,1], 'lightseagreen': [32,178,170,1], + 'lightskyblue': [135,206,250,1], 'lightslategray': [119,136,153,1], + 'lightslategrey': [119,136,153,1], 'lightsteelblue': [176,196,222,1], + 'lightyellow': [255,255,224,1], 'lime': [0,255,0,1], + 'limegreen': [50,205,50,1], 'linen': [250,240,230,1], + 'magenta': [255,0,255,1], 'maroon': [128,0,0,1], + 'mediumaquamarine': [102,205,170,1], 'mediumblue': [0,0,205,1], + 'mediumorchid': [186,85,211,1], 'mediumpurple': [147,112,219,1], + 'mediumseagreen': [60,179,113,1], 'mediumslateblue': [123,104,238,1], + 'mediumspringgreen': [0,250,154,1], 'mediumturquoise': [72,209,204,1], + 'mediumvioletred': [199,21,133,1], 'midnightblue': [25,25,112,1], + 'mintcream': [245,255,250,1], 'mistyrose': [255,228,225,1], + 'moccasin': [255,228,181,1], 'navajowhite': [255,222,173,1], + 'navy': [0,0,128,1], 'oldlace': [253,245,230,1], + 'olive': [128,128,0,1], 'olivedrab': [107,142,35,1], + 'orange': [255,165,0,1], 'orangered': [255,69,0,1], + 'orchid': [218,112,214,1], 'palegoldenrod': [238,232,170,1], + 'palegreen': [152,251,152,1], 'paleturquoise': [175,238,238,1], + 'palevioletred': [219,112,147,1], 'papayawhip': [255,239,213,1], + 'peachpuff': [255,218,185,1], 'peru': [205,133,63,1], + 'pink': [255,192,203,1], 'plum': [221,160,221,1], + 'powderblue': [176,224,230,1], 'purple': [128,0,128,1], + 'red': [255,0,0,1], 'rosybrown': [188,143,143,1], + 'royalblue': [65,105,225,1], 'saddlebrown': [139,69,19,1], + 'salmon': [250,128,114,1], 'sandybrown': [244,164,96,1], + 'seagreen': [46,139,87,1], 'seashell': [255,245,238,1], + 'sienna': [160,82,45,1], 'silver': [192,192,192,1], + 'skyblue': [135,206,235,1], 'slateblue': [106,90,205,1], + 'slategray': [112,128,144,1], 'slategrey': [112,128,144,1], + 'snow': [255,250,250,1], 'springgreen': [0,255,127,1], + 'steelblue': [70,130,180,1], 'tan': [210,180,140,1], + 'teal': [0,128,128,1], 'thistle': [216,191,216,1], + 'tomato': [255,99,71,1], 'turquoise': [64,224,208,1], + 'violet': [238,130,238,1], 'wheat': [245,222,179,1], + 'white': [255,255,255,1], 'whitesmoke': [245,245,245,1], + 'yellow': [255,255,0,1], 'yellowgreen': [154,205,50,1] +}; -/* TextureMagFilter */ -/** - * @type {number} - */ -Texture.NEAREST = glenum.NEAREST; -/** - * @type {number} - */ -Texture.LINEAR = glenum.LINEAR; +function clampCssByte(i) { // Clamp to integer 0 .. 255. + i = Math.round(i); // Seems to be what Chrome does (vs truncation). + return i < 0 ? 0 : i > 255 ? 255 : i; +} -/* TextureMinFilter */ -/** - * @type {number} - */ -Texture.NEAREST_MIPMAP_NEAREST = glenum.NEAREST_MIPMAP_NEAREST; -/** - * @type {number} - */ -Texture.LINEAR_MIPMAP_NEAREST = glenum.LINEAR_MIPMAP_NEAREST; -/** - * @type {number} - */ -Texture.NEAREST_MIPMAP_LINEAR = glenum.NEAREST_MIPMAP_LINEAR; -/** - * @type {number} - */ -Texture.LINEAR_MIPMAP_LINEAR = glenum.LINEAR_MIPMAP_LINEAR; +function clampCssAngle(i) { // Clamp to integer 0 .. 360. + i = Math.round(i); // Seems to be what Chrome does (vs truncation). + return i < 0 ? 0 : i > 360 ? 360 : i; +} -/* TextureWrapMode */ -/** - * @type {number} - */ -Texture.REPEAT = glenum.REPEAT; -/** - * @type {number} - */ -Texture.CLAMP_TO_EDGE = glenum.CLAMP_TO_EDGE; -/** - * @type {number} - */ -Texture.MIRRORED_REPEAT = glenum.MIRRORED_REPEAT; +function clampCssFloat(f) { // Clamp to float 0.0 .. 1.0. + return f < 0 ? 0 : f > 1 ? 1 : f; +} -/** - * @constructor qtek.Material - * @extends qtek.core.Base - */ -var Material = Base.extend( -/** @lends qtek.Material# */ -{ - /** - * @type {string} - */ - name: '', +function parseCssInt(str) { // int or percentage. + if (str.length && str.charAt(str.length - 1) === '%') { + return clampCssByte(parseFloat(str) / 100 * 255); + } + return clampCssByte(parseInt(str, 10)); +} - /** - * @type {Object} - */ - // uniforms: null, +function parseCssFloat(str) { // float or percentage. + if (str.length && str.charAt(str.length - 1) === '%') { + return clampCssFloat(parseFloat(str) / 100); + } + return clampCssFloat(parseFloat(str)); +} - /** - * @type {qtek.Shader} - */ - // shader: null, +function cssHueToRgb(m1, m2, h) { + if (h < 0) { + h += 1; + } + else if (h > 1) { + h -= 1; + } - /** - * @type {boolean} - */ - depthTest: true, + if (h * 6 < 1) { + return m1 + (m2 - m1) * h * 6; + } + if (h * 2 < 1) { + return m2; + } + if (h * 3 < 2) { + return m1 + (m2 - m1) * (2/3 - h) * 6; + } + return m1; +} - /** - * @type {boolean} - */ - depthMask: true, +function lerpNumber(a, b, p) { + return a + (b - a) * p; +} - /** - * @type {boolean} - */ - transparent: false, - /** - * Blend func is a callback function when the material - * have custom blending - * The gl context will be the only argument passed in tho the - * blend function - * Detail of blend function in WebGL: - * http://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf - * - * Example : - * function(_gl) { - * _gl.blendEquation(_gl.FUNC_ADD); - * _gl.blendFunc(_gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA); - * } - */ - blend: null, +function setRgba(out, r, g, b, a) { + out[0] = r; out[1] = g; out[2] = b; out[3] = a; + return out; +} +function copyRgba(out, a) { + out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; + return out; +} - // shadowTransparentMap : null +var colorCache = new LRU(20); +var lastRemovedArr = null; - _enabledUniforms: null, -}, function () { - if (!this.name) { - this.name = 'MATERIAL_' + this.__GUID__; - } - if (this.shader) { - this.attachShader(this.shader); - } - if (!this.uniforms) { - this.uniforms = {}; +function putToCache(colorStr, rgbaArr) { + // Reuse removed array + if (lastRemovedArr) { + copyRgba(lastRemovedArr, rgbaArr); } -}, -/** @lends qtek.Material.prototype */ -{ + lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice())); +} - bind: function(renderer, shader, prevMaterial, prevShader) { - var _gl = renderer.gl; - // PENDING Same texture in different material take different slot? +/** + * @name clay.core.color.parse + * @param {string} colorStr + * @param {Array.} out + * @return {Array.} + */ +colorUtil.parse = function (colorStr, rgbaArr) { + if (!colorStr) { + return; + } + rgbaArr = rgbaArr || []; - // May use shader of other material if shader code are same - var shader = shader || this.shader; + var cached = colorCache.get(colorStr); + if (cached) { + return copyRgba(rgbaArr, cached); + } - // var sameShader = prevShader === shader; + // colorStr may be not string + colorStr = colorStr + ''; + // Remove all whitespace, not compliant, but should just be more accepting. + var str = colorStr.replace(/ /g, '').toLowerCase(); - var currentTextureSlot = shader.currentTextureSlot(); + // Color keywords (and transparent) lookup. + if (str in kCSSColorTable) { + copyRgba(rgbaArr, kCSSColorTable[str]); + putToCache(colorStr, rgbaArr); + return rgbaArr; + } - for (var u = 0; u < this._enabledUniforms.length; u++) { - var symbol = this._enabledUniforms[u]; - var uniformValue = this.uniforms[symbol].value; - if (uniformValue instanceof Texture) { - // Reset slot - uniformValue.__slot = -1; - } - else if (Array.isArray(uniformValue)) { - for (var i = 0; i < uniformValue.length; i++) { - if (uniformValue[i] instanceof Texture) { - uniformValue[i].__slot = -1; - } - } + // #abc and #abc123 syntax. + if (str.charAt(0) === '#') { + if (str.length === 4) { + var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. + if (!(iv >= 0 && iv <= 0xfff)) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; // Covers NaN. } + setRgba(rgbaArr, + ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8), + (iv & 0xf0) | ((iv & 0xf0) >> 4), + (iv & 0xf) | ((iv & 0xf) << 4), + 1 + ); + putToCache(colorStr, rgbaArr); + return rgbaArr; } - // Set uniforms - for (var u = 0; u < this._enabledUniforms.length; u++) { - var symbol = this._enabledUniforms[u]; - var uniform = this.uniforms[symbol]; - var uniformValue = uniform.value; - - // PENDING - // When binding two materials with the same shader - // Many uniforms will be be set twice even if they have the same value - // So add a evaluation to see if the uniform is really needed to be set - // if (prevMaterial && sameShader) { - // if (prevMaterial.uniforms[symbol].value === uniformValue) { - // continue; - // } - // } - - if (uniformValue === null) { - // FIXME Assume material with same shader have same order uniforms - // Or if different material use same textures, - // the slot will be different and still skipped because optimization - if (uniform.type === 't') { - var slot = shader.currentTextureSlot(); - var res = shader.setUniform(_gl, '1i', symbol, slot); - if (res) { // Texture is enabled - // Still occupy the slot to make sure same texture in different materials have same slot. - shader.takeCurrentTextureSlot(renderer, null); - } - } - continue; + else if (str.length === 7) { + var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. + if (!(iv >= 0 && iv <= 0xffffff)) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; // Covers NaN. } - else if (uniformValue instanceof Texture) { - if (uniformValue.__slot < 0) { - var slot = shader.currentTextureSlot(); - var res = shader.setUniform(_gl, '1i', symbol, slot); - if (!res) { // Texture uniform is not enabled - continue; - } - shader.takeCurrentTextureSlot(renderer, uniformValue); - uniformValue.__slot = slot; + setRgba(rgbaArr, + (iv & 0xff0000) >> 16, + (iv & 0xff00) >> 8, + iv & 0xff, + 1 + ); + putToCache(colorStr, rgbaArr); + return rgbaArr; + } + + return; + } + var op = str.indexOf('('), ep = str.indexOf(')'); + if (op !== -1 && ep + 1 === str.length) { + var fname = str.substr(0, op); + var params = str.substr(op + 1, ep - (op + 1)).split(','); + var alpha = 1; // To allow case fallthrough. + switch (fname) { + case 'rgba': + if (params.length !== 4) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; } - // Multiple uniform use same texture.. - else { - shader.setUniform(_gl, '1i', symbol, uniformValue.__slot); + alpha = parseCssFloat(params.pop()); // jshint ignore:line + // Fall through. + case 'rgb': + if (params.length !== 3) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; } - } - else if (Array.isArray(uniformValue)) { - if (uniformValue.length === 0) { - continue; + setRgba(rgbaArr, + parseCssInt(params[0]), + parseCssInt(params[1]), + parseCssInt(params[2]), + alpha + ); + putToCache(colorStr, rgbaArr); + return rgbaArr; + case 'hsla': + if (params.length !== 4) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; } - // Texture Array - var exampleValue = uniformValue[0]; + params[3] = parseCssFloat(params[3]); + hsla2rgba(params, rgbaArr); + putToCache(colorStr, rgbaArr); + return rgbaArr; + case 'hsl': + if (params.length !== 3) { + setRgba(rgbaArr, 0, 0, 0, 1); + return; + } + hsla2rgba(params, rgbaArr); + putToCache(colorStr, rgbaArr); + return rgbaArr; + default: + return; + } + } - if (exampleValue instanceof Texture) { - if (!shader.hasUniform(symbol)) { - continue; - } + setRgba(rgbaArr, 0, 0, 0, 1); + return; +}; - var arr = []; - for (var i = 0; i < uniformValue.length; i++) { - var texture = uniformValue[i]; +colorUtil.parseToFloat = function (colorStr, rgbaArr) { + rgbaArr = colorUtil.parse(colorStr, rgbaArr); + if (!rgbaArr) { + return; + } + rgbaArr[0] /= 255; + rgbaArr[1] /= 255; + rgbaArr[2] /= 255; + return rgbaArr; +}; - if (texture.__slot < 0) { - var slot = shader.currentTextureSlot(); - arr.push(slot); - shader.takeCurrentTextureSlot(renderer, texture); - texture.__slot = slot; - } - else { - arr.push(texture.__slot); - } - } +/** + * @name clay.core.color.hsla2rgba + * @param {Array.} hsla + * @param {Array.} rgba + * @return {Array.} rgba + */ +function hsla2rgba(hsla, rgba) { + var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360; // 0 .. 1 + // NOTE(deanm): According to the CSS spec s/l should only be + // percentages, but we don't bother and let float or percentage. + var s = parseCssFloat(hsla[1]); + var l = parseCssFloat(hsla[2]); + var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; + var m1 = l * 2 - m2; - shader.setUniform(_gl, '1iv', symbol, arr); - } - else { - shader.setUniform(_gl, uniform.type, symbol, uniformValue); - } - } - else{ - shader.setUniform(_gl, uniform.type, symbol, uniformValue); - } - } - // Texture slot maybe used out of material. - shader.resetTextureSlot(currentTextureSlot); - }, + rgba = rgba || []; + setRgba(rgba, + clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255), + clampCssByte(cssHueToRgb(m1, m2, h) * 255), + clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255), + 1 + ); - /** - * Set material uniform - * @example - * mat.setUniform('color', [1, 1, 1, 1]); - * @param {string} symbol - * @param {number|array|qtek.Texture|ArrayBufferView} value - */ - setUniform: function (symbol, value) { - if (value === undefined) { - console.warn('Uniform value "' + symbol + '" is undefined'); - } - var uniform = this.uniforms[symbol]; - if (uniform) { - uniform.value = value; - } - }, + if (hsla.length === 4) { + rgba[3] = hsla[3]; + } - /** - * @param {Object} obj - */ - setUniforms: function(obj) { - for (var key in obj) { - var val = obj[key]; - this.setUniform(key, val); - } - }, + return rgba; +} - // /** - // * Enable a uniform - // * It only have effect on the uniform exists in shader. - // * @param {string} symbol - // */ - // enableUniform: function (symbol) { - // if (this.uniforms[symbol] && !this.isUniformEnabled(symbol)) { - // this._enabledUniforms.push(symbol); - // } - // }, +/** + * @name clay.core.color.rgba2hsla + * @param {Array.} rgba + * @return {Array.} hsla + */ +function rgba2hsla(rgba) { + if (!rgba) { + return; + } - // /** - // * Disable a uniform - // * It will not affect the uniform state in the shader. Because the shader uniforms is parsed from shader code with naive regex. When using micro to disable some uniforms in the shader. It will still try to set these uniforms in each rendering pass. We can disable these uniforms manually if we need this bit performance improvement. Mostly we can simply ignore it. - // * @param {string} symbol - // */ - // disableUniform: function (symbol) { - // var idx = this._enabledUniforms.indexOf(symbol); - // if (idx >= 0) { - // this._enabledUniforms.splice(idx, 1); - // } - // }, + // RGB from 0 to 255 + var R = rgba[0] / 255; + var G = rgba[1] / 255; + var B = rgba[2] / 255; - /** - * @param {string} symbol - * @return {boolean} - */ - isUniformEnabled: function (symbol) { - return this._enabledUniforms.indexOf(symbol) >= 0; - }, + var vMin = Math.min(R, G, B); // Min. value of RGB + var vMax = Math.max(R, G, B); // Max. value of RGB + var delta = vMax - vMin; // Delta RGB value - /** - * Alias of setUniform and setUniforms - * @param {object|string} symbol - * @param {number|array|qtek.Texture|ArrayBufferView} [value] - */ - set: function (symbol, value) { - if (typeof(symbol) === 'object') { - for (var key in symbol) { - var val = symbol[key]; - this.set(key, val); - } + var L = (vMax + vMin) / 2; + var H; + var S; + // HSL results from 0 to 1 + if (delta === 0) { + H = 0; + S = 0; + } + else { + if (L < 0.5) { + S = delta / (vMax + vMin); } else { - var uniform = this.uniforms[symbol]; - if (uniform) { - if (typeof value === 'undefined') { - console.warn('Uniform value "' + symbol + '" is undefined'); - value = null; - } - uniform.value = value; - } + S = delta / (2 - vMax - vMin); } - }, - /** - * Get uniform value - * @param {string} symbol - * @return {number|array|qtek.Texture|ArrayBufferView} - */ - get: function (symbol) { - var uniform = this.uniforms[symbol]; - if (uniform) { - return uniform.value; + + var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta; + var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta; + var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta; + + if (R === vMax) { + H = deltaB - deltaG; } - }, - /** - * Attach a shader instance - * @param {qtek.Shader} shader - * @param {boolean} keepUniform If try to keep uniform value - */ - attachShader: function(shader, keepUniform) { - if (this.shader) { - this.shader.detached(); + else if (G === vMax) { + H = (1 / 3) + deltaR - deltaB; + } + else if (B === vMax) { + H = (2 / 3) + deltaG - deltaR; } - var originalUniforms = this.uniforms; + if (H < 0) { + H += 1; + } - // Ignore if uniform can use in shader. - this.uniforms = shader.createUniforms(); - this.shader = shader; + if (H > 1) { + H -= 1; + } + } - var uniforms = this.uniforms; - this._enabledUniforms = Object.keys(uniforms); - // Make sure uniforms are set in same order to avoid texture slot wrong - this._enabledUniforms.sort(); + var hsla = [H * 360, S, L]; - if (keepUniform) { - for (var symbol in originalUniforms) { - if (uniforms[symbol]) { - uniforms[symbol].value = originalUniforms[symbol].value; - } + if (rgba[3] != null) { + hsla.push(rgba[3]); + } + + return hsla; +} + +/** + * @name clay.core.color.lift + * @param {string} color + * @param {number} level + * @return {string} + */ +colorUtil.lift = function (color, level) { + var colorArr = colorUtil.parse(color); + if (colorArr) { + for (var i = 0; i < 3; i++) { + if (level < 0) { + colorArr[i] = colorArr[i] * (1 - level) | 0; + } + else { + colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0; } } + return colorUtil.stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb'); + } +}; - shader.attached(); - }, +/** + * @name clay.core.color.toHex + * @param {string} color + * @return {string} + */ +colorUtil.toHex = function (color) { + var colorArr = colorUtil.parse(color); + if (colorArr) { + return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1); + } +}; - /** - * Detach a shader instance - */ - detachShader: function() { - this.shader.detached(); - this.shader = null; - this.uniforms = {}; - }, +/** + * Map value to color. Faster than lerp methods because color is represented by rgba array. + * @name clay.core.color + * @param {number} normalizedValue A float between 0 and 1. + * @param {Array.>} colors List of rgba color array + * @param {Array.} [out] Mapped gba color array + * @return {Array.} will be null/undefined if input illegal. + */ +colorUtil.fastLerp = function (normalizedValue, colors, out) { + if (!(colors && colors.length) + || !(normalizedValue >= 0 && normalizedValue <= 1) + ) { + return; + } - /** - * Clone a new material and keep uniforms, shader will not be cloned - * @return {qtek.Material} - */ - clone: function () { - var material = new this.constructor({ - name: this.name, - shader: this.shader - }); - for (var symbol in this.uniforms) { - material.uniforms[symbol].value = this.uniforms[symbol].value; + out = out || []; + + var value = normalizedValue * (colors.length - 1); + var leftIndex = Math.floor(value); + var rightIndex = Math.ceil(value); + var leftColor = colors[leftIndex]; + var rightColor = colors[rightIndex]; + var dv = value - leftIndex; + out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)); + out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)); + out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)); + out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv)); + + return out; +}; + +colorUtil.fastMapToColor = colorUtil.fastLerp; + +/** + * @param {number} normalizedValue A float between 0 and 1. + * @param {Array.} colors Color list. + * @param {boolean=} fullOutput Default false. + * @return {(string|Object)} Result color. If fullOutput, + * return {color: ..., leftIndex: ..., rightIndex: ..., value: ...}, + */ +colorUtil.lerp = function (normalizedValue, colors, fullOutput) { + if (!(colors && colors.length) + || !(normalizedValue >= 0 && normalizedValue <= 1) + ) { + return; + } + + var value = normalizedValue * (colors.length - 1); + var leftIndex = Math.floor(value); + var rightIndex = Math.ceil(value); + var leftColor = colorUtil.parse(colors[leftIndex]); + var rightColor = colorUtil.parse(colors[rightIndex]); + var dv = value - leftIndex; + + var color = colorUtil.stringify( + [ + clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)), + clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)), + clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)), + clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv)) + ], + 'rgba' + ); + + return fullOutput + ? { + color: color, + leftIndex: leftIndex, + rightIndex: rightIndex, + value: value } - material.depthTest = this.depthTest; - material.depthMask = this.depthMask; - material.transparent = this.transparent; - material.blend = this.blend; + : color; +}; - return material; - }, +/** + * @deprecated + */ +colorUtil.mapToColor = colorUtil.lerp; - /** - * Dispose material, if material shader is not attached to any other materials - * Shader will also be disposed - * @param {WebGLRenderingContext} gl - * @param {boolean} [disposeTexture=false] If dispose the textures used in the material - */ - dispose: function(renderer, disposeTexture) { - if (disposeTexture) { - for (var name in this.uniforms) { - var val = this.uniforms[name].value; - if (!val) { - continue; - } - if (val instanceof Texture) { - val.dispose(renderer); - } - else if (Array.isArray(val)) { - for (var i = 0; i < val.length; i++) { - if (val[i] instanceof Texture) { - val[i].dispose(renderer); - } - } - } - } +/** + * @name clay.core.color + * @param {string} color + * @param {number=} h 0 ~ 360, ignore when null. + * @param {number=} s 0 ~ 1, ignore when null. + * @param {number=} l 0 ~ 1, ignore when null. + * @return {string} Color string in rgba format. + */ +colorUtil.modifyHSL = function (color, h, s, l) { + color = colorUtil.parse(color); + + if (color) { + color = rgba2hsla(color); + h != null && (color[0] = clampCssAngle(h)); + s != null && (color[1] = parseCssFloat(s)); + l != null && (color[2] = parseCssFloat(l)); + + return colorUtil.stringify(hsla2rgba(color), 'rgba'); + } +}; + +/** + * @param {string} color + * @param {number=} alpha 0 ~ 1 + * @return {string} Color string in rgba format. + */ +colorUtil.modifyAlpha = function (color, alpha) { + color = colorUtil.parse(color); + + if (color && alpha != null) { + color[3] = clampCssFloat(alpha); + return colorUtil.stringify(color, 'rgba'); + } +}; + +/** + * @param {Array.} arrColor like [12,33,44,0.4] + * @param {string} type 'rgba', 'hsva', ... + * @return {string} Result color. (If input illegal, return undefined). + */ +colorUtil.stringify = function (arrColor, type) { + if (!arrColor || !arrColor.length) { + return; + } + var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2]; + if (type === 'rgba' || type === 'hsva' || type === 'hsla') { + colorStr += ',' + arrColor[3]; + } + return type + '(' + colorStr + ')'; +}; + +var parseColor = colorUtil.parseToFloat; + +var programKeyCache = {}; + +function getDefineCode(defines) { + var defineKeys = Object.keys(defines); + defineKeys.sort(); + var defineStr = []; + // Custom Defines + for (var i = 0; i < defineKeys.length; i++) { + var key = defineKeys[i]; + var value = defines[key]; + if (value === null) { + defineStr.push(key); } - var shader = this.shader; - if (shader) { - this.detachShader(); - if (!shader.isAttachedToAny()) { - shader.dispose(renderer); - } + else{ + defineStr.push(key + ' ' + value.toString()); } } -}); + return defineStr.join('\n'); +} -var vec2 = glmatrix.vec2; +function getProgramKey(vertexDefines, fragmentDefines, enabledTextures) { + enabledTextures.sort(); + var defineStr = []; + for (var i = 0; i < enabledTextures.length; i++) { + var symbol = enabledTextures[i]; + defineStr.push(symbol); + } + var key = getDefineCode(vertexDefines) + '\n' + + getDefineCode(fragmentDefines) + '\n' + + defineStr.join('\n'); + + if (programKeyCache[key]) { + return programKeyCache[key]; + } + + var id = util.genGUID(); + programKeyCache[key] = id; + return id; +} /** - * @constructor - * @alias qtek.math.Vector2 - * @param {number} x - * @param {number} y + * Material defines the appearance of mesh surface, like `color`, `roughness`, `metalness`, etc. + * It contains a {@link clay.Shader} and corresponding uniforms. + * + * Here is a basic example to create a standard material +```js +var material = new clay.Material({ + shader: new clay.Shader( + clay.Shader.source('clay.vertex'), + clay.Shader.source('clay.fragment') + ) +}); +``` + * @constructor clay.Material + * @extends clay.core.Base */ -var Vector2 = function(x, y) { +var Material = Base.extend(function () { + return /** @lends clay.Material# */ { + /** + * @type {string} + */ + name: '', - x = x || 0; - y = y || 0; + /** + * @type {Object} + */ + // uniforms: null, - /** - * Storage of Vector2, read and write of x, y will change the values in _array - * All methods also operate on the _array instead of x, y components - * @name _array - * @type {Float32Array} - */ - this._array = vec2.fromValues(x, y); + /** + * @type {clay.Shader} + */ + // shader: null, - /** - * Dirty flag is used by the Node to determine - * if the matrix is updated to latest - * @name _dirty - * @type {boolean} - */ - this._dirty = true; -}; + /** + * @type {boolean} + */ + depthTest: true, -Vector2.prototype = { + /** + * @type {boolean} + */ + depthMask: true, - constructor: Vector2, + /** + * @type {boolean} + */ + transparent: false, + /** + * Blend func is a callback function when the material + * have custom blending + * The gl context will be the only argument passed in tho the + * blend function + * Detail of blend function in WebGL: + * http://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf + * + * Example : + * function(_gl) { + * _gl.blendEquation(_gl.FUNC_ADD); + * _gl.blendFunc(_gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA); + * } + */ + blend: null, - /** - * Add b to self - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} - */ - add: function(b) { - vec2.add(this._array, this._array, b._array); - this._dirty = true; - return this; - }, + /** + * If update texture status automatically. + */ + autoUpdateTextureStatus: true, - /** - * Set x and y components - * @param {number} x - * @param {number} y - * @return {qtek.math.Vector2} - */ - set: function(x, y) { - this._array[0] = x; - this._array[1] = y; - this._dirty = true; - return this; - }, + uniforms: {}, + vertexDefines: {}, + fragmentDefines: {}, + _textureStatus: {}, - /** - * Set x and y components from array - * @param {Float32Array|number[]} arr - * @return {qtek.math.Vector2} - */ - setArray: function(arr) { - this._array[0] = arr[0]; - this._array[1] = arr[1]; + // shadowTransparentMap : null - this._dirty = true; - return this; - }, + // PENDING enable the uniform that only used in shader. + _enabledUniforms: null, + }; +}, function () { + if (!this.name) { + this.name = 'MATERIAL_' + this.__uid__; + } + + if (this.shader) { + // Keep status, mainly preset uniforms, vertexDefines and fragmentDefines + this.attachShader(this.shader, true); + } +}, +/** @lends clay.Material.prototype */ +{ + precision: 'highp', /** - * Clone a new Vector2 - * @return {qtek.math.Vector2} + * Set material uniform + * @example + * mat.setUniform('color', [1, 1, 1, 1]); + * @param {string} symbol + * @param {number|array|clay.Texture|ArrayBufferView} value */ - clone: function() { - return new Vector2(this.x, this.y); + setUniform: function (symbol, value) { + if (value === undefined) { + console.warn('Uniform value "' + symbol + '" is undefined'); + } + var uniform = this.uniforms[symbol]; + if (uniform) { + + if (typeof value === 'string') { + // Try to parse as a color. Invalid color string will return null. + value = parseColor(value) || value; + } + + uniform.value = value; + + if (this.autoUpdateTextureStatus && uniform.type === 't') { + if (value) { + this.enableTexture(symbol); + } + else { + this.disableTexture(symbol); + } + } + } }, /** - * Copy x, y from b - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @param {Object} obj */ - copy: function(b) { - vec2.copy(this._array, b._array); - this._dirty = true; - return this; + setUniforms: function(obj) { + for (var key in obj) { + var val = obj[key]; + this.setUniform(key, val); + } }, /** - * Cross product of self and b, written to a Vector3 out - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @param {string} symbol + * @return {boolean} */ - cross: function(out, b) { - vec2.cross(out._array, this._array, b._array); - out._dirty = true; - return this; + isUniformEnabled: function (symbol) { + return this._enabledUniforms.indexOf(symbol) >= 0; }, - /** - * Alias for distance - * @param {qtek.math.Vector2} b - * @return {number} - */ - dist: function(b) { - return vec2.dist(this._array, b._array); + getEnabledUniforms: function () { + return this._enabledUniforms; + }, + getTextureUniforms: function () { + return this._textureUniforms; }, /** - * Distance between self and b - * @param {qtek.math.Vector2} b - * @return {number} + * Alias of setUniform and setUniforms + * @param {object|string} symbol + * @param {number|array|clay.Texture|ArrayBufferView} [value] */ - distance: function(b) { - return vec2.distance(this._array, b._array); + set: function (symbol, value) { + if (typeof(symbol) === 'object') { + for (var key in symbol) { + var val = symbol[key]; + this.setUniform(key, val); + } + } + else { + this.setUniform(symbol, value); + } }, - /** - * Alias for divide - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * Get uniform value + * @param {string} symbol + * @return {number|array|clay.Texture|ArrayBufferView} */ - div: function(b) { - vec2.div(this._array, this._array, b._array); - this._dirty = true; - return this; + get: function (symbol) { + var uniform = this.uniforms[symbol]; + if (uniform) { + return uniform.value; + } }, - /** - * Divide self by b - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * Attach a shader instance + * @param {clay.Shader} shader + * @param {boolean} keepStatus If try to keep uniform and texture */ - divide: function(b) { - vec2.divide(this._array, this._array, b._array); - this._dirty = true; - return this; - }, + attachShader: function(shader, keepStatus) { + var originalUniforms = this.uniforms; - /** - * Dot product of self and b - * @param {qtek.math.Vector2} b - * @return {number} - */ - dot: function(b) { - return vec2.dot(this._array, b._array); - }, + // Ignore if uniform can use in shader. + this.uniforms = shader.createUniforms(); + this.shader = shader; - /** - * Alias of length - * @return {number} - */ - len: function() { - return vec2.len(this._array); - }, + var uniforms = this.uniforms; + this._enabledUniforms = Object.keys(uniforms); + // Make sure uniforms are set in same order to avoid texture slot wrong + this._enabledUniforms.sort(); + this._textureUniforms = this._enabledUniforms.filter(function (uniformName) { + var type = this.uniforms[uniformName].type; + return type === 't' || type === 'tv'; + }, this); - /** - * Calculate the length - * @return {number} - */ - length: function() { - return vec2.length(this._array); - }, + var originalVertexDefines = this.vertexDefines; + var originalFragmentDefines = this.fragmentDefines; - /** - * Linear interpolation between a and b - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b - * @param {number} t - * @return {qtek.math.Vector2} - */ - lerp: function(a, b, t) { - vec2.lerp(this._array, a._array, b._array, t); - this._dirty = true; - return this; + this.vertexDefines = util.clone(shader.vertexDefines); + this.fragmentDefines = util.clone(shader.fragmentDefines); + + if (keepStatus) { + for (var symbol in originalUniforms) { + if (uniforms[symbol]) { + uniforms[symbol].value = originalUniforms[symbol].value; + } + } + + util.defaults(this.vertexDefines, originalVertexDefines); + util.defaults(this.fragmentDefines, originalFragmentDefines); + } + + var textureStatus = {}; + for (var key in shader.textures) { + textureStatus[key] = { + shaderType: shader.textures[key].shaderType, + type: shader.textures[key].type, + enabled: (keepStatus && this._textureStatus[key]) ? this._textureStatus[key].enabled : false + }; + } + + this._textureStatus = textureStatus; + + this._programKey = ''; }, /** - * Minimum of self and b - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * Clone a new material and keep uniforms, shader will not be cloned + * @return {clay.Material} */ - min: function(b) { - vec2.min(this._array, this._array, b._array); - this._dirty = true; - return this; + clone: function () { + var material = new this.constructor({ + name: this.name, + shader: this.shader + }); + for (var symbol in this.uniforms) { + material.uniforms[symbol].value = this.uniforms[symbol].value; + } + material.depthTest = this.depthTest; + material.depthMask = this.depthMask; + material.transparent = this.transparent; + material.blend = this.blend; + + material.vertexDefines = util.clone(this.vertexDefines); + material.fragmentDefines = util.clone(this.fragmentDefines); + material.enableTexture(this.getEnabledTextures()); + material.precision = this.precision; + + return material; }, /** - * Maximum of self and b - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * Add a #define macro in shader code + * @param {string} shaderType Can be vertex, fragment or both + * @param {string} symbol + * @param {number} [val] */ - max: function(b) { - vec2.max(this._array, this._array, b._array); - this._dirty = true; - return this; + define: function (shaderType, symbol, val) { + var vertexDefines = this.vertexDefines; + var fragmentDefines = this.fragmentDefines; + if (shaderType !== 'vertex' && shaderType !== 'fragment' && shaderType !== 'both' + && arguments.length < 3 + ) { + // shaderType default to be 'both' + val = symbol; + symbol = shaderType; + shaderType = 'both'; + } + val = val != null ? val : null; + if (shaderType === 'vertex' || shaderType === 'both') { + if (vertexDefines[symbol] !== val) { + vertexDefines[symbol] = val; + // Mark as dirty + this._programKey = ''; + } + } + if (shaderType === 'fragment' || shaderType === 'both') { + if (fragmentDefines[symbol] !== val) { + fragmentDefines[symbol] = val; + if (shaderType !== 'both') { + this._programKey = ''; + } + } + } }, /** - * Alias for multiply - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * Remove a #define macro in shader code + * @param {string} shaderType Can be vertex, fragment or both + * @param {string} symbol */ - mul: function(b) { - vec2.mul(this._array, this._array, b._array); - this._dirty = true; - return this; + undefine: function (shaderType, symbol) { + if (shaderType !== 'vertex' && shaderType !== 'fragment' && shaderType !== 'both' + && arguments.length < 2 + ) { + // shaderType default to be 'both' + symbol = shaderType; + shaderType = 'both'; + } + if (shaderType === 'vertex' || shaderType === 'both') { + if (this.isDefined('vertex', symbol)) { + delete this.vertexDefines[symbol]; + // Mark as dirty + this._programKey = ''; + } + } + if (shaderType === 'fragment' || shaderType === 'both') { + if (this.isDefined('fragment', symbol)) { + delete this.fragmentDefines[symbol]; + if (shaderType !== 'both') { + this._programKey = ''; + } + } + } }, /** - * Mutiply self and b - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * If macro is defined in shader. + * @param {string} shaderType Can be vertex, fragment or both + * @param {string} symbol */ - multiply: function(b) { - vec2.multiply(this._array, this._array, b._array); - this._dirty = true; - return this; + isDefined: function (shaderType, symbol) { + // PENDING hasOwnProperty ? + switch (shaderType) { + case 'vertex': + return this.vertexDefines[symbol] !== undefined; + case 'fragment': + return this.fragmentDefines[symbol] !== undefined; + } }, - /** - * Negate self - * @return {qtek.math.Vector2} + * Get macro value defined in shader. + * @param {string} shaderType Can be vertex, fragment or both + * @param {string} symbol */ - negate: function() { - vec2.negate(this._array, this._array); - this._dirty = true; - return this; + getDefine: function (shaderType, symbol) { + switch(shaderType) { + case 'vertex': + return this.vertexDefines[symbol]; + case 'fragment': + return this.fragmentDefines[symbol]; + } }, - /** - * Normalize self - * @return {qtek.math.Vector2} + * Enable a texture, actually it will add a #define macro in the shader code + * For example, if texture symbol is diffuseMap, it will add a line `#define DIFFUSEMAP_ENABLED` in the shader code + * @param {string} symbol */ - normalize: function() { - vec2.normalize(this._array, this._array); - this._dirty = true; - return this; - }, + enableTexture: function (symbol) { + if (Array.isArray(symbol)) { + for (var i = 0; i < symbol.length; i++) { + this.enableTexture(symbol[i]); + } + return; + } + var status = this._textureStatus[symbol]; + if (status) { + var isEnabled = status.enabled; + if (!isEnabled) { + status.enabled = true; + this._programKey = ''; + } + } + }, /** - * Generate random x, y components with a given scale - * @param {number} scale - * @return {qtek.math.Vector2} + * Enable all textures used in the shader */ - random: function(scale) { - vec2.random(this._array, scale); - this._dirty = true; - return this; - }, + enableTexturesAll: function () { + var textureStatus = this._textureStatus; + for (var symbol in textureStatus) { + textureStatus[symbol].enabled = true; + } + this._programKey = ''; + }, /** - * Scale self - * @param {number} scale - * @return {qtek.math.Vector2} + * Disable a texture, it remove a #define macro in the shader + * @param {string} symbol */ - scale: function(s) { - vec2.scale(this._array, this._array, s); - this._dirty = true; - return this; - }, + disableTexture: function (symbol) { + if (Array.isArray(symbol)) { + for (var i = 0; i < symbol.length; i++) { + this.disableTexture(symbol[i]); + } + return; + } + var status = this._textureStatus[symbol]; + if (status) { + var isDisabled = ! status.enabled; + if (!isDisabled) { + status.enabled = false; + this._programKey = ''; + } + } + }, /** - * Scale b and add to self - * @param {qtek.math.Vector2} b - * @param {number} scale - * @return {qtek.math.Vector2} + * Disable all textures used in the shader */ - scaleAndAdd: function(b, s) { - vec2.scaleAndAdd(this._array, this._array, b._array, s); - this._dirty = true; - return this; - }, + disableTexturesAll: function () { + var textureStatus = this._textureStatus; + for (var symbol in textureStatus) { + textureStatus[symbol].enabled = false; + } + this._programKey = ''; + }, /** - * Alias for squaredDistance - * @param {qtek.math.Vector2} b - * @return {number} + * If texture of given type is enabled. + * @param {string} symbol + * @return {boolean} */ - sqrDist: function(b) { - return vec2.sqrDist(this._array, b._array); + isTextureEnabled: function (symbol) { + var textureStatus = this._textureStatus; + return !!textureStatus[symbol] + && textureStatus[symbol].enabled; }, /** - * Squared distance between self and b - * @param {qtek.math.Vector2} b - * @return {number} + * Get all enabled textures + * @return {string[]} */ - squaredDistance: function(b) { - return vec2.squaredDistance(this._array, b._array); + getEnabledTextures: function () { + var enabledTextures = []; + var textureStatus = this._textureStatus; + for (var symbol in textureStatus) { + if (textureStatus[symbol].enabled) { + enabledTextures.push(symbol); + } + } + return enabledTextures; }, /** - * Alias for squaredLength - * @return {number} + * Mark defines are updated. */ - sqrLen: function() { - return vec2.sqrLen(this._array); + dirtyDefines: function () { + this._programKey = ''; + }, + + getProgramKey: function () { + if (!this._programKey) { + this._programKey = getProgramKey( + this.vertexDefines, this.fragmentDefines, this.getEnabledTextures() + ); + } + return this._programKey; + } +}); + +var vec2 = glmatrix.vec2; + +/** + * @constructor + * @alias clay.Vector2 + * @param {number} x + * @param {number} y + */ +var Vector2 = function(x, y) { + + x = x || 0; + y = y || 0; + + /** + * Storage of Vector2, read and write of x, y will change the values in array + * All methods also operate on the array instead of x, y components + * @name array + * @type {Float32Array} + * @memberOf clay.Vector2# + */ + this.array = vec2.fromValues(x, y); + + /** + * Dirty flag is used by the Node to determine + * if the matrix is updated to latest + * @name _dirty + * @type {boolean} + * @memberOf clay.Vector2# + */ + this._dirty = true; +}; + +Vector2.prototype = { + + constructor: Vector2, + + /** + * Add b to self + * @param {clay.Vector2} b + * @return {clay.Vector2} + */ + add: function(b) { + vec2.add(this.array, this.array, b.array); + this._dirty = true; + return this; + }, + + /** + * Set x and y components + * @param {number} x + * @param {number} y + * @return {clay.Vector2} + */ + set: function(x, y) { + this.array[0] = x; + this.array[1] = y; + this._dirty = true; + return this; + }, + + /** + * Set x and y components from array + * @param {Float32Array|number[]} arr + * @return {clay.Vector2} + */ + setArray: function(arr) { + this.array[0] = arr[0]; + this.array[1] = arr[1]; + + this._dirty = true; + return this; + }, + + /** + * Clone a new Vector2 + * @return {clay.Vector2} + */ + clone: function() { + return new Vector2(this.x, this.y); + }, + + /** + * Copy x, y from b + * @param {clay.Vector2} b + * @return {clay.Vector2} + */ + copy: function(b) { + vec2.copy(this.array, b.array); + this._dirty = true; + return this; + }, + + /** + * Cross product of self and b, written to a Vector3 out + * @param {clay.Vector3} out + * @param {clay.Vector2} b + * @return {clay.Vector2} + */ + cross: function(out, b) { + vec2.cross(out.array, this.array, b.array); + out._dirty = true; + return this; + }, + + /** + * Alias for distance + * @param {clay.Vector2} b + * @return {number} + */ + dist: function(b) { + return vec2.dist(this.array, b.array); + }, + + /** + * Distance between self and b + * @param {clay.Vector2} b + * @return {number} + */ + distance: function(b) { + return vec2.distance(this.array, b.array); + }, + + /** + * Alias for divide + * @param {clay.Vector2} b + * @return {clay.Vector2} + */ + div: function(b) { + vec2.div(this.array, this.array, b.array); + this._dirty = true; + return this; + }, + + /** + * Divide self by b + * @param {clay.Vector2} b + * @return {clay.Vector2} + */ + divide: function(b) { + vec2.divide(this.array, this.array, b.array); + this._dirty = true; + return this; + }, + + /** + * Dot product of self and b + * @param {clay.Vector2} b + * @return {number} + */ + dot: function(b) { + return vec2.dot(this.array, b.array); + }, + + /** + * Alias of length + * @return {number} + */ + len: function() { + return vec2.len(this.array); + }, + + /** + * Calculate the length + * @return {number} + */ + length: function() { + return vec2.length(this.array); + }, + + /** + * Linear interpolation between a and b + * @param {clay.Vector2} a + * @param {clay.Vector2} b + * @param {number} t + * @return {clay.Vector2} + */ + lerp: function(a, b, t) { + vec2.lerp(this.array, a.array, b.array, t); + this._dirty = true; + return this; + }, + + /** + * Minimum of self and b + * @param {clay.Vector2} b + * @return {clay.Vector2} + */ + min: function(b) { + vec2.min(this.array, this.array, b.array); + this._dirty = true; + return this; + }, + + /** + * Maximum of self and b + * @param {clay.Vector2} b + * @return {clay.Vector2} + */ + max: function(b) { + vec2.max(this.array, this.array, b.array); + this._dirty = true; + return this; + }, + + /** + * Alias for multiply + * @param {clay.Vector2} b + * @return {clay.Vector2} + */ + mul: function(b) { + vec2.mul(this.array, this.array, b.array); + this._dirty = true; + return this; + }, + + /** + * Mutiply self and b + * @param {clay.Vector2} b + * @return {clay.Vector2} + */ + multiply: function(b) { + vec2.multiply(this.array, this.array, b.array); + this._dirty = true; + return this; + }, + + /** + * Negate self + * @return {clay.Vector2} + */ + negate: function() { + vec2.negate(this.array, this.array); + this._dirty = true; + return this; + }, + + /** + * Normalize self + * @return {clay.Vector2} + */ + normalize: function() { + vec2.normalize(this.array, this.array); + this._dirty = true; + return this; + }, + + /** + * Generate random x, y components with a given scale + * @param {number} scale + * @return {clay.Vector2} + */ + random: function(scale) { + vec2.random(this.array, scale); + this._dirty = true; + return this; + }, + + /** + * Scale self + * @param {number} scale + * @return {clay.Vector2} + */ + scale: function(s) { + vec2.scale(this.array, this.array, s); + this._dirty = true; + return this; + }, + + /** + * Scale b and add to self + * @param {clay.Vector2} b + * @param {number} scale + * @return {clay.Vector2} + */ + scaleAndAdd: function(b, s) { + vec2.scaleAndAdd(this.array, this.array, b.array, s); + this._dirty = true; + return this; + }, + + /** + * Alias for squaredDistance + * @param {clay.Vector2} b + * @return {number} + */ + sqrDist: function(b) { + return vec2.sqrDist(this.array, b.array); + }, + + /** + * Squared distance between self and b + * @param {clay.Vector2} b + * @return {number} + */ + squaredDistance: function(b) { + return vec2.squaredDistance(this.array, b.array); + }, + + /** + * Alias for squaredLength + * @return {number} + */ + sqrLen: function() { + return vec2.sqrLen(this.array); }, /** @@ -10005,81 +9594,81 @@ Vector2.prototype = { * @return {number} */ squaredLength: function() { - return vec2.squaredLength(this._array); + return vec2.squaredLength(this.array); }, /** * Alias for subtract - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @param {clay.Vector2} b + * @return {clay.Vector2} */ sub: function(b) { - vec2.sub(this._array, this._array, b._array); + vec2.sub(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Subtract b from self - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @param {clay.Vector2} b + * @return {clay.Vector2} */ subtract: function(b) { - vec2.subtract(this._array, this._array, b._array); + vec2.subtract(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Transform self with a Matrix2 m - * @param {qtek.math.Matrix2} m - * @return {qtek.math.Vector2} + * @param {clay.Matrix2} m + * @return {clay.Vector2} */ transformMat2: function(m) { - vec2.transformMat2(this._array, this._array, m._array); + vec2.transformMat2(this.array, this.array, m.array); this._dirty = true; return this; }, /** * Transform self with a Matrix2d m - * @param {qtek.math.Matrix2d} m - * @return {qtek.math.Vector2} + * @param {clay.Matrix2d} m + * @return {clay.Vector2} */ transformMat2d: function(m) { - vec2.transformMat2d(this._array, this._array, m._array); + vec2.transformMat2d(this.array, this.array, m.array); this._dirty = true; return this; }, /** * Transform self with a Matrix3 m - * @param {qtek.math.Matrix3} m - * @return {qtek.math.Vector2} + * @param {clay.Matrix3} m + * @return {clay.Vector2} */ transformMat3: function(m) { - vec2.transformMat3(this._array, this._array, m._array); + vec2.transformMat3(this.array, this.array, m.array); this._dirty = true; return this; }, /** * Transform self with a Matrix4 m - * @param {qtek.math.Matrix4} m - * @return {qtek.math.Vector2} + * @param {clay.Matrix4} m + * @return {clay.Vector2} */ transformMat4: function(m) { - vec2.transformMat4(this._array, this._array, m._array); + vec2.transformMat4(this.array, this.array, m.array); this._dirty = true; return this; }, toString: function() { - return '[' + Array.prototype.join.call(this._array, ',') + ']'; + return '[' + Array.prototype.join.call(this.array, ',') + ']'; }, toArray: function () { - return Array.prototype.slice.call(this._array); + return Array.prototype.slice.call(this.array); } }; @@ -10090,15 +9679,15 @@ if (Object.defineProperty) { /** * @name x * @type {number} - * @memberOf qtek.math.Vector2 + * @memberOf clay.Vector2 * @instance */ Object.defineProperty(proto$2, 'x', { get: function () { - return this._array[0]; + return this.array[0]; }, set: function (value) { - this._array[0] = value; + this.array[0] = value; this._dirty = true; } }); @@ -10106,15 +9695,15 @@ if (Object.defineProperty) { /** * @name y * @type {number} - * @memberOf qtek.math.Vector2 + * @memberOf clay.Vector2 * @instance */ Object.defineProperty(proto$2, 'y', { get: function () { - return this._array[1]; + return this.array[1]; }, set: function (value) { - this._array[1] = value; + this.array[1] = value; this._dirty = true; } }); @@ -10123,548 +9712,1724 @@ if (Object.defineProperty) { // Supply methods that are not in place /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @param {clay.Vector2} b + * @return {clay.Vector2} */ Vector2.add = function(out, a, b) { - vec2.add(out._array, a._array, b._array); + vec2.add(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector2} out + * @param {clay.Vector2} out * @param {number} x * @param {number} y - * @return {qtek.math.Vector2} + * @return {clay.Vector2} */ Vector2.set = function(out, x, y) { - vec2.set(out._array, x, y); + vec2.set(out.array, x, y); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @param {clay.Vector2} out + * @param {clay.Vector2} b + * @return {clay.Vector2} */ Vector2.copy = function(out, b) { - vec2.copy(out._array, b._array); + vec2.copy(out.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector3} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @param {clay.Vector3} out + * @param {clay.Vector2} a + * @param {clay.Vector2} b + * @return {clay.Vector2} */ Vector2.cross = function(out, a, b) { - vec2.cross(out._array, a._array, b._array); + vec2.cross(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b + * @param {clay.Vector2} a + * @param {clay.Vector2} b * @return {number} */ Vector2.dist = function(a, b) { - return vec2.distance(a._array, b._array); + return vec2.distance(a.array, b.array); }; /** - * @method - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b + * @function + * @param {clay.Vector2} a + * @param {clay.Vector2} b * @return {number} */ Vector2.distance = Vector2.dist; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @param {clay.Vector2} b + * @return {clay.Vector2} */ Vector2.div = function(out, a, b) { - vec2.divide(out._array, a._array, b._array); + vec2.divide(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @method - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @function + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @param {clay.Vector2} b + * @return {clay.Vector2} */ Vector2.divide = Vector2.div; /** - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b + * @param {clay.Vector2} a + * @param {clay.Vector2} b * @return {number} */ Vector2.dot = function(a, b) { - return vec2.dot(a._array, b._array); + return vec2.dot(a.array, b.array); }; /** - * @param {qtek.math.Vector2} a + * @param {clay.Vector2} a * @return {number} */ Vector2.len = function(b) { - return vec2.length(b._array); + return vec2.length(b.array); }; // Vector2.length = Vector2.len; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @param {clay.Vector2} b * @param {number} t - * @return {qtek.math.Vector2} + * @return {clay.Vector2} */ Vector2.lerp = function(out, a, b, t) { - vec2.lerp(out._array, a._array, b._array, t); + vec2.lerp(out.array, a.array, b.array, t); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @param {clay.Vector2} b + * @return {clay.Vector2} */ Vector2.min = function(out, a, b) { - vec2.min(out._array, a._array, b._array); + vec2.min(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @param {clay.Vector2} b + * @return {clay.Vector2} */ Vector2.max = function(out, a, b) { - vec2.max(out._array, a._array, b._array); + vec2.max(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @param {clay.Vector2} b + * @return {clay.Vector2} */ Vector2.mul = function(out, a, b) { - vec2.multiply(out._array, a._array, b._array); + vec2.multiply(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @method - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @function + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @param {clay.Vector2} b + * @return {clay.Vector2} */ Vector2.multiply = Vector2.mul; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @return {qtek.math.Vector2} + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @return {clay.Vector2} */ Vector2.negate = function(out, a) { - vec2.negate(out._array, a._array); + vec2.negate(out.array, a.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @return {qtek.math.Vector2} + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @return {clay.Vector2} */ Vector2.normalize = function(out, a) { - vec2.normalize(out._array, a._array); + vec2.normalize(out.array, a.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector2} out + * @param {clay.Vector2} out * @param {number} scale - * @return {qtek.math.Vector2} + * @return {clay.Vector2} */ Vector2.random = function(out, scale) { - vec2.random(out._array, scale); + vec2.random(out.array, scale); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a + * @param {clay.Vector2} out + * @param {clay.Vector2} a * @param {number} scale - * @return {qtek.math.Vector2} + * @return {clay.Vector2} */ Vector2.scale = function(out, a, scale) { - vec2.scale(out._array, a._array, scale); + vec2.scale(out.array, a.array, scale); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @param {clay.Vector2} b * @param {number} scale - * @return {qtek.math.Vector2} + * @return {clay.Vector2} */ Vector2.scaleAndAdd = function(out, a, b, scale) { - vec2.scaleAndAdd(out._array, a._array, b._array, scale); + vec2.scaleAndAdd(out.array, a.array, b.array, scale); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b + * @param {clay.Vector2} a + * @param {clay.Vector2} b * @return {number} */ Vector2.sqrDist = function(a, b) { - return vec2.sqrDist(a._array, b._array); + return vec2.sqrDist(a.array, b.array); }; /** - * @method - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b + * @function + * @param {clay.Vector2} a + * @param {clay.Vector2} b * @return {number} */ Vector2.squaredDistance = Vector2.sqrDist; /** - * @param {qtek.math.Vector2} a + * @param {clay.Vector2} a * @return {number} */ Vector2.sqrLen = function(a) { - return vec2.sqrLen(a._array); + return vec2.sqrLen(a.array); }; /** - * @method - * @param {qtek.math.Vector2} a + * @function + * @param {clay.Vector2} a * @return {number} */ Vector2.squaredLength = Vector2.sqrLen; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @param {clay.Vector2} b + * @return {clay.Vector2} */ Vector2.sub = function(out, a, b) { - vec2.subtract(out._array, a._array, b._array); + vec2.subtract(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @method - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Vector2} b - * @return {qtek.math.Vector2} + * @function + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @param {clay.Vector2} b + * @return {clay.Vector2} */ Vector2.subtract = Vector2.sub; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Matrix2} m - * @return {qtek.math.Vector2} + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @param {clay.Matrix2} m + * @return {clay.Vector2} */ Vector2.transformMat2 = function(out, a, m) { - vec2.transformMat2(out._array, a._array, m._array); + vec2.transformMat2(out.array, a.array, m.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Matrix2d} m - * @return {qtek.math.Vector2} + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @param {clay.Matrix2d} m + * @return {clay.Vector2} */ Vector2.transformMat2d = function(out, a, m) { - vec2.transformMat2d(out._array, a._array, m._array); + vec2.transformMat2d(out.array, a.array, m.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a + * @param {clay.Vector2} out + * @param {clay.Vector2} a * @param {Matrix3} m - * @return {qtek.math.Vector2} + * @return {clay.Vector2} */ Vector2.transformMat3 = function(out, a, m) { - vec2.transformMat3(out._array, a._array, m._array); + vec2.transformMat3(out.array, a.array, m.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector2} out - * @param {qtek.math.Vector2} a - * @param {qtek.math.Matrix4} m - * @return {qtek.math.Vector2} + * @param {clay.Vector2} out + * @param {clay.Vector2} a + * @param {clay.Matrix4} m + * @return {clay.Vector2} */ Vector2.transformMat4 = function(out, a, m) { - vec2.transformMat4(out._array, a._array, m._array); + vec2.transformMat4(out.array, a.array, m.array); out._dirty = true; return out; }; -var calcAmbientSHLightEssl = "vec3 calcAmbientSHLight(int idx, vec3 N) {\n int offset = 9 * idx;\n return ambientSHLightCoefficients[0]\n + ambientSHLightCoefficients[1] * N.x\n + ambientSHLightCoefficients[2] * N.y\n + ambientSHLightCoefficients[3] * N.z\n + ambientSHLightCoefficients[4] * N.x * N.z\n + ambientSHLightCoefficients[5] * N.z * N.y\n + ambientSHLightCoefficients[6] * N.y * N.x\n + ambientSHLightCoefficients[7] * (3.0 * N.z * N.z - 1.0)\n + ambientSHLightCoefficients[8] * (N.x * N.x - N.y * N.y);\n}"; +var SHADER_STATE_TO_ENABLE = 1; +var SHADER_STATE_KEEP_ENABLE = 2; +var SHADER_STATE_PENDING = 3; -var uniformVec3Prefix = 'uniform vec3 '; -var uniformFloatPrefix = 'uniform float '; -var exportHeaderPrefix = '@export qtek.header.'; -var exportEnd = '@end'; -var unconfigurable = ':unconfigurable;'; -var lightEssl = [ - exportHeaderPrefix + 'directional_light', - uniformVec3Prefix + 'directionalLightDirection[DIRECTIONAL_LIGHT_COUNT]' + unconfigurable, - uniformVec3Prefix + 'directionalLightColor[DIRECTIONAL_LIGHT_COUNT]' + unconfigurable, - exportEnd, - - exportHeaderPrefix + 'ambient_light', - uniformVec3Prefix + 'ambientLightColor[AMBIENT_LIGHT_COUNT]' + unconfigurable, - exportEnd, - - exportHeaderPrefix + 'ambient_sh_light', - uniformVec3Prefix + 'ambientSHLightColor[AMBIENT_SH_LIGHT_COUNT]' + unconfigurable, - uniformVec3Prefix + 'ambientSHLightCoefficients[AMBIENT_SH_LIGHT_COUNT * 9]' + unconfigurable, - calcAmbientSHLightEssl, - exportEnd, - - exportHeaderPrefix + 'ambient_cubemap_light', - uniformVec3Prefix + 'ambientCubemapLightColor[AMBIENT_CUBEMAP_LIGHT_COUNT]' + unconfigurable, - 'uniform samplerCube ambientCubemapLightCubemap[AMBIENT_CUBEMAP_LIGHT_COUNT]' + unconfigurable, - 'uniform sampler2D ambientCubemapLightBRDFLookup[AMBIENT_CUBEMAP_LIGHT_COUNT]' + unconfigurable, - exportEnd, - - exportHeaderPrefix + 'point_light', - uniformVec3Prefix + 'pointLightPosition[POINT_LIGHT_COUNT]' + unconfigurable, - uniformFloatPrefix + 'pointLightRange[POINT_LIGHT_COUNT]' + unconfigurable, - uniformVec3Prefix + 'pointLightColor[POINT_LIGHT_COUNT]' + unconfigurable, - exportEnd, - - exportHeaderPrefix + 'spot_light', - uniformVec3Prefix + 'spotLightPosition[SPOT_LIGHT_COUNT]' + unconfigurable, - uniformVec3Prefix + 'spotLightDirection[SPOT_LIGHT_COUNT]' + unconfigurable, - uniformFloatPrefix + 'spotLightRange[SPOT_LIGHT_COUNT]' + unconfigurable, - uniformFloatPrefix + 'spotLightUmbraAngleCosine[SPOT_LIGHT_COUNT]' + unconfigurable, - uniformFloatPrefix + 'spotLightPenumbraAngleCosine[SPOT_LIGHT_COUNT]' + unconfigurable, - uniformFloatPrefix + 'spotLightFalloffFactor[SPOT_LIGHT_COUNT]' + unconfigurable, - uniformVec3Prefix + 'spotLightColor[SPOT_LIGHT_COUNT]' + unconfigurable, - exportEnd -].join('\n'); - -var prezEssl = "@export qtek.prez.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\n@import qtek.chunk.skinning_header\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import qtek.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n}\n@end\n@export qtek.prez.fragment\nvoid main()\n{\n gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n}\n@end"; - -// TODO Resources like shader, texture, geometry reference management -// Trace and find out which shader, texture, geometry can be destroyed -// -// TODO prez skinning -// Light header -Shader['import'](lightEssl); -Shader['import'](prezEssl); - -var mat4 = glmatrix.mat4; -var vec3 = glmatrix.vec3; - -var mat4Create = mat4.create; - -var errorShader = {}; - -/** - * @constructor qtek.Renderer - */ -var Renderer = Base.extend(function () { - return /** @lends qtek.Renderer# */ { - - /** - * @type {HTMLCanvasElement} - * @readonly - */ - canvas: null, - - /** - * Canvas width, set by resize method - * @type {number} - * @private - */ - _width: 100, - - /** - * Canvas width, set by resize method - * @type {number} - * @private - */ - _height: 100, +// Enable attribute operation is global to all programs +// Here saved the list of all enabled attribute index +// http://www.mjbshaw.com/2013/03/webgl-fixing-invalidoperation.html +var enabledAttributeList = {}; - /** - * Device pixel ratio, set by setDevicePixelRatio method - * Specially for high defination display - * @see http://www.khronos.org/webgl/wiki/HandlingHighDPI - * @type {number} - * @private - */ - devicePixelRatio: window.devicePixelRatio || 1.0, +// some util functions +function addLineNumbers(string) { + var chunks = string.split('\n'); + for (var i = 0, il = chunks.length; i < il; i ++) { + // Chrome reports shader errors on lines + // starting counting from 1 + chunks[i] = (i + 1) + ': ' + chunks[i]; + } + return chunks.join('\n'); +} - /** - * Clear color - * @type {number[]} - */ - clearColor: [0.0, 0.0, 0.0, 0.0], +// Return true or error msg if error happened +function checkShaderErrorMsg(_gl, shader, shaderString) { + if (!_gl.getShaderParameter(shader, _gl.COMPILE_STATUS)) { + return [_gl.getShaderInfoLog(shader), addLineNumbers(shaderString)].join('\n'); + } +} - /** - * Default: - * _gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT | _gl.STENCIL_BUFFER_BIT - * @type {number} - */ - clearBit: 17664, +var tmpFloat32Array16 = new vendor.Float32Array(16); - // Settings when getting context - // http://www.khronos.org/registry/webgl/specs/latest/#2.4 +var GLProgram = Base.extend({ - /** - * If enable alpha, default true - * @type {boolean} - */ - alpha: true, - /** - * If enable depth buffer, default true - * @type {boolean} - */ - depth: true, - /** - * If enable stencil buffer, default false - * @type {boolean} - */ - stencil: false, - /** - * If enable antialias, default true - * @type {boolean} - */ - antialias: true, - /** - * If enable premultiplied alpha, default true - * @type {boolean} - */ - premultipliedAlpha: true, - /** - * If preserve drawing buffer, default false - * @type {boolean} - */ - preserveDrawingBuffer: false, - /** - * If throw context error, usually turned on in debug mode - * @type {boolean} - */ - throwError: true, - /** - * WebGL Context created from given canvas - * @type {WebGLRenderingContext} - */ - gl: null, - /** - * Renderer viewport, read-only, can be set by setViewport method - * @type {Object} - */ - viewport: {}, + uniformSemantics: {}, + attributes: {} - // Set by FrameBuffer#bind - __currentFrameBuffer: null, +}, function () { + this._locations = {}; - _viewportStack: [], - _clearStack: [], + this._textureSlot = 0; - _sceneRendering: null - }; -}, function () { + this._program = null; +}, { - if (!this.canvas) { - this.canvas = document.createElement('canvas'); - } - var canvas = this.canvas; - try { - var opts = { - alpha: this.alpha, - depth: this.depth, - stencil: this.stencil, - antialias: this.antialias, - premultipliedAlpha: this.premultipliedAlpha, - preserveDrawingBuffer: this.preserveDrawingBuffer - }; + bind: function (renderer) { + this._textureSlot = 0; + renderer.gl.useProgram(this._program); + }, - this.gl = canvas.getContext('webgl', opts) - || canvas.getContext('experimental-webgl', opts); + hasUniform: function (symbol) { + var location = this._locations[symbol]; + return location !== null && location !== undefined; + }, - if (!this.gl) { - throw new Error(); + useTextureSlot: function (renderer, texture, slot) { + if (texture) { + renderer.gl.activeTexture(renderer.gl.TEXTURE0 + slot); + // Maybe texture is not loaded yet; + if (texture.isRenderable()) { + texture.bind(renderer); + } + else { + // Bind texture to null + texture.unbind(renderer); + } } + }, - this._glinfo = new GLInfo(this.gl); + currentTextureSlot: function () { + return this._textureSlot; + }, - if (this.gl.targetRenderer) { - console.error('Already created a renderer'); - } - this.gl.targetRenderer = this; + resetTextureSlot: function (slot) { + this._textureSlot = slot || 0; + }, - this.resize(); - } - catch (e) { - throw 'Error creating WebGL Context ' + e; - } -}, -/** @lends qtek.Renderer.prototype. **/ -{ - /** - * Resize the canvas - * @param {number} width - * @param {number} height - */ - resize: function(width, height) { - var canvas = this.canvas; - // http://www.khronos.org/webgl/wiki/HandlingHighDPI - // set the display size of the canvas. - var dpr = this.devicePixelRatio; - if (width != null) { - canvas.style.width = width + 'px'; - canvas.style.height = height + 'px'; - // set the size of the drawingBuffer - canvas.width = width * dpr; - canvas.height = height * dpr; + takeCurrentTextureSlot: function (renderer, texture) { + var textureSlot = this._textureSlot; - this._width = width; - this._height = height; - } - else { - this._width = canvas.width / dpr; - this._height = canvas.height / dpr; - } + this.useTextureSlot(renderer, texture, textureSlot); - this.setViewport(0, 0, this._width, this._height); - }, + this._textureSlot++; - /** - * Get renderer width - * @return {number} - */ - getWidth: function () { - return this._width; + return textureSlot; }, - /** + setUniform: function (_gl, type, symbol, value) { + var locationMap = this._locations; + var location = locationMap[symbol]; + // Uniform is not existed in the shader + if (location === null || location === undefined) { + return false; + } + + switch (type) { + case 'm4': + if (!(value instanceof Float32Array)) { + // Use Float32Array is much faster than array when uniformMatrix4fv. + for (var i = 0; i < value.length; i++) { + tmpFloat32Array16[i] = value[i]; + } + value = tmpFloat32Array16; + } + _gl.uniformMatrix4fv(location, false, value); + break; + case '2i': + _gl.uniform2i(location, value[0], value[1]); + break; + case '2f': + _gl.uniform2f(location, value[0], value[1]); + break; + case '3i': + _gl.uniform3i(location, value[0], value[1], value[2]); + break; + case '3f': + _gl.uniform3f(location, value[0], value[1], value[2]); + break; + case '4i': + _gl.uniform4i(location, value[0], value[1], value[2], value[3]); + break; + case '4f': + _gl.uniform4f(location, value[0], value[1], value[2], value[3]); + break; + case '1i': + _gl.uniform1i(location, value); + break; + case '1f': + _gl.uniform1f(location, value); + break; + case '1fv': + _gl.uniform1fv(location, value); + break; + case '1iv': + _gl.uniform1iv(location, value); + break; + case '2iv': + _gl.uniform2iv(location, value); + break; + case '2fv': + _gl.uniform2fv(location, value); + break; + case '3iv': + _gl.uniform3iv(location, value); + break; + case '3fv': + _gl.uniform3fv(location, value); + break; + case '4iv': + _gl.uniform4iv(location, value); + break; + case '4fv': + _gl.uniform4fv(location, value); + break; + case 'm2': + case 'm2v': + _gl.uniformMatrix2fv(location, false, value); + break; + case 'm3': + case 'm3v': + _gl.uniformMatrix3fv(location, false, value); + break; + case 'm4v': + // Raw value + if (Array.isArray(value) && Array.isArray(value[0])) { + var array = new vendor.Float32Array(value.length * 16); + var cursor = 0; + for (var i = 0; i < value.length; i++) { + var item = value[i]; + for (var j = 0; j < 16; j++) { + array[cursor++] = item[j]; + } + } + _gl.uniformMatrix4fv(location, false, array); + } + else { // ArrayBufferView + _gl.uniformMatrix4fv(location, false, value); + } + break; + } + return true; + }, + + setUniformOfSemantic: function (_gl, semantic, val) { + var semanticInfo = this.uniformSemantics[semantic]; + if (semanticInfo) { + return this.setUniform(_gl, semanticInfo.type, semanticInfo.symbol, val); + } + return false; + }, + + // Used for creating VAO + // Enable the attributes passed in and disable the rest + // Example Usage: + // enableAttributes(renderer, ["position", "texcoords"]) + enableAttributes: function (renderer, attribList, vao) { + var _gl = renderer.gl; + var program = this._program; + + var locationMap = this._locations; + + var enabledAttributeListInContext; + if (vao) { + enabledAttributeListInContext = vao.__enabledAttributeList; + } + else { + enabledAttributeListInContext = enabledAttributeList[renderer.__uid__]; + } + if (!enabledAttributeListInContext) { + // In vertex array object context + // PENDING Each vao object needs to enable attributes again? + if (vao) { + enabledAttributeListInContext + = vao.__enabledAttributeList + = []; + } + else { + enabledAttributeListInContext + = enabledAttributeList[renderer.__uid__] + = []; + } + } + var locationList = []; + for (var i = 0; i < attribList.length; i++) { + var symbol = attribList[i]; + if (!this.attributes[symbol]) { + locationList[i] = -1; + continue; + } + var location = locationMap[symbol]; + if (location == null) { + location = _gl.getAttribLocation(program, symbol); + // Attrib location is a number from 0 to ... + if (location === -1) { + locationList[i] = -1; + continue; + } + locationMap[symbol] = location; + } + locationList[i] = location; + + if (!enabledAttributeListInContext[location]) { + enabledAttributeListInContext[location] = SHADER_STATE_TO_ENABLE; + } + else { + enabledAttributeListInContext[location] = SHADER_STATE_KEEP_ENABLE; + } + } + + for (var i = 0; i < enabledAttributeListInContext.length; i++) { + switch(enabledAttributeListInContext[i]){ + case SHADER_STATE_TO_ENABLE: + _gl.enableVertexAttribArray(i); + enabledAttributeListInContext[i] = SHADER_STATE_PENDING; + break; + case SHADER_STATE_KEEP_ENABLE: + enabledAttributeListInContext[i] = SHADER_STATE_PENDING; + break; + // Expired + case SHADER_STATE_PENDING: + _gl.disableVertexAttribArray(i); + enabledAttributeListInContext[i] = 0; + break; + } + } + + return locationList; + }, + + buildProgram: function (_gl, shader, vertexShaderCode, fragmentShaderCode) { + var vertexShader = _gl.createShader(_gl.VERTEX_SHADER); + var program = _gl.createProgram(); + + _gl.shaderSource(vertexShader, vertexShaderCode); + _gl.compileShader(vertexShader); + + var fragmentShader = _gl.createShader(_gl.FRAGMENT_SHADER); + _gl.shaderSource(fragmentShader, fragmentShaderCode); + _gl.compileShader(fragmentShader); + + var msg = checkShaderErrorMsg(_gl, vertexShader, vertexShaderCode); + if (msg) { + return msg; + } + msg = checkShaderErrorMsg(_gl, fragmentShader, fragmentShaderCode); + if (msg) { + return msg; + } + + _gl.attachShader(program, vertexShader); + _gl.attachShader(program, fragmentShader); + // Force the position bind to location 0; + if (shader.attributeSemantics['POSITION']) { + _gl.bindAttribLocation(program, 0, shader.attributeSemantics['POSITION'].symbol); + } + else { + // Else choose an attribute and bind to location 0; + var keys = Object.keys(this.attributes); + _gl.bindAttribLocation(program, 0, keys[0]); + } + + _gl.linkProgram(program); + + if (!_gl.getProgramParameter(program, _gl.LINK_STATUS)) { + return 'Could not link program\n' + 'VALIDATE_STATUS: ' + _gl.getProgramParameter(program, _gl.VALIDATE_STATUS) + ', gl error [' + _gl.getError() + ']'; + } + + // Cache uniform locations + for (var i = 0; i < shader.uniforms.length; i++) { + var uniformSymbol = shader.uniforms[i]; + this._locations[uniformSymbol] = _gl.getUniformLocation(program, uniformSymbol); + } + + _gl.deleteShader(vertexShader); + _gl.deleteShader(fragmentShader); + + this._program = program; + + // Save code. + this.vertexCode = vertexShaderCode; + this.fragmentCode = fragmentShaderCode; + } +}); + +var loopRegex = /for\s*?\(int\s*?_idx_\s*\=\s*([\w-]+)\;\s*_idx_\s*<\s*([\w-]+);\s*_idx_\s*\+\+\s*\)\s*\{\{([\s\S]+?)(?=\}\})\}\}/g; + +function unrollLoop(shaderStr, defines, lightsNumbers) { + // Loop unroll from three.js, https://github.com/mrdoob/three.js/blob/master/src/renderers/webgl/WebGLProgram.js#L175 + // In some case like shadowMap in loop use 'i' to index value much slower. + + // Loop use _idx_ and increased with _idx_++ will be unrolled + // Use {{ }} to match the pair so the if statement will not be affected + // Write like following + // for (int _idx_ = 0; _idx_ < 4; _idx_++) {{ + // vec3 color = texture2D(textures[_idx_], uv).rgb; + // }} + function replace(match, start, end, snippet) { + var unroll = ''; + // Try to treat as define + if (isNaN(start)) { + if (start in defines) { + start = defines[start]; + } + else { + start = lightNumberDefines[start]; + } + } + if (isNaN(end)) { + if (end in defines) { + end = defines[end]; + } + else { + end = lightNumberDefines[end]; + } + } + // TODO Error checking + + for (var idx = parseInt(start); idx < parseInt(end); idx++) { + // PENDING Add scope? + unroll += '{' + + snippet + .replace(/float\s*\(\s*_idx_\s*\)/g, idx.toFixed(1)) + .replace(/_idx_/g, idx) + + '}'; + } + + return unroll; + } + + var lightNumberDefines = {}; + for (var lightType in lightsNumbers) { + lightNumberDefines[lightType + '_COUNT'] = lightsNumbers[lightType]; + } + return shaderStr.replace(loopRegex, replace); +} + +function getDefineCode$1(defines, lightsNumbers, enabledTextures) { + var defineStr = []; + if (lightsNumbers) { + for (var lightType in lightsNumbers) { + var count = lightsNumbers[lightType]; + if (count > 0) { + defineStr.push('#define ' + lightType.toUpperCase() + '_COUNT ' + count); + } + } + } + if (enabledTextures) { + for (var i = 0; i < enabledTextures.length; i++) { + var symbol = enabledTextures[i]; + defineStr.push('#define ' + symbol.toUpperCase() + '_ENABLED'); + } + } + // Custom Defines + for (var symbol in defines) { + var value = defines[symbol]; + if (value === null) { + defineStr.push('#define ' + symbol); + } + else{ + defineStr.push('#define ' + symbol + ' ' + value.toString()); + } + } + return defineStr.join('\n'); +} + +function getExtensionCode(exts) { + // Extension declaration must before all non-preprocessor codes + // TODO vertex ? extension enum ? + var extensionStr = []; + for (var i = 0; i < exts.length; i++) { + extensionStr.push('#extension GL_' + exts[i] + ' : enable'); + } + return extensionStr.join('\n'); +} + +function getPrecisionCode(precision) { + return ['precision', precision, 'float'].join(' ') + ';\n' + + ['precision', precision, 'int'].join(' ') + ';\n' + // depth texture may have precision problem on iOS device. + + ['precision', precision, 'sampler2D'].join(' ') + ';\n'; +} + +function ProgramManager(renderer) { + this._renderer = renderer; + this._cache = {}; +} + +ProgramManager.prototype.getProgram = function (renderable, material, scene) { + var cache = this._cache; + + var key = 's' + material.shader.shaderID + 'm' + material.getProgramKey(); + if (scene) { + key += 'se' + scene.getProgramKey(renderable.lightGroup); + } + if (renderable.isSkinnedMesh()) { + key += ',' + renderable.joints.length; + } + var program = cache[key]; + + if (program) { + return program; + } + + var lightsNumbers = scene ? scene.getLightsNumbers(renderable.lightGroup) : {}; + var renderer = this._renderer; + var _gl = renderer.gl; + var enabledTextures = material.getEnabledTextures(); + var skinDefineCode = ''; + if (renderable.isSkinnedMesh()) { + // TODO Add skinning code? + skinDefineCode = '\n' + getDefineCode$1({ + SKINNING: null, + JOINT_COUNT: renderable.joints.length + }) + '\n'; + } + // TODO Optimize key generation + // VERTEX + var vertexDefineStr = skinDefineCode + getDefineCode$1(material.vertexDefines, lightsNumbers, enabledTextures); + // FRAGMENT + var fragmentDefineStr = skinDefineCode + getDefineCode$1(material.fragmentDefines, lightsNumbers, enabledTextures); + + var vertexCode = vertexDefineStr + '\n' + material.shader.vertex; + var fragmentCode = getExtensionCode([ + // TODO Not hard coded + 'OES_standard_derivatives', + 'EXT_shader_texture_lod' + ]) + '\n' + + getPrecisionCode(material.precision) + '\n' + + fragmentDefineStr + '\n' + material.shader.fragment; + + var finalVertexCode = unrollLoop(vertexCode, material.vertexDefines, lightsNumbers); + var finalFragmentCode = unrollLoop(fragmentCode, material.fragmentDefines, lightsNumbers); + + var program = new GLProgram(); + program.uniformSemantics = material.shader.uniformSemantics; + program.attributes = material.shader.attributes; + var errorMsg = program.buildProgram(_gl, material.shader, finalVertexCode, finalFragmentCode); + program.__error = errorMsg; + + cache[key] = program; + + return program; +}; + +/** + * Mainly do the parse and compile of shader string + * Support shader code chunk import and export + * Support shader semantics + * http://www.nvidia.com/object/using_sas.html + * https://github.com/KhronosGroup/collada2json/issues/45 + * + * TODO: Use etpl or other string template engine + */ +var mat2 = glmatrix.mat2; +var mat3$1 = glmatrix.mat3; +var mat4$2 = glmatrix.mat4; + +var uniformRegex = /uniform\s+(bool|float|int|vec2|vec3|vec4|ivec2|ivec3|ivec4|mat2|mat3|mat4|sampler2D|samplerCube)\s+([\s\S]*?);/g; +var attributeRegex = /attribute\s+(float|int|vec2|vec3|vec4)\s+([\s\S]*?);/g; +var defineRegex = /#define\s+(\w+)?(\s+[\w-.]+)?\s*;?\s*\n/g; + +var uniformTypeMap = { + 'bool': '1i', + 'int': '1i', + 'sampler2D': 't', + 'samplerCube': 't', + 'float': '1f', + 'vec2': '2f', + 'vec3': '3f', + 'vec4': '4f', + 'ivec2': '2i', + 'ivec3': '3i', + 'ivec4': '4i', + 'mat2': 'm2', + 'mat3': 'm3', + 'mat4': 'm4' +}; + +var uniformValueConstructor = { + 'bool': function () { return true; }, + 'int': function () { return 0; }, + 'float': function () { return 0; }, + 'sampler2D': function () { return null; }, + 'samplerCube': function () { return null; }, + + 'vec2': function () { return [0, 0]; }, + 'vec3': function () { return [0, 0, 0]; }, + 'vec4': function () { return [0, 0, 0, 0]; }, + + 'ivec2': function () { return [0, 0]; }, + 'ivec3': function () { return [0, 0, 0]; }, + 'ivec4': function () { return [0, 0, 0, 0]; }, + + 'mat2': function () { return mat2.create(); }, + 'mat3': function () { return mat3$1.create(); }, + 'mat4': function () { return mat4$2.create(); }, + + 'array': function () { return []; } +}; + +var attributeSemantics = [ + 'POSITION', + 'NORMAL', + 'BINORMAL', + 'TANGENT', + 'TEXCOORD', + 'TEXCOORD_0', + 'TEXCOORD_1', + 'COLOR', + // Skinning + // https://github.com/KhronosGroup/glTF/blob/master/specification/README.md#semantics + 'JOINT', + 'WEIGHT' +]; +var uniformSemantics = [ + 'SKIN_MATRIX', + // Information about viewport + 'VIEWPORT_SIZE', + 'VIEWPORT', + 'DEVICEPIXELRATIO', + // Window size for window relative coordinate + // https://www.opengl.org/sdk/docs/man/html/gl_FragCoord.xhtml + 'WINDOW_SIZE', + // Infomation about camera + 'NEAR', + 'FAR', + // Time + 'TIME' +]; +var matrixSemantics = [ + 'WORLD', + 'VIEW', + 'PROJECTION', + 'WORLDVIEW', + 'VIEWPROJECTION', + 'WORLDVIEWPROJECTION', + 'WORLDINVERSE', + 'VIEWINVERSE', + 'PROJECTIONINVERSE', + 'WORLDVIEWINVERSE', + 'VIEWPROJECTIONINVERSE', + 'WORLDVIEWPROJECTIONINVERSE', + 'WORLDTRANSPOSE', + 'VIEWTRANSPOSE', + 'PROJECTIONTRANSPOSE', + 'WORLDVIEWTRANSPOSE', + 'VIEWPROJECTIONTRANSPOSE', + 'WORLDVIEWPROJECTIONTRANSPOSE', + 'WORLDINVERSETRANSPOSE', + 'VIEWINVERSETRANSPOSE', + 'PROJECTIONINVERSETRANSPOSE', + 'WORLDVIEWINVERSETRANSPOSE', + 'VIEWPROJECTIONINVERSETRANSPOSE', + 'WORLDVIEWPROJECTIONINVERSETRANSPOSE' +]; + +var attributeSizeMap = { + // WebGL does not support integer attributes + 'vec4': 4, + 'vec3': 3, + 'vec2': 2, + 'float': 1 +}; + + +var shaderIDCache = {}; +var shaderCodeCache = {}; + +function getShaderID(vertex, fragment) { + var key = 'vertex:' + vertex + 'fragment:' + fragment; + if (shaderIDCache[key]) { + return shaderIDCache[key]; + } + var id = util.genGUID(); + shaderIDCache[key] = id; + + shaderCodeCache[id] = { + vertex: vertex, + fragment: fragment + }; + + return id; +} + +function removeComment(code) { + return code.replace(/[ \t]*\/\/.*\n/g, '' ) // remove // + .replace(/[ \t]*\/\*[\s\S]*?\*\//g, '' ); // remove /* */ +} + +function logSyntaxError() { + console.error('Wrong uniform/attributes syntax'); +} + +function parseDeclarations(type, line) { + var speratorsRegexp = /[,=\(\):]/; + var tokens = line + // Convert `symbol: [1,2,3]` to `symbol: vec3(1,2,3)` + .replace(/:\s*\[\s*(.*)\s*\]/g, '=' + type + '($1)') + .replace(/\s+/g, '') + .split(/(?=[,=\(\):])/g); + + var newTokens = []; + for (var i = 0; i < tokens.length; i++) { + if (tokens[i].match(speratorsRegexp)) { + newTokens.push( + tokens[i].charAt(0), + tokens[i].slice(1) + ); + } + else { + newTokens.push(tokens[i]); + } + } + tokens = newTokens; + + var TYPE_SYMBOL = 0; + var TYPE_ASSIGN = 1; + var TYPE_VEC = 2; + var TYPE_ARR = 3; + var TYPE_SEMANTIC = 4; + var TYPE_NORMAL = 5; + + var opType = TYPE_SYMBOL; + var declarations = {}; + var declarationValue = null; + var currentDeclaration; + + addSymbol(tokens[0]); + + function addSymbol(symbol) { + if (!symbol) { + logSyntaxError(); + } + var arrResult = symbol.match(/\[(.*?)\]/); + currentDeclaration = symbol.replace(/\[(.*?)\]/, ''); + declarations[currentDeclaration] = {}; + if (arrResult) { + declarations[currentDeclaration].isArray = true; + declarations[currentDeclaration].arraySize = arrResult[1]; + } + } + + for (var i = 1; i < tokens.length; i++) { + var token = tokens[i]; + if (!token) { // Empty token; + continue; + } + if (token === '=') { + if (opType !== TYPE_SYMBOL + && opType !== TYPE_ARR) { + logSyntaxError(); + break; + } + opType = TYPE_ASSIGN; + + continue; + } + else if (token === ':') { + opType = TYPE_SEMANTIC; + + continue; + } + else if (token === ',') { + if (opType === TYPE_VEC) { + if (!(declarationValue instanceof Array)) { + logSyntaxError(); + break; + } + declarationValue.push(+tokens[++i]); + } + else { + opType = TYPE_NORMAL; + } + + continue; + } + else if (token === ')') { + declarations[currentDeclaration].value = new vendor.Float32Array(declarationValue); + declarationValue = null; + opType = TYPE_NORMAL; + continue; + } + else if (token === '(') { + if (opType !== TYPE_VEC) { + logSyntaxError(); + break; + } + if (!(declarationValue instanceof Array)) { + logSyntaxError(); + break; + } + declarationValue.push(+tokens[++i]); + continue; + } + else if (token.indexOf('vec') >= 0) { + if (opType !== TYPE_ASSIGN + // Compatitable with old syntax `symbol: [1,2,3]` + && opType !== TYPE_SEMANTIC) { + logSyntaxError(); + break; + } + opType = TYPE_VEC; + declarationValue = []; + continue; + } + else if (opType === TYPE_ASSIGN) { + if (type === 'bool') { + declarations[currentDeclaration].value = token === 'true'; + } + else { + declarations[currentDeclaration].value = parseFloat(token); + } + declarationValue = null; + continue; + } + else if (opType === TYPE_SEMANTIC) { + var semantic = token; + if (attributeSemantics.indexOf(semantic) >= 0 + || uniformSemantics.indexOf(semantic) >= 0 + || matrixSemantics.indexOf(semantic) >= 0 + ) { + declarations[currentDeclaration].semantic = semantic; + } + else if (semantic === 'ignore' || semantic === 'unconfigurable') { + declarations[currentDeclaration].ignore = true; + } + else { + // Try to parse as a default tvalue. + if (type === 'bool') { + declarations[currentDeclaration].value = semantic === 'true'; + } + else { + declarations[currentDeclaration].value = parseFloat(semantic); + } + } + continue; + } + + // treat as symbol. + addSymbol(token); + opType = TYPE_SYMBOL; + } + + return declarations; +} + + +/** + * @constructor + * @extends clay.core.Base + * @alias clay.Shader + * @param {string} vertex + * @param {string} fragment + * @example + * // Create a phong shader + * var shader = new clay.Shader( + * clay.Shader.source('clay.standard.vertex'), + * clay.Shader.source('clay.standard.fragment') + * ); + */ +function Shader(vertex, fragment) { + // First argument can be { vertex, fragment } + if (typeof vertex === 'object') { + fragment = vertex.fragment; + vertex = vertex.vertex; + } + + vertex = removeComment(vertex); + fragment = removeComment(fragment); + + this._shaderID = getShaderID(vertex, fragment); + + this._vertexCode = Shader.parseImport(vertex); + this._fragmentCode = Shader.parseImport(fragment); + + /** + * @readOnly + */ + this.attributeSemantics = {}; + /** + * @readOnly + */ + this.matrixSemantics = {}; + /** + * @readOnly + */ + this.uniformSemantics = {}; + /** + * @readOnly + */ + this.matrixSemanticKeys = []; + /** + * @readOnly + */ + this.uniformTemplates = {}; + /** + * @readOnly + */ + this.attributes = {}; + /** + * @readOnly + */ + this.textures = {}; + /** + * @readOnly + */ + this.vertexDefines = {}; + /** + * @readOnly + */ + this.fragmentDefines = {}; + + this._parseAttributes(); + this._parseUniforms(); + this._parseDefines(); +} + +Shader.prototype = { + + constructor: Shader, + + // Create a new uniform instance for material + createUniforms: function () { + var uniforms = {}; + + for (var symbol in this.uniformTemplates){ + var uniformTpl = this.uniformTemplates[symbol]; + uniforms[symbol] = { + type: uniformTpl.type, + value: uniformTpl.value() + }; + } + + return uniforms; + }, + + _parseImport: function () { + this._vertexCode = Shader.parseImport(this.vertex); + this._fragmentCode = Shader.parseImport(this.fragment); + }, + + _addSemanticUniform: function (symbol, uniformType, semantic) { + // This case is only for SKIN_MATRIX + // TODO + if (attributeSemantics.indexOf(semantic) >= 0) { + this.attributeSemantics[semantic] = { + symbol: symbol, + type: uniformType + }; + } + else if (matrixSemantics.indexOf(semantic) >= 0) { + var isTranspose = false; + var semanticNoTranspose = semantic; + if (semantic.match(/TRANSPOSE$/)) { + isTranspose = true; + semanticNoTranspose = semantic.slice(0, -9); + } + this.matrixSemantics[semantic] = { + symbol: symbol, + type: uniformType, + isTranspose: isTranspose, + semanticNoTranspose: semanticNoTranspose + }; + } + else if (uniformSemantics.indexOf(semantic) >= 0) { + this.uniformSemantics[semantic] = { + symbol: symbol, + type: uniformType + }; + } + }, + + _addMaterialUniform: function (symbol, type, uniformType, defaultValueFunc, isArray, materialUniforms) { + materialUniforms[symbol] = { + type: uniformType, + value: isArray ? uniformValueConstructor['array'] : (defaultValueFunc || uniformValueConstructor[type]), + semantic: null + }; + }, + + _parseUniforms: function () { + var uniforms = {}; + var self = this; + var shaderType = 'vertex'; + this._uniformList = []; + + this._vertexCode = this._vertexCode.replace(uniformRegex, _uniformParser); + shaderType = 'fragment'; + this._fragmentCode = this._fragmentCode.replace(uniformRegex, _uniformParser); + + self.matrixSemanticKeys = Object.keys(this.matrixSemantics); + + function makeDefaultValueFunc(value) { + return value != null ? function () { return value; } : null; + } + + function _uniformParser(str, type, content) { + var declaredUniforms = parseDeclarations(type, content); + var uniformMainStr = []; + for (var symbol in declaredUniforms) { + + var uniformInfo = declaredUniforms[symbol]; + var semantic = uniformInfo.semantic; + var tmpStr = symbol; + var uniformType = uniformTypeMap[type]; + var defaultValueFunc = makeDefaultValueFunc(declaredUniforms[symbol].value); + if (declaredUniforms[symbol].isArray) { + tmpStr += '[' + declaredUniforms[symbol].arraySize + ']'; + uniformType += 'v'; + } + + uniformMainStr.push(tmpStr); + + self._uniformList.push(symbol); + + if (!uniformInfo.ignore) { + if (type === 'sampler2D' || type === 'samplerCube') { + // Texture is default disabled + self.textures[symbol] = { + shaderType: shaderType, + type: type + }; + } + + if (semantic) { + // TODO Should not declare multiple symbols if have semantic. + self._addSemanticUniform(symbol, uniformType, semantic); + } + else { + self._addMaterialUniform( + symbol, type, uniformType, defaultValueFunc, + declaredUniforms[symbol].isArray, uniforms + ); + } + } + } + return uniformMainStr.length > 0 + ? 'uniform ' + type + ' ' + uniformMainStr.join(',') + ';\n' : ''; + } + + this.uniformTemplates = uniforms; + }, + + _parseAttributes: function () { + var attributes = {}; + var self = this; + this._vertexCode = this._vertexCode.replace(attributeRegex, _attributeParser); + + function _attributeParser(str, type, content) { + var declaredAttributes = parseDeclarations(type, content); + + var size = attributeSizeMap[type] || 1; + var attributeMainStr = []; + for (var symbol in declaredAttributes) { + var semantic = declaredAttributes[symbol].semantic; + attributes[symbol] = { + // TODO Can only be float + type: 'float', + size: size, + semantic: semantic || null + }; + // TODO Should not declare multiple symbols if have semantic. + if (semantic) { + if (attributeSemantics.indexOf(semantic) < 0) { + throw new Error('Unkown semantic "' + semantic + '"'); + } + else { + self.attributeSemantics[semantic] = { + symbol: symbol, + type: type + }; + } + } + attributeMainStr.push(symbol); + } + + return 'attribute ' + type + ' ' + attributeMainStr.join(',') + ';\n'; + } + + this.attributes = attributes; + }, + + _parseDefines: function () { + var self = this; + var shaderType = 'vertex'; + this._vertexCode = this._vertexCode.replace(defineRegex, _defineParser); + shaderType = 'fragment'; + this._fragmentCode = this._fragmentCode.replace(defineRegex, _defineParser); + + function _defineParser(str, symbol, value) { + var defines = shaderType === 'vertex' ? self.vertexDefines : self.fragmentDefines; + if (!defines[symbol]) { // Haven't been defined by user + if (value === 'false') { + defines[symbol] = false; + } + else if (value === 'true') { + defines[symbol] = true; + } + else { + defines[symbol] = value + // If can parse to float + ? (isNaN(parseFloat(value)) ? value.trim() : parseFloat(value)) + : null; + } + } + return ''; + } + }, + + /** + * Clone a new shader + * @return {clay.Shader} + */ + clone: function () { + var code = shaderCodeCache[this._shaderID]; + var shader = new Shader(code.vertex, code.fragment); + return shader; + } +}; + +if (Object.defineProperty) { + Object.defineProperty(Shader.prototype, 'shaderID', { + get: function () { + return this._shaderID; + } + }); + Object.defineProperty(Shader.prototype, 'vertex', { + get: function () { + return this._vertexCode; + } + }); + Object.defineProperty(Shader.prototype, 'fragment', { + get: function () { + return this._fragmentCode; + } + }); + Object.defineProperty(Shader.prototype, 'uniforms', { + get: function () { + return this._uniformList; + } + }); +} + +var importRegex = /(@import)\s*([0-9a-zA-Z_\-\.]*)/g; +Shader.parseImport = function (shaderStr) { + shaderStr = shaderStr.replace(importRegex, function (str, importSymbol, importName) { + var str = Shader.source(importName); + if (str) { + // Recursively parse + return Shader.parseImport(str); + } + else { + console.error('Shader chunk "' + importName + '" not existed in library'); + return ''; + } + }); + return shaderStr; +}; + +var exportRegex = /(@export)\s*([0-9a-zA-Z_\-\.]*)\s*\n([\s\S]*?)@end/g; + +/** + * Import shader source + * @param {string} shaderStr + * @memberOf clay.Shader + */ +Shader['import'] = function (shaderStr) { + shaderStr.replace(exportRegex, function (str, exportSymbol, exportName, code) { + var code = code.replace(/(^[\s\t\xa0\u3000]+)|([\u3000\xa0\s\t]+\x24)/g, ''); + if (code) { + var parts = exportName.split('.'); + var obj = Shader.codes; + var i = 0; + var key; + while (i < parts.length - 1) { + key = parts[i++]; + if (!obj[key]) { + obj[key] = {}; + } + obj = obj[key]; + } + key = parts[i]; + obj[key] = code; + } + return code; + }); +}; + +/** + * Library to store all the loaded shader codes + * @type {Object} + * @readOnly + * @memberOf clay.Shader + */ +Shader.codes = {}; + +/** + * Get shader source + * @param {string} name + * @return {string} + */ +Shader.source = function (name) { + var parts = name.split('.'); + var obj = Shader.codes; + var i = 0; + while (obj && i < parts.length) { + var key = parts[i++]; + obj = obj[key]; + } + if (typeof obj !== 'string') { + // FIXME Use default instead + console.error('Shader "' + name + '" not existed in library'); + return ''; + } + return obj; +}; + +var calcAmbientSHLightEssl = "vec3 calcAmbientSHLight(int idx, vec3 N) {\n int offset = 9 * idx;\n return ambientSHLightCoefficients[0]\n + ambientSHLightCoefficients[1] * N.x\n + ambientSHLightCoefficients[2] * N.y\n + ambientSHLightCoefficients[3] * N.z\n + ambientSHLightCoefficients[4] * N.x * N.z\n + ambientSHLightCoefficients[5] * N.z * N.y\n + ambientSHLightCoefficients[6] * N.y * N.x\n + ambientSHLightCoefficients[7] * (3.0 * N.z * N.z - 1.0)\n + ambientSHLightCoefficients[8] * (N.x * N.x - N.y * N.y);\n}"; + +var uniformVec3Prefix = 'uniform vec3 '; +var uniformFloatPrefix = 'uniform float '; +var exportHeaderPrefix = '@export clay.header.'; +var exportEnd = '@end'; +var unconfigurable = ':unconfigurable;'; +var lightEssl = [ + exportHeaderPrefix + 'directional_light', + uniformVec3Prefix + 'directionalLightDirection[DIRECTIONAL_LIGHT_COUNT]' + unconfigurable, + uniformVec3Prefix + 'directionalLightColor[DIRECTIONAL_LIGHT_COUNT]' + unconfigurable, + exportEnd, + + exportHeaderPrefix + 'ambient_light', + uniformVec3Prefix + 'ambientLightColor[AMBIENT_LIGHT_COUNT]' + unconfigurable, + exportEnd, + + exportHeaderPrefix + 'ambient_sh_light', + uniformVec3Prefix + 'ambientSHLightColor[AMBIENT_SH_LIGHT_COUNT]' + unconfigurable, + uniformVec3Prefix + 'ambientSHLightCoefficients[AMBIENT_SH_LIGHT_COUNT * 9]' + unconfigurable, + calcAmbientSHLightEssl, + exportEnd, + + exportHeaderPrefix + 'ambient_cubemap_light', + uniformVec3Prefix + 'ambientCubemapLightColor[AMBIENT_CUBEMAP_LIGHT_COUNT]' + unconfigurable, + 'uniform samplerCube ambientCubemapLightCubemap[AMBIENT_CUBEMAP_LIGHT_COUNT]' + unconfigurable, + 'uniform sampler2D ambientCubemapLightBRDFLookup[AMBIENT_CUBEMAP_LIGHT_COUNT]' + unconfigurable, + exportEnd, + + exportHeaderPrefix + 'point_light', + uniformVec3Prefix + 'pointLightPosition[POINT_LIGHT_COUNT]' + unconfigurable, + uniformFloatPrefix + 'pointLightRange[POINT_LIGHT_COUNT]' + unconfigurable, + uniformVec3Prefix + 'pointLightColor[POINT_LIGHT_COUNT]' + unconfigurable, + exportEnd, + + exportHeaderPrefix + 'spot_light', + uniformVec3Prefix + 'spotLightPosition[SPOT_LIGHT_COUNT]' + unconfigurable, + uniformVec3Prefix + 'spotLightDirection[SPOT_LIGHT_COUNT]' + unconfigurable, + uniformFloatPrefix + 'spotLightRange[SPOT_LIGHT_COUNT]' + unconfigurable, + uniformFloatPrefix + 'spotLightUmbraAngleCosine[SPOT_LIGHT_COUNT]' + unconfigurable, + uniformFloatPrefix + 'spotLightPenumbraAngleCosine[SPOT_LIGHT_COUNT]' + unconfigurable, + uniformFloatPrefix + 'spotLightFalloffFactor[SPOT_LIGHT_COUNT]' + unconfigurable, + uniformVec3Prefix + 'spotLightColor[SPOT_LIGHT_COUNT]' + unconfigurable, + exportEnd +].join('\n'); + +var prezEssl = "@export clay.prez.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\n@import clay.chunk.skinning_header\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n}\n@end\n@export clay.prez.fragment\nvoid main()\n{\n gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n}\n@end"; + +// TODO Resources like shader, texture, geometry reference management +// Trace and find out which shader, texture, geometry can be destroyed +// Light header +Shader['import'](lightEssl); +Shader['import'](prezEssl); + +var mat4 = glmatrix.mat4; +var vec3 = glmatrix.vec3; + +var mat4Create = mat4.create; + +var errorShader = {}; + +function defaultGetMaterial(renderable) { + return renderable.material; +} + +function noop() {} + +var attributeBufferTypeMap = { + float: glenum.FLOAT, + byte: glenum.BYTE, + ubyte: glenum.UNSIGNED_BYTE, + short: glenum.SHORT, + ushort: glenum.UNSIGNED_SHORT +}; + +function VertexArrayObject(availableAttributes, availableAttributeSymbols, indicesBuffer) { + this.availableAttributes = availableAttributes; + this.availableAttributeSymbols = availableAttributeSymbols; + this.indicesBuffer = indicesBuffer; + + this.vao = null; +} +/** + * @constructor clay.Renderer + */ +var Renderer = Base.extend(function () { + return /** @lends clay.Renderer# */ { + + /** + * @type {HTMLCanvasElement} + * @readonly + */ + canvas: null, + + /** + * Canvas width, set by resize method + * @type {number} + * @private + */ + _width: 100, + + /** + * Canvas width, set by resize method + * @type {number} + * @private + */ + _height: 100, + + /** + * Device pixel ratio, set by setDevicePixelRatio method + * Specially for high defination display + * @see http://www.khronos.org/webgl/wiki/HandlingHighDPI + * @type {number} + * @private + */ + devicePixelRatio: (window && window.devicePixelRatio) || 1.0, + + /** + * Clear color + * @type {number[]} + */ + clearColor: [0.0, 0.0, 0.0, 0.0], + + /** + * Default: + * _gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT | _gl.STENCIL_BUFFER_BIT + * @type {number} + */ + clearBit: 17664, + + // Settings when getting context + // http://www.khronos.org/registry/webgl/specs/latest/#2.4 + + /** + * If enable alpha, default true + * @type {boolean} + */ + alpha: true, + /** + * If enable depth buffer, default true + * @type {boolean} + */ + depth: true, + /** + * If enable stencil buffer, default false + * @type {boolean} + */ + stencil: false, + /** + * If enable antialias, default true + * @type {boolean} + */ + antialias: true, + /** + * If enable premultiplied alpha, default true + * @type {boolean} + */ + premultipliedAlpha: true, + /** + * If preserve drawing buffer, default false + * @type {boolean} + */ + preserveDrawingBuffer: false, + /** + * If throw context error, usually turned on in debug mode + * @type {boolean} + */ + throwError: true, + /** + * WebGL Context created from given canvas + * @type {WebGLRenderingContext} + */ + gl: null, + /** + * Renderer viewport, read-only, can be set by setViewport method + * @type {Object} + */ + viewport: {}, + + // Set by FrameBuffer#bind + __currentFrameBuffer: null, + + _viewportStack: [], + _clearStack: [], + + _sceneRendering: null + }; +}, function () { + + if (!this.canvas) { + this.canvas = document.createElement('canvas'); + } + var canvas = this.canvas; + try { + var opts = { + alpha: this.alpha, + depth: this.depth, + stencil: this.stencil, + antialias: this.antialias, + premultipliedAlpha: this.premultipliedAlpha, + preserveDrawingBuffer: this.preserveDrawingBuffer + }; + + this.gl = canvas.getContext('webgl', opts) + || canvas.getContext('experimental-webgl', opts); + + if (!this.gl) { + throw new Error(); + } + + this._glinfo = new GLInfo(this.gl); + + if (this.gl.targetRenderer) { + console.error('Already created a renderer'); + } + this.gl.targetRenderer = this; + + this.resize(); + } + catch (e) { + throw 'Error creating WebGL Context ' + e; + } + + // Init managers + this._programMgr = new ProgramManager(this); +}, +/** @lends clay.Renderer.prototype. **/ +{ + /** + * Resize the canvas + * @param {number} width + * @param {number} height + */ + resize: function(width, height) { + var canvas = this.canvas; + // http://www.khronos.org/webgl/wiki/HandlingHighDPI + // set the display size of the canvas. + var dpr = this.devicePixelRatio; + if (width != null) { + canvas.style.width = width + 'px'; + canvas.style.height = height + 'px'; + // set the size of the drawingBuffer + canvas.width = width * dpr; + canvas.height = height * dpr; + + this._width = width; + this._height = height; + } + else { + this._width = canvas.width / dpr; + this._height = canvas.height / dpr; + } + + this.setViewport(0, 0, this._width, this._height); + }, + + /** + * Get renderer width + * @return {number} + */ + getWidth: function () { + return this._width; + }, + + /** * Get renderer height * @return {number} */ @@ -10803,13 +11568,10 @@ var Renderer = Base.extend(function () { this._sceneRendering = scene; }, - // Hook before and after render each object - beforeRenderObject: function () {}, - afterRenderObject: function () {}, /** * Render the scene in camera to the screen or binded offline framebuffer - * @param {qtek.Scene} scene - * @param {qtek.Camera} camera + * @param {clay.Scene} scene + * @param {clay.Camera} camera * @param {boolean} [notUpdateScene] If not call the scene.update methods in the rendering, default true * @param {boolean} [preZ] If use preZ optimization, default false * @return {IRenderInfo} @@ -10817,8 +11579,6 @@ var Renderer = Base.extend(function () { render: function(scene, camera, notUpdateScene, preZ) { var _gl = this.gl; - this._sceneRendering = scene; - var clearColor = this.clearColor; if (this.clearBit) { @@ -10851,102 +11611,139 @@ var Renderer = Base.extend(function () { if (!notUpdateScene) { scene.update(false); } - // Update if camera not mounted on the scene - if (!camera.getScene()) { - camera.update(true); + scene.updateLights(); + + camera = camera || scene.getMainCamera(); + if (!camera) { + console.error('Can\'t find camera in the scene.'); + return; } + camera.update(); + var renderList = scene.updateRenderList(camera); + + this._sceneRendering = scene; - var opaqueQueue = scene.opaqueQueue; - var transparentQueue = scene.transparentQueue; + var opaqueList = renderList.opaque; + var transparentList = renderList.transparent; var sceneMaterial = scene.material; - // StandardMaterial needs updateShader method so shader can be created on demand. - for (var i = 0; i < opaqueQueue.length; i++) { - var material = opaqueQueue[i].material; - material.updateShader && material.updateShader(this); - } - // StandardMaterial needs updateShader method so shader can be created on demand. - for (var i = 0; i < transparentQueue.length; i++) { - var material = transparentQueue[i].material; - material.updateShader && material.updateShader(this); + scene.trigger('beforerender', this, scene, camera, renderList); + + // Render pre z + if (preZ) { + this.renderPreZ(opaqueList, scene, camera); + _gl.depthFunc(_gl.LEQUAL); } - scene.trigger('beforerender', this, scene, camera); - // Sort render queue - // Calculate the object depth - if (transparentQueue.length > 0) { - var worldViewMat = mat4Create(); - var posViewSpace = vec3.create(); - for (var i = 0; i < transparentQueue.length; i++) { - var node = transparentQueue[i]; - mat4.multiplyAffine(worldViewMat, camera.viewMatrix._array, node.worldTransform._array); - vec3.transformMat4(posViewSpace, node.position._array, worldViewMat); - node.__depth = posViewSpace[2]; - } + else { + _gl.depthFunc(_gl.LESS); } - opaqueQueue.sort(this.opaqueSortFunc); - transparentQueue.sort(this.transparentSortFunc); - - // Render Opaque queue - scene.trigger('beforerender:opaque', this, opaqueQueue); - - // Reset the scene bounding box; - scene.viewBoundingBoxLastFrame.min.set(Infinity, Infinity, Infinity); - scene.viewBoundingBoxLastFrame.max.set(-Infinity, -Infinity, -Infinity); - _gl.disable(_gl.BLEND); - _gl.enable(_gl.DEPTH_TEST); - var opaqueRenderInfo = this.renderQueue(opaqueQueue, camera, sceneMaterial, preZ); - - scene.trigger('afterrender:opaque', this, opaqueQueue, opaqueRenderInfo); - scene.trigger('beforerender:transparent', this, transparentQueue); + // Update the depth of transparent list. + var worldViewMat = mat4Create(); + var posViewSpace = vec3.create(); + for (var i = 0; i < transparentList.length; i++) { + var renderable = transparentList[i]; + mat4.multiplyAffine(worldViewMat, camera.viewMatrix.array, renderable.worldTransform.array); + vec3.transformMat4(posViewSpace, renderable.position.array, worldViewMat); + renderable.__depth = posViewSpace[2]; + } - // Render Transparent Queue - _gl.enable(_gl.BLEND); - var transparentRenderInfo = this.renderQueue(transparentQueue, camera, sceneMaterial); + // Render opaque list + this.renderPass(opaqueList, camera, { + getMaterial: function (renderable) { + return sceneMaterial || renderable.material; + }, + sortCompare: this.opaqueSortCompare + }); - scene.trigger('afterrender:transparent', this, transparentQueue, transparentRenderInfo); - var renderInfo = {}; - for (var name in opaqueRenderInfo) { - renderInfo[name] = opaqueRenderInfo[name] + transparentRenderInfo[name]; - } + this.renderPass(transparentList, camera, { + getMaterial: function (renderable) { + return sceneMaterial || renderable.material; + }, + sortCompare: this.transparentSortCompare + }); - scene.trigger('afterrender', this, scene, camera, renderInfo); + scene.trigger('afterrender', this, scene, camera, renderList); // Cleanup this._sceneRendering = null; - return renderInfo; }, - resetRenderStatus: function () { - this._currentShader = null; + getProgram: function (renderable, renderMaterial, scene) { + renderMaterial = renderMaterial || renderable.material; + return this._programMgr.getProgram(renderable, renderMaterial, scene); }, - /** - * Callback during rendering process to determine if render given renderable. - * @param {qtek.Renderable} given renderable. - * @return {boolean} - */ - ifRenderObject: function (obj) { - return true; + validateProgram: function (program) { + if (program.__error) { + var errorMsg = program.__error; + if (errorShader[program.__uid__]) { + return; + } + errorShader[program.__uid__] = true; + + if (this.throwError) { + throw new Error(errorMsg); + } + else { + this.trigger('error', errorMsg); + } + } + + }, + + updatePrograms: function (list, scene, passConfig) { + var getMaterial = (passConfig && passConfig.getMaterial) || defaultGetMaterial; + scene = scene || null; + for (var i = 0; i < list.length; i++) { + var renderable = list[i]; + var renderMaterial = getMaterial.call(this, renderable); + if (i > 0) { + var prevRenderable = list[i - 1]; + var prevJointsLen = prevRenderable.joints ? prevRenderable.joints.length : 0; + var jointsLen = renderable.joints ? renderable.joints.length : 0; + // Keep program not change if joints, material, lightGroup are same of two renderables. + if (jointsLen === prevJointsLen + && renderable.material === prevRenderable.material + && renderable.lightGroup === prevRenderable.lightGroup + ) { + renderable.__program = prevRenderable.__program; + continue; + } + } + + var program = this._programMgr.getProgram(renderable, renderMaterial, scene); + + this.validateProgram(program); + + renderable.__program = program; + } }, /** * Render a single renderable list in camera in sequence - * @param {qtek.Renderable[]} queue List of all renderables. - * Best to be sorted by Renderer.opaqueSortFunc or Renderer.transparentSortFunc - * @param {qtek.Camera} camera - * @param {qtek.Material} [globalMaterial] globalMaterial will override the material of each renderable - * @param {boolean} [preZ] If use preZ optimization, default false + * @param {clay.Renderable[]} list List of all renderables. + * @param {clay.Camera} camera + * @param {Object} [passConfig] + * @param {Function} [passConfig.getMaterial] Get renderable material. + * @param {Function} [passConfig.beforeRender] Before render each renderable. + * @param {Function} [passConfig.afterRender] After render each renderable + * @param {Function} [passConfig.ifRender] If render the renderable. + * @param {Function} [passConfig.sortCompare] Sort compare function. * @return {IRenderInfo} */ - renderQueue: function(queue, camera, globalMaterial, preZ) { - var renderInfo = { - triangleCount: 0, - vertexCount: 0, - drawCallCount: 0, - meshCount: queue.length, - renderedMeshCount: 0 - }; + renderPass: function(list, camera, passConfig) { + this.trigger('beforerenderpass', this, list, camera, passConfig); + + passConfig = passConfig || {}; + passConfig.getMaterial = passConfig.getMaterial || defaultGetMaterial; + passConfig.beforeRender = passConfig.beforeRender || noop; + passConfig.afterRender = passConfig.afterRender || noop; + + this.updatePrograms(list, this._sceneRendering, passConfig); + if (passConfig.sortCompare) { + list.sort(passConfig.sortCompare); + } // Some common builtin uniforms var viewport = this.viewport; @@ -10966,10 +11763,10 @@ var Renderer = Base.extend(function () { var time = Date.now(); // Calculate view and projection matrix - mat4.copy(matrices.VIEW, camera.viewMatrix._array); - mat4.copy(matrices.PROJECTION, camera.projectionMatrix._array); - mat4.multiply(matrices.VIEWPROJECTION, camera.projectionMatrix._array, matrices.VIEW); - mat4.copy(matrices.VIEWINVERSE, camera.worldTransform._array); + mat4.copy(matrices.VIEW, camera.viewMatrix.array); + mat4.copy(matrices.PROJECTION, camera.projectionMatrix.array); + mat4.multiply(matrices.VIEWPROJECTION, camera.projectionMatrix.array, matrices.VIEW); + mat4.copy(matrices.VIEWINVERSE, camera.worldTransform.array); mat4.invert(matrices.PROJECTIONINVERSE, matrices.PROJECTION); mat4.invert(matrices.VIEWPROJECTIONINVERSE, matrices.VIEWPROJECTION); @@ -10977,48 +11774,42 @@ var Renderer = Base.extend(function () { var scene = this._sceneRendering; var prevMaterial; - var prevShader; - - var culledRenderQueue; - if (preZ) { - culledRenderQueue = this._renderPreZ(queue, scene, camera); - } - else { - culledRenderQueue = queue; - _gl.depthFunc(_gl.LESS); - } + var prevProgram; // Status var depthTest, depthMask; var culling, cullFace, frontFace; + var transparent; + var drawID; + var currentVAO; + + var vaoExt = this.getGLExtension('OES_vertex_array_object'); - for (var i = 0; i < culledRenderQueue.length; i++) { - var renderable = culledRenderQueue[i]; - if (!this.ifRenderObject(renderable)) { + for (var i = 0; i < list.length; i++) { + var renderable = list[i]; + if (passConfig.ifRender && !passConfig.ifRender(renderable)) { continue; } - var geometry = renderable.geometry; - // Skinned mesh will transformed to joint space. Ignore the mesh transform - var worldM = renderable.isSkinnedMesh() ? matrices.IDENTITY : renderable.worldTransform._array; - // All matrices ralated to world matrix will be updated on demand; - mat4.multiplyAffine(matrices.WORLDVIEW, matrices.VIEW , worldM); - // TODO Skinned mesh may have wrong bounding box. - if (geometry.boundingBox && !preZ) { - if (this.isFrustumCulled( - renderable, scene, camera, matrices.WORLDVIEW, matrices.PROJECTION - )) { - continue; - } - } - - var material = globalMaterial || renderable.material; + var worldM = renderable.isSkinnedMesh() ? matrices.IDENTITY : renderable.worldTransform.array; + var geometry = renderable.geometry; + var material = passConfig.getMaterial.call(this, renderable); + var program = renderable.__program; var shader = material.shader; + var currentDrawID = geometry.__uid__ + '-' + program.__uid__; + var drawIDChanged = currentDrawID !== drawID; + drawID = currentDrawID; + if (drawIDChanged && vaoExt) { + // TODO Seems need to be bound to null immediately (or before bind another program?) if vao is changed + vaoExt.bindVertexArrayOES(null); + } + mat4.copy(matrices.WORLD, worldM); - mat4.multiply(matrices.WORLDVIEWPROJECTION, matrices.VIEWPROJECTION , worldM); + mat4.multiply(matrices.WORLDVIEWPROJECTION, matrices.VIEWPROJECTION, worldM); + mat4.multiplyAffine(matrices.WORLDVIEW, camera.viewMatrix.array, worldM); if (shader.matrixSemantics.WORLDINVERSE || shader.matrixSemantics.WORLDINVERSETRANSPOSE) { mat4.invert(matrices.WORLDINVERSE, worldM); @@ -11032,85 +11823,62 @@ var Renderer = Base.extend(function () { mat4.invert(matrices.WORLDVIEWPROJECTIONINVERSE, matrices.WORLDVIEWPROJECTION); } - // FIXME Optimize for compositing. - // var prevShader = this._sceneRendering ? null : this._currentShader; - // var prevShader = null; - // Before render hook renderable.beforeRender(this); - this.beforeRenderObject(renderable, prevMaterial, prevShader); + passConfig.beforeRender.call(this, renderable, material, prevMaterial); - var shaderChanged = !shader.isEqual(prevShader); - if (shaderChanged) { + var programChanged = program !== prevProgram; + if (programChanged) { // Set lights number - if (scene && scene.isShaderLightNumberChanged(shader)) { - scene.setShaderLightNumber(shader); - } - var errMsg = shader.bind(this); - if (errMsg) { - - if (errorShader[shader.__GUID__]) { - continue; - } - errorShader[shader.__GUID__] = true; - - if (this.throwError) { - throw new Error(errMsg); - } - else { - this.trigger('error', errMsg); - } - } + program.bind(this); // Set some common uniforms - shader.setUniformOfSemantic(_gl, 'VIEWPORT', viewportUniform); - shader.setUniformOfSemantic(_gl, 'WINDOW_SIZE', windowSizeUniform); - shader.setUniformOfSemantic(_gl, 'NEAR', camera.near); - shader.setUniformOfSemantic(_gl, 'FAR', camera.far); - shader.setUniformOfSemantic(_gl, 'DEVICEPIXELRATIO', vDpr); - shader.setUniformOfSemantic(_gl, 'TIME', time); + program.setUniformOfSemantic(_gl, 'VIEWPORT', viewportUniform); + program.setUniformOfSemantic(_gl, 'WINDOW_SIZE', windowSizeUniform); + program.setUniformOfSemantic(_gl, 'NEAR', camera.near); + program.setUniformOfSemantic(_gl, 'FAR', camera.far); + program.setUniformOfSemantic(_gl, 'DEVICEPIXELRATIO', vDpr); + program.setUniformOfSemantic(_gl, 'TIME', time); // DEPRECATED - shader.setUniformOfSemantic(_gl, 'VIEWPORT_SIZE', viewportSizeUniform); + program.setUniformOfSemantic(_gl, 'VIEWPORT_SIZE', viewportSizeUniform); // Set lights uniforms // TODO needs optimized if (scene) { - scene.setLightUniforms(shader, this); + scene.setLightUniforms(program, renderable.lightGroup, this); } - - // Save current used shader in the renderer - // ALWAYS USE RENDERER TO DRAW THE MESH - // this._currentShader = shader; } else { - shader = prevShader; + program = prevProgram; } - if (prevMaterial !== material) { - if (!preZ) { - if (material.depthTest !== depthTest) { - material.depthTest ? - _gl.enable(_gl.DEPTH_TEST) : - _gl.disable(_gl.DEPTH_TEST); - depthTest = material.depthTest; - } - if (material.depthMask !== depthMask) { - _gl.depthMask(material.depthMask); - depthMask = material.depthMask; - } + // Program changes also needs reset the materials. + if (prevMaterial !== material || programChanged) { + if (material.depthTest !== depthTest) { + material.depthTest ? _gl.enable(_gl.DEPTH_TEST) : _gl.disable(_gl.DEPTH_TEST); + depthTest = material.depthTest; + } + if (material.depthMask !== depthMask) { + _gl.depthMask(material.depthMask); + depthMask = material.depthMask; + } + if (material.transparent !== transparent) { + material.transparent ? _gl.enable(_gl.BLEND) : _gl.disable(_gl.BLEND); + transparent = material.transparent; } - material.bind(this, shader, prevMaterial, prevShader); - prevMaterial = material; - // TODO cache blending if (material.transparent) { if (material.blend) { material.blend(_gl); } - else { // Default blend function + else { + // Default blend function _gl.blendEquationSeparate(_gl.FUNC_ADD, _gl.FUNC_ADD); _gl.blendFuncSeparate(_gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA); } } + + this._bindMaterial(material, program, prevMaterial || null, prevProgram || null); + prevMaterial = material; } var matrixSemanticKeys = shader.matrixSemanticKeys; @@ -11122,7 +11890,7 @@ var Renderer = Base.extend(function () { var matrixNoTranspose = matrices[semanticInfo.semanticNoTranspose]; mat4.transpose(matrix, matrixNoTranspose); } - shader.setUniform(_gl, semanticInfo.type, semanticInfo.symbol, matrix); + program.setUniform(_gl, semanticInfo.type, semanticInfo.symbol, matrix); } if (renderable.cullFace !== cullFace) { @@ -11138,162 +11906,294 @@ var Renderer = Base.extend(function () { culling ? _gl.enable(_gl.CULL_FACE) : _gl.disable(_gl.CULL_FACE); } - var objectRenderInfo = renderable.render(this, shader); - - if (objectRenderInfo) { - renderInfo.triangleCount += objectRenderInfo.triangleCount; - renderInfo.vertexCount += objectRenderInfo.vertexCount; - renderInfo.drawCallCount += objectRenderInfo.drawCallCount; - renderInfo.renderedMeshCount ++; + this._updateSkeleton(renderable, program); + if (drawIDChanged) { + currentVAO = this._bindVAO(vaoExt, shader, geometry, program); } + this._renderObject(renderable, currentVAO); // After render hook - this.afterRenderObject(renderable, objectRenderInfo); - renderable.afterRender(this, objectRenderInfo); + passConfig.afterRender.call(this, renderable); + renderable.afterRender(this); - prevShader = shader; + prevProgram = program; } - return renderInfo; + // TODO Seems need to be bound to null immediately if vao is changed? + if (vaoExt) { + vaoExt.bindVertexArrayOES(null); + } + + this.trigger('afterrenderpass', this, list, camera, passConfig); }, - _renderPreZ: function (queue, scene, camera) { + _updateSkeleton: function (object, program) { var _gl = this.gl; - var preZPassMaterial = this._prezMaterial || new Material({ - shader: new Shader({ - vertex: Shader.source('qtek.prez.vertex'), - fragment: Shader.source('qtek.prez.fragment') - }) - }); - this._prezMaterial = preZPassMaterial; - var preZPassShader = preZPassMaterial.shader; + // Set pose matrices of skinned mesh + if (object.skeleton) { + object.skeleton.update(); + var skinMatricesArray = object.skeleton.getSubSkinMatrices(object.__uid__, object.joints); + program.setUniformOfSemantic(_gl, 'SKIN_MATRIX', skinMatricesArray); + } + }, - var culledRenderQueue = []; - // Status - var culling, cullFace, frontFace; + _renderObject: function (renderable, vao) { + var _gl = this.gl; + var geometry = renderable.geometry; - preZPassShader.bind(this); - _gl.colorMask(false, false, false, false); - _gl.depthMask(true); - _gl.enable(_gl.DEPTH_TEST); - for (var i = 0; i < queue.length; i++) { - var renderable = queue[i]; + var glDrawMode = renderable.mode; + + // if (glDrawMode === glenum.LINES || glDrawMode === glenum.LINE_STRIP || glDrawMode === glenum.LINE_LOOP) { + // _gl.lineWidth(this.lineWidth); + // } + + if (vao.indicesBuffer) { + var uintExt = this.getGLExtension('OES_element_index_uint'); + var useUintExt = uintExt && (geometry.indices instanceof Uint32Array); + var indicesType = useUintExt ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT; + + _gl.drawElements(glDrawMode, vao.indicesBuffer.count, indicesType, 0); + } + else { + // FIXME Use vertex number in buffer + // vertexCount may get the wrong value when geometry forget to mark dirty after update + _gl.drawArrays(glDrawMode, 0, geometry.vertexCount); + } + }, + + _bindMaterial: function (material, program, prevMaterial, prevProgram) { + var _gl = this.gl; + // PENDING Same texture in different material take different slot? + + // May use shader of other material if shader code are same + var sameProgram = prevProgram === program; + + var currentTextureSlot = program.currentTextureSlot(); + var enabledUniforms = material.getEnabledUniforms(); + var textureUniforms = material.getTextureUniforms(); + + for (var u = 0; u < textureUniforms.length; u++) { + var symbol = textureUniforms[u]; + var uniformValue = material.uniforms[symbol].value; + var uniformType = material.uniforms[symbol].type; + // Not use `instanceof` to determine if a value is texture in Material#bind. + // Use type instead, in some case texture may be in different namespaces. + // TODO Duck type validate. + if (uniformType === 't' && uniformValue) { + // Reset slot + uniformValue.__slot = -1; + } + else if (uniformType === 'tv') { + for (var i = 0; i < uniformValue.length; i++) { + if (uniformValue[i] instanceof Texture) { + uniformValue[i].__slot = -1; + } + } + } + } + + // Set uniforms + for (var u = 0; u < enabledUniforms.length; u++) { + var symbol = enabledUniforms[u]; + var uniform = material.uniforms[symbol]; + var uniformValue = uniform.value; // PENDING - if (!this.ifRenderObject(renderable)) { + // When binding two materials with the same shader + // Many uniforms will be be set twice even if they have the same value + // So add a evaluation to see if the uniform is really needed to be set + if (prevMaterial && sameProgram) { + if (prevMaterial.uniforms[symbol].value === uniformValue) { + continue; + } + } + var uniformType = uniform.type; + + if (uniformValue == null) { + // FIXME Assume material with same shader have same order uniforms + // Or if different material use same textures, + // the slot will be different and still skipped because optimization + if (uniform.type === 't') { + var slot = program.currentTextureSlot(); + var res = program.setUniform(_gl, '1i', symbol, slot); + if (res) { // Texture is enabled + // Still occupy the slot to make sure same texture in different materials have same slot. + program.takeCurrentTextureSlot(this, null); + } + } continue; } + else if (uniformType === 't') { + if (uniformValue.__slot < 0) { + var slot = program.currentTextureSlot(); + var res = program.setUniform(_gl, '1i', symbol, slot); + if (!res) { // Texture uniform is not enabled + continue; + } + program.takeCurrentTextureSlot(this, uniformValue); + uniformValue.__slot = slot; + } + // Multiple uniform use same texture.. + else { + program.setUniform(_gl, '1i', symbol, uniformValue.__slot); + } + } + else if (Array.isArray(uniformValue)) { + if (uniformValue.length === 0) { + continue; + } + // Texture Array + if (uniformType === 'tv') { + if (!program.hasUniform(symbol)) { + continue; + } - var worldM = renderable.isSkinnedMesh() ? matrices.IDENTITY : renderable.worldTransform._array; - var geometry = renderable.geometry; + var arr = []; + for (var i = 0; i < uniformValue.length; i++) { + var texture = uniformValue[i]; - mat4.multiplyAffine(matrices.WORLDVIEW, matrices.VIEW , worldM); + if (texture.__slot < 0) { + var slot = program.currentTextureSlot(); + arr.push(slot); + program.takeCurrentTextureSlot(this, texture); + texture.__slot = slot; + } + else { + arr.push(texture.__slot); + } + } - if (geometry.boundingBox) { - if (this.isFrustumCulled( - renderable, scene, camera, matrices.WORLDVIEW, matrices.PROJECTION - )) { - continue; + program.setUniform(_gl, '1iv', symbol, arr); + } + else { + program.setUniform(_gl, uniform.type, symbol, uniformValue); } } - culledRenderQueue.push(renderable); - if (renderable.skeleton || renderable.ignorePreZ) { // FIXME skinned mesh and custom vertex shader material. - continue; + else{ + program.setUniform(_gl, uniform.type, symbol, uniformValue); } + } + // Texture slot maybe used out of material. + program.resetTextureSlot(currentTextureSlot); + }, - mat4.multiply(matrices.WORLDVIEWPROJECTION, matrices.VIEWPROJECTION , worldM); + _bindVAO: function (vaoExt, shader, geometry, program) { + var isStatic = !geometry.dynamic; + var _gl = this.gl; - if (renderable.cullFace !== cullFace) { - cullFace = renderable.cullFace; - _gl.cullFace(cullFace); + var vaoId = this.__uid__ + '-' + program.__uid__; + var vao = geometry.__vaoCache[vaoId]; + if (!vao) { + var chunks = geometry.getBufferChunks(this); + if (!chunks || !chunks.length) { // Empty mesh + return; } - if (renderable.frontFace !== frontFace) { - frontFace = renderable.frontFace; - _gl.frontFace(frontFace); + var chunk = chunks[0]; + var attributeBuffers = chunk.attributeBuffers; + var indicesBuffer = chunk.indicesBuffer; + + var availableAttributes = []; + var availableAttributeSymbols = []; + for (var a = 0; a < attributeBuffers.length; a++) { + var attributeBufferInfo = attributeBuffers[a]; + var name = attributeBufferInfo.name; + var semantic = attributeBufferInfo.semantic; + var symbol; + if (semantic) { + var semanticInfo = shader.attributeSemantics[semantic]; + symbol = semanticInfo && semanticInfo.symbol; + } + else { + symbol = name; + } + if (symbol && program.attributes[symbol]) { + availableAttributes.push(attributeBufferInfo); + availableAttributeSymbols.push(symbol); + } } - if (renderable.culling !== culling) { - culling = renderable.culling; - culling ? _gl.enable(_gl.CULL_FACE) : _gl.disable(_gl.CULL_FACE); + + vao = new VertexArrayObject( + availableAttributes, + availableAttributeSymbols, + indicesBuffer + ); + + if (isStatic) { + geometry.__vaoCache[vaoId] = vao; } + } - var semanticInfo = preZPassShader.matrixSemantics.WORLDVIEWPROJECTION; - preZPassShader.setUniform(_gl, semanticInfo.type, semanticInfo.symbol, matrices.WORLDVIEWPROJECTION); + var needsBindAttributes = true; - // PENDING If invoke beforeRender hook - renderable.render(this, preZPassMaterial.shader); + // Create vertex object array cost a lot + // So we don't use it on the dynamic object + if (vaoExt && isStatic) { + // Use vertex array object + // http://blog.tojicode.com/2012/10/oesvertexarrayobject-extension.html + if (vao.vao == null) { + vao.vao = vaoExt.createVertexArrayOES(); + } + else { + needsBindAttributes = false; + } + vaoExt.bindVertexArrayOES(vao.vao); } - _gl.depthFunc(_gl.LEQUAL); - _gl.colorMask(true, true, true, true); - _gl.depthMask(true); - return culledRenderQueue; - }, + var availableAttributes = vao.availableAttributes; + var indicesBuffer = vao.indicesBuffer; - /** - * If an scene object is culled by camera frustum - * - * Object can be a renderable or a light - * - * @param {qtek.Node} Scene object - * @param {qtek.Camera} camera - * @param {Array.} worldViewMat represented with array - * @param {Array.} projectionMat represented with array - */ - isFrustumCulled: (function () { - // Frustum culling - // http://www.cse.chalmers.se/~uffe/vfc_bbox.pdf - var cullingBoundingBox = new BoundingBox(); - var cullingMatrix = new Matrix4(); - return function (object, scene, camera, worldViewMat, projectionMat) { - // Bounding box can be a property of object(like light) or renderable.geometry - var geoBBox = object.boundingBox || object.geometry.boundingBox; - cullingMatrix._array = worldViewMat; - cullingBoundingBox.copy(geoBBox); - cullingBoundingBox.applyTransform(cullingMatrix); + if (needsBindAttributes) { + var locationList = program.enableAttributes(this, vao.availableAttributeSymbols, (vaoExt && isStatic && vao)); + // Setting attributes; + for (var a = 0; a < availableAttributes.length; a++) { + var location = locationList[a]; + if (location === -1) { + continue; + } + var attributeBufferInfo = availableAttributes[a]; + var buffer = attributeBufferInfo.buffer; + var size = attributeBufferInfo.size; + var glType = attributeBufferTypeMap[attributeBufferInfo.type] || _gl.FLOAT; - // Passingly update the scene bounding box - // FIXME exclude very large mesh like ground plane or terrain ? - // FIXME Only rendererable which cast shadow ? + _gl.bindBuffer(_gl.ARRAY_BUFFER, buffer); + _gl.vertexAttribPointer(location, size, glType, false, 0, 0); + } - // FIXME boundingBox becomes much larger after transformd. - if (scene && object.isRenderable() && object.castShadow) { - scene.viewBoundingBoxLastFrame.union(cullingBoundingBox); + if (geometry.isUseIndices()) { + _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, indicesBuffer.buffer); } - // Ignore frustum culling if object is skinned mesh. - if (object.frustumCulling && !object.isSkinnedMesh()) { - if (!cullingBoundingBox.intersectBoundingBox(camera.frustum.boundingBox)) { - return true; - } + } - cullingMatrix._array = projectionMat; - if ( - cullingBoundingBox.max._array[2] > 0 && - cullingBoundingBox.min._array[2] < 0 - ) { - // Clip in the near plane - cullingBoundingBox.max._array[2] = -1e-20; - } + return vao; + }, - cullingBoundingBox.applyProjection(cullingMatrix); + renderPreZ: function (list, scene, camera) { + var _gl = this.gl; + var preZPassMaterial = this._prezMaterial || new Material({ + shader: new Shader(Shader.source('clay.prez.vertex'), Shader.source('clay.prez.fragment')) + }); + this._prezMaterial = preZPassMaterial; - var min = cullingBoundingBox.min._array; - var max = cullingBoundingBox.max._array; + _gl.colorMask(false, false, false, false); + _gl.depthMask(true); - if ( - max[0] < -1 || min[0] > 1 - || max[1] < -1 || min[1] > 1 - || max[2] < -1 || min[2] > 1 - ) { - return true; - } - } + // Status + this.renderPass(list, camera, { + ifRender: function (renderable) { + return !renderable.ignorePreZ; + }, + getMaterial: function () { + return preZPassMaterial; + }, + sort: this.opaqueSortCompare + }); - return false; - }; - })(), + _gl.colorMask(true, true, true, true); + _gl.depthMask(true); + }, /** * Dispose given scene, including all geometris, textures and shaders in the scene - * @param {qtek.Scene} scene + * @param {clay.Scene} scene */ disposeScene: function(scene) { this.disposeNode(scene, true, true); @@ -11302,45 +12202,53 @@ var Renderer = Base.extend(function () { /** * Dispose given node, including all geometries, textures and shaders attached on it or its descendant - * @param {qtek.Node} node + * @param {clay.Node} node * @param {boolean} [disposeGeometry=false] If dispose the geometries used in the descendant mesh * @param {boolean} [disposeTexture=false] If dispose the textures used in the descendant mesh */ disposeNode: function(root, disposeGeometry, disposeTexture) { - var materials = {}; // Dettached from parent if (root.getParent()) { root.getParent().remove(root); } + var disposedMap = {}; root.traverse(function(node) { + var material = node.material; if (node.geometry && disposeGeometry) { node.geometry.dispose(this); } - if (node.material) { - materials[node.material.__GUID__] = node.material; + if (disposeTexture && material && !disposedMap[material.__uid__]) { + var textureUniforms = material.getTextureUniforms(); + for (var u = 0; u < textureUniforms.length; u++) { + var uniformName = textureUniforms[u]; + var val = material.uniforms[uniformName].value; + var uniformType = material.uniforms[uniformName].type; + if (!val) { + continue; + } + if (uniformType === 't') { + val.dispose && val.dispose(this); + } + else if (uniformType === 'tv') { + for (var k = 0; k < val.length; k++) { + if (val[k]) { + val[k].dispose && val[k].dispose(this); + } + } + } + } + disposedMap[material.__uid__] = true; } // Particle system and AmbientCubemap light need to dispose if (node.dispose) { node.dispose(this); } }, this); - for (var guid in materials) { - var mat = materials[guid]; - mat.dispose(this, disposeTexture); - } - }, - - /** - * Dispose given shader - * @param {qtek.Shader} shader - */ - disposeShader: function(shader) { - shader.dispose(this); }, /** * Dispose given geometry - * @param {qtek.Geometry} geometry + * @param {clay.Geometry} geometry */ disposeGeometry: function(geometry) { geometry.dispose(this); @@ -11348,7 +12256,7 @@ var Renderer = Base.extend(function () { /** * Dispose given texture - * @param {qtek.Texture} texture + * @param {clay.Texture} texture */ disposeTexture: function(texture) { texture.dispose(this); @@ -11356,7 +12264,7 @@ var Renderer = Base.extend(function () { /** * Dispose given frame buffer - * @param {qtek.FrameBuffer} frameBuffer + * @param {clay.FrameBuffer} frameBuffer */ disposeFrameBuffer: function(frameBuffer) { frameBuffer.dispose(this); @@ -11374,8 +12282,8 @@ var Renderer = Base.extend(function () { * * @param {number} x * @param {number} y - * @param {qtek.math.Vector2} [out] - * @return {qtek.math.Vector2} + * @param {clay.Vector2} [out] + * @return {clay.Vector2} */ screenToNDC: function(x, y, out) { if (!out) { @@ -11385,7 +12293,7 @@ var Renderer = Base.extend(function () { y = this._height - y; var viewport = this.viewport; - var arr = out._array; + var arr = out.array; arr[0] = (x - viewport.x) / viewport.width; arr[0] = arr[0] * 2 - 1; arr[1] = (y - viewport.y) / viewport.height; @@ -11397,44 +12305,50 @@ var Renderer = Base.extend(function () { /** * Opaque renderables compare function - * @param {qtek.Renderable} x - * @param {qtek.Renderable} y + * @param {clay.Renderable} x + * @param {clay.Renderable} y * @return {boolean} * @static */ -Renderer.opaqueSortFunc = Renderer.prototype.opaqueSortFunc = function(x, y) { - // Priority renderOrder -> shader -> material -> geometry +Renderer.opaqueSortCompare = Renderer.prototype.opaqueSortCompare = function(x, y) { + // Priority renderOrder -> program -> material -> geometry if (x.renderOrder === y.renderOrder) { - if (x.material.shader === y.material.shader) { + if (x.__program === y.__program) { if (x.material === y.material) { - return x.geometry.__GUID__ - y.geometry.__GUID__; + return x.geometry.__uid__ - y.geometry.__uid__; } - return x.material.__GUID__ - y.material.__GUID__; + return x.material.__uid__ - y.material.__uid__; } - return x.material.shader.__GUID__ - y.material.shader.__GUID__; + if (x.__program && y.__program) { + return x.__program.__uid__ - y.__program.__uid__; + } + return 0; } return x.renderOrder - y.renderOrder; }; /** * Transparent renderables compare function - * @param {qtek.Renderable} a - * @param {qtek.Renderable} b + * @param {clay.Renderable} a + * @param {clay.Renderable} b * @return {boolean} * @static */ -Renderer.transparentSortFunc = Renderer.prototype.transparentSortFunc = function(x, y) { - // Priority renderOrder -> depth -> shader -> material -> geometry +Renderer.transparentSortCompare = Renderer.prototype.transparentSortCompare = function(x, y) { + // Priority renderOrder -> depth -> program -> material -> geometry if (x.renderOrder === y.renderOrder) { if (x.__depth === y.__depth) { - if (x.material.shader === y.material.shader) { + if (x.__program === y.__program) { if (x.material === y.material) { - return x.geometry.__GUID__ - y.geometry.__GUID__; + return x.geometry.__uid__ - y.geometry.__uid__; } - return x.material.__GUID__ - y.material.__GUID__; + return x.material.__uid__ - y.material.__uid__; } - return x.material.shader.__GUID__ - y.material.shader.__GUID__; + if (x.__program && y.__program) { + return x.__program.__uid__ - y.__program.__uid__; + } + return 0; } // Depth is negative // So farther object has smaller depth value @@ -11446,7 +12360,7 @@ Renderer.transparentSortFunc = Renderer.prototype.transparentSortFunc = function // Temporary variables var matrices = { IDENTITY: mat4Create(), - + WORLD: mat4Create(), VIEW: mat4Create(), PROJECTION: mat4Create(), @@ -11476,17 +12390,17 @@ var matrices = { }; /** - * @name qtek.Renderer.COLOR_BUFFER_BIT + * @name clay.Renderer.COLOR_BUFFER_BIT * @type {number} */ Renderer.COLOR_BUFFER_BIT = glenum.COLOR_BUFFER_BIT; /** - * @name qtek.Renderer.DEPTH_BUFFER_BIT + * @name clay.Renderer.DEPTH_BUFFER_BIT * @type {number} */ Renderer.DEPTH_BUFFER_BIT = glenum.DEPTH_BUFFER_BIT; /** - * @name qtek.Renderer.STENCIL_BUFFER_BIT + * @name clay.Renderer.STENCIL_BUFFER_BIT * @type {number} */ Renderer.STENCIL_BUFFER_BIT = glenum.STENCIL_BUFFER_BIT; @@ -11536,7 +12450,7 @@ var quat$1 = glmatrix.quat; /** * @constructor - * @alias qtek.math.Quaternion + * @alias clay.Quaternion * @param {number} x * @param {number} y * @param {number} z @@ -11550,18 +12464,20 @@ var Quaternion = function (x, y, z, w) { w = w === undefined ? 1 : w; /** - * Storage of Quaternion, read and write of x, y, z, w will change the values in _array - * All methods also operate on the _array instead of x, y, z, w components - * @name _array + * Storage of Quaternion, read and write of x, y, z, w will change the values in array + * All methods also operate on the array instead of x, y, z, w components + * @name array * @type {Float32Array} + * @memberOf clay.Quaternion# */ - this._array = quat$1.fromValues(x, y, z, w); + this.array = quat$1.fromValues(x, y, z, w); /** * Dirty flag is used by the Node to determine * if the matrix is updated to latest * @name _dirty * @type {boolean} + * @memberOf clay.Quaternion# */ this._dirty = true; }; @@ -11572,21 +12488,21 @@ Quaternion.prototype = { /** * Add b to self - * @param {qtek.math.Quaternion} b - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} b + * @return {clay.Quaternion} */ add: function (b) { - quat$1.add(this._array, this._array, b._array); + quat$1.add(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Calculate the w component from x, y, z component - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ calculateW: function () { - quat$1.calculateW(this._array, this._array); + quat$1.calculateW(this.array, this.array); this._dirty = true; return this; }, @@ -11597,13 +12513,13 @@ Quaternion.prototype = { * @param {number} y * @param {number} z * @param {number} w - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ set: function (x, y, z, w) { - this._array[0] = x; - this._array[1] = y; - this._array[2] = z; - this._array[3] = w; + this.array[0] = x; + this.array[1] = y; + this.array[2] = z; + this.array[3] = w; this._dirty = true; return this; }, @@ -11611,13 +12527,13 @@ Quaternion.prototype = { /** * Set x, y, z and w components from array * @param {Float32Array|number[]} arr - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ setArray: function (arr) { - this._array[0] = arr[0]; - this._array[1] = arr[1]; - this._array[2] = arr[2]; - this._array[3] = arr[3]; + this.array[0] = arr[0]; + this.array[1] = arr[1]; + this.array[2] = arr[2]; + this.array[3] = arr[3]; this._dirty = true; return this; @@ -11625,7 +12541,7 @@ Quaternion.prototype = { /** * Clone a new Quaternion - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ clone: function () { return new Quaternion(this.x, this.y, this.z, this.w); @@ -11635,41 +12551,41 @@ Quaternion.prototype = { * Calculates the conjugate of self If the quaternion is normalized, * this function is faster than invert and produces the same result. * - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ conjugate: function () { - quat$1.conjugate(this._array, this._array); + quat$1.conjugate(this.array, this.array); this._dirty = true; return this; }, /** * Copy from b - * @param {qtek.math.Quaternion} b - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} b + * @return {clay.Quaternion} */ copy: function (b) { - quat$1.copy(this._array, b._array); + quat$1.copy(this.array, b.array); this._dirty = true; return this; }, /** * Dot product of self and b - * @param {qtek.math.Quaternion} b + * @param {clay.Quaternion} b * @return {number} */ dot: function (b) { - return quat$1.dot(this._array, b._array); + return quat$1.dot(this.array, b.array); }, /** * Set from the given 3x3 rotation matrix - * @param {qtek.math.Matrix3} m - * @return {qtek.math.Quaternion} + * @param {clay.Matrix3} m + * @return {clay.Quaternion} */ fromMat3: function (m) { - quat$1.fromMat3(this._array, m._array); + quat$1.fromMat3(this.array, m.array); this._dirty = true; return this; }, @@ -11677,17 +12593,17 @@ Quaternion.prototype = { /** * Set from the given 4x4 rotation matrix * The 4th column and 4th row will be droped - * @param {qtek.math.Matrix4} m - * @return {qtek.math.Quaternion} + * @param {clay.Matrix4} m + * @return {clay.Quaternion} */ fromMat4: (function () { var mat3 = glmatrix.mat3; var m3 = mat3.create(); return function (m) { - mat3.fromMat4(m3, m._array); + mat3.fromMat4(m3, m.array); // TODO Not like mat4, mat3 in glmatrix seems to be row-based mat3.transpose(m3, m3); - quat$1.fromMat3(this._array, m3); + quat$1.fromMat3(this.array, m3); this._dirty = true; return this; }; @@ -11695,19 +12611,19 @@ Quaternion.prototype = { /** * Set to identity quaternion - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ identity: function () { - quat$1.identity(this._array); + quat$1.identity(this.array); this._dirty = true; return this; }, /** * Invert self - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ invert: function () { - quat$1.invert(this._array, this._array); + quat$1.invert(this.array, this.array); this._dirty = true; return this; }, @@ -11716,7 +12632,7 @@ Quaternion.prototype = { * @return {number} */ len: function () { - return quat$1.len(this._array); + return quat$1.len(this.array); }, /** @@ -11724,51 +12640,51 @@ Quaternion.prototype = { * @return {number} */ length: function () { - return quat$1.length(this._array); + return quat$1.length(this.array); }, /** * Linear interpolation between a and b - * @param {qtek.math.Quaternion} a - * @param {qtek.math.Quaternion} b + * @param {clay.Quaternion} a + * @param {clay.Quaternion} b * @param {number} t - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ lerp: function (a, b, t) { - quat$1.lerp(this._array, a._array, b._array, t); + quat$1.lerp(this.array, a.array, b.array, t); this._dirty = true; return this; }, /** * Alias for multiply - * @param {qtek.math.Quaternion} b - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} b + * @return {clay.Quaternion} */ mul: function (b) { - quat$1.mul(this._array, this._array, b._array); + quat$1.mul(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Alias for multiplyLeft - * @param {qtek.math.Quaternion} a - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} a + * @return {clay.Quaternion} */ mulLeft: function (a) { - quat$1.multiply(this._array, a._array, this._array); + quat$1.multiply(this.array, a.array, this.array); this._dirty = true; return this; }, /** * Mutiply self and b - * @param {qtek.math.Quaternion} b - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} b + * @return {clay.Quaternion} */ multiply: function (b) { - quat$1.multiply(this._array, this._array, b._array); + quat$1.multiply(this.array, this.array, b.array); this._dirty = true; return this; }, @@ -11776,21 +12692,21 @@ Quaternion.prototype = { /** * Mutiply a and self * Quaternion mutiply is not commutative, so the result of mutiplyLeft is different with multiply. - * @param {qtek.math.Quaternion} a - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} a + * @return {clay.Quaternion} */ multiplyLeft: function (a) { - quat$1.multiply(this._array, a._array, this._array); + quat$1.multiply(this.array, a.array, this.array); this._dirty = true; return this; }, /** * Normalize self - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ normalize: function () { - quat$1.normalize(this._array, this._array); + quat$1.normalize(this.array, this.array); this._dirty = true; return this; }, @@ -11798,10 +12714,10 @@ Quaternion.prototype = { /** * Rotate self by a given radian about X axis * @param {number} rad - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ rotateX: function (rad) { - quat$1.rotateX(this._array, this._array, rad); + quat$1.rotateX(this.array, this.array, rad); this._dirty = true; return this; }, @@ -11809,10 +12725,10 @@ Quaternion.prototype = { /** * Rotate self by a given radian about Y axis * @param {number} rad - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ rotateY: function (rad) { - quat$1.rotateY(this._array, this._array, rad); + quat$1.rotateY(this.array, this.array, rad); this._dirty = true; return this; }, @@ -11820,10 +12736,10 @@ Quaternion.prototype = { /** * Rotate self by a given radian about Z axis * @param {number} rad - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ rotateZ: function (rad) { - quat$1.rotateZ(this._array, this._array, rad); + quat$1.rotateZ(this.array, this.array, rad); this._dirty = true; return this; }, @@ -11831,48 +12747,48 @@ Quaternion.prototype = { /** * Sets self to represent the shortest rotation from Vector3 a to Vector3 b. * a and b needs to be normalized - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b - * @return {qtek.math.Quaternion} + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Quaternion} */ rotationTo: function (a, b) { - quat$1.rotationTo(this._array, a._array, b._array); + quat$1.rotationTo(this.array, a.array, b.array); this._dirty = true; return this; }, /** * Sets self with values corresponding to the given axes - * @param {qtek.math.Vector3} view - * @param {qtek.math.Vector3} right - * @param {qtek.math.Vector3} up - * @return {qtek.math.Quaternion} + * @param {clay.Vector3} view + * @param {clay.Vector3} right + * @param {clay.Vector3} up + * @return {clay.Quaternion} */ setAxes: function (view, right, up) { - quat$1.setAxes(this._array, view._array, right._array, up._array); + quat$1.setAxes(this.array, view.array, right.array, up.array); this._dirty = true; return this; }, /** * Sets self with a rotation axis and rotation angle - * @param {qtek.math.Vector3} axis + * @param {clay.Vector3} axis * @param {number} rad - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ setAxisAngle: function (axis, rad) { - quat$1.setAxisAngle(this._array, axis._array, rad); + quat$1.setAxisAngle(this.array, axis.array, rad); this._dirty = true; return this; }, /** * Perform spherical linear interpolation between a and b - * @param {qtek.math.Quaternion} a - * @param {qtek.math.Quaternion} b + * @param {clay.Quaternion} a + * @param {clay.Quaternion} b * @param {number} t - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ slerp: function (a, b, t) { - quat$1.slerp(this._array, a._array, b._array, t); + quat$1.slerp(this.array, a.array, b.array, t); this._dirty = true; return this; }, @@ -11882,7 +12798,7 @@ Quaternion.prototype = { * @return {number} */ sqrLen: function () { - return quat$1.sqrLen(this._array); + return quat$1.sqrLen(this.array); }, /** @@ -11890,12 +12806,12 @@ Quaternion.prototype = { * @return {number} */ squaredLength: function () { - return quat$1.squaredLength(this._array); + return quat$1.squaredLength(this.array); }, /** * Set from euler - * @param {qtek.math.Vector3} v + * @param {clay.Vector3} v * @param {String} order */ fromEuler: function (v, order) { @@ -11903,11 +12819,11 @@ Quaternion.prototype = { }, toString: function () { - return '[' + Array.prototype.join.call(this._array, ',') + ']'; + return '[' + Array.prototype.join.call(this.array, ',') + ']'; }, toArray: function () { - return Array.prototype.slice.call(this._array); + return Array.prototype.slice.call(this.array); } }; @@ -11919,15 +12835,15 @@ if (defineProperty$2) { /** * @name x * @type {number} - * @memberOf qtek.math.Quaternion + * @memberOf clay.Quaternion * @instance */ defineProperty$2(proto$3, 'x', { get: function () { - return this._array[0]; + return this.array[0]; }, set: function (value) { - this._array[0] = value; + this.array[0] = value; this._dirty = true; } }); @@ -11935,15 +12851,15 @@ if (defineProperty$2) { /** * @name y * @type {number} - * @memberOf qtek.math.Quaternion + * @memberOf clay.Quaternion * @instance */ defineProperty$2(proto$3, 'y', { get: function () { - return this._array[1]; + return this.array[1]; }, set: function (value) { - this._array[1] = value; + this.array[1] = value; this._dirty = true; } }); @@ -11951,15 +12867,15 @@ if (defineProperty$2) { /** * @name z * @type {number} - * @memberOf qtek.math.Quaternion + * @memberOf clay.Quaternion * @instance */ defineProperty$2(proto$3, 'z', { get: function () { - return this._array[2]; + return this.array[2]; }, set: function (value) { - this._array[2] = value; + this.array[2] = value; this._dirty = true; } }); @@ -11967,15 +12883,15 @@ if (defineProperty$2) { /** * @name w * @type {number} - * @memberOf qtek.math.Quaternion + * @memberOf clay.Quaternion * @instance */ defineProperty$2(proto$3, 'w', { get: function () { - return this._array[3]; + return this.array[3]; }, set: function (value) { - this._array[3] = value; + this.array[3] = value; this._dirty = true; } }); @@ -11984,272 +12900,272 @@ if (defineProperty$2) { // Supply methods that are not in place /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Quaternion} a - * @param {qtek.math.Quaternion} b - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} out + * @param {clay.Quaternion} a + * @param {clay.Quaternion} b + * @return {clay.Quaternion} */ Quaternion.add = function (out, a, b) { - quat$1.add(out._array, a._array, b._array); + quat$1.add(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} out + * @param {clay.Quaternion} out * @param {number} x * @param {number} y * @param {number} z * @param {number} w - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ Quaternion.set = function (out, x, y, z, w) { - quat$1.set(out._array, x, y, z, w); + quat$1.set(out.array, x, y, z, w); out._dirty = true; }; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Quaternion} b - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} out + * @param {clay.Quaternion} b + * @return {clay.Quaternion} */ Quaternion.copy = function (out, b) { - quat$1.copy(out._array, b._array); + quat$1.copy(out.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Quaternion} a - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} out + * @param {clay.Quaternion} a + * @return {clay.Quaternion} */ Quaternion.calculateW = function (out, a) { - quat$1.calculateW(out._array, a._array); + quat$1.calculateW(out.array, a.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Quaternion} a - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} out + * @param {clay.Quaternion} a + * @return {clay.Quaternion} */ Quaternion.conjugate = function (out, a) { - quat$1.conjugate(out._array, a._array); + quat$1.conjugate(out.array, a.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} out - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} out + * @return {clay.Quaternion} */ Quaternion.identity = function (out) { - quat$1.identity(out._array); + quat$1.identity(out.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Quaternion} a - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} out + * @param {clay.Quaternion} a + * @return {clay.Quaternion} */ Quaternion.invert = function (out, a) { - quat$1.invert(out._array, a._array); + quat$1.invert(out.array, a.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} a - * @param {qtek.math.Quaternion} b + * @param {clay.Quaternion} a + * @param {clay.Quaternion} b * @return {number} */ Quaternion.dot = function (a, b) { - return quat$1.dot(a._array, b._array); + return quat$1.dot(a.array, b.array); }; /** - * @param {qtek.math.Quaternion} a + * @param {clay.Quaternion} a * @return {number} */ Quaternion.len = function (a) { - return quat$1.length(a._array); + return quat$1.length(a.array); }; // Quaternion.length = Quaternion.len; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Quaternion} a - * @param {qtek.math.Quaternion} b + * @param {clay.Quaternion} out + * @param {clay.Quaternion} a + * @param {clay.Quaternion} b * @param {number} t - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ Quaternion.lerp = function (out, a, b, t) { - quat$1.lerp(out._array, a._array, b._array, t); + quat$1.lerp(out.array, a.array, b.array, t); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Quaternion} a - * @param {qtek.math.Quaternion} b + * @param {clay.Quaternion} out + * @param {clay.Quaternion} a + * @param {clay.Quaternion} b * @param {number} t - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ Quaternion.slerp = function (out, a, b, t) { - quat$1.slerp(out._array, a._array, b._array, t); + quat$1.slerp(out.array, a.array, b.array, t); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Quaternion} a - * @param {qtek.math.Quaternion} b - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} out + * @param {clay.Quaternion} a + * @param {clay.Quaternion} b + * @return {clay.Quaternion} */ Quaternion.mul = function (out, a, b) { - quat$1.multiply(out._array, a._array, b._array); + quat$1.multiply(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @method - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Quaternion} a - * @param {qtek.math.Quaternion} b - * @return {qtek.math.Quaternion} + * @function + * @param {clay.Quaternion} out + * @param {clay.Quaternion} a + * @param {clay.Quaternion} b + * @return {clay.Quaternion} */ Quaternion.multiply = Quaternion.mul; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Quaternion} a + * @param {clay.Quaternion} out + * @param {clay.Quaternion} a * @param {number} rad - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ Quaternion.rotateX = function (out, a, rad) { - quat$1.rotateX(out._array, a._array, rad); + quat$1.rotateX(out.array, a.array, rad); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Quaternion} a + * @param {clay.Quaternion} out + * @param {clay.Quaternion} a * @param {number} rad - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ Quaternion.rotateY = function (out, a, rad) { - quat$1.rotateY(out._array, a._array, rad); + quat$1.rotateY(out.array, a.array, rad); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Quaternion} a + * @param {clay.Quaternion} out + * @param {clay.Quaternion} a * @param {number} rad - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ Quaternion.rotateZ = function (out, a, rad) { - quat$1.rotateZ(out._array, a._array, rad); + quat$1.rotateZ(out.array, a.array, rad); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Vector3} axis + * @param {clay.Quaternion} out + * @param {clay.Vector3} axis * @param {number} rad - * @return {qtek.math.Quaternion} + * @return {clay.Quaternion} */ Quaternion.setAxisAngle = function (out, axis, rad) { - quat$1.setAxisAngle(out._array, axis._array, rad); + quat$1.setAxisAngle(out.array, axis.array, rad); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Quaternion} a - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} out + * @param {clay.Quaternion} a + * @return {clay.Quaternion} */ Quaternion.normalize = function (out, a) { - quat$1.normalize(out._array, a._array); + quat$1.normalize(out.array, a.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} a + * @param {clay.Quaternion} a * @return {number} */ Quaternion.sqrLen = function (a) { - return quat$1.sqrLen(a._array); + return quat$1.sqrLen(a.array); }; /** - * @method - * @param {qtek.math.Quaternion} a + * @function + * @param {clay.Quaternion} a * @return {number} */ Quaternion.squaredLength = Quaternion.sqrLen; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Matrix3} m - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} out + * @param {clay.Matrix3} m + * @return {clay.Quaternion} */ Quaternion.fromMat3 = function (out, m) { - quat$1.fromMat3(out._array, m._array); + quat$1.fromMat3(out.array, m.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Vector3} view - * @param {qtek.math.Vector3} right - * @param {qtek.math.Vector3} up - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} out + * @param {clay.Vector3} view + * @param {clay.Vector3} right + * @param {clay.Vector3} up + * @return {clay.Quaternion} */ Quaternion.setAxes = function (out, view, right, up) { - quat$1.setAxes(out._array, view._array, right._array, up._array); + quat$1.setAxes(out.array, view.array, right.array, up.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b - * @return {qtek.math.Quaternion} + * @param {clay.Quaternion} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Quaternion} */ Quaternion.rotationTo = function (out, a, b) { - quat$1.rotationTo(out._array, a._array, b._array); + quat$1.rotationTo(out.array, a.array, b.array); out._dirty = true; return out; }; /** * Set quaternion from euler - * @param {qtek.math.Quaternion} out - * @param {qtek.math.Vector3} v + * @param {clay.Quaternion} out + * @param {clay.Vector3} v * @param {String} order */ Quaternion.fromEuler = function (out, v, order) { out._dirty = true; - v = v._array; - var target = out._array; + v = v.array; + var target = out.array; var c1 = Math.cos(v[0] / 2); var c2 = Math.cos(v[1] / 2); var c3 = Math.cos(v[2] / 2); @@ -12303,17 +13219,15 @@ Quaternion.fromEuler = function (out, v, order) { } }; -var mat4$3 = glmatrix.mat4; +var mat4$4 = glmatrix.mat4; var nameId = 0; /** - * @constructor qtek.Node - * @extends qtek.core.Base + * @constructor clay.Node + * @extends clay.core.Base */ -var Node = Base.extend( -/** @lends qtek.Node# */ -{ +var Node = Base.extend(/** @lends clay.Node# */{ /** * Scene node name * @type {string} @@ -12322,32 +13236,32 @@ var Node = Base.extend( /** * Position relative to its parent node. aka translation. - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ position: null, /** * Rotation relative to its parent node. Represented by a quaternion - * @type {qtek.math.Quaternion} + * @type {clay.Quaternion} */ rotation: null, /** * Scale relative to its parent node - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ scale: null, /** * Affine transform matrix relative to its root scene. - * @type {qtek.math.Matrix4} + * @type {clay.Matrix4} */ worldTransform: null, /** * Affine transform matrix relative to its parent node. * Composited with position, rotation and scale. - * @type {qtek.math.Matrix4} + * @type {clay.Matrix4} */ localTransform: null, @@ -12359,13 +13273,13 @@ var Node = Base.extend( /** * Parent of current scene node - * @type {?qtek.Node} + * @type {?clay.Node} * @private */ _parent: null, /** * The root scene mounted. Null if it is a isolated node - * @type {?qtek.Scene} + * @type {?clay.Scene} * @private */ _scene: null, @@ -12380,7 +13294,7 @@ var Node = Base.extend( */ _inIterating: false, - // Depth for transparent queue sorting + // Depth for transparent list sorting __depth: 0 }, function () { @@ -12405,11 +13319,11 @@ var Node = Base.extend( this._children = []; }, -/**@lends qtek.Node.prototype. */ +/**@lends clay.Node.prototype. */ { /** - * @type {?qtek.math.Vector3} + * @type {?clay.Vector3} * @instance */ target: null, @@ -12451,12 +13365,9 @@ var Node = Base.extend( /** * Add a child node - * @param {qtek.Node} node + * @param {clay.Node} node */ add: function (node) { - if (this._inIterating) { - console.warn('Add operation can cause unpredictable error when in iterating'); - } var originalParent = node._parent; if (originalParent === this) { return; @@ -12478,12 +13389,9 @@ var Node = Base.extend( /** * Remove the given child scene node - * @param {qtek.Node} node + * @param {clay.Node} node */ remove: function (node) { - if (this._inIterating) { - console.warn('Remove operation can cause unpredictable error when in iterating'); - } var children = this._children; var idx = children.indexOf(node); if (idx < 0) { @@ -12517,7 +13425,7 @@ var Node = Base.extend( /** * Get the scene mounted - * @return {qtek.Scene} + * @return {clay.Scene} */ getScene: function () { return this._scene; @@ -12525,7 +13433,7 @@ var Node = Base.extend( /** * Get parent node - * @return {qtek.Scene} + * @return {clay.Scene} */ getParent: function () { return this._parent; @@ -12543,7 +13451,7 @@ var Node = Base.extend( /** * Return true if it is ancestor of the given scene node - * @param {qtek.Node} node + * @param {clay.Node} node */ isAncestor: function (node) { var parent = node._parent; @@ -12558,7 +13466,7 @@ var Node = Base.extend( /** * Get a new created array of all children nodes - * @return {qtek.Node[]} + * @return {clay.Node[]} */ children: function () { return this._children.slice(); @@ -12567,7 +13475,7 @@ var Node = Base.extend( /** * Get child scene node at given index. * @param {number} idx - * @return {qtek.Node} + * @return {clay.Node} */ childAt: function (idx) { return this._children[idx]; @@ -12576,7 +13484,7 @@ var Node = Base.extend( /** * Get first child with the given name * @param {string} name - * @return {qtek.Node} + * @return {clay.Node} */ getChildByName: function (name) { var children = this._children; @@ -12590,7 +13498,7 @@ var Node = Base.extend( /** * Get first descendant have the given name * @param {string} name - * @return {qtek.Node} + * @return {clay.Node} */ getDescendantByName: function (name) { var children = this._children; @@ -12610,7 +13518,7 @@ var Node = Base.extend( /** * Query descendant node by path * @param {string} path - * @return {qtek.Node} + * @return {clay.Node} * @example * node.queryNode('root/parent/child'); */ @@ -12648,7 +13556,7 @@ var Node = Base.extend( /** * Get query path, relative to rootNode(default is scene) - * @param {qtek.Node} [rootNode] + * @param {clay.Node} [rootNode] * @return {string} */ getPath: function (rootNode) { @@ -12672,47 +13580,42 @@ var Node = Base.extend( }, /** - * Depth first traverse all its descendant scene nodes and + * Depth first traverse all its descendant scene nodes. + * + * **WARN** Don't do `add`, `remove` operation in the callback during traverse. * @param {Function} callback * @param {Node} [context] - * @param {Function} [filter] */ - traverse: function (callback, context, filter) { - - this._inIterating = true; - - if (!filter || filter.call(context, this)) { - callback.call(context, this); - } + traverse: function (callback, context) { + callback.call(context, this); var _children = this._children; for(var i = 0, len = _children.length; i < len; i++) { - _children[i].traverse(callback, context, filter); + _children[i].traverse(callback, context); } - - this._inIterating = false; }, - eachChild: function (callback, context, ctor) { - this._inIterating = true; - + /** + * Traverse all children nodes. + * + * **WARN** DON'T do `add`, `remove` operation in the callback during iteration. + * + * @param {Function} callback + * @param {Node} [context] + */ + eachChild: function (callback, context) { var _children = this._children; - var noCtor = ctor == null; for(var i = 0, len = _children.length; i < len; i++) { var child = _children[i]; - if (noCtor || child.constructor === ctor) { - callback.call(context, child, i); - } + callback.call(context, child, i); } - - this._inIterating = false; }, /** * Set the local transform and decompose to SRT - * @param {qtek.math.Matrix4} matrix + * @param {clay.Matrix4} matrix */ setLocalTransform: function (matrix) { - mat4$3.copy(this.localTransform._array, matrix._array); + mat4$4.copy(this.localTransform.array, matrix.array); this.decomposeLocalTransform(); }, @@ -12726,30 +13629,30 @@ var Node = Base.extend( /** * Set the world transform and decompose to SRT - * @param {qtek.math.Matrix4} matrix + * @param {clay.Matrix4} matrix */ setWorldTransform: function (matrix) { - mat4$3.copy(this.worldTransform._array, matrix._array); + mat4$4.copy(this.worldTransform.array, matrix.array); this.decomposeWorldTransform(); }, /** * Decompose the world transform to SRT - * @method + * @function */ decomposeWorldTransform: (function () { - var tmp = mat4$3.create(); + var tmp = mat4$4.create(); return function (keepScale) { var localTransform = this.localTransform; var worldTransform = this.worldTransform; // Assume world transform is updated if (this._parent) { - mat4$3.invert(tmp, this._parent.worldTransform._array); - mat4$3.multiply(localTransform._array, tmp, worldTransform._array); + mat4$4.invert(tmp, this._parent.worldTransform.array); + mat4$4.multiply(localTransform.array, tmp, worldTransform.array); } else { - mat4$3.copy(localTransform._array, worldTransform._array); + mat4$4.copy(localTransform.array, worldTransform.array); } var scale = !keepScale ? this.scale: null; localTransform.decomposeMatrix(scale, this.rotation, this.position); @@ -12772,12 +13675,12 @@ var Node = Base.extend( var scale = this.scale; if (this.transformNeedsUpdate()) { - var m = this.localTransform._array; + var m = this.localTransform.array; // Transform order, scale->rotation->position - mat4$3.fromRotationTranslation(m, rotation._array, position._array); + mat4$4.fromRotationTranslation(m, rotation.array, position.array); - mat4$3.scale(m, m, scale._array); + mat4$4.scale(m, m, scale.array); rotation._dirty = false; scale._dirty = false; @@ -12792,17 +13695,17 @@ var Node = Base.extend( * @private */ _updateWorldTransformTopDown: function () { - var localTransform = this.localTransform._array; - var worldTransform = this.worldTransform._array; + var localTransform = this.localTransform.array; + var worldTransform = this.worldTransform.array; if (this._parent) { - mat4$3.multiplyAffine( + mat4$4.multiplyAffine( worldTransform, - this._parent.worldTransform._array, + this._parent.worldTransform.array, localTransform ); } else { - mat4$3.copy(worldTransform, localTransform); + mat4$4.copy(worldTransform, localTransform); } }, @@ -12816,7 +13719,8 @@ var Node = Base.extend( && rootNodeIsDirty.getParent().transformNeedsUpdate() ) { rootNodeIsDirty = rootNodeIsDirty.getParent(); - }rootNodeIsDirty.update(); + } + rootNodeIsDirty.update(); }, /** @@ -12847,8 +13751,8 @@ var Node = Base.extend( /** * Get bounding box of node * @param {Function} [filter] - * @param {qtek.math.BoundingBox} [out] - * @return {qtek.math.BoundingBox} + * @param {clay.BoundingBox} [out] + * @return {clay.BoundingBox} */ // TODO Skinning getBoundingBox: (function () { @@ -12861,7 +13765,7 @@ var Node = Base.extend( return function (filter, out) { out = out || new BoundingBox(); filter = filter || defaultFilter; - + if (this._parent) { Matrix4.invert(invWorldTransform, this._parent.worldTransform); } @@ -12877,24 +13781,24 @@ var Node = Base.extend( out.union(tmpBBox); } }, this, defaultFilter); - + return out; }; })(), /** * Get world position, extracted from world transform - * @param {qtek.math.Vector3} [out] - * @return {qtek.math.Vector3} + * @param {clay.Vector3} [out] + * @return {clay.Vector3} */ getWorldPosition: function (out) { // PENDING if (this.transformNeedsUpdate()) { this.updateWorldTransform(); } - var m = this.worldTransform._array; + var m = this.worldTransform.array; if (out) { - var arr = out._array; + var arr = out.array; arr[0] = m[12]; arr[1] = m[13]; arr[2] = m[14]; @@ -12911,6 +13815,7 @@ var Node = Base.extend( */ clone: function () { var node = new this.constructor(); + var children = this._children; node.setName(this.name); @@ -12921,16 +13826,17 @@ var Node = Base.extend( for (var i = 0; i < children.length; i++) { node.add(children[i].clone()); } + return node; }, /** * Rotate the node around a axis by angle degrees, axis passes through point - * @param {qtek.math.Vector3} point Center point - * @param {qtek.math.Vector3} axis Center axis + * @param {clay.Vector3} point Center point + * @param {clay.Vector3} axis Center axis * @param {number} angle Rotation angle * @see http://docs.unity3d.com/Documentation/ScriptReference/Transform.RotateAround.html - * @method + * @function */ rotateAround: (function () { var v = new Vector3(); @@ -12957,10 +13863,10 @@ var Node = Base.extend( })(), /** - * @param {qtek.math.Vector3} target - * @param {qtek.math.Vector3} [up] + * @param {clay.Vector3} target + * @param {clay.Vector3} [up] * @see http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml - * @method + * @function */ lookAt: (function () { var m = new Matrix4(); @@ -12974,11 +13880,11 @@ var Node = Base.extend( }); /** - * @constructor qtek.Light - * @extends qtek.Node + * @constructor clay.Light + * @extends clay.Node */ var Light = Node.extend(function(){ - return /** @lends qtek.Light# */ { + return /** @lends clay.Light# */ { /** * Light RGB color * @type {number[]} @@ -13013,18 +13919,18 @@ var Light = Node.extend(function(){ group: 0 }; }, -/** @lends qtek.Light.prototype. */ +/** @lends clay.Light.prototype. */ { /** * Light type * @type {string} - * @memberOf qtek.Light# + * @memberOf clay.Light# */ type: '', /** - * @return {qtek.Light} - * @memberOf qtek.Light.prototype + * @return {clay.Light} + * @memberOf clay.Light.prototype */ clone: function() { var light = Node.prototype.clone.call(this); @@ -13037,2722 +13943,2540 @@ var Light = Node.extend(function(){ } }); +var vec3$6 = glmatrix.vec3; +var mat4$5 = glmatrix.mat4; +var vec4$1 = glmatrix.vec4; + /** - * @constructor qtek.Scene - * @extends qtek.Node + * @constructor + * @alias clay.Plane + * @param {clay.Vector3} [normal] + * @param {number} [distance] */ -var Scene = Node.extend(function () { - return /** @lends qtek.Scene# */ { - /** - * Global material of scene - * @type {qtek.Material} - */ - material: null, - - /** - * @type {boolean} - */ - autoUpdate: true, - - /** - * Opaque renderable list, it will be updated automatically - * @type {qtek.Renderable[]} - * @readonly - */ - opaqueQueue: [], - - /** - * Opaque renderable list, it will be updated automatically - * @type {qtek.Renderable[]} - * @readonly - */ - transparentQueue: [], - - lights: [], - - - /** - * Scene bounding box in view space. - * Used when camera needs to adujst the near and far plane automatically - * so that the view frustum contains the visible objects as tightly as possible. - * Notice: - * It is updated after rendering (in the step of frustum culling passingly). So may be not so accurate, but saves a lot of calculation - * - * @type {qtek.math.BoundingBox} - */ - viewBoundingBoxLastFrame: new BoundingBox(), - - // Properties to save the light information in the scene - // Will be set in the render function - _lightUniforms: {}, +var Plane = function(normal, distance) { + /** + * Normal of the plane + * @type {clay.Vector3} + */ + this.normal = normal || new Vector3(0, 1, 0); - _lightNumber: { - // groupId: { - // POINT_LIGHT: 0, - // DIRECTIONAL_LIGHT: 0, - // SPOT_LIGHT: 0, - // AMBIENT_LIGHT: 0, - // AMBIENT_SH_LIGHT: 0 - // } - }, + /** + * Constant of the plane equation, used as distance to the origin + * @type {number} + */ + this.distance = distance || 0; +}; - _opaqueObjectCount: 0, - _transparentObjectCount: 0, +Plane.prototype = { - _nodeRepository: {}, + constructor: Plane, - }; -}, function () { - this._scene = this; -}, -/** @lends qtek.Scene.prototype. */ -{ /** - * Add node to scene - * @param {Node} node + * Distance from a given point to the plane + * @param {clay.Vector3} point + * @return {number} */ - addToScene: function (node) { - if (node.name) { - this._nodeRepository[node.name] = node; - } + distanceToPoint: function(point) { + return vec3$6.dot(point.array, this.normal.array) - this.distance; }, /** - * Remove node from scene - * @param {Node} node + * Calculate the projection point on the plane + * @param {clay.Vector3} point + * @param {clay.Vector3} out + * @return {clay.Vector3} */ - removeFromScene: function (node) { - if (node.name) { - delete this._nodeRepository[node.name]; + projectPoint: function(point, out) { + if (!out) { + out = new Vector3(); } + var d = this.distanceToPoint(point); + vec3$6.scaleAndAdd(out.array, point.array, this.normal.array, -d); + out._dirty = true; + return out; }, /** - * Get node by name - * @param {string} name - * @return {Node} - * @DEPRECATED + * Normalize the plane's normal and calculate the distance */ - getNode: function (name) { - return this._nodeRepository[name]; + normalize: function() { + var invLen = 1 / vec3$6.len(this.normal.array); + vec3$6.scale(this.normal.array, invLen); + this.distance *= invLen; }, /** - * Clone a new scene node recursively, including material, skeleton. - * Shader and geometry instances will not been cloned - * @param {qtek.Node} node - * @return {qtek.Node} + * If the plane intersect a frustum + * @param {clay.Frustum} Frustum + * @return {boolean} */ - cloneNode: function (node) { - var newNode = node.clone(); - var materialsMap = {}; + intersectFrustum: function(frustum) { + // Check if all coords of frustum is on plane all under plane + var coords = frustum.vertices; + var normal = this.normal.array; + var onPlane = vec3$6.dot(coords[0].array, normal) > this.distance; + for (var i = 1; i < 8; i++) { + if ((vec3$6.dot(coords[i].array, normal) > this.distance) != onPlane) { + return true; + } + } + }, - var cloneSkeleton = function (current, currentNew) { - if (current.skeleton) { - currentNew.skeleton = current.skeleton.clone(node, newNode); - currentNew.joints = current.joints.slice(); + /** + * Calculate the intersection point between plane and a given line + * @function + * @param {clay.Vector3} start start point of line + * @param {clay.Vector3} end end point of line + * @param {clay.Vector3} [out] + * @return {clay.Vector3} + */ + intersectLine: (function() { + var rd = vec3$6.create(); + return function(start, end, out) { + var d0 = this.distanceToPoint(start); + var d1 = this.distanceToPoint(end); + if ((d0 > 0 && d1 > 0) || (d0 < 0 && d1 < 0)) { + return null; } - if (current.material) { - materialsMap[current.material.__GUID__] = { - oldMat: current.material - }; + // Ray intersection + var pn = this.normal.array; + var d = this.distance; + var ro = start.array; + // direction + vec3$6.sub(rd, end.array, start.array); + vec3$6.normalize(rd, rd); + + var divider = vec3$6.dot(pn, rd); + // ray is parallel to the plane + if (divider === 0) { + return null; } - for (var i = 0; i < current._children.length; i++) { - cloneSkeleton(current._children[i], currentNew._children[i]); + if (!out) { + out = new Vector3(); } + var t = (vec3$6.dot(pn, ro) - d) / divider; + vec3$6.scaleAndAdd(out.array, ro, rd, -t); + out._dirty = true; + return out; + }; + })(), + + /** + * Apply an affine transform matrix to plane + * @function + * @return {clay.Matrix4} + */ + applyTransform: (function() { + var inverseTranspose = mat4$5.create(); + var normalv4 = vec4$1.create(); + var pointv4 = vec4$1.create(); + pointv4[3] = 1; + return function(m4) { + m4 = m4.array; + // Transform point on plane + vec3$6.scale(pointv4, this.normal.array, this.distance); + vec4$1.transformMat4(pointv4, pointv4, m4); + this.distance = vec3$6.dot(pointv4, this.normal.array); + // Transform plane normal + mat4$5.invert(inverseTranspose, m4); + mat4$5.transpose(inverseTranspose, inverseTranspose); + normalv4[3] = 0; + vec3$6.copy(normalv4, this.normal.array); + vec4$1.transformMat4(normalv4, normalv4, inverseTranspose); + vec3$6.copy(this.normal.array, normalv4); }; + })(), + + /** + * Copy from another plane + * @param {clay.Vector3} plane + */ + copy: function(plane) { + vec3$6.copy(this.normal.array, plane.normal.array); + this.normal._dirty = true; + this.distance = plane.distance; + }, + + /** + * Clone a new plane + * @return {clay.Plane} + */ + clone: function() { + var plane = new Plane(); + plane.copy(this); + return plane; + } +}; + +var vec3$5 = glmatrix.vec3; + +var vec3Set$1 = vec3$5.set; +var vec3Copy$1 = vec3$5.copy; +var vec3TranformMat4 = vec3$5.transformMat4; +var mathMin = Math.min; +var mathMax = Math.max; +/** + * @constructor + * @alias clay.Frustum + */ +var Frustum = function() { + + /** + * Eight planes to enclose the frustum + * @type {clay.Plane[]} + */ + this.planes = []; + + for (var i = 0; i < 6; i++) { + this.planes.push(new Plane()); + } + + /** + * Bounding box of frustum + * @type {clay.BoundingBox} + */ + this.boundingBox = new BoundingBox(); + + /** + * Eight vertices of frustum + * @type {Float32Array[]} + */ + this.vertices = []; + for (var i = 0; i < 8; i++) { + this.vertices[i] = vec3$5.fromValues(0, 0, 0); + } +}; + +Frustum.prototype = { + + // http://web.archive.org/web/20120531231005/http://crazyjoke.free.fr/doc/3D/plane%20extraction.pdf + /** + * Set frustum from a projection matrix + * @param {clay.Matrix4} projectionMatrix + */ + setFromProjection: function(projectionMatrix) { + + var planes = this.planes; + var m = projectionMatrix.array; + var m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3]; + var m4 = m[4], m5 = m[5], m6 = m[6], m7 = m[7]; + var m8 = m[8], m9 = m[9], m10 = m[10], m11 = m[11]; + var m12 = m[12], m13 = m[13], m14 = m[14], m15 = m[15]; + + // Update planes + vec3Set$1(planes[0].normal.array, m3 - m0, m7 - m4, m11 - m8); + planes[0].distance = -(m15 - m12); + planes[0].normalize(); + + vec3Set$1(planes[1].normal.array, m3 + m0, m7 + m4, m11 + m8); + planes[1].distance = -(m15 + m12); + planes[1].normalize(); + + vec3Set$1(planes[2].normal.array, m3 + m1, m7 + m5, m11 + m9); + planes[2].distance = -(m15 + m13); + planes[2].normalize(); + + vec3Set$1(planes[3].normal.array, m3 - m1, m7 - m5, m11 - m9); + planes[3].distance = -(m15 - m13); + planes[3].normalize(); + + vec3Set$1(planes[4].normal.array, m3 - m2, m7 - m6, m11 - m10); + planes[4].distance = -(m15 - m14); + planes[4].normalize(); - cloneSkeleton(node, newNode); + vec3Set$1(planes[5].normal.array, m3 + m2, m7 + m6, m11 + m10); + planes[5].distance = -(m15 + m14); + planes[5].normalize(); - for (var guid in materialsMap) { - materialsMap[guid].newMat = materialsMap[guid].oldMat.clone(); + // Perspective projection + var boundingBox = this.boundingBox; + var vertices = this.vertices; + if (m15 === 0) { + var aspect = m5 / m0; + var zNear = -m14 / (m10 - 1); + var zFar = -m14 / (m10 + 1); + var farY = -zFar / m5; + var nearY = -zNear / m5; + // Update bounding box + boundingBox.min.set(-farY * aspect, -farY, zFar); + boundingBox.max.set(farY * aspect, farY, zNear); + // update vertices + //--- min z + // min x + vec3Set$1(vertices[0], -farY * aspect, -farY, zFar); + vec3Set$1(vertices[1], -farY * aspect, farY, zFar); + // max x + vec3Set$1(vertices[2], farY * aspect, -farY, zFar); + vec3Set$1(vertices[3], farY * aspect, farY, zFar); + //-- max z + vec3Set$1(vertices[4], -nearY * aspect, -nearY, zNear); + vec3Set$1(vertices[5], -nearY * aspect, nearY, zNear); + vec3Set$1(vertices[6], nearY * aspect, -nearY, zNear); + vec3Set$1(vertices[7], nearY * aspect, nearY, zNear); } + else { // Orthographic projection + var left = (-1 - m12) / m0; + var right = (1 - m12) / m0; + var top = (1 - m13) / m5; + var bottom = (-1 - m13) / m5; + var near = (-1 - m14) / m10; + var far = (1 - m14) / m10; - // Replace material - newNode.traverse(function (current) { - if (current.material) { - current.material = materialsMap[current.material.__GUID__].newMat; - } - }); - return newNode; - }, + boundingBox.min.set(Math.min(left, right), Math.min(bottom, top), Math.min(far, near)); + boundingBox.max.set(Math.max(right, left), Math.max(top, bottom), Math.max(near, far)); + var min = boundingBox.min.array; + var max = boundingBox.max.array; + //--- min z + // min x + vec3Set$1(vertices[0], min[0], min[1], min[2]); + vec3Set$1(vertices[1], min[0], max[1], min[2]); + // max x + vec3Set$1(vertices[2], max[0], min[1], min[2]); + vec3Set$1(vertices[3], max[0], max[1], min[2]); + //-- max z + vec3Set$1(vertices[4], min[0], min[1], max[2]); + vec3Set$1(vertices[5], min[0], max[1], max[2]); + vec3Set$1(vertices[6], max[0], min[1], max[2]); + vec3Set$1(vertices[7], max[0], max[1], max[2]); + } + }, /** - * Scene update - * @param {boolean} force - * @param {boolean} notUpdateLights - * Useful in deferred pipeline + * Apply a affine transform matrix and set to the given bounding box + * @function + * @param {clay.BoundingBox} + * @param {clay.Matrix4} + * @return {clay.BoundingBox} */ - update: function (force, notUpdateLights) { - if (!(this.autoUpdate || force)) { - return; - } - Node.prototype.update.call(this, force); + getTransformedBoundingBox: (function() { - var lights = this.lights; - var sceneMaterialTransparent = this.material && this.material.transparent; + var tmpVec3 = vec3$5.create(); - this._opaqueObjectCount = 0; - this._transparentObjectCount = 0; + return function(bbox, matrix) { + var vertices = this.vertices; - lights.length = 0; + var m4 = matrix.array; + var min = bbox.min; + var max = bbox.max; + var minArr = min.array; + var maxArr = max.array; + var v = vertices[0]; + vec3TranformMat4(tmpVec3, v, m4); + vec3Copy$1(minArr, tmpVec3); + vec3Copy$1(maxArr, tmpVec3); - this._updateRenderQueue(this, sceneMaterialTransparent); + for (var i = 1; i < 8; i++) { + v = vertices[i]; + vec3TranformMat4(tmpVec3, v, m4); - this.opaqueQueue.length = this._opaqueObjectCount; - this.transparentQueue.length = this._transparentObjectCount; + minArr[0] = mathMin(tmpVec3[0], minArr[0]); + minArr[1] = mathMin(tmpVec3[1], minArr[1]); + minArr[2] = mathMin(tmpVec3[2], minArr[2]); - // reset - if (!notUpdateLights) { - var lightNumber = this._lightNumber; - // Reset light numbers - for (var group in lightNumber) { - for (var type in lightNumber[group]) { - lightNumber[group][type] = 0; - } - } - for (var i = 0; i < lights.length; i++) { - var light = lights[i]; - var group = light.group; - if (!lightNumber[group]) { - lightNumber[group] = {}; - } - // User can use any type of light - lightNumber[group][light.type] = lightNumber[group][light.type] || 0; - lightNumber[group][light.type]++; + maxArr[0] = mathMax(tmpVec3[0], maxArr[0]); + maxArr[1] = mathMax(tmpVec3[1], maxArr[1]); + maxArr[2] = mathMax(tmpVec3[2], maxArr[2]); } - // PENDING Remove unused group? - - this._updateLightUniforms(); - } - }, - // Traverse the scene and add the renderable - // object to the render queue - _updateRenderQueue: function (parent, sceneMaterialTransparent) { - if (parent.invisible) { - return; - } + min._dirty = true; + max._dirty = true; - for (var i = 0; i < parent._children.length; i++) { - var child = parent._children[i]; + return bbox; + }; + }) () +}; - if (child instanceof Light) { - this.lights.push(child); - } - if (child.isRenderable()) { - if (child.material.transparent || sceneMaterialTransparent) { - this.transparentQueue[this._transparentObjectCount++] = child; - } - else { - this.opaqueQueue[this._opaqueObjectCount++] = child; - } - } - if (child._children.length > 0) { - this._updateRenderQueue(child); - } - } - }, +var vec3$7 = glmatrix.vec3; - _updateLightUniforms: function () { - var lights = this.lights; - // Put the light cast shadow before the light not cast shadow - lights.sort(lightSortFunc); +var EPSILON = 1e-5; - var lightUniforms = this._lightUniforms; - for (var group in lightUniforms) { - for (var symbol in lightUniforms[group]) { - lightUniforms[group][symbol].value.length = 0; - } - } - for (var i = 0; i < lights.length; i++) { +/** + * @constructor + * @alias clay.Ray + * @param {clay.Vector3} [origin] + * @param {clay.Vector3} [direction] + */ +var Ray = function (origin, direction) { + /** + * @type {clay.Vector3} + */ + this.origin = origin || new Vector3(); + /** + * @type {clay.Vector3} + */ + this.direction = direction || new Vector3(); +}; - var light = lights[i]; - var group = light.group; +Ray.prototype = { - for (var symbol in light.uniformTemplates) { + constructor: Ray, - var uniformTpl = light.uniformTemplates[symbol]; - if (!lightUniforms[group]) { - lightUniforms[group] = {}; - } - if (!lightUniforms[group][symbol]) { - lightUniforms[group][symbol] = { - type: '', - value: [] - }; - } - var value = uniformTpl.value(light); - var lu = lightUniforms[group][symbol]; - lu.type = uniformTpl.type + 'v'; - switch (uniformTpl.type) { - case '1i': - case '1f': - case 't': - lu.value.push(value); - break; - case '2f': - case '3f': - case '4f': - for (var j =0; j < value.length; j++) { - lu.value.push(value[j]); - } - break; - default: - console.error('Unkown light uniform type ' + uniformTpl.type); - } - } - } - }, - + // http://www.siggraph.org/education/materials/HyperGraph/raytrace/rayplane_intersection.htm /** - * Determine if light group of the shader is different from scene's - * Used to determine whether to update shader and scene's uniforms in Renderer.render - * @param {Shader} shader - * @returns {Boolean} + * Calculate intersection point between ray and a give plane + * @param {clay.Plane} plane + * @param {clay.Vector3} [out] + * @return {clay.Vector3} */ - isShaderLightNumberChanged: function (shader) { - var group = shader.lightGroup; - // PENDING Performance - for (var type in this._lightNumber[group]) { - if (this._lightNumber[group][type] !== shader.lightNumber[type]) { - return true; - } + intersectPlane: function (plane, out) { + var pn = plane.normal.array; + var d = plane.distance; + var ro = this.origin.array; + var rd = this.direction.array; + + var divider = vec3$7.dot(pn, rd); + // ray is parallel to the plane + if (divider === 0) { + return null; } - for (var type in shader.lightNumber) { - if (this._lightNumber[group][type] !== shader.lightNumber[type]) { - return true; - } + if (!out) { + out = new Vector3(); } - return false; + var t = (vec3$7.dot(pn, ro) - d) / divider; + vec3$7.scaleAndAdd(out.array, ro, rd, -t); + out._dirty = true; + return out; }, /** - * Set shader's light group with scene's - * @param {Shader} shader + * Mirror the ray against plane + * @param {clay.Plane} plane */ - setShaderLightNumber: function (shader) { - var group = shader.lightGroup; - for (var type in this._lightNumber[group]) { - shader.lightNumber[type] = this._lightNumber[group][type]; - } - shader.dirty(); + mirrorAgainstPlane: function (plane) { + // Distance to plane + var d = vec3$7.dot(plane.normal.array, this.direction.array); + vec3$7.scaleAndAdd(this.direction.array, this.direction.array, plane.normal.array, -d * 2); + this.direction._dirty = true; }, - setLightUniforms: function (shader, renderer) { - var group = shader.lightGroup; - for (var symbol in this._lightUniforms[group]) { - var lu = this._lightUniforms[group][symbol]; - if (lu.type === 'tv') { - for (var i = 0; i < lu.value.length; i++) { - var texture = lu.value[i]; - var slot = shader.currentTextureSlot(); - var result = shader.setUniform(renderer.gl, '1i', symbol, slot); - if (result) { - shader.takeCurrentTextureSlot(renderer, texture); - } - } - } - else { - shader.setUniform(renderer.gl, lu.type, symbol, lu.value); + distanceToPoint: (function () { + var v = vec3$7.create(); + return function (point) { + vec3$7.sub(v, point, this.origin.array); + // Distance from projection point to origin + var b = vec3$7.dot(v, this.direction.array); + if (b < 0) { + return vec3$7.distance(this.origin.array, point); } - } - }, + // Squared distance from center to origin + var c2 = vec3$7.lenSquared(v); + // Squared distance from center to projection point + return Math.sqrt(c2 - b * b); + }; + })(), /** - * Dispose self, clear all the scene objects - * But resources of gl like texuture, shader will not be disposed. - * Mostly you should use disposeScene method in Renderer to do dispose. + * Calculate intersection point between ray and sphere + * @param {clay.Vector3} center + * @param {number} radius + * @param {clay.Vector3} out + * @return {clay.Vector3} */ - dispose: function () { - this.material = null; - this.opaqueQueue = []; - this.transparentQueue = []; - - this.lights = []; - - this._lightUniforms = {}; - - this._lightNumber = {}; - this._nodeRepository = {}; - } -}); - -function lightSortFunc(a, b) { - if (b.castShadow && !a.castShadow) { - return true; - } -} - -var standardEssl = "\n@export qtek.standard.vertex\n#define SHADER_NAME standard\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\n#if defined(AOMAP_ENABLED)\nattribute vec2 texcoord2 : TEXCOORD_1;\n#endif\nattribute vec3 normal : NORMAL;\nattribute vec4 tangent : TANGENT;\n#ifdef VERTEX_COLOR\nattribute vec4 color : COLOR;\n#endif\nattribute vec3 barycentric;\n@import qtek.chunk.skinning_header\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nvarying vec3 v_Barycentric;\n#if defined(PARALLAXOCCLUSIONMAP_ENABLED) || defined(NORMALMAP_ENABLED)\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\n#endif\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\n#if defined(AOMAP_ENABLED)\nvarying vec2 v_Texcoord2;\n#endif\nvoid main()\n{\n vec3 skinnedPosition = position;\n vec3 skinnedNormal = normal;\n vec3 skinnedTangent = tangent.xyz;\n#ifdef SKINNING\n @import qtek.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n skinnedTangent = (skinMatrixWS * vec4(tangent.xyz, 0.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_WorldPosition = (world * vec4(skinnedPosition, 1.0)).xyz;\n v_Barycentric = barycentric;\n v_Normal = normalize((worldInverseTranspose * vec4(skinnedNormal, 0.0)).xyz);\n#if defined(PARALLAXOCCLUSIONMAP_ENABLED) || defined(NORMALMAP_ENABLED)\n v_Tangent = normalize((worldInverseTranspose * vec4(skinnedTangent, 0.0)).xyz);\n v_Bitangent = normalize(cross(v_Normal, v_Tangent) * tangent.w);\n#endif\n#ifdef VERTEX_COLOR\n v_Color = color;\n#endif\n#if defined(AOMAP_ENABLED)\n v_Texcoord2 = texcoord2;\n#endif\n}\n@end\n@export qtek.standard.fragment\n#define PI 3.14159265358979\n#define GLOSSINESS_CHANNEL 0\n#define ROUGHNESS_CHANNEL 0\n#define METALNESS_CHANNEL 1\nuniform mat4 viewInverse : VIEWINVERSE;\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n#if defined(PARALLAXOCCLUSIONMAP_ENABLED) || defined(NORMALMAP_ENABLED)\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\n#endif\n#ifdef NORMALMAP_ENABLED\nuniform sampler2D normalMap;\n#endif\n#ifdef DIFFUSEMAP_ENABLED\nuniform sampler2D diffuseMap;\n#endif\n#ifdef SPECULARMAP_ENABLED\nuniform sampler2D specularMap;\n#endif\n#ifdef USE_ROUGHNESS\nuniform float roughness : 0.5;\n #ifdef ROUGHNESSMAP_ENABLED\nuniform sampler2D roughnessMap;\n #endif\n#else\nuniform float glossiness: 0.5;\n #ifdef GLOSSINESSMAP_ENABLED\nuniform sampler2D glossinessMap;\n #endif\n#endif\n#ifdef METALNESSMAP_ENABLED\nuniform sampler2D metalnessMap;\n#endif\n#ifdef ENVIRONMENTMAP_ENABLED\nuniform samplerCube environmentMap;\n #ifdef PARALLAX_CORRECTED\nuniform vec3 environmentBoxMin;\nuniform vec3 environmentBoxMax;\n #endif\n#endif\n#ifdef BRDFLOOKUP_ENABLED\nuniform sampler2D brdfLookup;\n#endif\n#ifdef EMISSIVEMAP_ENABLED\nuniform sampler2D emissiveMap;\n#endif\n#ifdef SSAOMAP_ENABLED\nuniform sampler2D ssaoMap;\nuniform vec4 viewport : VIEWPORT;\n#endif\n#ifdef AOMAP_ENABLED\nuniform sampler2D aoMap;\nuniform float aoIntensity;\nvarying vec2 v_Texcoord2;\n#endif\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\n#ifdef USE_METALNESS\nuniform float metalness : 0.0;\n#else\nuniform vec3 specularColor : [0.1, 0.1, 0.1];\n#endif\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float emissionIntensity: 1;\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\nvarying vec3 v_Barycentric;\n#ifdef ENVIRONMENTMAP_PREFILTER\nuniform float maxMipmapLevel: 5;\n#endif\n#ifdef AMBIENT_LIGHT_COUNT\n@import qtek.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import qtek.header.ambient_sh_light\n#endif\n#ifdef AMBIENT_CUBEMAP_LIGHT_COUNT\n@import qtek.header.ambient_cubemap_light\n#endif\n#ifdef POINT_LIGHT_COUNT\n@import qtek.header.point_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import qtek.header.directional_light\n#endif\n#ifdef SPOT_LIGHT_COUNT\n@import qtek.header.spot_light\n#endif\n@import qtek.util.calculate_attenuation\n@import qtek.util.edge_factor\n@import qtek.util.rgbm\n@import qtek.util.srgb\n@import qtek.plugin.compute_shadow_map\n@import qtek.util.parallax_correct\nfloat G_Smith(float g, float ndv, float ndl)\n{\n float roughness = 1.0 - g;\n float k = roughness * roughness / 2.0;\n float G1V = ndv / (ndv * (1.0 - k) + k);\n float G1L = ndl / (ndl * (1.0 - k) + k);\n return G1L * G1V;\n}\nvec3 F_Schlick(float ndv, vec3 spec) {\n return spec + (1.0 - spec) * pow(1.0 - ndv, 5.0);\n}\nfloat D_Phong(float g, float ndh) {\n float a = pow(8192.0, g);\n return (a + 2.0) / 8.0 * pow(ndh, a);\n}\nfloat D_GGX(float g, float ndh) {\n float r = 1.0 - g;\n float a = r * r;\n float tmp = ndh * ndh * (a - 1.0) + 1.0;\n return a / (PI * tmp * tmp);\n}\n#ifdef PARALLAXOCCLUSIONMAP_ENABLED\nuniform float parallaxOcclusionScale : 0.02;\nuniform float parallaxMaxLayers : 20;\nuniform float parallaxMinLayers : 5;\nuniform sampler2D parallaxOcclusionMap;\nmat3 transpose(in mat3 inMat)\n{\n vec3 i0 = inMat[0];\n vec3 i1 = inMat[1];\n vec3 i2 = inMat[2];\n return mat3(\n vec3(i0.x, i1.x, i2.x),\n vec3(i0.y, i1.y, i2.y),\n vec3(i0.z, i1.z, i2.z)\n );\n}\nvec2 parallaxUv(vec2 uv, vec3 viewDir)\n{\n float numLayers = mix(parallaxMaxLayers, parallaxMinLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));\n float layerHeight = 1.0 / numLayers;\n float curLayerHeight = 0.0;\n vec2 deltaUv = viewDir.xy * parallaxOcclusionScale / (viewDir.z * numLayers);\n vec2 curUv = uv;\n float height = 1.0 - texture2D(parallaxOcclusionMap, curUv).r;\n for (int i = 0; i < 30; i++) {\n curLayerHeight += layerHeight;\n curUv -= deltaUv;\n height = 1.0 - texture2D(parallaxOcclusionMap, curUv).r;\n if (height < curLayerHeight) {\n break;\n }\n }\n vec2 prevUv = curUv + deltaUv;\n float next = height - curLayerHeight;\n float prev = 1.0 - texture2D(parallaxOcclusionMap, prevUv).r - curLayerHeight + layerHeight;\n return mix(curUv, prevUv, next / (next - prev));\n}\n#endif\nvoid main()\n{\n vec4 albedoColor = vec4(color, alpha);\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = normalize(eyePos - v_WorldPosition);\n vec2 uv = v_Texcoord;\n#if defined(PARALLAXOCCLUSIONMAP_ENABLED) || defined(NORMALMAP_ENABLED)\n mat3 tbn = mat3(v_Tangent, v_Bitangent, v_Normal);\n#endif\n#ifdef PARALLAXOCCLUSIONMAP_ENABLED\n uv = parallaxUv(v_Texcoord, normalize(transpose(tbn) * -V));\n#endif\n#ifdef DIFFUSEMAP_ENABLED\n vec4 texel = texture2D(diffuseMap, uv);\n #ifdef SRGB_DECODE\n texel = sRGBToLinear(texel);\n #endif\n albedoColor.rgb *= texel.rgb;\n #ifdef DIFFUSEMAP_ALPHA_ALPHA\n albedoColor.a *= texel.a;\n #endif\n#endif\n#ifdef USE_METALNESS\n float m = metalness;\n #ifdef METALNESSMAP_ENABLED\n float m2 = texture2D(metalnessMap, uv)[METALNESS_CHANNEL];\n m = clamp(m2 + (m - 0.5) * 2.0, 0.0, 1.0);\n #endif\n vec3 baseColor = albedoColor.rgb;\n albedoColor.rgb = baseColor * (1.0 - m);\n vec3 spec = mix(vec3(0.04), baseColor, m);\n#else\n vec3 spec = specularColor;\n#endif\n#ifdef USE_ROUGHNESS\n float g = 1.0 - roughness;\n #ifdef ROUGHNESSMAP_ENABLED\n float g2 = 1.0 - texture2D(roughnessMap, uv)[ROUGHNESS_CHANNEL];\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n #endif\n#else\n float g = glossiness;\n #ifdef GLOSSINESSMAP_ENABLED\n float g2 = texture2D(glossinessMap, uv)[GLOSSINESS_CHANNEL];\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n #endif\n#endif\n#ifdef SPECULARMAP_ENABLED\n spec *= sRGBToLinear(texture2D(specularMap, uv)).rgb;\n#endif\n vec3 N = v_Normal;\n#ifdef DOUBLE_SIDED\n if (dot(N, V) < 0.0) {\n N = -N;\n }\n#endif\n#ifdef NORMALMAP_ENABLED\n if (dot(v_Tangent, v_Tangent) > 0.0) {\n vec3 normalTexel = texture2D(normalMap, uv).xyz;\n if (dot(normalTexel, normalTexel) > 0.0) { N = normalTexel * 2.0 - 1.0;\n tbn[1] = -tbn[1];\n N = normalize(tbn * N);\n }\n }\n#endif\n vec3 diffuseTerm = vec3(0.0, 0.0, 0.0);\n vec3 specularTerm = vec3(0.0, 0.0, 0.0);\n float ndv = clamp(dot(N, V), 0.0, 1.0);\n vec3 fresnelTerm = F_Schlick(ndv, spec);\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {{\n diffuseTerm += ambientLightColor[_idx_];\n }}\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseTerm += calcAmbientSHLight(_idx_, N) * ambientSHLightColor[_idx_];\n }}\n#endif\n#ifdef POINT_LIGHT_COUNT\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsPoint[POINT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfPointLights(v_WorldPosition, shadowContribsPoint);\n }\n#endif\n for(int _idx_ = 0; _idx_ < POINT_LIGHT_COUNT; _idx_++)\n {{\n vec3 lightPosition = pointLightPosition[_idx_];\n vec3 lc = pointLightColor[_idx_];\n float range = pointLightRange[_idx_];\n vec3 L = lightPosition - v_WorldPosition;\n float dist = length(L);\n float attenuation = lightAttenuation(dist, range);\n L /= dist;\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n if(shadowEnabled)\n {\n shadowContrib = shadowContribsPoint[_idx_];\n }\n#endif\n vec3 li = lc * ndl * attenuation * shadowContrib;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }}\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int _idx_ = 0; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++)\n {{\n vec3 L = -normalize(directionalLightDirection[_idx_]);\n vec3 lc = directionalLightColor[_idx_];\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if(shadowEnabled)\n {\n shadowContrib = shadowContribsDir[_idx_];\n }\n#endif\n vec3 li = lc * ndl * shadowContrib;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }}\n#endif\n#ifdef SPOT_LIGHT_COUNT\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsSpot[SPOT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfSpotLights(v_WorldPosition, shadowContribsSpot);\n }\n#endif\n for(int i = 0; i < SPOT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = spotLightPosition[i];\n vec3 spotLightDirection = -normalize(spotLightDirection[i]);\n vec3 lc = spotLightColor[i];\n float range = spotLightRange[i];\n float a = spotLightUmbraAngleCosine[i];\n float b = spotLightPenumbraAngleCosine[i];\n float falloffFactor = spotLightFalloffFactor[i];\n vec3 L = lightPosition - v_WorldPosition;\n float dist = length(L);\n float attenuation = lightAttenuation(dist, range);\n L /= dist;\n float c = dot(spotLightDirection, L);\n float falloff;\n falloff = clamp((c - a) /( b - a), 0.0, 1.0);\n falloff = pow(falloff, falloffFactor);\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n if (shadowEnabled)\n {\n shadowContrib = shadowContribsSpot[i];\n }\n#endif\n vec3 li = lc * attenuation * (1.0 - falloff) * shadowContrib * ndl;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }\n#endif\n vec4 outColor = albedoColor;\n outColor.rgb *= diffuseTerm;\n outColor.rgb += specularTerm;\n#ifdef AMBIENT_CUBEMAP_LIGHT_COUNT\n vec3 L = reflect(-V, N);\n float rough2 = clamp(1.0 - g, 0.0, 1.0);\n float bias2 = rough2 * 5.0;\n vec2 brdfParam2 = texture2D(ambientCubemapLightBRDFLookup[0], vec2(rough2, ndv)).xy;\n vec3 envWeight2 = spec * brdfParam2.x + brdfParam2.y;\n vec3 envTexel2;\n for(int _idx_ = 0; _idx_ < AMBIENT_CUBEMAP_LIGHT_COUNT; _idx_++)\n {{\n envTexel2 = RGBMDecode(textureCubeLodEXT(ambientCubemapLightCubemap[_idx_], L, bias2), 51.5);\n outColor.rgb += ambientCubemapLightColor[_idx_] * envTexel2 * envWeight2;\n }}\n#endif\n#ifdef ENVIRONMENTMAP_ENABLED\n vec3 envWeight = g * fresnelTerm;\n vec3 L = reflect(-V, N);\n #ifdef PARALLAX_CORRECTED\n L = parallaxCorrect(L, v_WorldPosition, environmentBoxMin, environmentBoxMax);\n #endif\n #ifdef ENVIRONMENTMAP_PREFILTER\n float rough = clamp(1.0 - g, 0.0, 1.0);\n float bias = rough * maxMipmapLevel;\n vec3 envTexel = decodeHDR(textureCubeLodEXT(environmentMap, L, bias)).rgb;\n #ifdef BRDFLOOKUP_ENABLED\n vec2 brdfParam = texture2D(brdfLookup, vec2(rough, ndv)).xy;\n envWeight = spec * brdfParam.x + brdfParam.y;\n #endif\n #else\n vec3 envTexel = textureCube(environmentMap, L).xyz;\n #endif\n outColor.rgb += envTexel * envWeight;\n#endif\n float aoFactor = 1.0;\n#ifdef SSAOMAP_ENABLED\n aoFactor = min(texture2D(ssaoMap, (gl_FragCoord.xy - viewport.xy) / viewport.zw).r, aoFactor);\n#endif\n#ifdef AOMAP_ENABLED\n aoFactor = min(1.0 - clamp((1.0 - texture2D(aoMap, v_Texcoord2).r) * aoIntensity, 0.0, 1.0), aoFactor);\n#endif\n outColor.rgb *= aoFactor;\n vec3 lEmission = emission;\n#ifdef EMISSIVEMAP_ENABLED\n lEmission *= texture2D(emissiveMap, uv).rgb;\n#endif\n outColor.rgb += lEmission * emissionIntensity;\n#ifdef GAMMA_ENCODE\n outColor.rgb = pow(outColor.rgb, vec3(1 / 2.2));\n#endif\n if(lineWidth > 0.)\n {\n outColor.rgb = mix(outColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (outColor.a < alphaCutoff) {\n discard;\n }\n#endif\n gl_FragColor = encodeHDR(outColor);\n}\n@end\n"; - -// Import standard shader -Shader['import'](standardEssl); - -var shaderLibrary = {}; -var shaderUsedCount = {}; - -var TEXTURE_PROPERTIES = ['diffuseMap', 'normalMap', 'roughnessMap', 'metalnessMap', 'emissiveMap', 'environmentMap', 'brdfLookup', 'ssaoMap', 'aoMap']; -var SIMPLE_PROPERTIES = ['color', 'emission', 'emissionIntensity', 'alpha', 'roughness', 'metalness', 'uvRepeat', 'uvOffset', 'aoIntensity', 'alphaCutoff']; -var PROPERTIES_CHANGE_SHADER = ['jointCount', 'linear', 'encodeRGBM', 'decodeRGBM', 'doubleSided', 'alphaTest', 'roughnessChannel', 'metalnessChannel']; - -var OTHER_SHADER_KEYS = [ - 'environmentMapPrefiltered', - 'linear', - 'encodeRGBM', - 'decodeRGBM', - 'doubleSided', - 'alphaTest', - 'parallaxCorrected' -]; -var SHADER_KEYS = TEXTURE_PROPERTIES.concat(OTHER_SHADER_KEYS); - -var KEY_OFFSETS = SHADER_KEYS.reduce(function (obj, name, idx) { - obj[name] = 4096 << idx; - return obj; -}, {}); - -function makeKey(enabledMaps, jointCount, shaderDefines) { - // jointCount from 0 to 255 - var key = jointCount; - // roughnessChannel from 256 to 1024 - // metalnessChannel from 1024 to 4096 - key += 256 * shaderDefines.roughnessChannel; - key += 1024 * shaderDefines.metalnessChannel; + intersectSphere: (function () { + var v = vec3$7.create(); + return function (center, radius, out) { + var origin = this.origin.array; + var direction = this.direction.array; + center = center.array; + vec3$7.sub(v, center, origin); + // Distance from projection point to origin + var b = vec3$7.dot(v, direction); + // Squared distance from center to origin + var c2 = vec3$7.squaredLength(v); + // Squared distance from center to projection point + var d2 = c2 - b * b; - for (var i = 0; i < enabledMaps.length; i++) { - key += KEY_OFFSETS[enabledMaps[i]]; - } - for (var i = 0; i < OTHER_SHADER_KEYS.length; i++) { - var propName = OTHER_SHADER_KEYS[i]; - if (shaderDefines[propName]) { - key += KEY_OFFSETS[propName]; - } - } + var r2 = radius * radius; + // No intersection + if (d2 > r2) { + return; + } - return key; -} + var a = Math.sqrt(r2 - d2); + // First intersect point + var t0 = b - a; + // Second intersect point + var t1 = b + a; -function allocateShader(renderer, enabledMaps, jointCount, shaderDefines) { - var key = makeKey(enabledMaps, jointCount, shaderDefines); - if (!shaderUsedCount[renderer.__GUID__]) { - shaderUsedCount[renderer.__GUID__] = {}; - } + if (!out) { + out = new Vector3(); + } + if (t0 < 0) { + if (t1 < 0) { + return null; + } + else { + vec3$7.scaleAndAdd(out.array, origin, direction, t1); + return out; + } + } + else { + vec3$7.scaleAndAdd(out.array, origin, direction, t0); + return out; + } + }; + })(), - var shader = shaderLibrary[key]; + // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ + /** + * Calculate intersection point between ray and bounding box + * @param {clay.BoundingBox} bbox + * @param {clay.Vector3} + * @return {clay.Vector3} + */ + intersectBoundingBox: function (bbox, out) { + var dir = this.direction.array; + var origin = this.origin.array; + var min = bbox.min.array; + var max = bbox.max.array; - if (!shader) { - shader = new Shader({ - vertex: Shader.source('qtek.standard.vertex'), - fragment: Shader.source('qtek.standard.fragment') - }); - shader.enableTexture(enabledMaps); - shader.define('fragment', 'USE_METALNESS'); - shader.define('fragment', 'USE_ROUGHNESS'); - shader.define('ROUGHNESS_CHANNEL', shaderDefines.roughnessChannel); - shader.define('METALNESS_CHANNEL', shaderDefines.metalnessChannel); - if (jointCount) { - shader.define('vertex', 'SKINNING'); - shader.define('vertex', 'JOINT_COUNT', jointCount); - } - if (shaderDefines.environmentMapPrefiltered) { - shader.define('fragment', 'ENVIRONMENTMAP_PREFILTER'); + var invdirx = 1 / dir[0]; + var invdiry = 1 / dir[1]; + var invdirz = 1 / dir[2]; + + var tmin, tmax, tymin, tymax, tzmin, tzmax; + if (invdirx >= 0) { + tmin = (min[0] - origin[0]) * invdirx; + tmax = (max[0] - origin[0]) * invdirx; } - if (shaderDefines.linear) { - shader.define('fragment', 'SRGB_DECODE'); + else { + tmax = (min[0] - origin[0]) * invdirx; + tmin = (max[0] - origin[0]) * invdirx; } - if (shaderDefines.encodeRGBM) { - shader.define('fragment', 'RGBM_ENCODE'); + if (invdiry >= 0) { + tymin = (min[1] - origin[1]) * invdiry; + tymax = (max[1] - origin[1]) * invdiry; } - if (shaderDefines.decodeRGBM) { - shader.define('fragment', 'RGBM_DECODE'); + else { + tymax = (min[1] - origin[1]) * invdiry; + tymin = (max[1] - origin[1]) * invdiry; } - if (shaderDefines.parallaxCorrected) { - shader.define('fragment', 'PARALLAX_CORRECTED'); + + if ((tmin > tymax) || (tymin > tmax)) { + return null; } - if (shaderDefines.doubleSided) { - shader.define('fragment', 'DOUBLE_SIDED'); + + if (tymin > tmin || tmin !== tmin) { + tmin = tymin; } - if (shaderDefines.alphaTest) { - shader.define('fragment', 'ALPHA_TEST'); + if (tymax < tmax || tmax !== tmax) { + tmax = tymax; } - shaderLibrary[key] = shader; - } - if (!shaderUsedCount[renderer.__GUID__][key]) { - shaderUsedCount[renderer.__GUID__][key] = 0; - } - shaderUsedCount[renderer.__GUID__][key]++; - - shader.__key__ = key; - - return shader; -} -function releaseShader(shader, renderer) { - var key = shader.__key__; - if (shaderLibrary[key]) { - shaderUsedCount[renderer.__GUID__][key]--; - if (!shaderUsedCount[renderer.__GUID__][key]) { - if (renderer) { - // Since shader may not be used on any material. We need to dispose it - shader.dispose(renderer); - } + if (invdirz >= 0) { + tzmin = (min[2] - origin[2]) * invdirz; + tzmax = (max[2] - origin[2]) * invdirz; + } + else { + tzmax = (min[2] - origin[2]) * invdirz; + tzmin = (max[2] - origin[2]) * invdirz; } - } -} - -/** - * Standard material without custom shader. - * @constructor qtek.StandardMaterial - * @extends qtek.Base - * @example - * var mat = new qtek.StandardMaterial({ - * color: [1, 1, 1], - * diffuseMap: diffuseTexture - * }); - * mat.roughness = 1; - */ -var StandardMaterial = Material.extend(function () { - - return /** @lends qtek.StandardMaterial# */ { - - /** - * @type {Array.} - * @default [1, 1, 1] - */ - color: [1, 1, 1], - /** - * @type {Array.} - * @default [0, 0, 0] - */ - emission: [0, 0, 0], + if ((tmin > tzmax) || (tzmin > tmax)) { + return null; + } - /** - * @type {number} - * @default 0 - */ - emissionIntensity: 0, + if (tzmin > tmin || tmin !== tmin) { + tmin = tzmin; + } + if (tzmax < tmax || tmax !== tmax) { + tmax = tzmax; + } + if (tmax < 0) { + return null; + } - /** - * @type {number} - * @default 0.5 - */ - roughness: 0.5, + var t = tmin >= 0 ? tmin : tmax; - /** - * @type {number} - * @default 0 - */ - metalness: 0, + if (!out) { + out = new Vector3(); + } + vec3$7.scaleAndAdd(out.array, origin, dir, t); + return out; + }, - /** - * @type {number} - * @default 1 - */ - alpha: 1, + // http://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm + /** + * Calculate intersection point between ray and three triangle vertices + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @param {clay.Vector3} c + * @param {boolean} singleSided, CW triangle will be ignored + * @param {clay.Vector3} [out] + * @param {clay.Vector3} [barycenteric] barycentric coords + * @return {clay.Vector3} + */ + intersectTriangle: (function () { - /** - * @type {boolean} - */ - alphaTest: false, + var eBA = vec3$7.create(); + var eCA = vec3$7.create(); + var AO = vec3$7.create(); + var vCross = vec3$7.create(); - /** - * Cutoff threshold for alpha test - * @type {number} - */ - alphaCutoff: 0.9, + return function (a, b, c, singleSided, out, barycenteric) { + var dir = this.direction.array; + var origin = this.origin.array; + a = a.array; + b = b.array; + c = c.array; - /** - * @type {boolean} - */ - // TODO Must disable culling. - doubleSided: false, + vec3$7.sub(eBA, b, a); + vec3$7.sub(eCA, c, a); - /** - * @type {qtek.Texture2D} - */ + vec3$7.cross(vCross, eCA, dir); - /** - * @type {qtek.Texture2D} - */ + var det = vec3$7.dot(eBA, vCross); - /** - * @type {qtek.Texture2D} - */ + if (singleSided) { + if (det > -EPSILON) { + return null; + } + } + else { + if (det > -EPSILON && det < EPSILON) { + return null; + } + } - /** - * @type {qtek.Texture2D} - */ - /** - * @type {qtek.Texture2D} - */ + vec3$7.sub(AO, origin, a); + var u = vec3$7.dot(vCross, AO) / det; + if (u < 0 || u > 1) { + return null; + } - /** - * @type {qtek.TextureCube} - */ + vec3$7.cross(vCross, eBA, AO); + var v = vec3$7.dot(dir, vCross) / det; - /** - * @type {qtek.math.BoundingBox} - */ + if (v < 0 || v > 1 || (u + v > 1)) { + return null; + } - /** - * BRDF Lookup is generated by qtek.util.cubemap.integrateBrdf - * @type {qtek.Texture2D} - */ + vec3$7.cross(vCross, eBA, eCA); + var t = -vec3$7.dot(AO, vCross) / det; - /** - * @type {qtek.Texture2D} - */ + if (t < 0) { + return null; + } - /** - * @type {qtek.Texture2D} - */ + if (!out) { + out = new Vector3(); + } + if (barycenteric) { + Vector3.set(barycenteric, (1 - u - v), u, v); + } + vec3$7.scaleAndAdd(out.array, origin, dir, t); - /** - * @type {Array.} - * @default [1, 1] - */ - uvRepeat: [1, 1], + return out; + }; + })(), - /** - * @type {Array.} - * @default [0, 0] - */ - uvOffset: [0, 0], + /** + * Apply an affine transform matrix to the ray + * @return {clay.Matrix4} matrix + */ + applyTransform: function (matrix) { + Vector3.add(this.direction, this.direction, this.origin); + Vector3.transformMat4(this.origin, this.origin, matrix); + Vector3.transformMat4(this.direction, this.direction, matrix); - /** - * @type {number} - * @default 1 - */ - aoIntensity: 1, + Vector3.sub(this.direction, this.direction, this.origin); + Vector3.normalize(this.direction, this.direction); + }, - /** - * @type {number} - * @default 0 - */ - // FIXME Redundant with mesh - jointCount: 0, + /** + * Copy values from another ray + * @param {clay.Ray} ray + */ + copy: function (ray) { + Vector3.copy(this.origin, ray.origin); + Vector3.copy(this.direction, ray.direction); + }, - /** - * @type {boolean} - */ - environmentMapPrefiltered: false, + /** + * Clone a new ray + * @return {clay.Ray} + */ + clone: function () { + var ray = new Ray(); + ray.copy(this); + return ray; + } +}; - /** - * @type {boolean} - */ - linear: false, +var vec3$4 = glmatrix.vec3; +var vec4 = glmatrix.vec4; +/** + * @constructor clay.Camera + * @extends clay.Node + */ +var Camera = Node.extend(function () { + return /** @lends clay.Camera# */ { /** - * @type {boolean} + * Camera projection matrix + * @type {clay.Matrix4} */ - encodeRGBM: false, + projectionMatrix: new Matrix4(), /** - * @type {boolean} + * Inverse of camera projection matrix + * @type {clay.Matrix4} */ - decodeRGBM: false, + invProjectionMatrix: new Matrix4(), /** - * @type {Number} + * View matrix, equal to inverse of camera's world matrix + * @type {clay.Matrix4} */ - roughnessChannel: 0, + viewMatrix: new Matrix4(), + /** - * @type {Number} + * Camera frustum in view space + * @type {clay.Frustum} */ - metalnessChannel: 1 + frustum: new Frustum() }; -}, { +}, function () { + this.update(true); +}, +/** @lends clay.Camera.prototype */ +{ - _doUpdateShader: function (renderer) { - var enabledTextures = TEXTURE_PROPERTIES.filter(function (name) { - return !!this[name]; - }, this); - if (this._shader) { - releaseShader(this._shader, renderer); - this._shader.detached(); - } - - var shader = allocateShader( - renderer, enabledTextures, this.jointCount || 0, { - environmentMapPrefiltered: this.environmentMapPrefiltered, - linear: this.linear, - encodeRGBM: this.encodeRGBM, - decodeRGBM: this.decodeRGBM, - parallaxCorrected: !!this._environmentBox, - alphaTest: this.alphaTest, - doubleSided: this.doubleSided, - metalnessChannel: this.metalnessChannel, - roughnessChannel: this.roughnessChannel - } - ); - var originalUniforms = this.uniforms; + update: function (force) { + Node.prototype.update.call(this, force); + Matrix4.invert(this.viewMatrix, this.worldTransform); - // Ignore if uniform can use in shader. - this.uniforms = shader.createUniforms(); - this._shader = shader; + this.updateProjectionMatrix(); + Matrix4.invert(this.invProjectionMatrix, this.projectionMatrix); - var uniforms = this.uniforms; - this._enabledUniforms = Object.keys(uniforms); + this.frustum.setFromProjection(this.projectionMatrix); + }, - // Keep uniform - for (var symbol in originalUniforms) { - if (uniforms[symbol]) { - uniforms[symbol].value = originalUniforms[symbol].value; - } - } + /** + * Set camera view matrix + */ + setViewMatrix: function (viewMatrix) { + Matrix4.copy(this.viewMatrix, viewMatrix); + Matrix4.invert(this.worldTransform, viewMatrix); + this.decomposeWorldTransform(); + }, - shader.attached(); + /** + * Decompose camera projection matrix + */ + decomposeProjectionMatrix: function () {}, - this._shaderDirty = false; + /** + * Set camera projection matrix + * @param {clay.Matrix4} projectionMatrix + */ + setProjectionMatrix: function (projectionMatrix) { + Matrix4.copy(this.projectionMatrix, projectionMatrix); + Matrix4.invert(this.invProjectionMatrix, projectionMatrix); + this.decomposeProjectionMatrix(); }, + /** + * Update projection matrix, called after update + */ + updateProjectionMatrix: function () {}, - updateShader: function (renderer) { - if (this._shaderDirty) { - this._doUpdateShader(renderer); - this._shaderDirty = false; - } - }, + /** + * Cast a picking ray from camera near plane to far plane + * @function + * @param {clay.Vector2} ndc + * @param {clay.Ray} [out] + * @return {clay.Ray} + */ + castRay: (function () { + var v4 = vec4.create(); + return function (ndc, out) { + var ray = out !== undefined ? out : new Ray(); + var x = ndc.array[0]; + var y = ndc.array[1]; + vec4.set(v4, x, y, -1, 1); + vec4.transformMat4(v4, v4, this.invProjectionMatrix.array); + vec4.transformMat4(v4, v4, this.worldTransform.array); + vec3$4.scale(ray.origin.array, v4, 1 / v4[3]); - attachShader: function () { - // Do nothing. - // console.warn('StandardMaterial can\'t change shader'); - }, + vec4.set(v4, x, y, 1, 1); + vec4.transformMat4(v4, v4, this.invProjectionMatrix.array); + vec4.transformMat4(v4, v4, this.worldTransform.array); + vec3$4.scale(v4, v4, 1 / v4[3]); + vec3$4.sub(ray.direction.array, v4, ray.origin.array); - dispose: function (gl, disposeTexture) { - if (this._shader) { - releaseShader(this._shader); - } - Material.prototype.dispose.call(gl, disposeTexture); - }, + vec3$4.normalize(ray.direction.array, ray.direction.array); + ray.direction._dirty = true; + ray.origin._dirty = true; + return ray; + }; + })(), - clone: function () { - var material = new StandardMaterial({ - name: this.name - }); - TEXTURE_PROPERTIES.forEach(function (propName) { - if (this[propName]) { - material[propName] = this[propName]; - } - }, this); - SIMPLE_PROPERTIES.concat(PROPERTIES_CHANGE_SHADER).forEach(function (propName) { - material[propName] = this[propName]; - }, this); - return material; - } + /** + * @function + * @name clone + * @return {clay.Camera} + * @memberOf clay.Camera.prototype + */ }); -SIMPLE_PROPERTIES.forEach(function (propName) { - Object.defineProperty(StandardMaterial.prototype, propName, { - get: function () { - return this.get(propName); - }, - set: function (value) { - var uniforms = this.uniforms = this.uniforms || {}; - uniforms[propName] = uniforms[propName] || { - value: null - }; - this.setUniform(propName, value); - } - }); -}); +var mat4$3 = glmatrix.mat4; -TEXTURE_PROPERTIES.forEach(function (propName) { - Object.defineProperty(StandardMaterial.prototype, propName, { - get: function () { - return this.get(propName); - }, - set: function (value) { - var uniforms = this.uniforms = this.uniforms || {}; - uniforms[propName] = uniforms[propName] || { - value: null - }; +var IDENTITY = mat4$3.create(); +var WORLDVIEW = mat4$3.create(); - var oldVal = this.get(propName); - this.setUniform(propName, value); +var programKeyCache$1 = {}; - if (!oldVal !== !value) { - this._shaderDirty = true; - } - } - }); -}); +function getProgramKey$1(lightNumbers) { + var defineStr = []; + var lightTypes = Object.keys(lightNumbers); + lightTypes.sort(); + for (var i = 0; i < lightTypes.length; i++) { + var lightType = lightTypes[i]; + defineStr.push(lightType + ' ' + lightNumbers[lightType]); + } + var key = defineStr.join('\n'); -PROPERTIES_CHANGE_SHADER.forEach(function (propName) { - var privateKey = '_' + propName; - Object.defineProperty(StandardMaterial.prototype, propName, { - get: function () { - return this[privateKey]; - }, - set: function (value) { - var oldVal = this[privateKey]; - this[privateKey] = value; - if (oldVal !== value) { - this._shaderDirty = true; - } - } - }); -}); + if (programKeyCache$1[key]) { + return programKeyCache$1[key]; + } -Object.defineProperty(StandardMaterial.prototype, 'environmentBox', { - get: function () { - var envBox = this._environmentBox; - if (envBox) { - envBox.min.setArray(this.get('environmentBoxMin')); - envBox.max.setArray(this.get('environmentBoxMax')); - } - return envBox; - }, + var id = util.genGUID(); + programKeyCache$1[key] = id; + return id; +} - set: function (value) { - var oldVal = this._environmentBox; - this._environmentBox = value; +function RenderList() { - var uniforms = this.uniforms = this.uniforms || {}; - uniforms['environmentBoxMin'] = uniforms['environmentBoxMin'] || { - value: null - }; - uniforms['environmentBoxMax'] = uniforms['environmentBoxMax'] || { - value: null - }; + this.opaque = []; + this.transparent = []; - // TODO Can't detect operation like box.min = new Vector() - if (value) { - this.setUniform('environmentBoxMin', value.min._array); - this.setUniform('environmentBoxMax', value.max._array); - } + this._opaqueCount = 0; + this._transparentCount = 0; +} - if (oldVal !== value) { - this._shaderDirty = true; - } - } -}); +RenderList.prototype.startCount = function () { + this._opaqueCount = 0; + this._transparentCount = 0; +}; -Object.defineProperty(StandardMaterial.prototype, 'shader', { - get: function () { - // FIXME updateShader needs gl context. - if (!this._shader) { - // this._shaderDirty = true; - // this.updateShader(); - } - return this._shader; - }, - set: function () { - console.warn('StandardMaterial can\'t change shader'); +RenderList.prototype.add = function (object, isTransparent) { + if (isTransparent) { + this.transparent[this._transparentCount++] = object; } -}); - -// Cache -var prevDrawID = 0; -var prevDrawIndicesBuffer = null; -var prevDrawIsUseIndices = true; - -var currentDrawID; + else { + this.opaque[this._opaqueCount++] = object; + } +}; -var RenderInfo = function() { - this.triangleCount = 0; - this.vertexCount = 0; - this.drawCallCount = 0; +RenderList.prototype.endCount = function () { + this.transparent.length = this._transparentCount; + this.opaque.length = this._opaqueCount; }; -function VertexArrayObject( - availableAttributes, - availableAttributeSymbols, - indicesBuffer -) { - this.availableAttributes = availableAttributes; - this.availableAttributeSymbols = availableAttributeSymbols; - this.indicesBuffer = indicesBuffer; +/** + * @typedef {Object} clay.Scene.RenderList + * @property {Array.} opaque + * @property {Array.} transparent + */ - this.vao = null; -} /** - * @constructor - * @alias qtek.Renderable - * @extends qtek.Node + * @constructor clay.Scene + * @extends clay.Node */ -var Renderable = Node.extend( -/** @lends qtek.Renderable# */ -{ - /** - * @type {qtek.Material} - */ - material: null, +var Scene = Node.extend(function () { + return /** @lends clay.Scene# */ { + /** + * Global material of scene + * @type {clay.Material} + */ + material: null, - /** - * @type {qtek.Geometry} - */ - geometry: null, + lights: [], - /** - * @type {number} - */ - mode: glenum.TRIANGLES, + /** + * Scene bounding box in view space. + * Used when camera needs to adujst the near and far plane automatically + * so that the view frustum contains the visible objects as tightly as possible. + * Notice: + * It is updated after rendering (in the step of frustum culling passingly). So may be not so accurate, but saves a lot of calculation + * + * @type {clay.BoundingBox} + */ + viewBoundingBoxLastFrame: new BoundingBox(), - _drawCache: null, + // Uniforms for shadow map. + shadowUniforms: {}, - _renderInfo: null -}, function() { - this._drawCache = {}; - this._renderInfo = new RenderInfo(); + _cameraList: [], + + // Properties to save the light information in the scene + // Will be set in the render function + _lightUniforms: {}, + + _previousLightNumber: {}, + + _lightNumber: { + // groupId: { + // POINT_LIGHT: 0, + // DIRECTIONAL_LIGHT: 0, + // SPOT_LIGHT: 0, + // AMBIENT_LIGHT: 0, + // AMBIENT_SH_LIGHT: 0 + // } + }, + + _lightProgramKeys: {}, + + _nodeRepository: {}, + + _renderLists: new LRU(20) + + }; +}, function () { + this._scene = this; }, -/** @lends qtek.Renderable.prototype */ +/** @lends clay.Scene.prototype. */ { - /** - * Render order, Nodes with smaller value renders before nodes with larger values. - * @type {Number} - */ - renderOrder: 0, - /** - * Used when mode is LINES, LINE_STRIP or LINE_LOOP - * @type {number} - */ - lineWidth: 1, + // Add node to scene + addToScene: function (node) { + if (node instanceof Camera) { + if (this._cameraList.length > 0) { + console.warn('Found multiple camera in one scene. Use the fist one.'); + } + this._cameraList.push(node); + } + else if (node instanceof Light) { + this.lights.push(node); + } + if (node.name) { + this._nodeRepository[node.name] = node; + } + }, + + // Remove node from scene + removeFromScene: function (node) { + var idx; + if (node instanceof Camera) { + idx = this._cameraList.indexOf(node); + if (idx >= 0) { + this._cameraList.splice(idx, 1); + } + } + else if (node instanceof Light) { + idx = this.lights.indexOf(node); + if (idx >= 0) { + this.lights.splice(idx, 1); + } + } + if (node.name) { + delete this._nodeRepository[node.name]; + } + }, /** - * If enable culling - * @type {boolean} - */ - culling: true, - /** - * Specify which side of polygon will be culled. - * Possible values: - * + {@link qtek.Renderable.BACK} - * + {@link qtek.Renderable.FRONT} - * + {@link qtek.Renderable.FRONT_AND_BACK} - * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/cullFace - * @type {number} - */ - cullFace: glenum.BACK, - /** - * Specify which side is front face. - * Possible values: - * + {@link qtek.Renderable.CW} - * + {@link qtek.Renderable.CCW} - * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/frontFace - * @type {number} + * Get node by name + * @param {string} name + * @return {Node} + * @DEPRECATED */ - frontFace: glenum.CCW, + getNode: function (name) { + return this._nodeRepository[name]; + }, /** - * If enable software frustum culling - * @type {boolean} - */ - frustumCulling: true, - /** - * @type {boolean} - */ - receiveShadow: true, - /** - * @type {boolean} - */ - castShadow: true, - /** - * @type {boolean} + * Set main camera of the scene. + * @param {claygl.Camera} camera */ - ignorePicking: false, + setMainCamera: function (camera) { + var idx = this._cameraList.indexOf(camera); + if (idx >= 0) { + this._cameraList.splice(idx, 1); + } + this._cameraList.unshift(camera); + }, /** - * @type {boolean} + * Get main camera of the scene. */ - ignorePreZ: false, + getMainCamera: function () { + return this._cameraList[0]; + }, + + getLights: function () { + return this.lights; + }, + + updateLights: function () { + var lights = this.lights; + this._previousLightNumber = this._lightNumber; + + var lightNumber = {}; + for (var i = 0; i < lights.length; i++) { + var light = lights[i]; + if (light.invisible) { + continue; + } + var group = light.group; + if (!lightNumber[group]) { + lightNumber[group] = {}; + } + // User can use any type of light + lightNumber[group][light.type] = lightNumber[group][light.type] || 0; + lightNumber[group][light.type]++; + } + this._lightNumber = lightNumber; + + for (var groupId in lightNumber) { + this._lightProgramKeys[groupId] = getProgramKey$1(lightNumber[groupId]); + } + + this._updateLightUniforms(); + }, /** - * @type {boolean} - */ - ignoreGBuffer: false, - - /** - * @return {boolean} + * Clone a node and it's children, including mesh, camera, light, etc. + * Unlike using `Node#clone`. It will clone skeleton and remap the joints. Material will also be cloned. + * + * @param {clay.Node} node + * @return {clay.Node} */ - isRenderable: function() { - // TODO Shader ? - return this.geometry && this.material && !this.invisible - && this.geometry.vertexCount > 0; + cloneNode: function (node) { + var newNode = node.clone(); + var clonedNodesMap = {}; + function buildNodesMap(sNode, tNode) { + clonedNodesMap[sNode.__uid__] = tNode; + + for (var i = 0; i < sNode._children.length; i++) { + var sChild = sNode._children[i]; + var tChild = tNode._children[i]; + buildNodesMap(sChild, tChild); + } + } + buildNodesMap(node, newNode); + + newNode.traverse(function (newChild) { + if (newChild.skeleton) { + newChild.skeleton = newChild.skeleton.clone(clonedNodesMap); + } + if (newChild.material) { + newChild.material = newChild.material.clone(); + } + }); + + return newNode; }, /** - * Before render hook - * @type {Function} + * Traverse the scene and add the renderable object to the render list. + * It needs camera for the frustum culling. + * + * @param {clay.Camera} camera + * @return {clay.Scene.RenderList} */ - beforeRender: function (_gl) {}, + updateRenderList: function (camera) { + var id = camera.__uid__; + var renderList = this._renderLists.get(id); + if (!renderList) { + renderList = new RenderList(); + this._renderLists.put(id, renderList); + } + renderList.startCount(); + + this.viewBoundingBoxLastFrame.min.set(Infinity, Infinity, Infinity); + this.viewBoundingBoxLastFrame.max.set(-Infinity, -Infinity, -Infinity); + + var sceneMaterialTransparent = this.material && this.material.transparent || false; + this._doUpdateRenderList(this, camera, sceneMaterialTransparent, renderList); + + renderList.endCount(); + + return renderList; + }, /** - * Before render hook - * @type {Function} + * Get render list. Used after {@link clay.Scene#updateRenderList} + * @param {clay.Camera} camera + * @return {clay.Scene.RenderList} */ - afterRender: function (_gl, renderStat) {}, + getRenderList: function (camera) { + return this._renderLists.get(camera.__uid__); + }, - getBoundingBox: function (filter, out) { - out = Node.prototype.getBoundingBox.call(this, filter, out); - if (this.geometry && this.geometry.boundingBox) { - out.union(this.geometry.boundingBox); + _doUpdateRenderList: function (parent, camera, sceneMaterialTransparent, renderList) { + if (parent.invisible) { + return; } + // TODO Optimize + for (var i = 0; i < parent._children.length; i++) { + var child = parent._children[i]; - return out; + if (child.isRenderable()) { + // Frustum culling + var worldM = child.isSkinnedMesh() ? IDENTITY : child.worldTransform.array; + var geometry = child.geometry; + + mat4$3.multiplyAffine(WORLDVIEW, camera.viewMatrix.array, worldM); + if (!geometry.boundingBox || !this.isFrustumCulled(child, camera, WORLDVIEW)) { + renderList.add(child, child.material.transparent || sceneMaterialTransparent); + } + } + if (child._children.length > 0) { + this._doUpdateRenderList(child, camera, sceneMaterialTransparent, renderList); + } + } }, /** - * @param {qtek.Renderer} renderer - * @param {qtek.Shader} [shader] May use shader of other material if shader code are same - * @return {Object} + * If an scene object is culled by camera frustum + * + * Object can be a renderable or a light + * + * @param {clay.Node} object + * @param {clay.Camera} camera + * @param {Array.} worldViewMat represented with array + * @param {Array.} projectionMat represented with array */ - render: function (renderer, shader) { - var _gl = renderer.gl; - // May use shader of other material if shader code are same - var shader = shader || this.material.shader; - var geometry = this.geometry; + isFrustumCulled: (function () { + // Frustum culling + // http://www.cse.chalmers.se/~uffe/vfc_bbox.pdf + var cullingBoundingBox = new BoundingBox(); + var cullingMatrix = new Matrix4(); + return function(object, camera, worldViewMat) { + // Bounding box can be a property of object(like light) or renderable.geometry + // PENDING + var geoBBox = object.boundingBox || object.geometry.boundingBox; + cullingMatrix.array = worldViewMat; + cullingBoundingBox.transformFrom(geoBBox, cullingMatrix); - var glDrawMode = this.mode; + // Passingly update the scene bounding box + // FIXME exclude very large mesh like ground plane or terrain ? + // FIXME Only rendererable which cast shadow ? - var nVertex = geometry.vertexCount; - var isUseIndices = geometry.isUseIndices(); + // FIXME boundingBox becomes much larger after transformd. + if (object.castShadow) { + this.viewBoundingBoxLastFrame.union(cullingBoundingBox); + } + // Ignore frustum culling if object is skinned mesh. + if (object.frustumCulling && !object.isSkinnedMesh()) { + if (!cullingBoundingBox.intersectBoundingBox(camera.frustum.boundingBox)) { + return true; + } - var uintExt = renderer.getGLExtension('OES_element_index_uint'); - var useUintExt = uintExt && nVertex > 0xffff; - var indicesType = useUintExt ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT; + cullingMatrix.array = camera.projectionMatrix.array; + if ( + cullingBoundingBox.max.array[2] > 0 && + cullingBoundingBox.min.array[2] < 0 + ) { + // Clip in the near plane + cullingBoundingBox.max.array[2] = -1e-20; + } - var vaoExt = renderer.getGLExtension('OES_vertex_array_object'); - // var vaoExt = null; + cullingBoundingBox.applyProjection(cullingMatrix); - var isStatic = !geometry.dynamic; + var min = cullingBoundingBox.min.array; + var max = cullingBoundingBox.max.array; - var renderInfo = this._renderInfo; - renderInfo.vertexCount = nVertex; - renderInfo.triangleCount = 0; - renderInfo.drawCallCount = 0; - // Draw each chunk - var drawHashChanged = false; - // Hash with shader id in case previous material has less attributes than next material - currentDrawID = renderer.__GUID__ + '-' + geometry.__GUID__ + '-' + shader.__GUID__; + if ( + max[0] < -1 || min[0] > 1 + || max[1] < -1 || min[1] > 1 + || max[2] < -1 || min[2] > 1 + ) { + return true; + } + } - if (currentDrawID !== prevDrawID) { - drawHashChanged = true; - } - else { - // The cache will be invalid in the following cases - // 1. Geometry is splitted to multiple chunks - // 2. VAO is enabled and is binded to null after render - // 3. Geometry needs update - if ( - ((nVertex > 0xffff && !uintExt) && isUseIndices) - || (vaoExt && isStatic) - || geometry._cache.isDirty() - ) { - drawHashChanged = true; + return false; + }; + })(), + + _updateLightUniforms: function () { + var lights = this.lights; + // Put the light cast shadow before the light not cast shadow + lights.sort(lightSortFunc); + + var lightUniforms = this._lightUniforms; + for (var group in lightUniforms) { + for (var symbol in lightUniforms[group]) { + lightUniforms[group][symbol].value.length = 0; } } - prevDrawID = currentDrawID; + for (var i = 0; i < lights.length; i++) { - if (!drawHashChanged) { - // Direct draw - if (prevDrawIsUseIndices) { - _gl.drawElements(glDrawMode, prevDrawIndicesBuffer.count, indicesType, 0); - renderInfo.triangleCount = prevDrawIndicesBuffer.count / 3; - } - else { - // FIXME Use vertex number in buffer - // vertexCount may get the wrong value when geometry forget to mark dirty after update - _gl.drawArrays(glDrawMode, 0, nVertex); + var light = lights[i]; + + if (light.invisible) { + continue; } - renderInfo.drawCallCount = 1; - } - else { - // Use the cache of static geometry - var vaoList = this._drawCache[currentDrawID]; - if (!vaoList) { - var chunks = geometry.getBufferChunks(renderer); - if (!chunks) { // Empty mesh - return; - } - vaoList = []; - for (var c = 0; c < chunks.length; c++) { - var chunk = chunks[c]; - var attributeBuffers = chunk.attributeBuffers; - var indicesBuffer = chunk.indicesBuffer; - - var availableAttributes = []; - var availableAttributeSymbols = []; - for (var a = 0; a < attributeBuffers.length; a++) { - var attributeBufferInfo = attributeBuffers[a]; - var name = attributeBufferInfo.name; - var semantic = attributeBufferInfo.semantic; - var symbol; - if (semantic) { - var semanticInfo = shader.attribSemantics[semantic]; - symbol = semanticInfo && semanticInfo.symbol; - } - else { - symbol = name; - } - if (symbol && shader.attributeTemplates[symbol]) { - availableAttributes.push(attributeBufferInfo); - availableAttributeSymbols.push(symbol); - } - } - var vao = new VertexArrayObject( - availableAttributes, - availableAttributeSymbols, - indicesBuffer - ); - vaoList.push(vao); + var group = light.group; + + for (var symbol in light.uniformTemplates) { + var uniformTpl = light.uniformTemplates[symbol]; + var value = uniformTpl.value(light); + if (value == null) { + continue; + } + if (!lightUniforms[group]) { + lightUniforms[group] = {}; } - if (isStatic) { - this._drawCache[currentDrawID] = vaoList; + if (!lightUniforms[group][symbol]) { + lightUniforms[group][symbol] = { + type: '', + value: [] + }; + } + var lu = lightUniforms[group][symbol]; + lu.type = uniformTpl.type + 'v'; + switch (uniformTpl.type) { + case '1i': + case '1f': + case 't': + lu.value.push(value); + break; + case '2f': + case '3f': + case '4f': + for (var j = 0; j < value.length; j++) { + lu.value.push(value[j]); + } + break; + default: + console.error('Unkown light uniform type ' + uniformTpl.type); } } + } + }, - for (var i = 0; i < vaoList.length; i++) { - var vao = vaoList[i]; - var needsBindAttributes = true; + getLightGroups: function () { + var lightGroups = []; + for (var groupId in this._lightNumber) { + lightGroups.push(groupId); + } + return lightGroups; + }, - // Create vertex object array cost a lot - // So we don't use it on the dynamic object - if (vaoExt && isStatic) { - // Use vertex array object - // http://blog.tojicode.com/2012/10/oesvertexarrayobject-extension.html - if (vao.vao == null) { - vao.vao = vaoExt.createVertexArrayOES(); - } - else { - needsBindAttributes = false; - } - vaoExt.bindVertexArrayOES(vao.vao); - } + getNumberChangedLightGroups: function () { + var lightGroups = []; + for (var groupId in this._lightNumber) { + if (this.isLightNumberChanged(groupId)) { + lightGroups.push(groupId); + } + } + return lightGroups; + }, - var availableAttributes = vao.availableAttributes; - var indicesBuffer = vao.indicesBuffer; + // Determine if light group is different with since last frame + // Used to determine whether to update shader and scene's uniforms in Renderer.render + isLightNumberChanged: function (lightGroup) { + var prevLightNumber = this._previousLightNumber; + var currentLightNumber = this._lightNumber; + // PENDING Performance + for (var type in currentLightNumber[lightGroup]) { + if (!prevLightNumber[lightGroup]) { + return true; + } + if (currentLightNumber[lightGroup][type] !== prevLightNumber[lightGroup][type]) { + return true; + } + } + for (var type in prevLightNumber[lightGroup]) { + if (!currentLightNumber[lightGroup]) { + return true; + } + if (currentLightNumber[lightGroup][type] !== prevLightNumber[lightGroup][type]) { + return true; + } + } + return false; + }, - if (needsBindAttributes) { - var locationList = shader.enableAttributes(renderer, vao.availableAttributeSymbols, (vaoExt && isStatic && vao.vao)); - // Setting attributes; - for (var a = 0; a < availableAttributes.length; a++) { - var location = locationList[a]; - if (location === -1) { - continue; - } - var attributeBufferInfo = availableAttributes[a]; - var buffer = attributeBufferInfo.buffer; - var size = attributeBufferInfo.size; - var glType; - switch (attributeBufferInfo.type) { - case 'float': - glType = _gl.FLOAT; - break; - case 'byte': - glType = _gl.BYTE; - break; - case 'ubyte': - glType = _gl.UNSIGNED_BYTE; - break; - case 'short': - glType = _gl.SHORT; - break; - case 'ushort': - glType = _gl.UNSIGNED_SHORT; - break; - default: - glType = _gl.FLOAT; - break; - } + getLightsNumbers: function (lightGroup) { + return this._lightNumber[lightGroup]; + }, - _gl.bindBuffer(_gl.ARRAY_BUFFER, buffer); - _gl.vertexAttribPointer(location, size, glType, false, 0, 0); - } - } - if ( - glDrawMode == glenum.LINES || - glDrawMode == glenum.LINE_STRIP || - glDrawMode == glenum.LINE_LOOP - ) { - _gl.lineWidth(this.lineWidth); - } + getProgramKey: function (lightGroup) { + return this._lightProgramKeys[lightGroup]; + }, - prevDrawIndicesBuffer = indicesBuffer; - prevDrawIsUseIndices = geometry.isUseIndices(); - // Do drawing - if (prevDrawIsUseIndices) { - if (needsBindAttributes) { - _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, indicesBuffer.buffer); + setLightUniforms: (function () { + function setUniforms(uniforms, program, renderer) { + for (var symbol in uniforms) { + var lu = uniforms[symbol]; + if (lu.type === 'tv') { + if (!program.hasUniform(symbol)) { + continue; } - _gl.drawElements(glDrawMode, indicesBuffer.count, indicesType, 0); - renderInfo.triangleCount += indicesBuffer.count / 3; - } else { - _gl.drawArrays(glDrawMode, 0, nVertex); + var texSlots = []; + for (var i = 0; i < lu.value.length; i++) { + var texture = lu.value[i]; + var slot = program.takeCurrentTextureSlot(renderer, texture); + texSlots.push(slot); + } + program.setUniform(renderer.gl, '1iv', symbol, texSlots); } - - if (vaoExt && isStatic) { - vaoExt.bindVertexArrayOES(null); + else { + program.setUniform(renderer.gl, lu.type, symbol, lu.value); } - - renderInfo.drawCallCount++; } } - return renderInfo; - }, + return function (program, lightGroup, renderer) { + setUniforms(this._lightUniforms[lightGroup], program, renderer); + // Set shadows + setUniforms(this.shadowUniforms, program, renderer); + }; + })(), /** - * Clone a new renderable - * @method - * @return {qtek.Renderable} + * Dispose self, clear all the scene objects + * But resources of gl like texuture, shader will not be disposed. + * Mostly you should use disposeScene method in Renderer to do dispose. */ - clone: (function() { - var properties = [ - 'castShadow', 'receiveShadow', - 'mode', 'culling', 'cullFace', 'frontFace', - 'frustumCulling', - 'renderOrder', 'lineWidth', - 'ignorePicking', 'ignorePreZ', 'ignoreGBuffer' - ]; - return function() { - var renderable = Node.prototype.clone.call(this); + dispose: function () { + this.material = null; + this._opaqueList = []; + this._transparentList = []; - renderable.geometry = this.geometry; - renderable.material = this.material; + this.lights = []; - for (var i = 0; i < properties.length; i++) { - var name = properties[i]; - // Try not to overwrite the prototype property - if (renderable[name] !== this[name]) { - renderable[name] = this[name]; - } - } + this._lightUniforms = {}; - return renderable; - }; - })() + this._lightNumber = {}; + this._nodeRepository = {}; + } }); -/** - * @type {number} - */ -Renderable.POINTS = glenum.POINTS; -/** - * @type {number} - */ -Renderable.LINES = glenum.LINES; -/** - * @type {number} - */ -Renderable.LINE_LOOP = glenum.LINE_LOOP; -/** - * @type {number} - */ -Renderable.LINE_STRIP = glenum.LINE_STRIP; -/** - * @type {number} - */ -Renderable.TRIANGLES = glenum.TRIANGLES; -/** - * @type {number} - */ -Renderable.TRIANGLE_STRIP = glenum.TRIANGLE_STRIP; -/** - * @type {number} - */ -Renderable.TRIANGLE_FAN = glenum.TRIANGLE_FAN; -/** - * @type {number} - */ -Renderable.BACK = glenum.BACK; -/** - * @type {number} - */ -Renderable.FRONT = glenum.FRONT; -/** - * @type {number} - */ -Renderable.FRONT_AND_BACK = glenum.FRONT_AND_BACK; -/** - * @type {number} - */ -Renderable.CW = glenum.CW; -/** - * @type {number} - */ -Renderable.CCW = glenum.CCW; - -Renderable.RenderInfo = RenderInfo; +function lightSortFunc(a, b) { + if (b.castShadow && !a.castShadow) { + return true; + } +} -var mathUtil = {}; +var standardEssl = "\n@export clay.standard.chunk.varying\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nvarying vec3 v_Barycentric;\n#if defined(PARALLAXOCCLUSIONMAP_ENABLED) || defined(NORMALMAP_ENABLED)\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\n#endif\n#if defined(AOMAP_ENABLED)\nvarying vec2 v_Texcoord2;\n#endif\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\n@end\n@export clay.standard.chunk.light_header\n#ifdef AMBIENT_LIGHT_COUNT\n@import clay.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import clay.header.ambient_sh_light\n#endif\n#ifdef AMBIENT_CUBEMAP_LIGHT_COUNT\n@import clay.header.ambient_cubemap_light\n#endif\n#ifdef POINT_LIGHT_COUNT\n@import clay.header.point_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n#ifdef SPOT_LIGHT_COUNT\n@import clay.header.spot_light\n#endif\n@end\n@export clay.standard.vertex\n#define SHADER_NAME standard\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\n#if defined(AOMAP_ENABLED)\nattribute vec2 texcoord2 : TEXCOORD_1;\n#endif\nattribute vec3 normal : NORMAL;\nattribute vec4 tangent : TANGENT;\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\n#endif\nattribute vec3 barycentric;\n@import clay.standard.chunk.varying\n@import clay.chunk.skinning_header\nvoid main()\n{\n vec3 skinnedPosition = position;\n vec3 skinnedNormal = normal;\n vec3 skinnedTangent = tangent.xyz;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n skinnedTangent = (skinMatrixWS * vec4(tangent.xyz, 0.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_WorldPosition = (world * vec4(skinnedPosition, 1.0)).xyz;\n v_Barycentric = barycentric;\n v_Normal = normalize((worldInverseTranspose * vec4(skinnedNormal, 0.0)).xyz);\n#if defined(PARALLAXOCCLUSIONMAP_ENABLED) || defined(NORMALMAP_ENABLED)\n v_Tangent = normalize((worldInverseTranspose * vec4(skinnedTangent, 0.0)).xyz);\n v_Bitangent = normalize(cross(v_Normal, v_Tangent) * tangent.w);\n#endif\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n#if defined(AOMAP_ENABLED)\n v_Texcoord2 = texcoord2;\n#endif\n}\n@end\n@export clay.standard.fragment\n#define PI 3.14159265358979\n#define GLOSSINESS_CHANNEL 0\n#define ROUGHNESS_CHANNEL 0\n#define METALNESS_CHANNEL 1\n@import clay.standard.chunk.varying\nuniform mat4 viewInverse : VIEWINVERSE;\n#ifdef NORMALMAP_ENABLED\nuniform sampler2D normalMap;\n#endif\n#ifdef DIFFUSEMAP_ENABLED\nuniform sampler2D diffuseMap;\n#endif\n#ifdef SPECULARMAP_ENABLED\nuniform sampler2D specularMap;\n#endif\n#ifdef USE_ROUGHNESS\nuniform float roughness : 0.5;\n #ifdef ROUGHNESSMAP_ENABLED\nuniform sampler2D roughnessMap;\n #endif\n#else\nuniform float glossiness: 0.5;\n #ifdef GLOSSINESSMAP_ENABLED\nuniform sampler2D glossinessMap;\n #endif\n#endif\n#ifdef METALNESSMAP_ENABLED\nuniform sampler2D metalnessMap;\n#endif\n#ifdef ENVIRONMENTMAP_ENABLED\nuniform samplerCube environmentMap;\n #ifdef PARALLAX_CORRECTED\nuniform vec3 environmentBoxMin;\nuniform vec3 environmentBoxMax;\n #endif\n#endif\n#ifdef BRDFLOOKUP_ENABLED\nuniform sampler2D brdfLookup;\n#endif\n#ifdef EMISSIVEMAP_ENABLED\nuniform sampler2D emissiveMap;\n#endif\n#ifdef SSAOMAP_ENABLED\nuniform sampler2D ssaoMap;\nuniform vec4 viewport : VIEWPORT;\n#endif\n#ifdef AOMAP_ENABLED\nuniform sampler2D aoMap;\nuniform float aoIntensity;\n#endif\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\n#ifdef USE_METALNESS\nuniform float metalness : 0.0;\n#else\nuniform vec3 specularColor : [0.1, 0.1, 0.1];\n#endif\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float emissionIntensity: 1;\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\n#ifdef ENVIRONMENTMAP_PREFILTER\nuniform float maxMipmapLevel: 5;\n#endif\n@import clay.standard.chunk.light_header\n@import clay.util.calculate_attenuation\n@import clay.util.edge_factor\n@import clay.util.rgbm\n@import clay.util.srgb\n@import clay.plugin.compute_shadow_map\n@import clay.util.parallax_correct\n@import clay.util.ACES\nfloat G_Smith(float g, float ndv, float ndl)\n{\n float roughness = 1.0 - g;\n float k = roughness * roughness / 2.0;\n float G1V = ndv / (ndv * (1.0 - k) + k);\n float G1L = ndl / (ndl * (1.0 - k) + k);\n return G1L * G1V;\n}\nvec3 F_Schlick(float ndv, vec3 spec) {\n return spec + (1.0 - spec) * pow(1.0 - ndv, 5.0);\n}\nfloat D_Phong(float g, float ndh) {\n float a = pow(8192.0, g);\n return (a + 2.0) / 8.0 * pow(ndh, a);\n}\nfloat D_GGX(float g, float ndh) {\n float r = 1.0 - g;\n float a = r * r;\n float tmp = ndh * ndh * (a - 1.0) + 1.0;\n return a / (PI * tmp * tmp);\n}\n#ifdef PARALLAXOCCLUSIONMAP_ENABLED\nuniform float parallaxOcclusionScale : 0.02;\nuniform float parallaxMaxLayers : 20;\nuniform float parallaxMinLayers : 5;\nuniform sampler2D parallaxOcclusionMap;\nmat3 transpose(in mat3 inMat)\n{\n vec3 i0 = inMat[0];\n vec3 i1 = inMat[1];\n vec3 i2 = inMat[2];\n return mat3(\n vec3(i0.x, i1.x, i2.x),\n vec3(i0.y, i1.y, i2.y),\n vec3(i0.z, i1.z, i2.z)\n );\n}\nvec2 parallaxUv(vec2 uv, vec3 viewDir)\n{\n float numLayers = mix(parallaxMaxLayers, parallaxMinLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));\n float layerHeight = 1.0 / numLayers;\n float curLayerHeight = 0.0;\n vec2 deltaUv = viewDir.xy * parallaxOcclusionScale / (viewDir.z * numLayers);\n vec2 curUv = uv;\n float height = 1.0 - texture2D(parallaxOcclusionMap, curUv).r;\n for (int i = 0; i < 30; i++) {\n curLayerHeight += layerHeight;\n curUv -= deltaUv;\n height = 1.0 - texture2D(parallaxOcclusionMap, curUv).r;\n if (height < curLayerHeight) {\n break;\n }\n }\n vec2 prevUv = curUv + deltaUv;\n float next = height - curLayerHeight;\n float prev = 1.0 - texture2D(parallaxOcclusionMap, prevUv).r - curLayerHeight + layerHeight;\n return mix(curUv, prevUv, next / (next - prev));\n}\n#endif\nvoid main() {\n vec4 albedoColor = vec4(color, alpha);\n#ifdef VERTEX_COLOR\n albedoColor *= v_Color;\n#endif\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = normalize(eyePos - v_WorldPosition);\n vec2 uv = v_Texcoord;\n#if defined(PARALLAXOCCLUSIONMAP_ENABLED) || defined(NORMALMAP_ENABLED)\n mat3 tbn = mat3(v_Tangent, v_Bitangent, v_Normal);\n#endif\n#ifdef PARALLAXOCCLUSIONMAP_ENABLED\n uv = parallaxUv(v_Texcoord, normalize(transpose(tbn) * -V));\n#endif\n#ifdef DIFFUSEMAP_ENABLED\n vec4 texel = texture2D(diffuseMap, uv);\n #ifdef SRGB_DECODE\n texel = sRGBToLinear(texel);\n #endif\n albedoColor.rgb *= texel.rgb;\n #ifdef DIFFUSEMAP_ALPHA_ALPHA\n albedoColor.a *= texel.a;\n #endif\n#endif\n#ifdef USE_METALNESS\n float m = metalness;\n #ifdef METALNESSMAP_ENABLED\n float m2 = texture2D(metalnessMap, uv)[METALNESS_CHANNEL];\n m = clamp(m2 + (m - 0.5) * 2.0, 0.0, 1.0);\n #endif\n vec3 baseColor = albedoColor.rgb;\n albedoColor.rgb = baseColor * (1.0 - m);\n vec3 spec = mix(vec3(0.04), baseColor, m);\n#else\n vec3 spec = specularColor;\n#endif\n#ifdef USE_ROUGHNESS\n float g = 1.0 - roughness;\n #ifdef ROUGHNESSMAP_ENABLED\n float g2 = 1.0 - texture2D(roughnessMap, uv)[ROUGHNESS_CHANNEL];\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n #endif\n#else\n float g = glossiness;\n #ifdef GLOSSINESSMAP_ENABLED\n float g2 = texture2D(glossinessMap, uv)[GLOSSINESS_CHANNEL];\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n #endif\n#endif\n#ifdef SPECULARMAP_ENABLED\n spec *= sRGBToLinear(texture2D(specularMap, uv)).rgb;\n#endif\n vec3 N = v_Normal;\n#ifdef DOUBLE_SIDED\n if (dot(N, V) < 0.0) {\n N = -N;\n }\n#endif\n#ifdef NORMALMAP_ENABLED\n if (dot(v_Tangent, v_Tangent) > 0.0) {\n vec3 normalTexel = texture2D(normalMap, uv).xyz;\n if (dot(normalTexel, normalTexel) > 0.0) { N = normalTexel * 2.0 - 1.0;\n tbn[1] = -tbn[1];\n N = normalize(tbn * N);\n }\n }\n#endif\n vec3 diffuseTerm = vec3(0.0, 0.0, 0.0);\n vec3 specularTerm = vec3(0.0, 0.0, 0.0);\n float ndv = clamp(dot(N, V), 0.0, 1.0);\n vec3 fresnelTerm = F_Schlick(ndv, spec);\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {{\n diffuseTerm += ambientLightColor[_idx_];\n }}\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseTerm += calcAmbientSHLight(_idx_, N) * ambientSHLightColor[_idx_];\n }}\n#endif\n#ifdef POINT_LIGHT_COUNT\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsPoint[POINT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfPointLights(v_WorldPosition, shadowContribsPoint);\n }\n#endif\n for(int _idx_ = 0; _idx_ < POINT_LIGHT_COUNT; _idx_++)\n {{\n vec3 lightPosition = pointLightPosition[_idx_];\n vec3 lc = pointLightColor[_idx_];\n float range = pointLightRange[_idx_];\n vec3 L = lightPosition - v_WorldPosition;\n float dist = length(L);\n float attenuation = lightAttenuation(dist, range);\n L /= dist;\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n if(shadowEnabled)\n {\n shadowContrib = shadowContribsPoint[_idx_];\n }\n#endif\n vec3 li = lc * ndl * attenuation * shadowContrib;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }}\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int _idx_ = 0; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++)\n {{\n vec3 L = -normalize(directionalLightDirection[_idx_]);\n vec3 lc = directionalLightColor[_idx_];\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if(shadowEnabled)\n {\n shadowContrib = shadowContribsDir[_idx_];\n }\n#endif\n vec3 li = lc * ndl * shadowContrib;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }}\n#endif\n#ifdef SPOT_LIGHT_COUNT\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsSpot[SPOT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfSpotLights(v_WorldPosition, shadowContribsSpot);\n }\n#endif\n for(int i = 0; i < SPOT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = spotLightPosition[i];\n vec3 spotLightDirection = -normalize(spotLightDirection[i]);\n vec3 lc = spotLightColor[i];\n float range = spotLightRange[i];\n float a = spotLightUmbraAngleCosine[i];\n float b = spotLightPenumbraAngleCosine[i];\n float falloffFactor = spotLightFalloffFactor[i];\n vec3 L = lightPosition - v_WorldPosition;\n float dist = length(L);\n float attenuation = lightAttenuation(dist, range);\n L /= dist;\n float c = dot(spotLightDirection, L);\n float falloff;\n falloff = clamp((c - a) /(b - a), 0.0, 1.0);\n falloff = pow(falloff, falloffFactor);\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n if (shadowEnabled)\n {\n shadowContrib = shadowContribsSpot[i];\n }\n#endif\n vec3 li = lc * attenuation * (1.0 - falloff) * shadowContrib * ndl;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }\n#endif\n vec4 outColor = albedoColor;\n outColor.rgb *= max(diffuseTerm, vec3(0.0));\n outColor.rgb += max(specularTerm, vec3(0.0));\n#ifdef AMBIENT_CUBEMAP_LIGHT_COUNT\n vec3 L = reflect(-V, N);\n float rough2 = clamp(1.0 - g, 0.0, 1.0);\n float bias2 = rough2 * 5.0;\n vec2 brdfParam2 = texture2D(ambientCubemapLightBRDFLookup[0], vec2(rough2, ndv)).xy;\n vec3 envWeight2 = spec * brdfParam2.x + brdfParam2.y;\n vec3 envTexel2;\n for(int _idx_ = 0; _idx_ < AMBIENT_CUBEMAP_LIGHT_COUNT; _idx_++)\n {{\n envTexel2 = RGBMDecode(textureCubeLodEXT(ambientCubemapLightCubemap[_idx_], L, bias2), 8.12);\n outColor.rgb += ambientCubemapLightColor[_idx_] * envTexel2 * envWeight2;\n }}\n#endif\n#ifdef ENVIRONMENTMAP_ENABLED\n vec3 envWeight = g * fresnelTerm;\n vec3 L = reflect(-V, N);\n #ifdef PARALLAX_CORRECTED\n L = parallaxCorrect(L, v_WorldPosition, environmentBoxMin, environmentBoxMax);\n#endif\n #ifdef ENVIRONMENTMAP_PREFILTER\n float rough = clamp(1.0 - g, 0.0, 1.0);\n float bias = rough * maxMipmapLevel;\n vec3 envTexel = decodeHDR(textureCubeLodEXT(environmentMap, L, bias)).rgb;\n #ifdef BRDFLOOKUP_ENABLED\n vec2 brdfParam = texture2D(brdfLookup, vec2(rough, ndv)).xy;\n envWeight = spec * brdfParam.x + brdfParam.y;\n #endif\n #else\n vec3 envTexel = textureCube(environmentMap, L).xyz;\n #endif\n outColor.rgb += envTexel * envWeight;\n#endif\n float aoFactor = 1.0;\n#ifdef SSAOMAP_ENABLED\n aoFactor = min(texture2D(ssaoMap, (gl_FragCoord.xy - viewport.xy) / viewport.zw).r, aoFactor);\n#endif\n#ifdef AOMAP_ENABLED\n aoFactor = min(1.0 - clamp((1.0 - texture2D(aoMap, v_Texcoord2).r) * aoIntensity, 0.0, 1.0), aoFactor);\n#endif\n outColor.rgb *= aoFactor;\n vec3 lEmission = emission;\n#ifdef EMISSIVEMAP_ENABLED\n lEmission *= texture2D(emissiveMap, uv).rgb;\n#endif\n outColor.rgb += lEmission * emissionIntensity;\n if(lineWidth > 0.)\n {\n outColor.rgb = mix(outColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (outColor.a < alphaCutoff) {\n discard;\n }\n#endif\n#ifdef TONEMAPPING\n outColor.rgb = ACESToneMapping(outColor.rgb);\n#endif\n#ifdef SRGB_ENCODE\n outColor = linearTosRGB(outColor);\n#endif\n gl_FragColor = encodeHDR(outColor);\n}\n@end\n@export clay.standardMR.vertex\n@import clay.standard.vertex\n@end\n@export clay.standardMR.fragment\n#define USE_METALNESS\n#define USE_ROUGHNESS\n@import clay.standard.fragment\n@end"; -mathUtil.isPowerOfTwo = function (value) { - return (value & (value - 1)) === 0; -}; +// Import standard shader +Shader['import'](standardEssl); -mathUtil.nextPowerOfTwo = function (value) { - value --; - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; - value ++; +var TEXTURE_PROPERTIES = ['diffuseMap', 'normalMap', 'roughnessMap', 'metalnessMap', 'emissiveMap', 'environmentMap', 'brdfLookup', 'ssaoMap', 'aoMap']; +var SIMPLE_PROPERTIES = ['color', 'emission', 'emissionIntensity', 'alpha', 'roughness', 'metalness', 'uvRepeat', 'uvOffset', 'aoIntensity', 'alphaCutoff']; +var PROPERTIES_CHANGE_SHADER = ['linear', 'encodeRGBM', 'decodeRGBM', 'doubleSided', 'alphaTest', 'roughnessChannel', 'metalnessChannel', 'environmentMapPrefiltered']; - return value; +var NUM_DEFINE_MAP = { + 'roughnessChannel': 'ROUGHNESS_CHANNEL', + 'metalnessChannel': 'METALNESS_CHANNEL' }; - -mathUtil.nearestPowerOfTwo = function (value) { - return Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) ); +var BOOL_DEFINE_MAP = { + 'linear': 'SRGB_DECODE', + 'encodeRGBM': 'RGBM_ENCODE', + 'decodeRGBM': 'RGBM_DECODE', + 'doubleSided': 'DOUBLE_SIDED', + 'alphaTest': 'ALPHA_TEST', + 'environmentMapPrefiltered': 'ENVIRONMENTMAP_PREFILTER' }; -var isPowerOfTwo = mathUtil.isPowerOfTwo; +var standardShader; /** - * @constructor qtek.Texture2D - * @extends qtek.Texture - * + * Standard material without custom shader. + * @constructor clay.StandardMaterial + * @extends clay.Base * @example - * ... - * var mat = new qtek.Material({ - * shader: qtek.shader.library.get('qtek.phong', 'diffuseMap') - * }); - * var diffuseMap = new qtek.Texture2D(); - * diffuseMap.load('assets/textures/diffuse.jpg'); - * mat.set('diffuseMap', diffuseMap); - * ... - * diffuseMap.success(function () { - * // Wait for the diffuse texture loaded - * animation.on('frame', function (frameTime) { - * renderer.render(scene, camera); - * }); - * }); + * var mat = new clay.StandardMaterial({ + * color: [1, 1, 1], + * diffuseMap: diffuseTexture + * }); + * mat.roughness = 1; */ -var Texture2D = Texture.extend(function () { - return /** @lends qtek.Texture2D# */ { +var StandardMaterial = Material.extend(function () { + if (!standardShader) { + standardShader = new Shader(Shader.source('clay.standard.vertex'), Shader.source('clay.standard.fragment')); + } + return /** @lends clay.StandardMaterial# */ { + shader: standardShader + }; +}, function (option) { + // PENDING + util.extend(this, option); + // Extend after shader is created. + util.defaults(this, /** @lends clay.StandardMaterial# */ { /** - * @type {?HTMLImageElement|HTMLCanvasElemnet} + * @type {Array.} + * @default [1, 1, 1] */ - image: null, + color: [1, 1, 1], + /** - * Pixels data. Will be ignored if image is set. - * @type {?Uint8Array|Float32Array} + * @type {Array.} + * @default [0, 0, 0] */ - pixels: null, + emission: [0, 0, 0], + /** - * @type {Array.} - * @example - * [{ - * image: mipmap0, - * pixels: null - * }, { - * image: mipmap1, - * pixels: null - * }, ....] + * @type {number} + * @default 0 */ - mipmaps: [] - }; -}, { - update: function (renderer) { - - var _gl = renderer.gl; - _gl.bindTexture(_gl.TEXTURE_2D, this._cache.get('webgl_texture')); - - this.updateCommon(renderer); - - var glFormat = this.format; - var glType = this.type; - - _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, this.getAvailableWrapS()); - _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, this.getAvailableWrapT()); - - _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, this.getAvailableMagFilter()); - _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, this.getAvailableMinFilter()); - - var anisotropicExt = renderer.getGLExtension('EXT_texture_filter_anisotropic'); - if (anisotropicExt && this.anisotropic > 1) { - _gl.texParameterf(_gl.TEXTURE_2D, anisotropicExt.TEXTURE_MAX_ANISOTROPY_EXT, this.anisotropic); - } + emissionIntensity: 0, - // Fallback to float type if browser don't have half float extension - if (glType === 36193) { - var halfFloatExt = renderer.getGLExtension('OES_texture_half_float'); - if (!halfFloatExt) { - glType = glenum.FLOAT; - } - } + /** + * @type {number} + * @default 0.5 + */ + roughness: 0.5, - if (this.mipmaps.length) { - var width = this.width; - var height = this.height; - for (var i = 0; i < this.mipmaps.length; i++) { - var mipmap = this.mipmaps[i]; - this._updateTextureData(_gl, mipmap, i, width, height, glFormat, glType); - width /= 2; - height /= 2; - } - } - else { - this._updateTextureData(_gl, this, 0, this.width, this.height, glFormat, glType); + /** + * @type {number} + * @default 0 + */ + metalness: 0, - if (this.useMipmap && !this.NPOT) { - _gl.generateMipmap(_gl.TEXTURE_2D); - } - } + /** + * @type {number} + * @default 1 + */ + alpha: 1, - _gl.bindTexture(_gl.TEXTURE_2D, null); - }, + /** + * @type {boolean} + */ + alphaTest: false, - _updateTextureData: function (_gl, data, level, width, height, glFormat, glType) { - if (data.image) { - _gl.texImage2D(_gl.TEXTURE_2D, level, glFormat, glFormat, glType, data.image); - } - else { - // Can be used as a blank texture when writing render to texture(RTT) - if ( - glFormat <= Texture.COMPRESSED_RGBA_S3TC_DXT5_EXT - && glFormat >= Texture.COMPRESSED_RGB_S3TC_DXT1_EXT - ) { - _gl.compressedTexImage2D(_gl.TEXTURE_2D, level, glFormat, width, height, 0, data.pixels); - } - else { - // Is a render target if pixels is null - _gl.texImage2D(_gl.TEXTURE_2D, level, glFormat, width, height, 0, glFormat, glType, data.pixels); - } - } - }, + /** + * Cutoff threshold for alpha test + * @type {number} + */ + alphaCutoff: 0.9, - /** - * @param {qtek.Renderer} renderer - * @memberOf qtek.Texture2D.prototype - */ - generateMipmap: function (renderer) { - var _gl = renderer.gl; - if (this.useMipmap && !this.NPOT) { - _gl.bindTexture(_gl.TEXTURE_2D, this._cache.get('webgl_texture')); - _gl.generateMipmap(_gl.TEXTURE_2D); - } - }, + /** + * @type {boolean} + */ + // TODO Must disable culling. + doubleSided: false, - isPowerOfTwo: function () { - var width; - var height; - if (this.image) { - width = this.image.width; - height = this.image.height; - } - else { - width = this.width; - height = this.height; - } - return isPowerOfTwo(width) && isPowerOfTwo(height); - }, + /** + * @type {clay.Texture2D} + */ - isRenderable: function () { - if (this.image) { - return this.image.nodeName === 'CANVAS' - || this.image.nodeName === 'VIDEO' - || this.image.complete; - } - else { - return !!(this.width && this.height); - } - }, + /** + * @type {clay.Texture2D} + */ - bind: function (renderer) { - renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, this.getWebGLTexture(renderer)); - }, + /** + * @type {clay.Texture2D} + */ - unbind: function (renderer) { - renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, null); - }, + /** + * @type {clay.Texture2D} + */ + /** + * @type {clay.Texture2D} + */ - load: function (src, crossOrigin) { - var image = new Image(); - if (crossOrigin) { - image.crossOrigin = crossOrigin; - } - var self = this; - image.onload = function () { - self.dirty(); - self.trigger('success', self); - image.onload = null; - }; - image.onerror = function () { - self.trigger('error', self); - image.onerror = null; - }; + /** + * @type {clay.TextureCube} + */ - image.src = src; - this.image = image; + /** + * @type {clay.BoundingBox} + */ - return this; - } -}); + /** + * BRDF Lookup is generated by clay.util.cubemap.integrateBrdf + * @type {clay.Texture2D} + */ -Object.defineProperty(Texture2D.prototype, 'width', { - get: function () { - if (this.image) { - return this.image.width; - } - return this._width; - }, - set: function (value) { - if (this.image) { - console.warn('Texture from image can\'t set width'); - } - else { - if (this._width !== value) { - this.dirty(); - } - this._width = value; - } - } -}); -Object.defineProperty(Texture2D.prototype, 'height', { - get: function () { - if (this.image) { - return this.image.height; - } - return this._height; - }, - set: function (value) { - if (this.image) { - console.warn('Texture from image can\'t set height'); - } - else { - if (this._height !== value) { - this.dirty(); - } - this._height = value; - } - } -}); + /** + * @type {clay.Texture2D} + */ -/** - * @constructor qtek.Mesh - * @extends qtek.Renderable - */ -var Mesh = Renderable.extend( -/** @lends qtek.Mesh# */ -{ - /** - * Used when it is a skinned mesh - * @type {qtek.Skeleton} - */ - skeleton: null, - /** - * Joints indices Meshes can share the one skeleton instance and each mesh can use one part of joints. Joints indices indicate the index of joint in the skeleton instance - * @type {number[]} - */ - joints: null, + /** + * @type {clay.Texture2D} + */ - /** - * If store the skin matrices in vertex texture - * @type {bool} - */ - useSkinMatricesTexture: false + /** + * @type {Array.} + * @default [1, 1] + */ + uvRepeat: [1, 1], -}, function () { - if (!this.joints) { - this.joints = []; - } -}, { + /** + * @type {Array.} + * @default [0, 0] + */ + uvOffset: [0, 0], - isSkinnedMesh: function () { - return !!(this.skeleton && this.material.shader.isDefined('vertex', 'SKINNING')); - }, + /** + * @type {number} + * @default 1 + */ + aoIntensity: 1, - render: function (renderer, shader) { - var _gl = renderer.gl; - shader = shader || this.material.shader; - // Set pose matrices of skinned mesh - if (this.skeleton) { - // TODO Multiple mesh share same skeleton - this.skeleton.update(); + /** + * @type {boolean} + */ + environmentMapPrefiltered: false, - var skinMatricesArray = this.skeleton.getSubSkinMatrices(this.__GUID__, this.joints); + /** + * @type {boolean} + */ + linear: false, - if (this.useSkinMatricesTexture) { - var size; - var numJoints = this.joints.length; - if (numJoints > 256) { - size = 64; - } - else if (numJoints > 64) { - size = 32; - } - else if (numJoints > 16) { - size = 16; - } - else { - size = 8; - } + /** + * @type {boolean} + */ + encodeRGBM: false, - var texture = this.getSkinMatricesTexture(); - texture.width = size; - texture.height = size; + /** + * @type {boolean} + */ + decodeRGBM: false, - if (!texture.pixels || texture.pixels.length !== size * size * 4) { - texture.pixels = new Float32Array(size * size * 4); - } - texture.pixels.set(skinMatricesArray); - texture.dirty(); + /** + * @type {Number} + */ + roughnessChannel: 0, + /** + * @type {Number} + */ + metalnessChannel: 1 + }); + + this.define('fragment', 'USE_METALNESS'); + this.define('fragment', 'USE_ROUGHNESS'); +}, { + clone: function () { + var material = new StandardMaterial({ + name: this.name + }); + TEXTURE_PROPERTIES.forEach(function (propName) { + if (this[propName]) { + material[propName] = this[propName]; + } + }, this); + SIMPLE_PROPERTIES.concat(PROPERTIES_CHANGE_SHADER).forEach(function (propName) { + material[propName] = this[propName]; + }, this); + return material; + } +}); - shader.setUniform(_gl, '1f', 'skinMatricesTextureSize', size); +SIMPLE_PROPERTIES.forEach(function (propName) { + Object.defineProperty(StandardMaterial.prototype, propName, { + get: function () { + return this.get(propName); + }, + set: function (value) { + this.setUniform(propName, value); + } + }); +}); + +TEXTURE_PROPERTIES.forEach(function (propName) { + Object.defineProperty(StandardMaterial.prototype, propName, { + get: function () { + return this.get(propName); + }, + set: function (value) { + this.setUniform(propName, value); + } + }); +}); + +PROPERTIES_CHANGE_SHADER.forEach(function (propName) { + var privateKey = '_' + propName; + Object.defineProperty(StandardMaterial.prototype, propName, { + get: function () { + return this[privateKey]; + }, + set: function (value) { + this[privateKey] = value; + if (propName in NUM_DEFINE_MAP) { + var defineName = NUM_DEFINE_MAP[propName]; + this.define('fragment', defineName, value); } else { - shader.setUniformOfSemantic(_gl, 'SKIN_MATRIX', skinMatricesArray); + var defineName = BOOL_DEFINE_MAP[propName]; + value ? this.define('fragment', defineName) : this.undefine('fragment', defineName); } } + }); +}); - return Renderable.prototype.render.call(this, renderer, shader); +Object.defineProperty(StandardMaterial.prototype, 'environmentBox', { + get: function () { + var envBox = this._environmentBox; + if (envBox) { + envBox.min.setArray(this.get('environmentBoxMin')); + envBox.max.setArray(this.get('environmentBoxMax')); + } + return envBox; }, - getSkinMatricesTexture: function () { - this._skinMatricesTexture = this._skinMatricesTexture || new Texture2D({ - type: glenum.FLOAT, - minFilter: glenum.NEAREST, - magFilter: glenum.NEAREST, - useMipmap: false, - flipY: false - }); + set: function (value) { + this._environmentBox = value; - return this._skinMatricesTexture; + var uniforms = this.uniforms = this.uniforms || {}; + uniforms['environmentBoxMin'] = uniforms['environmentBoxMin'] || { + value: null + }; + uniforms['environmentBoxMax'] = uniforms['environmentBoxMax'] || { + value: null + }; + + // TODO Can't detect operation like box.min = new Vector() + if (value) { + this.setUniform('environmentBoxMin', value.min.array); + this.setUniform('environmentBoxMax', value.max.array); + } + + if (value) { + this.define('fragment', 'PARALLAX_CORRECTED'); + } + else { + this.undefine('fragment', 'PARALLAX_CORRECTED'); + } } }); -// Enums -Mesh.POINTS = glenum.POINTS; -Mesh.LINES = glenum.LINES; -Mesh.LINE_LOOP = glenum.LINE_LOOP; -Mesh.LINE_STRIP = glenum.LINE_STRIP; -Mesh.TRIANGLES = glenum.TRIANGLES; -Mesh.TRIANGLE_STRIP = glenum.TRIANGLE_STRIP; -Mesh.TRIANGLE_FAN = glenum.TRIANGLE_FAN; - -Mesh.BACK = glenum.BACK; -Mesh.FRONT = glenum.FRONT; -Mesh.FRONT_AND_BACK = glenum.FRONT_AND_BACK; -Mesh.CW = glenum.CW; -Mesh.CCW = glenum.CCW; - /** - * @constructor qtek.Joint - * @extends qtek.core.Base + * @constructor + * @alias clay.Renderable + * @extends clay.Node */ -var Joint = Base.extend( -/** @lends qtek.Joint# */ -{ - // https://github.com/KhronosGroup/glTF/issues/193#issuecomment-29216576 - /** - * Joint name - * @type {string} - */ - name: '', +var Renderable = Node.extend(/** @lends clay.Renderable# */ { /** - * Index of joint in the skeleton - * @type {number} + * @type {clay.Material} */ - index: -1, + material: null, /** - * Scene node attached to - * @type {qtek.Node} + * @type {clay.Geometry} */ - node: null, + geometry: null, /** - * Root scene node of the skeleton, which parent node is null or don't have a joint - * @type {qtek.Node} + * @type {number} */ - rootNode: null -}); - -var quat$2 = glmatrix.quat; -var vec3$4 = glmatrix.vec3; -var mat4$4 = glmatrix.mat4; - -/** - * @constructor qtek.Skeleton - */ -var Skeleton = Base.extend(function () { - return /** @lends qtek.Skeleton# */{ - - /** - * Relative root node that not affect transform of joint. - * @type {qtek.Node} - */ - relativeRootNode: null, - /** - * @type {string} - */ - name: '', - - /** - * joints - * @type {Array.} - */ - joints: [], - - _clips: [], - - // Matrix to joint space (relative to root joint) - _invBindPoseMatricesArray: null, + mode: glenum.TRIANGLES, - // Use subarray instead of copy back each time computing matrix - // http://jsperf.com/subarray-vs-copy-for-array-transform/5 - _jointMatricesSubArrays: [], + _renderInfo: null +}, +/** @lends clay.Renderable.prototype */ +{ - // jointMatrix * currentPoseMatrix - // worldTransform is relative to the root bone - // still in model space not world space - _skinMatricesArray: null, + __program: null, - _skinMatricesSubArrays: [], + /** + * Group of received light. + */ + lightGroup: 0, + /** + * Render order, Nodes with smaller value renders before nodes with larger values. + * @type {Number} + */ + renderOrder: 0, - _subSkinMatricesArray: {} - }; -}, -/** @lends qtek.Skeleton.prototype */ -{ + /** + * Used when mode is LINES, LINE_STRIP or LINE_LOOP + * @type {number} + */ + // lineWidth: 1, /** - * Add a skinning clip and create a map between clip and skeleton - * @param {qtek.animation.SkinningClip} clip - * @param {Object} [mapRule] Map between joint name in skeleton and joint name in clip + * If enable culling + * @type {boolean} */ - addClip: function (clip, mapRule) { - // Clip have been exists in - for (var i = 0; i < this._clips.length; i++) { - if (this._clips[i].clip === clip) { - return; - } - } - // Map the joint index in skeleton to joint pose index in clip - var maps = []; - for (var i = 0; i < this.joints.length; i++) { - maps[i] = -1; - } - // Create avatar - for (var i = 0; i < clip.tracks.length; i++) { - for (var j = 0; j < this.joints.length; j++) { - var joint = this.joints[j]; - var track = clip.tracks[i]; - var jointName = joint.name; - if (mapRule) { - jointName = mapRule[jointName]; - } - if (track.name === jointName) { - maps[j] = i; - break; - } - } - } + culling: true, + /** + * Specify which side of polygon will be culled. + * Possible values: + * + {@link clay.Renderable.BACK} + * + {@link clay.Renderable.FRONT} + * + {@link clay.Renderable.FRONT_AND_BACK} + * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/cullFace + * @type {number} + */ + cullFace: glenum.BACK, + /** + * Specify which side is front face. + * Possible values: + * + {@link clay.Renderable.CW} + * + {@link clay.Renderable.CCW} + * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/frontFace + * @type {number} + */ + frontFace: glenum.CCW, - this._clips.push({ - maps: maps, - clip: clip - }); + /** + * If enable software frustum culling + * @type {boolean} + */ + frustumCulling: true, + /** + * @type {boolean} + */ + receiveShadow: true, + /** + * @type {boolean} + */ + castShadow: true, + /** + * @type {boolean} + */ + ignorePicking: false, + /** + * @type {boolean} + */ + ignorePreZ: false, - return this._clips.length - 1; - }, + /** + * @type {boolean} + */ + ignoreGBuffer: false, /** - * @param {qtek.animation.SkinningClip} clip + * @return {boolean} */ - removeClip: function (clip) { - var idx = -1; - for (var i = 0; i < this._clips.length; i++) { - if (this._clips[i].clip === clip) { - idx = i; - break; - } - } - if (idx > 0) { - this._clips.splice(idx, 1); - } + isRenderable: function() { + // TODO Shader ? + return this.geometry && this.material && this.material.shader && !this.invisible + && this.geometry.vertexCount > 0; }, + /** - * Remove all clips + * Before render hook + * @type {Function} */ - removeClipsAll: function () { - this._clips = []; - }, + beforeRender: function (_gl) {}, /** - * Get clip by index - * @param {number} index + * Before render hook + * @type {Function} */ - getClip: function (index) { - if (this._clips[index]) { - return this._clips[index].clip; + afterRender: function (_gl, renderStat) {}, + + getBoundingBox: function (filter, out) { + out = Node.prototype.getBoundingBox.call(this, filter, out); + if (this.geometry && this.geometry.boundingBox) { + out.union(this.geometry.boundingBox); } + + return out; }, - /** - * @return {number} - */ - getClipNumber: function () { - return this._clips.length; - }, + /** + * Clone a new renderable + * @function + * @return {clay.Renderable} + */ + clone: (function() { + var properties = [ + 'castShadow', 'receiveShadow', + 'mode', 'culling', 'cullFace', 'frontFace', + 'frustumCulling', + 'renderOrder', 'lineWidth', + 'ignorePicking', 'ignorePreZ', 'ignoreGBuffer' + ]; + return function() { + var renderable = Node.prototype.clone.call(this); + + renderable.geometry = this.geometry; + renderable.material = this.material; + + for (var i = 0; i < properties.length; i++) { + var name = properties[i]; + // Try not to overwrite the prototype property + if (renderable[name] !== this[name]) { + renderable[name] = this[name]; + } + } + + return renderable; + }; + })() +}); + +/** + * @type {number} + */ +Renderable.POINTS = glenum.POINTS; +/** + * @type {number} + */ +Renderable.LINES = glenum.LINES; +/** + * @type {number} + */ +Renderable.LINE_LOOP = glenum.LINE_LOOP; +/** + * @type {number} + */ +Renderable.LINE_STRIP = glenum.LINE_STRIP; +/** + * @type {number} + */ +Renderable.TRIANGLES = glenum.TRIANGLES; +/** + * @type {number} + */ +Renderable.TRIANGLE_STRIP = glenum.TRIANGLE_STRIP; +/** + * @type {number} + */ +Renderable.TRIANGLE_FAN = glenum.TRIANGLE_FAN; +/** + * @type {number} + */ +Renderable.BACK = glenum.BACK; +/** + * @type {number} + */ +Renderable.FRONT = glenum.FRONT; +/** + * @type {number} + */ +Renderable.FRONT_AND_BACK = glenum.FRONT_AND_BACK; +/** + * @type {number} + */ +Renderable.CW = glenum.CW; +/** + * @type {number} + */ +Renderable.CCW = glenum.CCW; + +var mathUtil = {}; - /** - * Calculate joint matrices from node transform - * @method - */ - updateJointMatrices: (function () { +mathUtil.isPowerOfTwo = function (value) { + return (value & (value - 1)) === 0; +}; - var m4 = mat4$4.create(); +mathUtil.nextPowerOfTwo = function (value) { + value --; + value |= value >> 1; + value |= value >> 2; + value |= value >> 4; + value |= value >> 8; + value |= value >> 16; + value ++; - return function () { - this._invBindPoseMatricesArray = new Float32Array(this.joints.length * 16); - this._skinMatricesArray = new Float32Array(this.joints.length * 16); + return value; +}; - for (var i = 0; i < this.joints.length; i++) { - var joint = this.joints[i]; - // if (this.relativeRootNode) { - // mat4.invert(m4, this.relativeRootNode.worldTransform._array); - // mat4.multiply( - // m4, - // m4, - // joint.node.worldTransform._array - // ); - // mat4.invert(m4, m4); - // } - // else { - mat4$4.copy(m4, joint.node.worldTransform._array); - mat4$4.invert(m4, m4); - // } +mathUtil.nearestPowerOfTwo = function (value) { + return Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) ); +}; - var offset = i * 16; - for (var j = 0; j < 16; j++) { - this._invBindPoseMatricesArray[offset + j] = m4[j]; - } - } +var isPowerOfTwo = mathUtil.isPowerOfTwo; - this.updateMatricesSubArrays(); - }; - })(), +function nearestPowerOfTwo(val) { + return Math.pow(2, Math.round(Math.log(val) / Math.LN2)); +} +function convertTextureToPowerOfTwo(texture, canvas) { + // var canvas = document.createElement('canvas'); + var width = nearestPowerOfTwo(texture.width); + var height = nearestPowerOfTwo(texture.height); + canvas = canvas || document.createElement('canvas'); + canvas.width = width; + canvas.height = height; + var ctx = canvas.getContext('2d'); + ctx.drawImage(texture.image, 0, 0, width, height); - setJointMatricesArray: function (arr) { - this._invBindPoseMatricesArray = arr; - this._skinMatricesArray = new Float32Array(arr.length); - this.updateMatricesSubArrays(); - }, + return canvas; +} - updateMatricesSubArrays: function () { - for (var i = 0; i < this.joints.length; i++) { - this._jointMatricesSubArrays[i] = this._invBindPoseMatricesArray.subarray(i * 16, (i+1) * 16); - this._skinMatricesSubArrays[i] = this._skinMatricesArray.subarray(i * 16, (i+1) * 16); - } - }, +/** + * @constructor clay.Texture2D + * @extends clay.Texture + * + * @example + * ... + * var mat = new clay.Material({ + * shader: clay.shader.library.get('clay.phong', 'diffuseMap') + * }); + * var diffuseMap = new clay.Texture2D(); + * diffuseMap.load('assets/textures/diffuse.jpg'); + * mat.set('diffuseMap', diffuseMap); + * ... + * diffuseMap.success(function () { + * // Wait for the diffuse texture loaded + * animation.on('frame', function (frameTime) { + * renderer.render(scene, camera); + * }); + * }); + */ +var Texture2D = Texture$1.extend(function () { + return /** @lends clay.Texture2D# */ { + /** + * @type {?HTMLImageElement|HTMLCanvasElemnet} + */ + image: null, + /** + * Pixels data. Will be ignored if image is set. + * @type {?Uint8Array|Float32Array} + */ + pixels: null, + /** + * @type {Array.} + * @example + * [{ + * image: mipmap0, + * pixels: null + * }, { + * image: mipmap1, + * pixels: null + * }, ....] + */ + mipmaps: [], - /** - * Update skinning matrices - */ - update: (function () { - // var m4 = mat4.create(); - return function () { - for (var i = 0; i < this.joints.length; i++) { - var joint = this.joints[i]; - mat4$4.multiply( - this._skinMatricesSubArrays[i], - joint.node.worldTransform._array, - this._jointMatricesSubArrays[i] - ); + /** + * If convert texture to power-of-two + * @type {boolean} + */ + convertToPOT: false + }; +}, { - // Joint space is relative to root, if have - // if (this.relativeRootNode) { - // mat4.invert(m4, this.relativeRootNode.worldTransform._array); - // mat4.multiply( - // this._skinMatricesSubArrays[i], - // m4, - // this._skinMatricesSubArrays[i] - // ); - // } - } - }; - })(), + textureType: 'texture2D', - getSubSkinMatrices: function (meshId, joints) { - var subArray = this._subSkinMatricesArray[meshId]; - if (!subArray) { - subArray - = this._subSkinMatricesArray[meshId] - = new Float32Array(joints.length * 16); - } - var cursor = 0; - for (var i = 0; i < joints.length; i++) { - var idx = joints[i]; - for (var j = 0; j < 16; j++) { - subArray[cursor++] = this._skinMatricesArray[idx * 16 + j]; - } - } - return subArray; - }, + update: function (renderer) { - /** - * Set pose and update skinning matrices - * @param {number} clipIndex - */ - setPose: function (clipIndex) { - if (this._clips[clipIndex]) { - var clip = this._clips[clipIndex].clip; - var maps = this._clips[clipIndex].maps; + var _gl = renderer.gl; + _gl.bindTexture(_gl.TEXTURE_2D, this._cache.get('webgl_texture')); - for (var i = 0; i < this.joints.length; i++) { - var joint = this.joints[i]; - if (maps[i] === -1) { - continue; - } - var pose = clip.tracks[maps[i]]; + this.updateCommon(renderer); - // Not update if there is no data. - // PENDING If sync pose.position, pose.rotation, pose.scale - if (pose.channels.position) { - vec3$4.copy(joint.node.position._array, pose.position); - } - if (pose.channels.rotation) { - quat$2.copy(joint.node.rotation._array, pose.rotation); - } - if (pose.channels.scale) { - vec3$4.copy(joint.node.scale._array, pose.scale); - } + var glFormat = this.format; + var glType = this.type; - joint.node.position._dirty = true; - joint.node.rotation._dirty = true; - joint.node.scale._dirty = true; - } - } - this.update(); - }, + // Convert to pot is only available when using image/canvas/video element. + var convertToPOT = !!(this.convertToPOT + && !this.mipmaps.length && this.image + && (this.wrapS === Texture$1.REPEAT || this.wrapT === Texture$1.REPEAT) + && this.NPOT + ); - clone: function (rootNode, newRootNode) { - var skeleton = new Skeleton(); - skeleton.name = this.name; + _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, convertToPOT ? this.wrapS : this.getAvailableWrapS()); + _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, convertToPOT ? this.wrapT : this.getAvailableWrapT()); - for (var i = 0; i < this.joints.length; i++) { - var newJoint = new Joint(); - newJoint.name = this.joints[i].name; - newJoint.index = this.joints[i].index; + _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, convertToPOT ? this.magFilter : this.getAvailableMagFilter()); + _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, convertToPOT ? this.minFilter : this.getAvailableMinFilter()); - var path = this.joints[i].node.getPath(rootNode); - var rootNodePath = this.joints[i].rootNode.getPath(rootNode); + var anisotropicExt = renderer.getGLExtension('EXT_texture_filter_anisotropic'); + if (anisotropicExt && this.anisotropic > 1) { + _gl.texParameterf(_gl.TEXTURE_2D, anisotropicExt.TEXTURE_MAX_ANISOTROPY_EXT, this.anisotropic); + } - if (path != null && rootNodePath != null) { - newJoint.node = newRootNode.queryNode(path); - } - else { - // PENDING - console.warn('Something wrong in clone, may be the skeleton root nodes is not mounted on the cloned root node.'); + // Fallback to float type if browser don't have half float extension + if (glType === 36193) { + var halfFloatExt = renderer.getGLExtension('OES_texture_half_float'); + if (!halfFloatExt) { + glType = glenum.FLOAT; } - skeleton.joints.push(newJoint); } - if (this._invBindPoseMatricesArray) { - var len = this._invBindPoseMatricesArray.length; - skeleton._invBindPoseMatricesArray = new Float32Array(len); - for (var i = 0; i < len; i++) { - skeleton._invBindPoseMatricesArray[i] = this._invBindPoseMatricesArray[i]; + if (this.mipmaps.length) { + var width = this.width; + var height = this.height; + for (var i = 0; i < this.mipmaps.length; i++) { + var mipmap = this.mipmaps[i]; + this._updateTextureData(_gl, mipmap, i, width, height, glFormat, glType, false); + width /= 2; + height /= 2; } - - skeleton._skinMatricesArray = new Float32Array(len); - - skeleton.updateMatricesSubArrays(); } + else { + this._updateTextureData(_gl, this, 0, this.width, this.height, glFormat, glType, convertToPOT); - skeleton.update(); - - return skeleton; - } -}); - -var vec3$7 = glmatrix.vec3; -var mat4$5 = glmatrix.mat4; -var vec4$1 = glmatrix.vec4; - -/** - * @constructor - * @alias qtek.math.Plane - * @param {qtek.math.Vector3} [normal] - * @param {number} [distance] - */ -var Plane = function(normal, distance) { - /** - * Normal of the plane - * @type {qtek.math.Vector3} - */ - this.normal = normal || new Vector3(0, 1, 0); - - /** - * Constant of the plane equation, used as distance to the origin - * @type {number} - */ - this.distance = distance || 0; -}; - -Plane.prototype = { + if (this.useMipmap && (!this.NPOT || convertToPOT)) { + _gl.generateMipmap(_gl.TEXTURE_2D); + } + } - constructor: Plane, + _gl.bindTexture(_gl.TEXTURE_2D, null); + }, - /** - * Distance from given point to plane - * @param {qtek.math.Vector3} point - * @return {number} - */ - distanceToPoint: function(point) { - return vec3$7.dot(point._array, this.normal._array) - this.distance; + _updateTextureData: function (_gl, data, level, width, height, glFormat, glType, convertToPOT) { + if (data.image) { + var imgData = data.image; + if (convertToPOT) { + this._potCanvas = convertTextureToPowerOfTwo(this, this._potCanvas); + imgData = this._potCanvas; + } + _gl.texImage2D(_gl.TEXTURE_2D, level, glFormat, glFormat, glType, imgData); + } + else { + // Can be used as a blank texture when writing render to texture(RTT) + if ( + glFormat <= Texture$1.COMPRESSED_RGBA_S3TC_DXT5_EXT + && glFormat >= Texture$1.COMPRESSED_RGB_S3TC_DXT1_EXT + ) { + _gl.compressedTexImage2D(_gl.TEXTURE_2D, level, glFormat, width, height, 0, data.pixels); + } + else { + // Is a render target if pixels is null + _gl.texImage2D(_gl.TEXTURE_2D, level, glFormat, width, height, 0, glFormat, glType, data.pixels); + } + } }, /** - * Calculate the projection on the plane of point - * @param {qtek.math.Vector3} point - * @param {qtek.math.Vector3} out - * @return {qtek.math.Vector3} + * @param {clay.Renderer} renderer + * @memberOf clay.Texture2D.prototype */ - projectPoint: function(point, out) { - if (!out) { - out = new Vector3(); + generateMipmap: function (renderer) { + var _gl = renderer.gl; + if (this.useMipmap && !this.NPOT) { + _gl.bindTexture(_gl.TEXTURE_2D, this._cache.get('webgl_texture')); + _gl.generateMipmap(_gl.TEXTURE_2D); } - var d = this.distanceToPoint(point); - vec3$7.scaleAndAdd(out._array, point._array, this.normal._array, -d); - out._dirty = true; - return out; }, - /** - * Normalize the plane's normal and calculate distance - */ - normalize: function() { - var invLen = 1 / vec3$7.len(this.normal._array); - vec3$7.scale(this.normal._array, invLen); - this.distance *= invLen; + isPowerOfTwo: function () { + return isPowerOfTwo(this.width) && isPowerOfTwo(this.height); }, - /** - * If the plane intersect a frustum - * @param {qtek.math.Frustum} Frustum - * @return {boolean} - */ - intersectFrustum: function(frustum) { - // Check if all coords of frustum is on plane all under plane - var coords = frustum.vertices; - var normal = this.normal._array; - var onPlane = vec3$7.dot(coords[0]._array, normal) > this.distance; - for (var i = 1; i < 8; i++) { - if ((vec3$7.dot(coords[i]._array, normal) > this.distance) != onPlane) { - return true; - } + isRenderable: function () { + if (this.image) { + return this.image.nodeName === 'CANVAS' + || this.image.nodeName === 'VIDEO' + || this.image.complete; + } + else { + return !!(this.width && this.height); } }, - /** - * Calculate the intersection point between plane and a given line - * @method - * @param {qtek.math.Vector3} start start point of line - * @param {qtek.math.Vector3} end end point of line - * @param {qtek.math.Vector3} [out] - * @return {qtek.math.Vector3} - */ - intersectLine: (function() { - var rd = vec3$7.create(); - return function(start, end, out) { - var d0 = this.distanceToPoint(start); - var d1 = this.distanceToPoint(end); - if ((d0 > 0 && d1 > 0) || (d0 < 0 && d1 < 0)) { - return null; - } - // Ray intersection - var pn = this.normal._array; - var d = this.distance; - var ro = start._array; - // direction - vec3$7.sub(rd, end._array, start._array); - vec3$7.normalize(rd, rd); + bind: function (renderer) { + renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, this.getWebGLTexture(renderer)); + }, - var divider = vec3$7.dot(pn, rd); - // ray is parallel to the plane - if (divider === 0) { - return null; - } - if (!out) { - out = new Vector3(); - } - var t = (vec3$7.dot(pn, ro) - d) / divider; - vec3$7.scaleAndAdd(out._array, ro, rd, -t); - out._dirty = true; - return out; - }; - })(), + unbind: function (renderer) { + renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, null); + }, - /** - * Apply an affine transform matrix to plane - * @method - * @return {qtek.math.Matrix4} - */ - applyTransform: (function() { - var inverseTranspose = mat4$5.create(); - var normalv4 = vec4$1.create(); - var pointv4 = vec4$1.create(); - pointv4[3] = 1; - return function(m4) { - m4 = m4._array; - // Transform point on plane - vec3$7.scale(pointv4, this.normal._array, this.distance); - vec4$1.transformMat4(pointv4, pointv4, m4); - this.distance = vec3$7.dot(pointv4, this.normal._array); - // Transform plane normal - mat4$5.invert(inverseTranspose, m4); - mat4$5.transpose(inverseTranspose, inverseTranspose); - normalv4[3] = 0; - vec3$7.copy(normalv4, this.normal._array); - vec4$1.transformMat4(normalv4, normalv4, inverseTranspose); - vec3$7.copy(this.normal._array, normalv4); + load: function (src, crossOrigin) { + var image = new Image(); + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + var self = this; + image.onload = function () { + self.dirty(); + self.trigger('success', self); + image.onload = null; + }; + image.onerror = function () { + self.trigger('error', self); + image.onerror = null; }; - })(), - /** - * Copy from another plane - * @param {qtek.math.Vector3} plane - */ - copy: function(plane) { - vec3$7.copy(this.normal._array, plane.normal._array); - this.normal._dirty = true; - this.distance = plane.distance; - }, + image.src = src; + this.image = image; - /** - * Clone a new plane - * @return {qtek.math.Plane} - */ - clone: function() { - var plane = new Plane(); - plane.copy(this); - return plane; + return this; } -}; +}); -var vec3$6 = glmatrix.vec3; +Object.defineProperty(Texture2D.prototype, 'width', { + get: function () { + if (this.image) { + return this.image.width; + } + return this._width; + }, + set: function (value) { + if (this.image) { + console.warn('Texture from image can\'t set width'); + } + else { + if (this._width !== value) { + this.dirty(); + } + this._width = value; + } + } +}); +Object.defineProperty(Texture2D.prototype, 'height', { + get: function () { + if (this.image) { + return this.image.height; + } + return this._height; + }, + set: function (value) { + if (this.image) { + console.warn('Texture from image can\'t set height'); + } + else { + if (this._height !== value) { + this.dirty(); + } + this._height = value; + } + } +}); -var vec3Set$1 = vec3$6.set; -var vec3Copy$1 = vec3$6.copy; -var vec3TranformMat4 = vec3$6.transformMat4; -var mathMin = Math.min; -var mathMax = Math.max; /** - * @constructor - * @alias qtek.math.Frustum + * @constructor clay.Mesh + * @extends clay.Renderable */ -var Frustum = function() { - - /** - * Eight planes to enclose the frustum - * @type {qtek.math.Plane[]} - */ - this.planes = []; - - for (var i = 0; i < 6; i++) { - this.planes.push(new Plane()); - } - +var Mesh = Renderable.extend(/** @lends clay.Mesh# */ { /** - * Bounding box of frustum - * @type {qtek.math.BoundingBox} + * Used when it is a skinned mesh + * @type {clay.Skeleton} */ - this.boundingBox = new BoundingBox(); - + skeleton: null, /** - * Eight vertices of frustum - * @type {Float32Array[]} + * Joints indices Meshes can share the one skeleton instance and each mesh can use one part of joints. Joints indices indicate the index of joint in the skeleton instance + * @type {number[]} */ - this.vertices = []; - for (var i = 0; i < 8; i++) { - this.vertices[i] = vec3$6.fromValues(0, 0, 0); - } -}; - -Frustum.prototype = { + joints: null, - // http://web.archive.org/web/20120531231005/http://crazyjoke.free.fr/doc/3D/plane%20extraction.pdf /** - * Set frustum from a projection matrix - * @param {qtek.math.Matrix4} projectionMatrix - */ - setFromProjection: function(projectionMatrix) { - - var planes = this.planes; - var m = projectionMatrix._array; - var m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3]; - var m4 = m[4], m5 = m[5], m6 = m[6], m7 = m[7]; - var m8 = m[8], m9 = m[9], m10 = m[10], m11 = m[11]; - var m12 = m[12], m13 = m[13], m14 = m[14], m15 = m[15]; - - // Update planes - vec3Set$1(planes[0].normal._array, m3 - m0, m7 - m4, m11 - m8); - planes[0].distance = -(m15 - m12); - planes[0].normalize(); - - vec3Set$1(planes[1].normal._array, m3 + m0, m7 + m4, m11 + m8); - planes[1].distance = -(m15 + m12); - planes[1].normalize(); - - vec3Set$1(planes[2].normal._array, m3 + m1, m7 + m5, m11 + m9); - planes[2].distance = -(m15 + m13); - planes[2].normalize(); - - vec3Set$1(planes[3].normal._array, m3 - m1, m7 - m5, m11 - m9); - planes[3].distance = -(m15 - m13); - planes[3].normalize(); - - vec3Set$1(planes[4].normal._array, m3 - m2, m7 - m6, m11 - m10); - planes[4].distance = -(m15 - m14); - planes[4].normalize(); - - vec3Set$1(planes[5].normal._array, m3 + m2, m7 + m6, m11 + m10); - planes[5].distance = -(m15 + m14); - planes[5].normalize(); - - // Perspective projection - var boundingBox = this.boundingBox; - if (m15 === 0) { - var aspect = m5 / m0; - var zNear = -m14 / (m10 - 1); - var zFar = -m14 / (m10 + 1); - var farY = -zFar / m5; - var nearY = -zNear / m5; - // Update bounding box - boundingBox.min.set(-farY * aspect, -farY, zFar); - boundingBox.max.set(farY * aspect, farY, zNear); - // update vertices - var vertices = this.vertices; - //--- min z - // min x - vec3Set$1(vertices[0], -farY * aspect, -farY, zFar); - vec3Set$1(vertices[1], -farY * aspect, farY, zFar); - // max x - vec3Set$1(vertices[2], farY * aspect, -farY, zFar); - vec3Set$1(vertices[3], farY * aspect, farY, zFar); - //-- max z - vec3Set$1(vertices[4], -nearY * aspect, -nearY, zNear); - vec3Set$1(vertices[5], -nearY * aspect, nearY, zNear); - vec3Set$1(vertices[6], nearY * aspect, -nearY, zNear); - vec3Set$1(vertices[7], nearY * aspect, nearY, zNear); - } - else { // Orthographic projection - var left = (-1 - m12) / m0; - var right = (1 - m12) / m0; - var top = (1 - m13) / m5; - var bottom = (-1 - m13) / m5; - var near = (-1 - m14) / m10; - var far = (1 - m14) / m10; - + * If store the skin matrices in vertex texture + * @type {bool} + */ + useSkinMatricesTexture: false - boundingBox.min.set(Math.min(left, right), Math.min(bottom, top), Math.min(far, near)); - boundingBox.max.set(Math.max(right, left), Math.max(top, bottom), Math.max(near, far)); +}, function () { + if (!this.joints) { + this.joints = []; + } +}, { - var min = boundingBox.min._array; - var max = boundingBox.max._array; - var vertices = this.vertices; - //--- min z - // min x - vec3Set$1(vertices[0], min[0], min[1], min[2]); - vec3Set$1(vertices[1], min[0], max[1], min[2]); - // max x - vec3Set$1(vertices[2], max[0], min[1], min[2]); - vec3Set$1(vertices[3], max[0], max[1], min[2]); - //-- max z - vec3Set$1(vertices[4], min[0], min[1], max[2]); - vec3Set$1(vertices[5], min[0], max[1], max[2]); - vec3Set$1(vertices[6], max[0], min[1], max[2]); - vec3Set$1(vertices[7], max[0], max[1], max[2]); - } + isSkinnedMesh: function () { + return !!(this.skeleton && this.joints && this.joints.length > 0); }, - /** - * Apply a affine transform matrix and set to the given bounding box - * @method - * @param {qtek.math.BoundingBox} - * @param {qtek.math.Matrix4} - * @return {qtek.math.BoundingBox} - */ - getTransformedBoundingBox: (function() { + getSkinMatricesTexture: function () { + this._skinMatricesTexture = this._skinMatricesTexture || new Texture2D({ + type: glenum.FLOAT, + minFilter: glenum.NEAREST, + magFilter: glenum.NEAREST, + useMipmap: false, + flipY: false + }); - var tmpVec3 = vec3$6.create(); + return this._skinMatricesTexture; + }, - return function(bbox, matrix) { - var vertices = this.vertices; + clone: function () { + var mesh = Renderable.prototype.clone.call(this); + mesh.skeleton = this.skeleton; + if (this.joints) { + mesh.joints = this.joints.slice(); + } + return mesh; + } +}); - var m4 = matrix._array; - var min = bbox.min; - var max = bbox.max; - var minArr = min._array; - var maxArr = max._array; - var v = vertices[0]; - vec3TranformMat4(tmpVec3, v, m4); - vec3Copy$1(minArr, tmpVec3); - vec3Copy$1(maxArr, tmpVec3); +// Enums +Mesh.POINTS = glenum.POINTS; +Mesh.LINES = glenum.LINES; +Mesh.LINE_LOOP = glenum.LINE_LOOP; +Mesh.LINE_STRIP = glenum.LINE_STRIP; +Mesh.TRIANGLES = glenum.TRIANGLES; +Mesh.TRIANGLE_STRIP = glenum.TRIANGLE_STRIP; +Mesh.TRIANGLE_FAN = glenum.TRIANGLE_FAN; - for (var i = 1; i < 8; i++) { - v = vertices[i]; - vec3TranformMat4(tmpVec3, v, m4); +Mesh.BACK = glenum.BACK; +Mesh.FRONT = glenum.FRONT; +Mesh.FRONT_AND_BACK = glenum.FRONT_AND_BACK; +Mesh.CW = glenum.CW; +Mesh.CCW = glenum.CCW; - minArr[0] = mathMin(tmpVec3[0], minArr[0]); - minArr[1] = mathMin(tmpVec3[1], minArr[1]); - minArr[2] = mathMin(tmpVec3[2], minArr[2]); +var _library = {}; - maxArr[0] = mathMax(tmpVec3[0], maxArr[0]); - maxArr[1] = mathMax(tmpVec3[1], maxArr[1]); - maxArr[2] = mathMax(tmpVec3[2], maxArr[2]); - } +function ShaderLibrary () { + this._pool = {}; +} - min._dirty = true; - max._dirty = true; +ShaderLibrary.prototype.get = function(name) { + var key = name; - return bbox; - }; - }) () + if (this._pool[key]) { + return this._pool[key]; + } + else { + var source = _library[name]; + if (!source) { + console.error('Shader "' + name + '"' + ' is not in the library'); + return; + } + var shader = new Shader(source.vertex, source.fragment); + this._pool[key] = shader; + return shader; + } }; -var vec3$8 = glmatrix.vec3; +ShaderLibrary.prototype.clear = function() { + this._pool = {}; +}; -var EPSILON = 1e-5; +function template(name, vertex, fragment) { + _library[name] = { + vertex: vertex, + fragment: fragment + }; +} + +var defaultLibrary = new ShaderLibrary(); /** - * @constructor - * @alias qtek.math.Ray - * @param {qtek.math.Vector3} [origin] - * @param {qtek.math.Vector3} [direction] + * ### Builin shaders + * + clay.standard + * + clay.basic + * + clay.lambert + * + clay.wireframe + * + * @namespace clay.shader.library */ -var Ray = function (origin, direction) { +var library = { /** - * @type {qtek.math.Vector3} + * Create a new shader library. */ - this.origin = origin || new Vector3(); + createLibrary: function () { + return new ShaderLibrary(); + }, + /** + * Get shader from default library. + * @param {string} name + * @return {clay.Shader} + * @memberOf clay.shader.library + * @example + * clay.shader.library.get('clay.standard') + */ + get: function () { + return defaultLibrary.get.apply(defaultLibrary, arguments); + }, /** - * @type {qtek.math.Vector3} + * @memberOf clay.shader.library + * @param {string} name + * @param {string} vertex - Vertex shader code + * @param {string} fragment - Fragment shader code */ - this.direction = direction || new Vector3(); + template: template, + clear: function () { + return defaultLibrary.clear(); + } }; -Ray.prototype = { - - constructor: Ray, - - // http://www.siggraph.org/education/materials/HyperGraph/raytrace/rayplane_intersection.htm +/** + * @constructor clay.Joint + * @extends clay.core.Base + */ +var Joint = Base.extend( +/** @lends clay.Joint# */ +{ + // https://github.com/KhronosGroup/glTF/issues/193#issuecomment-29216576 /** - * Calculate intersection point between ray and a give plane - * @param {qtek.math.Plane} plane - * @param {qtek.math.Vector3} [out] - * @return {qtek.math.Vector3} + * Joint name + * @type {string} */ - intersectPlane: function (plane, out) { - var pn = plane.normal._array; - var d = plane.distance; - var ro = this.origin._array; - var rd = this.direction._array; - - var divider = vec3$8.dot(pn, rd); - // ray is parallel to the plane - if (divider === 0) { - return null; - } - if (!out) { - out = new Vector3(); - } - var t = (vec3$8.dot(pn, ro) - d) / divider; - vec3$8.scaleAndAdd(out._array, ro, rd, -t); - out._dirty = true; - return out; - }, - + name: '', /** - * Mirror the ray against plane - * @param {qtek.math.Plane} plane + * Index of joint in the skeleton + * @type {number} */ - mirrorAgainstPlane: function (plane) { - // Distance to plane - var d = vec3$8.dot(plane.normal._array, this.direction._array); - vec3$8.scaleAndAdd(this.direction._array, this.direction._array, plane.normal._array, -d * 2); - this.direction._dirty = true; - }, - - distanceToPoint: (function () { - var v = vec3$8.create(); - return function (point) { - vec3$8.sub(v, point, this.origin._array); - // Distance from projection point to origin - var b = vec3$8.dot(v, this.direction._array); - if (b < 0) { - return vec3$8.distance(this.origin._array, point); - } - // Squared distance from center to origin - var c2 = vec3$8.lenSquared(v); - // Squared distance from center to projection point - return Math.sqrt(c2 - b * b); - }; - })(), + index: -1, /** - * Calculate intersection point between ray and sphere - * @param {qtek.math.Vector3} center - * @param {number} radius - * @param {qtek.math.Vector3} out - * @return {qtek.math.Vector3} + * Scene node attached to + * @type {clay.Node} */ - intersectSphere: (function () { - var v = vec3$8.create(); - return function (center, radius, out) { - var origin = this.origin._array; - var direction = this.direction._array; - center = center._array; - vec3$8.sub(v, center, origin); - // Distance from projection point to origin - var b = vec3$8.dot(v, direction); - // Squared distance from center to origin - var c2 = vec3$8.squaredLength(v); - // Squared distance from center to projection point - var d2 = c2 - b * b; - - var r2 = radius * radius; - // No intersection - if (d2 > r2) { - return; - } - - var a = Math.sqrt(r2 - d2); - // First intersect point - var t0 = b - a; - // Second intersect point - var t1 = b + a; + node: null +}); - if (!out) { - out = new Vector3(); - } - if (t0 < 0) { - if (t1 < 0) { - return null; - } - else { - vec3$8.scaleAndAdd(out._array, origin, direction, t1); - return out; - } - } - else { - vec3$8.scaleAndAdd(out._array, origin, direction, t0); - return out; - } - }; - })(), +var quat$2 = glmatrix.quat; +var vec3$8 = glmatrix.vec3; +var mat4$6 = glmatrix.mat4; - // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ - /** - * Calculate intersection point between ray and bounding box - * @param {qtek.math.BoundingBox} bbox - * @param {qtek.math.Vector3} - * @return {qtek.math.Vector3} - */ - intersectBoundingBox: function (bbox, out) { - var dir = this.direction._array; - var origin = this.origin._array; - var min = bbox.min._array; - var max = bbox.max._array; +/** + * @constructor clay.Skeleton + */ +var Skeleton = Base.extend(function () { + return /** @lends clay.Skeleton# */{ - var invdirx = 1 / dir[0]; - var invdiry = 1 / dir[1]; - var invdirz = 1 / dir[2]; + /** + * Relative root node that not affect transform of joint. + * @type {clay.Node} + */ + relativeRootNode: null, + /** + * @type {string} + */ + name: '', - var tmin, tmax, tymin, tymax, tzmin, tzmax; - if (invdirx >= 0) { - tmin = (min[0] - origin[0]) * invdirx; - tmax = (max[0] - origin[0]) * invdirx; - } - else { - tmax = (min[0] - origin[0]) * invdirx; - tmin = (max[0] - origin[0]) * invdirx; - } - if (invdiry >= 0) { - tymin = (min[1] - origin[1]) * invdiry; - tymax = (max[1] - origin[1]) * invdiry; - } - else { - tymax = (min[1] - origin[1]) * invdiry; - tymin = (max[1] - origin[1]) * invdiry; - } + /** + * joints + * @type {Array.} + */ + joints: [], - if ((tmin > tymax) || (tymin > tmax)) { - return null; - } + _clips: [], - if (tymin > tmin || tmin !== tmin) { - tmin = tymin; - } - if (tymax < tmax || tmax !== tmax) { - tmax = tymax; - } + // Matrix to joint space (relative to root joint) + _invBindPoseMatricesArray: null, - if (invdirz >= 0) { - tzmin = (min[2] - origin[2]) * invdirz; - tzmax = (max[2] - origin[2]) * invdirz; - } - else { - tzmax = (min[2] - origin[2]) * invdirz; - tzmin = (max[2] - origin[2]) * invdirz; - } + // Use subarray instead of copy back each time computing matrix + // http://jsperf.com/subarray-vs-copy-for-array-transform/5 + _jointMatricesSubArrays: [], - if ((tmin > tzmax) || (tzmin > tmax)) { - return null; - } + // jointMatrix * currentPoseMatrix + // worldTransform is relative to the root bone + // still in model space not world space + _skinMatricesArray: null, - if (tzmin > tmin || tmin !== tmin) { - tmin = tzmin; + _skinMatricesSubArrays: [], + + _subSkinMatricesArray: {} + }; +}, +/** @lends clay.Skeleton.prototype */ +{ + + /** + * Add a skinning clip and create a map between clip and skeleton + * @param {clay.animation.SkinningClip} clip + * @param {Object} [mapRule] Map between joint name in skeleton and joint name in clip + */ + addClip: function (clip, mapRule) { + // Clip have been exists in + for (var i = 0; i < this._clips.length; i++) { + if (this._clips[i].clip === clip) { + return; + } } - if (tzmax < tmax || tmax !== tmax) { - tmax = tzmax; + // Map the joint index in skeleton to joint pose index in clip + var maps = []; + for (var i = 0; i < this.joints.length; i++) { + maps[i] = -1; } - if (tmax < 0) { - return null; + // Create avatar + for (var i = 0; i < clip.tracks.length; i++) { + for (var j = 0; j < this.joints.length; j++) { + var joint = this.joints[j]; + var track = clip.tracks[i]; + var jointName = joint.name; + if (mapRule) { + jointName = mapRule[jointName]; + } + if (track.name === jointName) { + maps[j] = i; + break; + } + } } - var t = tmin >= 0 ? tmin : tmax; + this._clips.push({ + maps: maps, + clip: clip + }); - if (!out) { - out = new Vector3(); + return this._clips.length - 1; + }, + + /** + * @param {clay.animation.SkinningClip} clip + */ + removeClip: function (clip) { + var idx = -1; + for (var i = 0; i < this._clips.length; i++) { + if (this._clips[i].clip === clip) { + idx = i; + break; + } } - vec3$8.scaleAndAdd(out._array, origin, dir, t); - return out; + if (idx > 0) { + this._clips.splice(idx, 1); + } + }, + /** + * Remove all clips + */ + removeClipsAll: function () { + this._clips = []; }, - // http://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm /** - * Calculate intersection point between ray and three triangle vertices - * @param {qtek.math.Vector3} a - * @param {qtek.math.Vector3} b - * @param {qtek.math.Vector3} c - * @param {boolean} singleSided, CW triangle will be ignored - * @param {qtek.math.Vector3} [out] - * @param {qtek.math.Vector3} [barycenteric] barycentric coords - * @return {qtek.math.Vector3} + * Get clip by index + * @param {number} index */ - intersectTriangle: (function () { + getClip: function (index) { + if (this._clips[index]) { + return this._clips[index].clip; + } + }, - var eBA = vec3$8.create(); - var eCA = vec3$8.create(); - var AO = vec3$8.create(); - var vCross = vec3$8.create(); + /** + * @return {number} + */ + getClipNumber: function () { + return this._clips.length; + }, - return function (a, b, c, singleSided, out, barycenteric) { - var dir = this.direction._array; - var origin = this.origin._array; - a = a._array; - b = b._array; - c = c._array; + /** + * Calculate joint matrices from node transform + * @function + */ + updateJointMatrices: (function () { - vec3$8.sub(eBA, b, a); - vec3$8.sub(eCA, c, a); + var m4 = mat4$6.create(); - vec3$8.cross(vCross, eCA, dir); + return function () { + this._invBindPoseMatricesArray = new Float32Array(this.joints.length * 16); + this._skinMatricesArray = new Float32Array(this.joints.length * 16); - var det = vec3$8.dot(eBA, vCross); + for (var i = 0; i < this.joints.length; i++) { + var joint = this.joints[i]; + mat4$6.copy(m4, joint.node.worldTransform.array); + mat4$6.invert(m4, m4); - if (singleSided) { - if (det > -EPSILON) { - return null; - } - } - else { - if (det > -EPSILON && det < EPSILON) { - return null; + var offset = i * 16; + for (var j = 0; j < 16; j++) { + this._invBindPoseMatricesArray[offset + j] = m4[j]; } } - vec3$8.sub(AO, origin, a); - var u = vec3$8.dot(vCross, AO) / det; - if (u < 0 || u > 1) { - return null; - } - - vec3$8.cross(vCross, eBA, AO); - var v = vec3$8.dot(dir, vCross) / det; - - if (v < 0 || v > 1 || (u + v > 1)) { - return null; - } - - vec3$8.cross(vCross, eBA, eCA); - var t = -vec3$8.dot(AO, vCross) / det; - - if (t < 0) { - return null; - } - - if (!out) { - out = new Vector3(); - } - if (barycenteric) { - Vector3.set(barycenteric, (1 - u - v), u, v); - } - vec3$8.scaleAndAdd(out._array, origin, dir, t); - - return out; + this.updateMatricesSubArrays(); }; })(), - /** - * Apply an affine transform matrix to the ray - * @return {qtek.math.Matrix4} matrix - */ - applyTransform: function (matrix) { - Vector3.add(this.direction, this.direction, this.origin); - Vector3.transformMat4(this.origin, this.origin, matrix); - Vector3.transformMat4(this.direction, this.direction, matrix); - - Vector3.sub(this.direction, this.direction, this.origin); - Vector3.normalize(this.direction, this.direction); + setJointMatricesArray: function (arr) { + this._invBindPoseMatricesArray = arr; + this._skinMatricesArray = new Float32Array(arr.length); + this.updateMatricesSubArrays(); }, - /** - * Copy values from another ray - * @param {qtek.math.Ray} ray - */ - copy: function (ray) { - Vector3.copy(this.origin, ray.origin); - Vector3.copy(this.direction, ray.direction); + updateMatricesSubArrays: function () { + for (var i = 0; i < this.joints.length; i++) { + this._jointMatricesSubArrays[i] = this._invBindPoseMatricesArray.subarray(i * 16, (i+1) * 16); + this._skinMatricesSubArrays[i] = this._skinMatricesArray.subarray(i * 16, (i+1) * 16); + } }, /** - * Clone a new ray - * @return {qtek.math.Ray} + * Update skinning matrices */ - clone: function () { - var ray = new Ray(); - ray.copy(this); - return ray; - } -}; + update: function () { -var vec3$5 = glmatrix.vec3; -var vec4 = glmatrix.vec4; + this._setPose(); -/** - * @constructor qtek.Camera - * @extends qtek.Node - */ -var Camera = Node.extend(function () { - return /** @lends qtek.Camera# */ { - /** - * Camera projection matrix - * @type {qtek.math.Matrix4} - */ - projectionMatrix: new Matrix4(), + for (var i = 0; i < this.joints.length; i++) { + var joint = this.joints[i]; + mat4$6.multiply( + this._skinMatricesSubArrays[i], + joint.node.worldTransform.array, + this._jointMatricesSubArrays[i] + ); + } + }, - /** - * Inverse of camera projection matrix - * @type {qtek.math.Matrix4} - */ - invProjectionMatrix: new Matrix4(), + getSubSkinMatrices: function (meshId, joints) { + var subArray = this._subSkinMatricesArray[meshId]; + if (!subArray) { + subArray + = this._subSkinMatricesArray[meshId] + = new Float32Array(joints.length * 16); + } + var cursor = 0; + for (var i = 0; i < joints.length; i++) { + var idx = joints[i]; + for (var j = 0; j < 16; j++) { + subArray[cursor++] = this._skinMatricesArray[idx * 16 + j]; + } + } + return subArray; + }, - /** - * View matrix, equal to inverse of camera's world matrix - * @type {qtek.math.Matrix4} - */ - viewMatrix: new Matrix4(), + _setPose: function () { + if (this._clips[0]) { + var clip = this._clips[0].clip; + var maps = this._clips[0].maps; - /** - * Camera frustum in view space - * @type {qtek.math.Frustum} - */ - frustum: new Frustum() - }; -}, function () { - this.update(true); -}, -/** @lends qtek.Camera.prototype */ -{ + for (var i = 0; i < this.joints.length; i++) { + var joint = this.joints[i]; + if (maps[i] === -1) { + continue; + } + var pose = clip.tracks[maps[i]]; + + // Not update if there is no data. + // PENDING If sync pose.position, pose.rotation, pose.scale + if (pose.channels.position) { + vec3$8.copy(joint.node.position.array, pose.position); + } + if (pose.channels.rotation) { + quat$2.copy(joint.node.rotation.array, pose.rotation); + } + if (pose.channels.scale) { + vec3$8.copy(joint.node.scale.array, pose.scale); + } - update: function (force) { - Node.prototype.update.call(this, force); - Matrix4.invert(this.viewMatrix, this.worldTransform); + joint.node.position._dirty = true; + joint.node.rotation._dirty = true; + joint.node.scale._dirty = true; + } + } + }, - this.updateProjectionMatrix(); - Matrix4.invert(this.invProjectionMatrix, this.projectionMatrix); + clone: function (clonedNodesMap) { + var skeleton = new Skeleton(); + skeleton.name = this.name; - this.frustum.setFromProjection(this.projectionMatrix); - }, + for (var i = 0; i < this.joints.length; i++) { + var newJoint = new Joint(); + var joint = this.joints[i]; + newJoint.name = joint.name; + newJoint.index = joint.index; - /** - * Set camera view matrix - */ - setViewMatrix: function (viewMatrix) { - Matrix4.copy(this.viewMatrix, viewMatrix); - Matrix4.invert(this.worldTransform, viewMatrix); - this.decomposeWorldTransform(); - }, + if (clonedNodesMap) { + var newNode = clonedNodesMap[joint.node.__uid__]; - /** - * Decompose camera projection matrix - */ - decomposeProjectionMatrix: function () {}, + if (!newNode) { + // PENDING + console.warn('Can\'t find node'); + } - /** - * Set camera projection matrix - * @param {qtek.math.Matrix4} projectionMatrix - */ - setProjectionMatrix: function (projectionMatrix) { - Matrix4.copy(this.projectionMatrix, projectionMatrix); - Matrix4.invert(this.invProjectionMatrix, projectionMatrix); - this.decomposeProjectionMatrix(); - }, - /** - * Update projection matrix, called after update - */ - updateProjectionMatrix: function () {}, + newJoint.node = newNode || joint.node; + } + else { + newJoint.node = joint.node; + } - /** - * Cast a picking ray from camera near plane to far plane - * @method - * @param {qtek.math.Vector2} ndc - * @param {qtek.math.Ray} [out] - * @return {qtek.math.Ray} - */ - castRay: (function () { - var v4 = vec4.create(); - return function (ndc, out) { - var ray = out !== undefined ? out : new Ray(); - var x = ndc._array[0]; - var y = ndc._array[1]; - vec4.set(v4, x, y, -1, 1); - vec4.transformMat4(v4, v4, this.invProjectionMatrix._array); - vec4.transformMat4(v4, v4, this.worldTransform._array); - vec3$5.scale(ray.origin._array, v4, 1 / v4[3]); + skeleton.joints.push(newJoint); + } - vec4.set(v4, x, y, 1, 1); - vec4.transformMat4(v4, v4, this.invProjectionMatrix._array); - vec4.transformMat4(v4, v4, this.worldTransform._array); - vec3$5.scale(v4, v4, 1 / v4[3]); - vec3$5.sub(ray.direction._array, v4, ray.origin._array); + if (this._invBindPoseMatricesArray) { + var len = this._invBindPoseMatricesArray.length; + skeleton._invBindPoseMatricesArray = new Float32Array(len); + for (var i = 0; i < len; i++) { + skeleton._invBindPoseMatricesArray[i] = this._invBindPoseMatricesArray[i]; + } - vec3$5.normalize(ray.direction._array, ray.direction._array); - ray.direction._dirty = true; - ray.origin._dirty = true; + skeleton._skinMatricesArray = new Float32Array(len); - return ray; - }; - })() + skeleton.updateMatricesSubArrays(); + } - /** - * @method - * @name clone - * @return {qtek.Camera} - * @memberOf qtek.Camera.prototype - */ + skeleton.update(); + + return skeleton; + } }); /** - * @constructor qtek.camera.Perspective - * @extends qtek.Camera + * @constructor clay.camera.Perspective + * @extends clay.Camera */ var Perspective = Camera.extend( -/** @lends qtek.camera.Perspective# */ +/** @lends clay.camera.Perspective# */ { /** - * Vertical field of view in radians + * Vertical field of view in degrees * @type {number} */ fov: 50, @@ -15772,7 +16496,7 @@ var Perspective = Camera.extend( */ far: 2000 }, -/** @lends qtek.camera.Perspective.prototype */ +/** @lends clay.camera.Perspective.prototype */ { updateProjectionMatrix: function() { @@ -15780,7 +16504,7 @@ var Perspective = Camera.extend( this.projectionMatrix.perspective(rad, this.aspect, this.near, this.far); }, decomposeProjectionMatrix: function () { - var m = this.projectionMatrix._array; + var m = this.projectionMatrix.array; var rad = Math.atan(1 / m[5]) * 2; this.fov = rad / Math.PI * 180; this.aspect = m[5] / m[0]; @@ -15788,7 +16512,7 @@ var Perspective = Camera.extend( this.far = m[14] / (m[10] + 1); }, /** - * @return {qtek.camera.Perspective} + * @return {clay.camera.Perspective} */ clone: function() { var camera = Camera.prototype.clone.call(this); @@ -15802,11 +16526,11 @@ var Perspective = Camera.extend( }); /** - * @constructor qtek.camera.Orthographic - * @extends qtek.Camera + * @constructor clay.camera.Orthographic + * @extends clay.Camera */ var Orthographic = Camera.extend( -/** @lends qtek.camera.Orthographic# */ +/** @lends clay.camera.Orthographic# */ { /** * @type {number} @@ -15833,7 +16557,7 @@ var Orthographic = Camera.extend( */ bottom: -1 }, -/** @lends qtek.camera.Orthographic.prototype */ +/** @lends clay.camera.Orthographic.prototype */ { updateProjectionMatrix: function() { @@ -15841,7 +16565,7 @@ var Orthographic = Camera.extend( }, decomposeProjectionMatrix: function () { - var m = this.projectionMatrix._array; + var m = this.projectionMatrix.array; this.left = (-1 - m[12]) / m[0]; this.right = (1 - m[12]) / m[0]; this.top = (1 - m[13]) / m[5]; @@ -15850,7 +16574,7 @@ var Orthographic = Camera.extend( this.far = -(1 - m[14]) / m[10]; }, /** - * @return {qtek.camera.Orthographic} + * @return {clay.camera.Orthographic} */ clone: function() { var camera = Camera.prototype.clone.call(this); @@ -15868,11 +16592,11 @@ var Orthographic = Camera.extend( // 缓动函数来自 https://github.com/sole/tween.js/blob/master/src/Tween.js /** - * @namespace qtek.animation.easing + * @namespace clay.animation.easing */ var easing = { /** - * @alias qtek.animation.easing.linear + * @alias clay.animation.easing.linear * @param {number} k * @return {number} */ @@ -15880,7 +16604,7 @@ var easing = { return k; }, /** - * @alias qtek.animation.easing.quadraticIn + * @alias clay.animation.easing.quadraticIn * @param {number} k * @return {number} */ @@ -15888,7 +16612,7 @@ var easing = { return k * k; }, /** - * @alias qtek.animation.easing.quadraticOut + * @alias clay.animation.easing.quadraticOut * @param {number} k * @return {number} */ @@ -15896,7 +16620,7 @@ var easing = { return k * (2 - k); }, /** - * @alias qtek.animation.easing.quadraticInOut + * @alias clay.animation.easing.quadraticInOut * @param {number} k * @return {number} */ @@ -15907,7 +16631,7 @@ var easing = { return - 0.5 * (--k * (k - 2) - 1); }, /** - * @alias qtek.animation.easing.cubicIn + * @alias clay.animation.easing.cubicIn * @param {number} k * @return {number} */ @@ -15915,7 +16639,7 @@ var easing = { return k * k * k; }, /** - * @alias qtek.animation.easing.cubicOut + * @alias clay.animation.easing.cubicOut * @param {number} k * @return {number} */ @@ -15923,7 +16647,7 @@ var easing = { return --k * k * k + 1; }, /** - * @alias qtek.animation.easing.cubicInOut + * @alias clay.animation.easing.cubicInOut * @param {number} k * @return {number} */ @@ -15934,7 +16658,7 @@ var easing = { return 0.5 * ((k -= 2) * k * k + 2); }, /** - * @alias qtek.animation.easing.quarticIn + * @alias clay.animation.easing.quarticIn * @param {number} k * @return {number} */ @@ -15942,7 +16666,7 @@ var easing = { return k * k * k * k; }, /** - * @alias qtek.animation.easing.quarticOut + * @alias clay.animation.easing.quarticOut * @param {number} k * @return {number} */ @@ -15950,7 +16674,7 @@ var easing = { return 1 - (--k * k * k * k); }, /** - * @alias qtek.animation.easing.quarticInOut + * @alias clay.animation.easing.quarticInOut * @param {number} k * @return {number} */ @@ -15961,7 +16685,7 @@ var easing = { return - 0.5 * ((k -= 2) * k * k * k - 2); }, /** - * @alias qtek.animation.easing.quinticIn + * @alias clay.animation.easing.quinticIn * @param {number} k * @return {number} */ @@ -15969,7 +16693,7 @@ var easing = { return k * k * k * k * k; }, /** - * @alias qtek.animation.easing.quinticOut + * @alias clay.animation.easing.quinticOut * @param {number} k * @return {number} */ @@ -15977,7 +16701,7 @@ var easing = { return --k * k * k * k * k + 1; }, /** - * @alias qtek.animation.easing.quinticInOut + * @alias clay.animation.easing.quinticInOut * @param {number} k * @return {number} */ @@ -15988,7 +16712,7 @@ var easing = { return 0.5 * ((k -= 2) * k * k * k * k + 2); }, /** - * @alias qtek.animation.easing.sinusoidalIn + * @alias clay.animation.easing.sinusoidalIn * @param {number} k * @return {number} */ @@ -15996,7 +16720,7 @@ var easing = { return 1 - Math.cos(k * Math.PI / 2); }, /** - * @alias qtek.animation.easing.sinusoidalOut + * @alias clay.animation.easing.sinusoidalOut * @param {number} k * @return {number} */ @@ -16004,7 +16728,7 @@ var easing = { return Math.sin(k * Math.PI / 2); }, /** - * @alias qtek.animation.easing.sinusoidalInOut + * @alias clay.animation.easing.sinusoidalInOut * @param {number} k * @return {number} */ @@ -16012,7 +16736,7 @@ var easing = { return 0.5 * (1 - Math.cos(Math.PI * k)); }, /** - * @alias qtek.animation.easing.exponentialIn + * @alias clay.animation.easing.exponentialIn * @param {number} k * @return {number} */ @@ -16020,7 +16744,7 @@ var easing = { return k === 0 ? 0 : Math.pow(1024, k - 1); }, /** - * @alias qtek.animation.easing.exponentialOut + * @alias clay.animation.easing.exponentialOut * @param {number} k * @return {number} */ @@ -16028,7 +16752,7 @@ var easing = { return k === 1 ? 1 : 1 - Math.pow(2, - 10 * k); }, /** - * @alias qtek.animation.easing.exponentialInOut + * @alias clay.animation.easing.exponentialInOut * @param {number} k * @return {number} */ @@ -16045,7 +16769,7 @@ var easing = { return 0.5 * (- Math.pow(2, - 10 * (k - 1)) + 2); }, /** - * @alias qtek.animation.easing.circularIn + * @alias clay.animation.easing.circularIn * @param {number} k * @return {number} */ @@ -16053,7 +16777,7 @@ var easing = { return 1 - Math.sqrt(1 - k * k); }, /** - * @alias qtek.animation.easing.circularOut + * @alias clay.animation.easing.circularOut * @param {number} k * @return {number} */ @@ -16061,7 +16785,7 @@ var easing = { return Math.sqrt(1 - (--k * k)); }, /** - * @alias qtek.animation.easing.circularInOut + * @alias clay.animation.easing.circularInOut * @param {number} k * @return {number} */ @@ -16072,7 +16796,7 @@ var easing = { return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1); }, /** - * @alias qtek.animation.easing.elasticIn + * @alias clay.animation.easing.elasticIn * @param {number} k * @return {number} */ @@ -16093,7 +16817,7 @@ var easing = { Math.sin((k - s) * (2 * Math.PI) / p)); }, /** - * @alias qtek.animation.easing.elasticOut + * @alias clay.animation.easing.elasticOut * @param {number} k * @return {number} */ @@ -16115,7 +16839,7 @@ var easing = { Math.sin((k - s) * (2 * Math.PI) / p) + 1); }, /** - * @alias qtek.animation.easing.elasticInOut + * @alias clay.animation.easing.elasticInOut * @param {number} k * @return {number} */ @@ -16142,7 +16866,7 @@ var easing = { }, /** - * @alias qtek.animation.easing.backIn + * @alias clay.animation.easing.backIn * @param {number} k * @return {number} */ @@ -16151,7 +16875,7 @@ var easing = { return k * k * ((s + 1) * k - s); }, /** - * @alias qtek.animation.easing.backOut + * @alias clay.animation.easing.backOut * @param {number} k * @return {number} */ @@ -16160,7 +16884,7 @@ var easing = { return --k * k * ((s + 1) * k + s) + 1; }, /** - * @alias qtek.animation.easing.backInOut + * @alias clay.animation.easing.backInOut * @param {number} k * @return {number} */ @@ -16172,7 +16896,7 @@ var easing = { return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2); }, /** - * @alias qtek.animation.easing.bounceIn + * @alias clay.animation.easing.bounceIn * @param {number} k * @return {number} */ @@ -16180,7 +16904,7 @@ var easing = { return 1 - easing.bounceOut(1 - k); }, /** - * @alias qtek.animation.easing.bounceOut + * @alias clay.animation.easing.bounceOut * @param {number} k * @return {number} */ @@ -16197,7 +16921,7 @@ var easing = { } }, /** - * @alias qtek.animation.easing.bounceInOut + * @alias clay.animation.easing.bounceInOut * @param {number} k * @return {number} */ @@ -16209,10 +16933,10 @@ var easing = { } }; -function noop () {} +function noop$1 () {} /** * @constructor - * @alias qtek.animation.Clip + * @alias clay.animation.Clip * @param {Object} [opts] * @param {Object} [opts.target] * @param {number} [opts.life] @@ -16274,17 +16998,17 @@ var Clip = function (opts) { /** * @type {Function} */ - this.onframe = opts.onframe || noop; + this.onframe = opts.onframe || noop$1; /** * @type {Function} */ - this.onfinish = opts.onfinish || noop; + this.onfinish = opts.onfinish || noop$1; /** * @type {Function} */ - this.onrestart = opts.onrestart || noop; + this.onrestart = opts.onrestart || noop$1; this._paused = false; }; @@ -16303,17 +17027,17 @@ Clip.prototype = { setLoop: function (loop) { this._loop = loop; if (loop) { - if (typeof(loop) == 'number') { + if (typeof loop === 'number') { this._loopRemained = loop; } else { - this._loopRemained = 1e8; + this._loopRemained = Infinity; } } }, /** - * @param {string|function} easing + * @param {string|Function} easing */ setEasing: function (easing$$1) { if (typeof(easing$$1) === 'string') { @@ -16464,12 +17188,12 @@ var quat$3 = glmatrix.quat; var vec3$9 = glmatrix.vec3; /** - * - * Animation clip that manage a collection of {@link qtek.animation.SamplerTrack} + * + * Animation clip that manage a collection of {@link clay.animation.SamplerTrack} * @constructor - * @alias qtek.animation.TrackClip + * @alias clay.animation.TrackClip * - * @extends qtek.animation.Clip + * @extends clay.animation.Clip * @param {Object} [opts] * @param {string} [opts.name] * @param {Object} [opts.target] @@ -16478,11 +17202,11 @@ var vec3$9 = glmatrix.vec3; * @param {number} [opts.gap] * @param {number} [opts.playbackRatio] * @param {boolean|number} [opts.loop] If loop is a number, it indicate the loop count of animation - * @param {string|function} [opts.easing] - * @param {function} [opts.onframe] - * @param {function} [opts.onfinish] - * @param {function} [opts.onrestart] - * @param {Array.} [opts.tracks] + * @param {string|Function} [opts.easing] + * @param {Function} [opts.onframe] + * @param {Function} [opts.onfinish] + * @param {Function} [opts.onrestart] + * @param {Array.} [opts.tracks] */ var TrackClip = function (opts) { @@ -16491,10 +17215,12 @@ var TrackClip = function (opts) { Clip.call(this, opts); /** - * - * @type {qtek.animation.SamplerTrack[]} + * + * @type {clay.animation.SamplerTrack[]} */ this.tracks = opts.tracks || []; + + this.calcLifeFromTracks(); }; TrackClip.prototype = Object.create(Clip.prototype); @@ -16518,7 +17244,7 @@ TrackClip.prototype.step = function (time, dTime, silent) { if (!silent && ret !== 'paused') { this.fire('frame'); } - + return ret; }; @@ -16549,14 +17275,15 @@ TrackClip.prototype.calcLifeFromTracks = function () { }; /** - * @param {qtek.animation.SamplerTrack} jointClip + * @param {clay.animation.SamplerTrack} track */ TrackClip.prototype.addTrack = function (track) { this.tracks.push(track); + this.calcLifeFromTracks(); }; /** - * @param {qtek.animation.SamplerTrack} jointClip + * @param {clay.animation.SamplerTrack} track */ TrackClip.prototype.removeTarck = function (track) { var idx = this.tracks.indexOf(track); @@ -16569,7 +17296,7 @@ TrackClip.prototype.removeTarck = function (track) { * @param {number} startTime * @param {number} endTime * @param {boolean} isLoop - * @return {qtek.animation.TrackClip} + * @return {clay.animation.TrackClip} */ TrackClip.prototype.getSubClip = function (startTime, endTime, isLoop) { var subClip = new TrackClip({ @@ -16592,8 +17319,8 @@ TrackClip.prototype.getSubClip = function (startTime, endTime, isLoop) { /** * 1d blending from two skinning clips - * @param {qtek.animation.TrackClip} clip1 - * @param {qtek.animation.TrackClip} clip2 + * @param {clay.animation.TrackClip} clip1 + * @param {clay.animation.TrackClip} clip2 * @param {number} w */ TrackClip.prototype.blend1D = function (clip1, clip2, w) { @@ -16608,8 +17335,8 @@ TrackClip.prototype.blend1D = function (clip1, clip2, w) { /** * Additive blending from two skinning clips - * @param {qtek.animation.TrackClip} clip1 - * @param {qtek.animation.TrackClip} clip2 + * @param {clay.animation.TrackClip} clip1 + * @param {clay.animation.TrackClip} clip2 */ TrackClip.prototype.additiveBlend = function (clip1, clip2) { for (var i = 0; i < this.tracks.length; i++) { @@ -16622,318 +17349,65 @@ TrackClip.prototype.additiveBlend = function (clip1, clip2) { }; /** - * Subtractive blending from two skinning clips - * @param {qtek.animation.TrackClip} clip1 - * @param {qtek.animation.TrackClip} clip2 - */ -TrackClip.prototype.subtractiveBlend = function (clip1, clip2) { - for (var i = 0; i < this.tracks.length; i++) { - var c1 = clip1.tracks[i]; - var c2 = clip2.tracks[i]; - var tClip = this.tracks[i]; - - tClip.subtractiveBlend(c1, c2); - } -}; - -/** - * 2D blending from three skinning clips - * @param {qtek.animation.TrackClip} clip1 - * @param {qtek.animation.TrackClip} clip2 - * @param {qtek.animation.TrackClip} clip3 - * @param {number} f - * @param {number} g - */ -TrackClip.prototype.blend2D = function (clip1, clip2, clip3, f, g) { - for (var i = 0; i < this.tracks.length; i++) { - var c1 = clip1.tracks[i]; - var c2 = clip2.tracks[i]; - var c3 = clip3.tracks[i]; - var tClip = this.tracks[i]; - - tClip.blend2D(c1, c2, c3, f, g); - } -}; - -/** - * Copy SRT of all joints clips from another TrackClip - * @param {qtek.animation.TrackClip} clip - */ -TrackClip.prototype.copy = function (clip) { - for (var i = 0; i < this.tracks.length; i++) { - var sTrack = clip.tracks[i]; - var tTrack = this.tracks[i]; - - vec3$9.copy(tTrack.position, sTrack.position); - vec3$9.copy(tTrack.scale, sTrack.scale); - quat$3.copy(tTrack.rotation, sTrack.rotation); - } -}; - -TrackClip.prototype.clone = function () { - var clip = Clip.prototype.clone.call(this); - for (var i = 0; i < this.tracks.length; i++) { - clip.addTrack(this.tracks[i].clone()); - } - clip.life = this.life; - return clip; -}; - -var quat$5 = glmatrix.quat; -var vec3$11 = glmatrix.vec3; - -function keyframeSort(a, b) { - return a.time - b.time; -} - -var TransformTrack = function (opts) { - - this.name = opts.name || ''; - //[{ - // time: //ms - // position: // optional - // rotation: // optional - // scale: // optional - //}] - this.keyFrames = []; - if (opts.keyFrames) { - this.addKeyFrames(opts.keyFrames); - } - - /** - * @type {Float32Array} - */ - this.position = vec3$11.create(); - /** - * Rotation is represented by a quaternion - * @type {Float32Array} - */ - this.rotation = quat$5.create(); - /** - * @type {Float32Array} - */ - this.scale = vec3$11.fromValues(1, 1, 1); - - this._cacheKey = 0; - this._cacheTime = 0; -}; - -TransformTrack.prototype = Object.create(Clip.prototype); - -TransformTrack.prototype.constructor = TransformTrack; - -TransformTrack.prototype.step = function (time, dTime, silent) { - - var ret = Clip.prototype.step.call(this, time, dTime, true); - - if (ret !== 'finish') { - this.setTime(this.getElapsedTime()); - } - - // PENDING Schedule - if (!silent && ret !== 'paused') { - this.fire('frame'); - } - - return ret; -}; - -TransformTrack.prototype.setTime = function (time) { - this._interpolateField(time, 'position'); - this._interpolateField(time, 'rotation'); - this._interpolateField(time, 'scale'); -}; - -/** - * @return {number} - */ -TransformTrack.prototype.getMaxTime = function () { - var kf = this.keyFrames[this.keyFrames.length - 1]; - return kf ? kf.time : 0; -}; - -/** - * Add a key frame - * @param {Object} kf - */ -TransformTrack.prototype.addKeyFrame = function (kf) { - for (var i = 0; i < this.keyFrames.length - 1; i++) { - var prevFrame = this.keyFrames[i]; - var nextFrame = this.keyFrames[i + 1]; - if (prevFrame.time <= kf.time && nextFrame.time >= kf.time) { - this.keyFrames.splice(i, 0, kf); - return i; - } - } - - this.life = kf.time; - this.keyFrames.push(kf); -}; - -/** - * Add keyframes - * @param {object[]} kfs - */ -TransformTrack.prototype.addKeyFrames = function (kfs) { - for (var i = 0; i < kfs.length; i++) { - this.keyFrames.push(kfs[i]); - } - - this.keyFrames.sort(keyframeSort); - - this.life = this.keyFrames[this.keyFrames.length - 1].time; -}; - -TransformTrack.prototype._interpolateField = function (time, fieldName) { - var kfs = this.keyFrames; - var len = kfs.length; - var start; - var end; - - if (!kfs.length) { - return; - } - if (time < kfs[0].time || time > kfs[kfs.length-1].time) { - return; - } - if (time < this._cacheTime) { - var s = this._cacheKey >= len-1 ? len-1 : this._cacheKey+1; - for (var i = s; i >= 0; i--) { - if (kfs[i].time <= time && kfs[i][fieldName]) { - start = kfs[i]; - this._cacheKey = i; - this._cacheTime = time; - } else if (kfs[i][fieldName]) { - end = kfs[i]; - break; - } - } - } else { - for (var i = this._cacheKey; i < len; i++) { - if (kfs[i].time <= time && kfs[i][fieldName]) { - start = kfs[i]; - this._cacheKey = i; - this._cacheTime = time; - } else if (kfs[i][fieldName]) { - end = kfs[i]; - break; - } - } - } - - if (start && end) { - var percent = (time - start.time) / (end.time - start.time); - percent = Math.max(Math.min(percent, 1), 0); - if (fieldName === 'rotation') { - quat$5.slerp(this[fieldName], start[fieldName], end[fieldName], percent); - } else { - vec3$11.lerp(this[fieldName], start[fieldName], end[fieldName], percent); - } - } else { - this._cacheKey = 0; - this._cacheTime = 0; - } -}; -/** - * 1D blending between two tracks - * @param {qtek.animation.SamplerClip|qtek.animation.TransformTrack} t1 - * @param {qtek.animation.SamplerClip|qtek.animation.TransformTrack} t2 - * @param {number} w - */ -TransformTrack.prototype.blend1D = function (t1, t2, w) { - vec3$11.lerp(this.position, t1.position, t2.position, w); - vec3$11.lerp(this.scale, t1.scale, t2.scale, w); - quat$5.slerp(this.rotation, t1.rotation, t2.rotation, w); -}; - -/** - * 2D blending between three tracks - * @method - * @param {qtek.animation.SamplerClip|qtek.animation.TransformTrack} t1 - * @param {qtek.animation.SamplerClip|qtek.animation.TransformTrack} t2 - * @param {qtek.animation.SamplerClip|qtek.animation.TransformTrack} t3 - * @param {number} f - * @param {number} g - */ -TransformTrack.prototype.blend2D = (function () { - var q1 = quat$5.create(); - var q2 = quat$5.create(); - return function (t1, t2, t3, f, g) { - var a = 1 - f - g; - - this.position[0] = t1.position[0] * a + t2.position[0] * f + t3.position[0] * g; - this.position[1] = t1.position[1] * a + t2.position[1] * f + t3.position[1] * g; - this.position[2] = t1.position[2] * a + t2.position[2] * f + t3.position[2] * g; - - this.scale[0] = t1.scale[0] * a + t2.scale[0] * f + t3.scale[0] * g; - this.scale[1] = t1.scale[1] * a + t2.scale[1] * f + t3.scale[1] * g; - this.scale[2] = t1.scale[2] * a + t2.scale[2] * f + t3.scale[2] * g; - - // http://msdn.microsoft.com/en-us/library/windows/desktop/bb205403(v=vs.85).aspx - // http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.quaternion.xmquaternionbarycentric(v=vs.85).aspx - var s = f + g; - if (s === 0) { - quat$5.copy(this.rotation, t1.rotation); - } else { - quat$5.slerp(q1, t1.rotation, t2.rotation, s); - quat$5.slerp(q2, t1.rotation, c3.rotation, s); - quat$5.slerp(this.rotation, q1, q2, g / s); - } - }; -})(); - -/** - * Additive blending between two tracks - * @param {qtek.animation.SamplerClip|qtek.animation.TransformTrack} t1 - * @param {qtek.animation.SamplerClip|qtek.animation.TransformTrack} t2 - */ -TransformTrack.prototype.additiveBlend = function (t1, t2) { - vec3$11.add(this.position, t1.position, t2.position); - vec3$11.add(this.scale, t1.scale, t2.scale); - quat$5.multiply(this.rotation, t2.rotation, t1.rotation); -}; - -/** - * Subtractive blending between two tracks - * @param {qtek.animation.SamplerClip|qtek.animation.TransformTrack} t1 - * @param {qtek.animation.SamplerClip|qtek.animation.TransformTrack} t2 + * Subtractive blending from two skinning clips + * @param {clay.animation.TrackClip} clip1 + * @param {clay.animation.TrackClip} clip2 */ -TransformTrack.prototype.subtractiveBlend = function (t1, t2) { - vec3$11.sub(this.position, t1.position, t2.position); - vec3$11.sub(this.scale, t1.scale, t2.scale); - quat$5.invert(this.rotation, t2.rotation); - quat$5.multiply(this.rotation, this.rotation, t1.rotation); +TrackClip.prototype.subtractiveBlend = function (clip1, clip2) { + for (var i = 0; i < this.tracks.length; i++) { + var c1 = clip1.tracks[i]; + var c2 = clip2.tracks[i]; + var tClip = this.tracks[i]; + + tClip.subtractiveBlend(c1, c2); + } }; /** - * @param {number} startTime - * @param {number} endTime - * @param {boolean} isLoop + * 2D blending from three skinning clips + * @param {clay.animation.TrackClip} clip1 + * @param {clay.animation.TrackClip} clip2 + * @param {clay.animation.TrackClip} clip3 + * @param {number} f + * @param {number} g */ -TransformTrack.prototype.getSubClip = function (startTime, endTime) { - // TODO - console.warn('TODO'); +TrackClip.prototype.blend2D = function (clip1, clip2, clip3, f, g) { + for (var i = 0; i < this.tracks.length; i++) { + var c1 = clip1.tracks[i]; + var c2 = clip2.tracks[i]; + var c3 = clip3.tracks[i]; + var tClip = this.tracks[i]; + + tClip.blend2D(c1, c2, c3, f, g); + } }; /** - * Clone a new TransformTrack - * @return {qtek.animation.TransformTrack} + * Copy SRT of all joints clips from another TrackClip + * @param {clay.animation.TrackClip} clip */ -TransformTrack.prototype.clone = function () { - var track = TransformTrack.prototype.clone.call(this); - track.keyFrames = this.keyFrames; +TrackClip.prototype.copy = function (clip) { + for (var i = 0; i < this.tracks.length; i++) { + var sTrack = clip.tracks[i]; + var tTrack = this.tracks[i]; - vec3$11.copy(track.position, this.position); - quat$5.copy(track.rotation, this.rotation); - vec3$11.copy(track.scale, this.scale); + vec3$9.copy(tTrack.position, sTrack.position); + vec3$9.copy(tTrack.scale, sTrack.scale); + quat$3.copy(tTrack.rotation, sTrack.rotation); + } +}; - return track; +TrackClip.prototype.clone = function () { + var clip = Clip.prototype.clone.call(this); + for (var i = 0; i < this.tracks.length; i++) { + clip.addTrack(this.tracks[i].clone()); + } + clip.life = this.life; + return clip; }; // Sampler clip is especially for the animation sampler in glTF // Use Typed Array can reduce a lot of heap memory -// -// TODO Sync target transform var quat$4 = glmatrix.quat; var vec3$10 = glmatrix.vec3; @@ -16995,30 +17469,30 @@ function quatSlerp(out, a, b, t, oa, ob) { /** * SamplerTrack manages `position`, `rotation`, `scale` tracks in animation of single scene node. * @constructor - * @alias qtek.animation.SamplerTrack + * @alias clay.animation.SamplerTrack * @param {Object} [opts] * @param {string} [opts.name] Track name - * @param {qtek.Node} [opts.target] Target node's transform will updated automatically + * @param {clay.Node} [opts.target] Target node's transform will updated automatically */ var SamplerTrack = function (opts) { opts = opts || {}; this.name = opts.name || ''; /** - * @param {qtek.Node} + * @param {clay.Node} */ this.target = opts.target || null; /** - * @type {Float32Array} + * @type {Array} */ this.position = vec3$10.create(); /** * Rotation is represented by a quaternion - * @type {Float32Array} + * @type {Array} */ this.rotation = quat$4.create(); /** - * @type {Float32Array} + * @type {Array} */ this.scale = vec3$10.fromValues(1, 1, 1); @@ -17102,7 +17576,7 @@ SamplerTrack.prototype.setTime = function (time) { } } // Loop handling - if (key == len - 2) { + if (key === len - 2) { this._cacheKey = 0; this._cacheTime = 0; } @@ -17139,7 +17613,7 @@ SamplerTrack.prototype.getMaxTime = function () { /** * @param {number} startTime * @param {number} endTime - * @return {qtek.animation.SamplerTrack} + * @return {clay.animation.SamplerTrack} */ SamplerTrack.prototype.getSubTrack = function (startTime, endTime) { @@ -17226,40 +17700,79 @@ SamplerTrack.prototype._findRange = function (time) { /** * 1D blending between two clips - * @method - * @param {qtek.animation.SamplerTrack|qtek.animation.TransformTrack} c1 - * @param {qtek.animation.SamplerTrack|qtek.animation.TransformTrack} c2 + * @function + * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c1 + * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c2 * @param {number} w */ -SamplerTrack.prototype.blend1D = TransformTrack.prototype.blend1D; +SamplerTrack.prototype.blend1D = function (t1, t2, w) { + vec3$10.lerp(this.position, t1.position, t2.position, w); + vec3$10.lerp(this.scale, t1.scale, t2.scale, w); + quat$4.slerp(this.rotation, t1.rotation, t2.rotation, w); +}; /** * 2D blending between three clips - * @method - * @param {qtek.animation.SamplerTrack|qtek.animation.TransformTrack} c1 - * @param {qtek.animation.SamplerTrack|qtek.animation.TransformTrack} c2 - * @param {qtek.animation.SamplerTrack|qtek.animation.TransformTrack} c3 + * @function + * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c1 + * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c2 + * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c3 * @param {number} f * @param {number} g */ -SamplerTrack.prototype.blend2D = TransformTrack.prototype.blend2D; +SamplerTrack.prototype.blend2D = (function () { + var q1 = quat$4.create(); + var q2 = quat$4.create(); + return function (t1, t2, t3, f, g) { + var a = 1 - f - g; + + this.position[0] = t1.position[0] * a + t2.position[0] * f + t3.position[0] * g; + this.position[1] = t1.position[1] * a + t2.position[1] * f + t3.position[1] * g; + this.position[2] = t1.position[2] * a + t2.position[2] * f + t3.position[2] * g; + + this.scale[0] = t1.scale[0] * a + t2.scale[0] * f + t3.scale[0] * g; + this.scale[1] = t1.scale[1] * a + t2.scale[1] * f + t3.scale[1] * g; + this.scale[2] = t1.scale[2] * a + t2.scale[2] * f + t3.scale[2] * g; + + // http://msdn.microsoft.com/en-us/library/windows/desktop/bb205403(v=vs.85).aspx + // http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.quaternion.xmquaternionbarycentric(v=vs.85).aspx + var s = f + g; + if (s === 0) { + quat$4.copy(this.rotation, t1.rotation); + } + else { + quat$4.slerp(q1, t1.rotation, t2.rotation, s); + quat$4.slerp(q2, t1.rotation, t3.rotation, s); + quat$4.slerp(this.rotation, q1, q2, g / s); + } + }; +})(); /** * Additive blending between two clips - * @method - * @param {qtek.animation.SamplerTrack|qtek.animation.TransformTrack} c1 - * @param {qtek.animation.SamplerTrack|qtek.animation.TransformTrack} c2 + * @function + * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c1 + * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c2 */ -SamplerTrack.prototype.additiveBlend = TransformTrack.prototype.additiveBlend; +SamplerTrack.prototype.additiveBlend = function (t1, t2) { + vec3$10.add(this.position, t1.position, t2.position); + vec3$10.add(this.scale, t1.scale, t2.scale); + quat$4.multiply(this.rotation, t2.rotation, t1.rotation); +}; /** * Subtractive blending between two clips - * @method - * @param {qtek.animation.SamplerTrack|qtek.animation.TransformTrack} c1 - * @param {qtek.animation.SamplerTrack|qtek.animation.TransformTrack} c2 + * @function + * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c1 + * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c2 */ -SamplerTrack.prototype.subtractiveBlend = TransformTrack.prototype.subtractiveBlend; +SamplerTrack.prototype.subtractiveBlend = function (t1, t2) { + vec3$10.sub(this.position, t1.position, t2.position); + vec3$10.sub(this.scale, t1.scale, t2.scale); + quat$4.invert(this.rotation, t2.rotation); + quat$4.multiply(this.rotation, this.rotation, t1.rotation); +}; /** * Clone a new SamplerTrack - * @return {qtek.animation.SamplerTrack} + * @return {clay.animation.SamplerTrack} */ SamplerTrack.prototype.clone = function () { var track = SamplerTrack.prototype.clone.call(this); @@ -17280,12 +17793,12 @@ SamplerTrack.prototype.clone = function () { }; -var vec3$12 = glmatrix.vec3; -var mat4$6 = glmatrix.mat4; +var vec3$11 = glmatrix.vec3; +var mat4$7 = glmatrix.mat4; -var vec3Create = vec3$12.create; -var vec3Add = vec3$12.add; -var vec3Set$2 = vec3$12.set; +var vec3Create = vec3$11.create; +var vec3Add = vec3$11.add; +var vec3Set$2 = vec3$11.set; function getArrayCtorByType (type) { return ({ @@ -17301,7 +17814,7 @@ function makeAttrKey(attrName) { } /** * Geometry attribute - * @alias qtek.Geometry.Attribute + * @alias clay.Geometry.Attribute * @constructor */ function Attribute(name, type, size, semantic) { @@ -17339,7 +17852,7 @@ function Attribute(name, type, size, semantic) { * + `'COLOR'` * + `'JOINT'` * + `'WEIGHT'` - * + * * In shader, attribute with same semantic will be automatically mapped. For example: * ```glsl * attribute vec3 pos: POSITION @@ -17447,8 +17960,8 @@ function Attribute(name, type, size, semantic) { /** * Set item value at give index. Second parameter val is number if size is 1 - * @method - * @name qtek.Geometry.Attribute#set + * @function + * @name clay.Geometry.Attribute#set * @param {number} idx * @param {number[]|number} val * @example @@ -17457,8 +17970,8 @@ function Attribute(name, type, size, semantic) { /** * Get item value at give index. Second parameter out is no need if size is 1 - * @method - * @name qtek.Geometry.Attribute#set + * @function + * @name clay.Geometry.Attribute#set * @param {number} idx * @param {number[]} [out] * @example @@ -17467,7 +17980,7 @@ function Attribute(name, type, size, semantic) { /** * Initialize attribute with given vertex count - * @param {number} nVertex + * @param {number} nVertex */ Attribute.prototype.init = function (nVertex) { if (!this.value || this.value.length != nVertex * this.size) { @@ -17537,11 +18050,76 @@ function IndicesBuffer(buffer) { } /** - * @constructor qtek.Geometry - * @extends qtek.core.Base + * Geometry in ClayGL contains vertex attributes of mesh. These vertex attributes will be finally provided to the {@link clay.Shader}. + * Different {@link clay.Shader} needs different attributes. Here is a list of attributes used in the builtin shaders. + * + * + position: `clay.basic`, `clay.lambert`, `clay.standard` + * + texcoord0: `clay.basic`, `clay.lambert`, `clay.standard` + * + color: `clay.basic`, `clay.lambert`, `clay.standard` + * + weight: `clay.basic`, `clay.lambert`, `clay.standard` + * + joint: `clay.basic`, `clay.lambert`, `clay.standard` + * + normal: `clay.lambert`, `clay.standard` + * + tangent: `clay.standard` + * + * #### Create a procedural geometry + * + * ClayGL provides a couple of builtin procedural geometries. Inlcuding: + * + * + {@link clay.geometry.Cube} + * + {@link clay.geometry.Sphere} + * + {@link clay.geometry.Plane} + * + {@link clay.geometry.Cylinder} + * + {@link clay.geometry.Cone} + * + {@link clay.geometry.ParametricSurface} + * + * It's simple to create a basic geometry with these classes. + * +```js +var sphere = new clay.geometry.Sphere({ + radius: 2 +}); +``` + * + * #### Create the geometry data by yourself + * + * Usually the vertex attributes data are created by the {@link clay.loader.GLTF} or procedural geometries like {@link clay.geometry.Sphere}. + * Besides these, you can create the data manually. Here is a simple example to create a triangle. +```js +var TRIANGLE_POSITIONS = [ + [-0.5, -0.5, 0], + [0.5, -0.5, 0], + [0, 0.5, 0] +]; +var geometry = new clay.StaticGeometry(); +// Add triangle vertices to position attribute. +geometry.attributes.position.fromArray(TRIANGLE_POSITIONS); +``` + * Then you can use the utility methods like `generateVertexNormals`, `generateTangents` to create the remaining necessary attributes. + * + * + * #### Use with custom shaders + * + * If you wan't to write custom shaders. Don't forget to add SEMANTICS to these attributes. For example + * + ```glsl +uniform mat4 worldViewProjection : WORLDVIEWPROJECTION; +uniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE; +uniform mat4 world : WORLD; + +attribute vec3 position : POSITION; +attribute vec2 texcoord : TEXCOORD_0; +attribute vec3 normal : NORMAL; +``` + * These `POSITION`, `TEXCOORD_0`, `NORMAL` are SEMANTICS which will map the attributes in shader to the attributes in the Geometry + * + * Available attributes SEMANTICS includes `POSITION`, `TEXCOORD_0`, `TEXCOORD_1` `NORMAL`, `TANGENT`, `COLOR`, `WEIGHT`, `JOINT`. + * + * + * @constructor clay.Geometry + * @extends clay.core.Base */ var Geometry = Base.extend(function () { - return /** @lends qtek.Geometry# */ { + return /** @lends clay.Geometry# */ { /** * Attributes of geometry. Including: * + `position` @@ -17553,7 +18131,8 @@ var Geometry = Base.extend(function () { * + `weight` * + `joint` * + `barycentric` - * @type {Object} + * + * @type {Object.} */ attributes: { position: new Attribute('position', 'float', 3, 'POSITION'), @@ -17574,7 +18153,7 @@ var Geometry = Base.extend(function () { }, /** * Calculated bounding box of geometry. - * @type {qtek.math.BoundingBox} + * @type {clay.BoundingBox} */ boundingBox: null, @@ -17591,15 +18170,21 @@ var Geometry = Base.extend(function () { */ dynamic: true, - _enabledAttributes: null + _enabledAttributes: null, + + // PENDING + // Init it here to avoid deoptimization when it's assigned in application dynamically + __used: 0 }; }, function() { // Use cache this._cache = new Cache(); this._attributeList = Object.keys(this.attributes); + + this.__vaoCache = {}; }, -/** @lends qtek.Geometry.prototype */ +/** @lends clay.Geometry.prototype */ { /** * Main attribute will be used to count vertex number @@ -17621,7 +18206,7 @@ var Geometry = Base.extend(function () { * User defined ray picking algorithm instead of default * triangle ray intersection * ```typescript - * (ray: qtek.math.Ray, renderable: qtek.Renderable, out: Array) => boolean + * (ray: clay.Ray, renderable: clay.Renderable, out: Array) => boolean * ``` * @type {?Function} */ @@ -17639,10 +18224,10 @@ var Geometry = Base.extend(function () { if (posArr && posArr.length) { var min = bbox.min; var max = bbox.max; - var minArr = min._array; - var maxArr = max._array; - vec3$12.set(minArr, posArr[0], posArr[1], posArr[2]); - vec3$12.set(maxArr, posArr[0], posArr[1], posArr[2]); + var minArr = min.array; + var maxArr = max.array; + vec3$11.set(minArr, posArr[0], posArr[1], posArr[2]); + vec3$11.set(maxArr, posArr[0], posArr[1], posArr[2]); for (var i = 3; i < posArr.length;) { var x = posArr[i++]; var y = posArr[i++]; @@ -17661,6 +18246,7 @@ var Geometry = Base.extend(function () { }, /** * Mark attributes and indices in geometry needs to update. + * Usually called after you change the data in attributes. */ dirty: function () { var enabledAttributes = this.getEnabledAttributes(); @@ -17669,6 +18255,8 @@ var Geometry = Base.extend(function () { } this.dirtyIndices(); this._enabledAttributes = null; + + this._cache.dirty('any'); }, /** * Mark the indices needs to update. @@ -17721,7 +18309,7 @@ var Geometry = Base.extend(function () { /** * Initialize indices from an array. - * @param {Array} array + * @param {Array} array */ initIndicesFromArray: function (array) { var value; @@ -17779,10 +18367,10 @@ var Geometry = Base.extend(function () { /** * Get attribute * @param {string} name - * @return {qtek.Geometry.Attribute} + * @return {clay.Geometry.Attribute} */ getAttribute: function (name) { - return this.attribute[name]; + return this.attributes[name]; }, /** @@ -17818,7 +18406,7 @@ var Geometry = Base.extend(function () { getBufferChunks: function (renderer) { var cache = this._cache; - cache.use(renderer.__GUID__); + cache.use(renderer.__uid__); var isAttributesDirty = cache.isDirty('attributes'); var isIndicesDirty = cache.isDirty('indices'); if (isAttributesDirty || isIndicesDirty) { @@ -17830,6 +18418,7 @@ var Geometry = Base.extend(function () { cache.fresh('attributes'); cache.fresh('indices'); } + cache.fresh('any'); return cache.get('chunks'); }, @@ -17957,9 +18546,9 @@ var Geometry = Base.extend(function () { vec3Set$2(p2, positions[i2*3], positions[i2*3+1], positions[i2*3+2]); vec3Set$2(p3, positions[i3*3], positions[i3*3+1], positions[i3*3+2]); - vec3$12.sub(v21, p1, p2); - vec3$12.sub(v32, p2, p3); - vec3$12.cross(n, v21, v32); + vec3$11.sub(v21, p1, p2); + vec3$11.sub(v32, p2, p3); + vec3$11.cross(n, v21, v32); // Already be weighted by the triangle area for (var i = 0; i < 3; i++) { normals[i1*3+i] = normals[i1*3+i] + n[i]; @@ -17970,7 +18559,7 @@ var Geometry = Base.extend(function () { for (var i = 0; i < normals.length;) { vec3Set$2(n, normals[i], normals[i+1], normals[i+2]); - vec3$12.normalize(n, n); + vec3$11.normalize(n, n); normals[i++] = n[0]; normals[i++] = n[1]; normals[i++] = n[2]; @@ -18024,11 +18613,11 @@ var Geometry = Base.extend(function () { vec3Set$2(p2, positions[i2*3], positions[i2*3+1], positions[i2*3+2]); vec3Set$2(p3, positions[i3*3], positions[i3*3+1], positions[i3*3+2]); - vec3$12.sub(v21, p1, p2); - vec3$12.sub(v32, p2, p3); - vec3$12.cross(n, v21, v32); + vec3$11.sub(v21, p1, p2); + vec3$11.sub(v32, p2, p3); + vec3$11.cross(n, v21, v32); - vec3$12.normalize(n, n); + vec3$11.normalize(n, n); for (var i = 0; i < 3; i++) { normals[i1*3 + i] = n[i]; @@ -18142,20 +18731,20 @@ var Geometry = Base.extend(function () { var t = tan1[i]; // Gram-Schmidt orthogonalize - vec3$12.scale(tmp, n, vec3$12.dot(n, t)); - vec3$12.sub(tmp, t, tmp); - vec3$12.normalize(tmp, tmp); + vec3$11.scale(tmp, n, vec3$11.dot(n, t)); + vec3$11.sub(tmp, t, tmp); + vec3$11.normalize(tmp, tmp); // Calculate handedness. - vec3$12.cross(nCrossT, n, t); + vec3$11.cross(nCrossT, n, t); tangents[i * 4] = tmp[0]; tangents[i * 4 + 1] = tmp[1]; tangents[i * 4 + 2] = tmp[2]; // PENDING can config ? - tangents[i * 4 + 3] = vec3$12.dot(nCrossT, tan2[i]) < 0.0 ? -1.0 : 1.0; + tangents[i * 4 + 3] = vec3$11.dot(nCrossT, tan2[i]) < 0.0 ? -1.0 : 1.0; } this.dirty(); }, - + /** * If vertices are not shared by different indices. */ @@ -18230,7 +18819,7 @@ var Geometry = Base.extend(function () { return; } array = attributes.barycentric.value = new Float32Array(indices.length * 3); - + for (var i = 0; i < (indices ? indices.length : this.vertexCount / 3);) { for (var j = 0; j < 3; j++) { var ii = indices ? indices[i++] : (i * 3 + j); @@ -18242,7 +18831,7 @@ var Geometry = Base.extend(function () { /** * Apply transform to geometry attributes. - * @param {qtek.math.Matrix4} matrix + * @param {clay.Matrix4} matrix */ applyTransform: function (matrix) { @@ -18251,14 +18840,14 @@ var Geometry = Base.extend(function () { var normals = attributes.normal.value; var tangents = attributes.tangent.value; - matrix = matrix._array; + matrix = matrix.array; // Normal Matrix - var inverseTransposeMatrix = mat4$6.create(); - mat4$6.invert(inverseTransposeMatrix, matrix); - mat4$6.transpose(inverseTransposeMatrix, inverseTransposeMatrix); + var inverseTransposeMatrix = mat4$7.create(); + mat4$7.invert(inverseTransposeMatrix, matrix); + mat4$7.transpose(inverseTransposeMatrix, inverseTransposeMatrix); - var vec3TransformMat4 = vec3$12.transformMat4; - var vec3ForEach = vec3$12.forEach; + var vec3TransformMat4 = vec3$11.transformMat4; + var vec3ForEach = vec3$11.forEach; vec3ForEach(positions, 3, 0, null, vec3TransformMat4, matrix); if (normals) { vec3ForEach(normals, 3, 0, null, vec3TransformMat4, inverseTransposeMatrix); @@ -18273,13 +18862,13 @@ var Geometry = Base.extend(function () { }, /** * Dispose geometry data in GL context. - * @param {qtek.Renderer} renderer + * @param {clay.Renderer} renderer */ dispose: function (renderer) { var cache = this._cache; - cache.use(renderer.__GUID__); + cache.use(renderer.__uid__); var chunks = cache.get('chunks'); if (chunks) { for (var c = 0; c < chunks.length; c++) { @@ -18289,16 +18878,30 @@ var Geometry = Base.extend(function () { var attribs = chunk.attributeBuffers[k]; renderer.gl.deleteBuffer(attribs.buffer); } + + if (chunk.indicesBuffer) { + renderer.gl.deleteBuffer(chunk.indicesBuffer.buffer); + } } } - cache.deleteContext(renderer.__GUID__); + if (this.__vaoCache) { + var vaoExt = renderer.getGLExtension('OES_vertex_array_object'); + for (var id in this.__vaoCache) { + var vao = this.__vaoCache[id].vao; + if (vao) { + vaoExt.deleteVertexArrayOES(vao); + } + } + } + this.__vaoCache = {}; + cache.deleteContext(renderer.__uid__); } }); if (Object.defineProperty) { /** - * @name qtek.Geometry#vertexCount + * @name clay.Geometry#vertexCount * @type {number} * @readOnly */ @@ -18315,7 +18918,7 @@ if (Object.defineProperty) { } }); /** - * @name qtek.Geometry#triangleCount + * @name clay.Geometry#triangleCount * @type {number} * @readOnly */ @@ -18344,45 +18947,15 @@ Geometry.IndicesBuffer = IndicesBuffer; Geometry.Attribute = Attribute; -var utilEssl = "\n@export qtek.util.rand\nhighp float rand(vec2 uv) {\n const highp float a = 12.9898, b = 78.233, c = 43758.5453;\n highp float dt = dot(uv.xy, vec2(a,b)), sn = mod(dt, 3.141592653589793);\n return fract(sin(sn) * c);\n}\n@end\n@export qtek.util.calculate_attenuation\nuniform float attenuationFactor : 5.0;\nfloat lightAttenuation(float dist, float range)\n{\n float attenuation = 1.0;\n attenuation = dist*dist/(range*range+1.0);\n float att_s = attenuationFactor;\n attenuation = 1.0/(attenuation*att_s+1.0);\n att_s = 1.0/(att_s+1.0);\n attenuation = attenuation - att_s;\n attenuation /= 1.0 - att_s;\n return clamp(attenuation, 0.0, 1.0);\n}\n@end\n@export qtek.util.edge_factor\nfloat edgeFactor(float width)\n{\n vec3 d = fwidth(v_Barycentric);\n vec3 a3 = smoothstep(vec3(0.0), d * width, v_Barycentric);\n return min(min(a3.x, a3.y), a3.z);\n}\n@end\n@export qtek.util.encode_float\nvec4 encodeFloat(const in float depth)\n{\n const vec4 bitShifts = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);\n const vec4 bit_mask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);\n vec4 res = fract(depth * bitShifts);\n res -= res.xxyz * bit_mask;\n return res;\n}\n@end\n@export qtek.util.decode_float\nfloat decodeFloat(const in vec4 color)\n{\n const vec4 bitShifts = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);\n return dot(color, bitShifts);\n}\n@end\n@export qtek.util.float\n@import qtek.util.encode_float\n@import qtek.util.decode_float\n@end\n@export qtek.util.rgbm_decode\nvec3 RGBMDecode(vec4 rgbm, float range) {\n return range * rgbm.rgb * rgbm.a;\n}\n@end\n@export qtek.util.rgbm_encode\nvec4 RGBMEncode(vec3 color, float range) {\n if (dot(color, color) == 0.0) {\n return vec4(0.0);\n }\n vec4 rgbm;\n color /= range;\n rgbm.a = clamp(max(max(color.r, color.g), max(color.b, 1e-6)), 0.0, 1.0);\n rgbm.a = ceil(rgbm.a * 255.0) / 255.0;\n rgbm.rgb = color / rgbm.a;\n return rgbm;\n}\n@end\n@export qtek.util.rgbm\n@import qtek.util.rgbm_decode\n@import qtek.util.rgbm_encode\nvec4 decodeHDR(vec4 color)\n{\n#if defined(RGBM_DECODE) || defined(RGBM)\n return vec4(RGBMDecode(color, 51.5), 1.0);\n#else\n return color;\n#endif\n}\nvec4 encodeHDR(vec4 color)\n{\n#if defined(RGBM_ENCODE) || defined(RGBM)\n return RGBMEncode(color.xyz, 51.5);\n#else\n return color;\n#endif\n}\n@end\n@export qtek.util.srgb\nvec4 sRGBToLinear(in vec4 value) {\n return vec4(mix(pow(value.rgb * 0.9478672986 + vec3(0.0521327014), vec3(2.4)), value.rgb * 0.0773993808, vec3(lessThanEqual(value.rgb, vec3(0.04045)))), value.w);\n}\nvec4 linearTosRGB(in vec4 value) {\n return vec4(mix(pow(value.rgb, vec3(0.41666)) * 1.055 - vec3(0.055), value.rgb * 12.92, vec3(lessThanEqual(value.rgb, vec3(0.0031308)))), value.w);\n}\n@end\n@export qtek.chunk.skinning_header\n#ifdef SKINNING\nattribute vec3 weight : WEIGHT;\nattribute vec4 joint : JOINT;\n#ifdef USE_SKIN_MATRICES_TEXTURE\nuniform sampler2D skinMatricesTexture;\nuniform float skinMatricesTextureSize: unconfigurable;\nmat4 getSkinMatrix(float idx) {\n float j = idx * 4.0;\n float x = mod(j, skinMatricesTextureSize);\n float y = floor(j / skinMatricesTextureSize) + 0.5;\n vec2 scale = vec2(skinMatricesTextureSize);\n return mat4(\n texture2D(skinMatricesTexture, vec2(x + 0.5, y) / scale),\n texture2D(skinMatricesTexture, vec2(x + 1.5, y) / scale),\n texture2D(skinMatricesTexture, vec2(x + 2.5, y) / scale),\n texture2D(skinMatricesTexture, vec2(x + 3.5, y) / scale)\n );\n}\n#else\nuniform mat4 skinMatrix[JOINT_COUNT] : SKIN_MATRIX;\nmat4 getSkinMatrix(float idx) {\n return skinMatrix[int(idx)];\n}\n#endif\n#endif\n@end\n@export qtek.chunk.skin_matrix\nmat4 skinMatrixWS = getSkinMatrix(joint.x) * weight.x;\nif (weight.y > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.y) * weight.y;\n}\nif (weight.z > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.z) * weight.z;\n}\nfloat weightW = 1.0-weight.x-weight.y-weight.z;\nif (weightW > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.w) * weightW;\n}\n@end\n@export qtek.util.parallax_correct\nvec3 parallaxCorrect(in vec3 dir, in vec3 pos, in vec3 boxMin, in vec3 boxMax) {\n vec3 first = (boxMax - pos) / dir;\n vec3 second = (boxMin - pos) / dir;\n vec3 further = max(first, second);\n float dist = min(further.x, min(further.y, further.z));\n vec3 fixedPos = pos + dir * dist;\n vec3 boxCenter = (boxMax + boxMin) * 0.5;\n return normalize(fixedPos - boxCenter);\n}\n@end\n@export qtek.util.clamp_sample\nvec4 clampSample(const in sampler2D texture, const in vec2 coord)\n{\n#ifdef STEREO\n float eye = step(0.5, coord.x) * 0.5;\n vec2 coordClamped = clamp(coord, vec2(eye, 0.0), vec2(0.5 + eye, 1.0));\n#else\n vec2 coordClamped = clamp(coord, vec2(0.0), vec2(1.0));\n#endif\n return texture2D(texture, coordClamped);\n}\n@end"; - -var basicEssl = "@export qtek.basic.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec2 texcoord : TEXCOORD_0;\nattribute vec3 position : POSITION;\nattribute vec3 barycentric;\n@import qtek.chunk.skinning_header\nvarying vec2 v_Texcoord;\nvarying vec3 v_Barycentric;\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import qtek.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_Barycentric = barycentric;\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n}\n@end\n@export qtek.basic.fragment\nvarying vec2 v_Texcoord;\nuniform sampler2D diffuseMap;\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\nvarying vec3 v_Barycentric;\n@import qtek.util.edge_factor\n@import qtek.util.rgbm\n@import qtek.util.srgb\nvoid main()\n{\n#ifdef RENDER_TEXCOORD\n gl_FragColor = vec4(v_Texcoord, 1.0, 1.0);\n return;\n#endif\n gl_FragColor = vec4(color, alpha);\n#ifdef DIFFUSEMAP_ENABLED\n vec4 tex = decodeHDR(texture2D(diffuseMap, v_Texcoord));\n#ifdef SRGB_DECODE\n tex = sRGBToLinear(tex);\n#endif\n#if defined(DIFFUSEMAP_ALPHA_ALPHA)\n gl_FragColor.a = tex.a;\n#endif\n gl_FragColor.rgb *= tex.rgb;\n#endif\n gl_FragColor.rgb += emission;\n if( lineWidth > 0.)\n {\n gl_FragColor.rgb = mix(gl_FragColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef GAMMA_ENCODE\n gl_FragColor.rgb = pow(gl_FragColor.rgb, vec3(1 / 2.2));\n#endif\n#ifdef ALPHA_TEST\n if (gl_FragColor.a < alphaCutoff) {\n discard;\n }\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n}\n@end"; +var utilEssl = "\n@export clay.util.rand\nhighp float rand(vec2 uv) {\n const highp float a = 12.9898, b = 78.233, c = 43758.5453;\n highp float dt = dot(uv.xy, vec2(a,b)), sn = mod(dt, 3.141592653589793);\n return fract(sin(sn) * c);\n}\n@end\n@export clay.util.calculate_attenuation\nuniform float attenuationFactor : 5.0;\nfloat lightAttenuation(float dist, float range)\n{\n float attenuation = 1.0;\n attenuation = dist*dist/(range*range+1.0);\n float att_s = attenuationFactor;\n attenuation = 1.0/(attenuation*att_s+1.0);\n att_s = 1.0/(att_s+1.0);\n attenuation = attenuation - att_s;\n attenuation /= 1.0 - att_s;\n return clamp(attenuation, 0.0, 1.0);\n}\n@end\n@export clay.util.edge_factor\nfloat edgeFactor(float width)\n{\n vec3 d = fwidth(v_Barycentric);\n vec3 a3 = smoothstep(vec3(0.0), d * width, v_Barycentric);\n return min(min(a3.x, a3.y), a3.z);\n}\n@end\n@export clay.util.encode_float\nvec4 encodeFloat(const in float depth)\n{\n const vec4 bitShifts = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);\n const vec4 bit_mask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);\n vec4 res = fract(depth * bitShifts);\n res -= res.xxyz * bit_mask;\n return res;\n}\n@end\n@export clay.util.decode_float\nfloat decodeFloat(const in vec4 color)\n{\n const vec4 bitShifts = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);\n return dot(color, bitShifts);\n}\n@end\n@export clay.util.float\n@import clay.util.encode_float\n@import clay.util.decode_float\n@end\n@export clay.util.rgbm_decode\nvec3 RGBMDecode(vec4 rgbm, float range) {\n return range * rgbm.rgb * rgbm.a;\n}\n@end\n@export clay.util.rgbm_encode\nvec4 RGBMEncode(vec3 color, float range) {\n if (dot(color, color) == 0.0) {\n return vec4(0.0);\n }\n vec4 rgbm;\n color /= range;\n rgbm.a = clamp(max(max(color.r, color.g), max(color.b, 1e-6)), 0.0, 1.0);\n rgbm.a = ceil(rgbm.a * 255.0) / 255.0;\n rgbm.rgb = color / rgbm.a;\n return rgbm;\n}\n@end\n@export clay.util.rgbm\n@import clay.util.rgbm_decode\n@import clay.util.rgbm_encode\nvec4 decodeHDR(vec4 color)\n{\n#if defined(RGBM_DECODE) || defined(RGBM)\n return vec4(RGBMDecode(color, 8.12), 1.0);\n#else\n return color;\n#endif\n}\nvec4 encodeHDR(vec4 color)\n{\n#if defined(RGBM_ENCODE) || defined(RGBM)\n return RGBMEncode(color.xyz, 8.12);\n#else\n return color;\n#endif\n}\n@end\n@export clay.util.srgb\nvec4 sRGBToLinear(in vec4 value) {\n return vec4(mix(pow(value.rgb * 0.9478672986 + vec3(0.0521327014), vec3(2.4)), value.rgb * 0.0773993808, vec3(lessThanEqual(value.rgb, vec3(0.04045)))), value.w);\n}\nvec4 linearTosRGB(in vec4 value) {\n return vec4(mix(pow(value.rgb, vec3(0.41666)) * 1.055 - vec3(0.055), value.rgb * 12.92, vec3(lessThanEqual(value.rgb, vec3(0.0031308)))), value.w);\n}\n@end\n@export clay.chunk.skinning_header\n#ifdef SKINNING\nattribute vec3 weight : WEIGHT;\nattribute vec4 joint : JOINT;\nuniform mat4 skinMatrix[JOINT_COUNT] : SKIN_MATRIX;\nmat4 getSkinMatrix(float idx) {\n return skinMatrix[int(idx)];\n}\n#endif\n@end\n@export clay.chunk.skin_matrix\nmat4 skinMatrixWS = getSkinMatrix(joint.x) * weight.x;\nif (weight.y > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.y) * weight.y;\n}\nif (weight.z > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.z) * weight.z;\n}\nfloat weightW = 1.0-weight.x-weight.y-weight.z;\nif (weightW > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.w) * weightW;\n}\n@end\n@export clay.util.parallax_correct\nvec3 parallaxCorrect(in vec3 dir, in vec3 pos, in vec3 boxMin, in vec3 boxMax) {\n vec3 first = (boxMax - pos) / dir;\n vec3 second = (boxMin - pos) / dir;\n vec3 further = max(first, second);\n float dist = min(further.x, min(further.y, further.z));\n vec3 fixedPos = pos + dir * dist;\n vec3 boxCenter = (boxMax + boxMin) * 0.5;\n return normalize(fixedPos - boxCenter);\n}\n@end\n@export clay.util.clamp_sample\nvec4 clampSample(const in sampler2D texture, const in vec2 coord)\n{\n#ifdef STEREO\n float eye = step(0.5, coord.x) * 0.5;\n vec2 coordClamped = clamp(coord, vec2(eye, 0.0), vec2(0.5 + eye, 1.0));\n#else\n vec2 coordClamped = clamp(coord, vec2(0.0), vec2(1.0));\n#endif\n return texture2D(texture, coordClamped);\n}\n@end\n@export clay.util.ACES\nvec3 ACESToneMapping(vec3 color)\n{\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\n@end"; -var lambertEssl = "\n@export qtek.lambert.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\nattribute vec3 normal : NORMAL;\nattribute vec3 barycentric;\n@import qtek.chunk.skinning_header\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nvarying vec3 v_Barycentric;\nvoid main()\n{\n vec3 skinnedPosition = position;\n vec3 skinnedNormal = normal;\n#ifdef SKINNING\n @import qtek.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4( skinnedPosition, 1.0 );\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_Normal = normalize( ( worldInverseTranspose * vec4(skinnedNormal, 0.0) ).xyz );\n v_WorldPosition = ( world * vec4( skinnedPosition, 1.0) ).xyz;\n v_Barycentric = barycentric;\n}\n@end\n@export qtek.lambert.fragment\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nuniform sampler2D diffuseMap;\nuniform sampler2D alphaMap;\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\nvarying vec3 v_Barycentric;\n#ifdef AMBIENT_LIGHT_COUNT\n@import qtek.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import qtek.header.ambient_sh_light\n#endif\n#ifdef POINT_LIGHT_COUNT\n@import qtek.header.point_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import qtek.header.directional_light\n#endif\n#ifdef SPOT_LIGHT_COUNT\n@import qtek.header.spot_light\n#endif\n@import qtek.util.calculate_attenuation\n@import qtek.util.edge_factor\n@import qtek.util.rgbm\n@import qtek.plugin.compute_shadow_map\nvoid main()\n{\n#ifdef RENDER_NORMAL\n gl_FragColor = vec4(v_Normal * 0.5 + 0.5, 1.0);\n return;\n#endif\n#ifdef RENDER_TEXCOORD\n gl_FragColor = vec4(v_Texcoord, 1.0, 1.0);\n return;\n#endif\n gl_FragColor = vec4(color, alpha);\n#ifdef DIFFUSEMAP_ENABLED\n vec4 tex = texture2D( diffuseMap, v_Texcoord );\n#ifdef SRGB_DECODE\n tex.rgb = pow(tex.rgb, vec3(2.2));\n#endif\n gl_FragColor.rgb *= tex.rgb;\n#ifdef DIFFUSEMAP_ALPHA_ALPHA\n gl_FragColor.a *= tex.a;\n#endif\n#endif\n vec3 diffuseColor = vec3(0.0, 0.0, 0.0);\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {\n diffuseColor += ambientLightColor[_idx_];\n }\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseColor += calcAmbientSHLight(_idx_, v_Normal) * ambientSHLightColor[_idx_];\n }}\n#endif\n#ifdef POINT_LIGHT_COUNT\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsPoint[POINT_LIGHT_COUNT];\n if( shadowEnabled )\n {\n computeShadowOfPointLights(v_WorldPosition, shadowContribsPoint);\n }\n#endif\n for(int i = 0; i < POINT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = pointLightPosition[i];\n vec3 lightColor = pointLightColor[i];\n float range = pointLightRange[i];\n vec3 lightDirection = lightPosition - v_WorldPosition;\n float dist = length(lightDirection);\n float attenuation = lightAttenuation(dist, range);\n lightDirection /= dist;\n float ndl = dot( v_Normal, lightDirection );\n float shadowContrib = 1.0;\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsPoint[i];\n }\n#endif\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * attenuation * shadowContrib;\n }\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++)\n {\n vec3 lightDirection = -directionalLightDirection[i];\n vec3 lightColor = directionalLightColor[i];\n float ndl = dot(v_Normal, normalize(lightDirection));\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsDir[i];\n }\n#endif\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * shadowContrib;\n }\n#endif\n#ifdef SPOT_LIGHT_COUNT\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsSpot[SPOT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfSpotLights(v_WorldPosition, shadowContribsSpot);\n }\n#endif\n for(int i = 0; i < SPOT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = -spotLightPosition[i];\n vec3 spotLightDirection = -normalize( spotLightDirection[i] );\n vec3 lightColor = spotLightColor[i];\n float range = spotLightRange[i];\n float a = spotLightUmbraAngleCosine[i];\n float b = spotLightPenumbraAngleCosine[i];\n float falloffFactor = spotLightFalloffFactor[i];\n vec3 lightDirection = lightPosition - v_WorldPosition;\n float dist = length(lightDirection);\n float attenuation = lightAttenuation(dist, range);\n lightDirection /= dist;\n float c = dot(spotLightDirection, lightDirection);\n float falloff;\n falloff = clamp((c - a) /( b - a), 0.0, 1.0);\n falloff = pow(falloff, falloffFactor);\n float ndl = dot(v_Normal, lightDirection);\n ndl = clamp(ndl, 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsSpot[i];\n }\n#endif\n diffuseColor += lightColor * ndl * attenuation * (1.0-falloff) * shadowContrib;\n }\n#endif\n gl_FragColor.rgb *= diffuseColor;\n gl_FragColor.rgb += emission;\n if(lineWidth > 0.)\n {\n gl_FragColor.rgb = mix(gl_FragColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (gl_FragColor.a < alphaCutoff) {\n discard;\n }\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n}\n@end"; +var basicEssl = "@export clay.basic.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec2 texcoord : TEXCOORD_0;\nattribute vec3 position : POSITION;\nattribute vec3 barycentric;\n@import clay.chunk.skinning_header\nvarying vec2 v_Texcoord;\nvarying vec3 v_Barycentric;\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n#endif\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_Barycentric = barycentric;\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n}\n@end\n@export clay.basic.fragment\nvarying vec2 v_Texcoord;\nuniform sampler2D diffuseMap;\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\nvarying vec3 v_Barycentric;\n@import clay.util.edge_factor\n@import clay.util.rgbm\n@import clay.util.srgb\n@import clay.util.ACES\nvoid main()\n{\n#ifdef RENDER_TEXCOORD\n gl_FragColor = vec4(v_Texcoord, 1.0, 1.0);\n return;\n#endif\n gl_FragColor = vec4(color, alpha);\n#ifdef VERTEX_COLOR\n gl_FragColor *= v_Color;\n#endif\n#ifdef DIFFUSEMAP_ENABLED\n vec4 texel = decodeHDR(texture2D(diffuseMap, v_Texcoord));\n#ifdef SRGB_DECODE\n texel = sRGBToLinear(texel);\n#endif\n#if defined(DIFFUSEMAP_ALPHA_ALPHA)\n gl_FragColor.a = texel.a;\n#endif\n gl_FragColor.rgb *= texel.rgb;\n#endif\n gl_FragColor.rgb += emission;\n if( lineWidth > 0.)\n {\n gl_FragColor.rgb = mix(gl_FragColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (gl_FragColor.a < alphaCutoff) {\n discard;\n }\n#endif\n#ifdef TONEMAPPING\n gl_FragColor.rgb = ACESToneMapping(gl_FragColor.rgb);\n#endif\n#ifdef SRGB_ENCODE\n gl_FragColor = linearTosRGB(gl_FragColor);\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n}\n@end"; -var wireframeEssl = "@export qtek.wireframe.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 world : WORLD;\nattribute vec3 position : POSITION;\nattribute vec3 barycentric;\n@import qtek.chunk.skinning_header\nvarying vec3 v_Barycentric;\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import qtek.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0 );\n v_Barycentric = barycentric;\n}\n@end\n@export qtek.wireframe.fragment\nuniform vec3 color : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\nuniform float lineWidth : 1.0;\nvarying vec3 v_Barycentric;\n@import qtek.util.edge_factor\nvoid main()\n{\n gl_FragColor.rgb = color;\n gl_FragColor.a = (1.0-edgeFactor(lineWidth)) * alpha;\n}\n@end"; +var lambertEssl = "\n@export clay.lambert.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\nattribute vec3 normal : NORMAL;\nattribute vec3 barycentric;\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n#endif\n@import clay.chunk.skinning_header\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nvarying vec3 v_Barycentric;\nvoid main()\n{\n vec3 skinnedPosition = position;\n vec3 skinnedNormal = normal;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4( skinnedPosition, 1.0 );\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_Normal = normalize( ( worldInverseTranspose * vec4(skinnedNormal, 0.0) ).xyz );\n v_WorldPosition = ( world * vec4( skinnedPosition, 1.0) ).xyz;\n v_Barycentric = barycentric;\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n}\n@end\n@export clay.lambert.fragment\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nuniform sampler2D diffuseMap;\nuniform sampler2D alphaMap;\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\nvarying vec3 v_Barycentric;\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\n#ifdef AMBIENT_LIGHT_COUNT\n@import clay.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import clay.header.ambient_sh_light\n#endif\n#ifdef POINT_LIGHT_COUNT\n@import clay.header.point_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n#ifdef SPOT_LIGHT_COUNT\n@import clay.header.spot_light\n#endif\n@import clay.util.calculate_attenuation\n@import clay.util.edge_factor\n@import clay.util.rgbm\n@import clay.plugin.compute_shadow_map\n@import clay.util.ACES\nvoid main()\n{\n#ifdef RENDER_NORMAL\n gl_FragColor = vec4(v_Normal * 0.5 + 0.5, 1.0);\n return;\n#endif\n#ifdef RENDER_TEXCOORD\n gl_FragColor = vec4(v_Texcoord, 1.0, 1.0);\n return;\n#endif\n gl_FragColor = vec4(color, alpha);\n#ifdef VERTEX_COLOR\n gl_FragColor *= v_Color;\n#endif\n#ifdef DIFFUSEMAP_ENABLED\n vec4 tex = texture2D( diffuseMap, v_Texcoord );\n#ifdef SRGB_DECODE\n tex.rgb = pow(tex.rgb, vec3(2.2));\n#endif\n gl_FragColor.rgb *= tex.rgb;\n#ifdef DIFFUSEMAP_ALPHA_ALPHA\n gl_FragColor.a *= tex.a;\n#endif\n#endif\n vec3 diffuseColor = vec3(0.0, 0.0, 0.0);\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {\n diffuseColor += ambientLightColor[_idx_];\n }\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseColor += calcAmbientSHLight(_idx_, v_Normal) * ambientSHLightColor[_idx_];\n }}\n#endif\n#ifdef POINT_LIGHT_COUNT\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsPoint[POINT_LIGHT_COUNT];\n if( shadowEnabled )\n {\n computeShadowOfPointLights(v_WorldPosition, shadowContribsPoint);\n }\n#endif\n for(int i = 0; i < POINT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = pointLightPosition[i];\n vec3 lightColor = pointLightColor[i];\n float range = pointLightRange[i];\n vec3 lightDirection = lightPosition - v_WorldPosition;\n float dist = length(lightDirection);\n float attenuation = lightAttenuation(dist, range);\n lightDirection /= dist;\n float ndl = dot( v_Normal, lightDirection );\n float shadowContrib = 1.0;\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsPoint[i];\n }\n#endif\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * attenuation * shadowContrib;\n }\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++)\n {\n vec3 lightDirection = -directionalLightDirection[i];\n vec3 lightColor = directionalLightColor[i];\n float ndl = dot(v_Normal, normalize(lightDirection));\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsDir[i];\n }\n#endif\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * shadowContrib;\n }\n#endif\n#ifdef SPOT_LIGHT_COUNT\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsSpot[SPOT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfSpotLights(v_WorldPosition, shadowContribsSpot);\n }\n#endif\n for(int i = 0; i < SPOT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = -spotLightPosition[i];\n vec3 spotLightDirection = -normalize( spotLightDirection[i] );\n vec3 lightColor = spotLightColor[i];\n float range = spotLightRange[i];\n float a = spotLightUmbraAngleCosine[i];\n float b = spotLightPenumbraAngleCosine[i];\n float falloffFactor = spotLightFalloffFactor[i];\n vec3 lightDirection = lightPosition - v_WorldPosition;\n float dist = length(lightDirection);\n float attenuation = lightAttenuation(dist, range);\n lightDirection /= dist;\n float c = dot(spotLightDirection, lightDirection);\n float falloff;\n falloff = clamp((c - a) /( b - a), 0.0, 1.0);\n falloff = pow(falloff, falloffFactor);\n float ndl = dot(v_Normal, lightDirection);\n ndl = clamp(ndl, 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsSpot[i];\n }\n#endif\n diffuseColor += lightColor * ndl * attenuation * (1.0-falloff) * shadowContrib;\n }\n#endif\n gl_FragColor.rgb *= diffuseColor;\n gl_FragColor.rgb += emission;\n if(lineWidth > 0.)\n {\n gl_FragColor.rgb = mix(gl_FragColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (gl_FragColor.a < alphaCutoff) {\n discard;\n }\n#endif\n#ifdef TONEMAPPING\n gl_FragColor.rgb = ACESToneMapping(gl_FragColor.rgb);\n#endif\n#ifdef SRGB_ENCODE\n gl_FragColor = linearTosRGB(gl_FragColor);\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n}\n@end"; -var skyboxEssl = "@export qtek.skybox.vertex\nuniform mat4 world : WORLD;\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\nvarying vec3 v_WorldPosition;\nvoid main()\n{\n v_WorldPosition = (world * vec4(position, 1.0)).xyz;\n gl_Position = worldViewProjection * vec4(position, 1.0);\n}\n@end\n@export qtek.skybox.fragment\nuniform mat4 viewInverse : VIEWINVERSE;\nuniform samplerCube environmentMap;\nuniform float lod: 0.0;\nvarying vec3 v_WorldPosition;\n@import qtek.util.rgbm\nvoid main()\n{\n vec3 eyePos = viewInverse[3].xyz;\n vec3 viewDirection = normalize(v_WorldPosition - eyePos);\n vec3 tex = decodeHDR(textureCubeLodEXT(environmentMap, viewDirection, lod)).rgb;\n#ifdef SRGB_DECODE\n tex.rgb = pow(tex.rgb, vec3(2.2));\n#endif\n gl_FragColor = encodeHDR(vec4(tex, 1.0));\n}\n@end"; +var wireframeEssl = "@export clay.wireframe.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 world : WORLD;\nattribute vec3 position : POSITION;\nattribute vec3 barycentric;\n@import clay.chunk.skinning_header\nvarying vec3 v_Barycentric;\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0 );\n v_Barycentric = barycentric;\n}\n@end\n@export clay.wireframe.fragment\nuniform vec3 color : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\nuniform float lineWidth : 1.0;\nvarying vec3 v_Barycentric;\n@import clay.util.edge_factor\nvoid main()\n{\n gl_FragColor.rgb = color;\n gl_FragColor.a = (1.0-edgeFactor(lineWidth)) * alpha;\n}\n@end"; -var coloradjustEssl = "@export qtek.compositor.coloradjust\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float brightness : 0.0;\nuniform float contrast : 1.0;\nuniform float exposure : 0.0;\nuniform float gamma : 1.0;\nuniform float saturation : 1.0;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = clamp(tex.rgb + vec3(brightness), 0.0, 1.0);\n color = clamp( (color-vec3(0.5))*contrast+vec3(0.5), 0.0, 1.0);\n color = clamp( color * pow(2.0, exposure), 0.0, 1.0);\n color = clamp( pow(color, vec3(gamma)), 0.0, 1.0);\n float luminance = dot( color, w );\n color = mix(vec3(luminance), color, saturation);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export qtek.compositor.brightness\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float brightness : 0.0;\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = tex.rgb + vec3(brightness);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export qtek.compositor.contrast\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float contrast : 1.0;\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = (tex.rgb-vec3(0.5))*contrast+vec3(0.5);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export qtek.compositor.exposure\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float exposure : 0.0;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = tex.rgb * pow(2.0, exposure);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export qtek.compositor.gamma\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float gamma : 1.0;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = pow(tex.rgb, vec3(gamma));\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export qtek.compositor.saturation\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float saturation : 1.0;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = tex.rgb;\n float luminance = dot(color, w);\n color = mix(vec3(luminance), color, saturation);\n gl_FragColor = vec4(color, tex.a);\n}\n@end"; - -var blurGLSL = "@export qtek.compositor.kernel.gaussian_9\nfloat gaussianKernel[9];\ngaussianKernel[0] = 0.07;\ngaussianKernel[1] = 0.09;\ngaussianKernel[2] = 0.12;\ngaussianKernel[3] = 0.14;\ngaussianKernel[4] = 0.16;\ngaussianKernel[5] = 0.14;\ngaussianKernel[6] = 0.12;\ngaussianKernel[7] = 0.09;\ngaussianKernel[8] = 0.07;\n@end\n@export qtek.compositor.kernel.gaussian_13\nfloat gaussianKernel[13];\ngaussianKernel[0] = 0.02;\ngaussianKernel[1] = 0.03;\ngaussianKernel[2] = 0.06;\ngaussianKernel[3] = 0.08;\ngaussianKernel[4] = 0.11;\ngaussianKernel[5] = 0.13;\ngaussianKernel[6] = 0.14;\ngaussianKernel[7] = 0.13;\ngaussianKernel[8] = 0.11;\ngaussianKernel[9] = 0.08;\ngaussianKernel[10] = 0.06;\ngaussianKernel[11] = 0.03;\ngaussianKernel[12] = 0.02;\n@end\n@export qtek.compositor.gaussian_blur\n#define SHADER_NAME gaussian_blur\nuniform sampler2D texture;varying vec2 v_Texcoord;\nuniform float blurSize : 2.0;\nuniform vec2 textureSize : [512.0, 512.0];\nuniform float blurDir : 0.0;\n@import qtek.util.rgbm\n@import qtek.util.clamp_sample\nvoid main (void)\n{\n @import qtek.compositor.kernel.gaussian_9\n vec2 off = blurSize / textureSize;\n off *= vec2(1.0 - blurDir, blurDir);\n vec4 sum = vec4(0.0);\n float weightAll = 0.0;\n for (int i = 0; i < 9; i++) {\n float w = gaussianKernel[i];\n vec4 texel = decodeHDR(clampSample(texture, v_Texcoord + float(i - 4) * off));\n sum += texel * w;\n weightAll += w;\n }\n gl_FragColor = encodeHDR(sum / max(weightAll, 0.01));\n}\n@end\n"; - -var lumEssl = "@export qtek.compositor.hdr.log_lum\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\n@import qtek.util.rgbm\nvoid main()\n{\n vec4 tex = decodeHDR(texture2D(texture, v_Texcoord));\n float luminance = dot(tex.rgb, w);\n luminance = log(luminance + 0.001);\n gl_FragColor = encodeHDR(vec4(vec3(luminance), 1.0));\n}\n@end\n@export qtek.compositor.hdr.lum_adaption\nvarying vec2 v_Texcoord;\nuniform sampler2D adaptedLum;\nuniform sampler2D currentLum;\nuniform float frameTime : 0.02;\n@import qtek.util.rgbm\nvoid main()\n{\n float fAdaptedLum = decodeHDR(texture2D(adaptedLum, vec2(0.5, 0.5))).r;\n float fCurrentLum = exp(encodeHDR(texture2D(currentLum, vec2(0.5, 0.5))).r);\n fAdaptedLum += (fCurrentLum - fAdaptedLum) * (1.0 - pow(0.98, 30.0 * frameTime));\n gl_FragColor = encodeHDR(vec4(vec3(fAdaptedLum), 1.0));\n}\n@end\n@export qtek.compositor.lum\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord );\n float luminance = dot(tex.rgb, w);\n gl_FragColor = vec4(vec3(luminance), 1.0);\n}\n@end"; - -var lutEssl = "\n@export qtek.compositor.lut\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform sampler2D lookup;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n float blueColor = tex.b * 63.0;\n vec2 quad1;\n quad1.y = floor(floor(blueColor) / 8.0);\n quad1.x = floor(blueColor) - (quad1.y * 8.0);\n vec2 quad2;\n quad2.y = floor(ceil(blueColor) / 8.0);\n quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n vec2 texPos1;\n texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.r);\n texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.g);\n vec2 texPos2;\n texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.r);\n texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.g);\n vec4 newColor1 = texture2D(lookup, texPos1);\n vec4 newColor2 = texture2D(lookup, texPos2);\n vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n gl_FragColor = vec4(newColor.rgb, tex.w);\n}\n@end"; - -var vigentteEssl = "@export qtek.compositor.vignette\n#define OUTPUT_ALPHA\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float darkness: 1;\nuniform float offset: 1;\n@import qtek.util.rgbm\nvoid main()\n{\n vec4 texel = decodeHDR(texture2D(texture, v_Texcoord));\n gl_FragColor.rgb = texel.rgb;\n vec2 uv = (v_Texcoord - vec2(0.5)) * vec2(offset);\n gl_FragColor = encodeHDR(vec4(mix(texel.rgb, vec3(1.0 - darkness), dot(uv, uv)), texel.a));\n}\n@end"; - -var outputGLSL = "@export qtek.compositor.output\n#define OUTPUT_ALPHA\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\n@import qtek.util.rgbm\nvoid main()\n{\n vec4 tex = decodeHDR(texture2D(texture, v_Texcoord));\n gl_FragColor.rgb = tex.rgb;\n#ifdef OUTPUT_ALPHA\n gl_FragColor.a = tex.a;\n#else\n gl_FragColor.a = 1.0;\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n#ifdef PREMULTIPLY_ALPHA\n gl_FragColor.rgb *= gl_FragColor.a;\n#endif\n}\n@end"; - -var brightGLSL = "@export qtek.compositor.bright\nuniform sampler2D texture;\nuniform float threshold : 1;\nuniform float scale : 1.0;\nuniform vec2 textureSize: [512, 512];\nvarying vec2 v_Texcoord;\nconst vec3 lumWeight = vec3(0.2125, 0.7154, 0.0721);\n@import qtek.util.rgbm\nvec4 median(vec4 a, vec4 b, vec4 c)\n{\n return a + b + c - min(min(a, b), c) - max(max(a, b), c);\n}\nvoid main()\n{\n vec4 texel = decodeHDR(texture2D(texture, v_Texcoord));\n#ifdef ANTI_FLICKER\n vec3 d = 1.0 / textureSize.xyx * vec3(1.0, 1.0, 0.0);\n vec4 s1 = decodeHDR(texture2D(texture, v_Texcoord - d.xz));\n vec4 s2 = decodeHDR(texture2D(texture, v_Texcoord + d.xz));\n vec4 s3 = decodeHDR(texture2D(texture, v_Texcoord - d.zy));\n vec4 s4 = decodeHDR(texture2D(texture, v_Texcoord + d.zy));\n texel = median(median(texel, s1, s2), s3, s4);\n#endif\n float lum = dot(texel.rgb , lumWeight);\n vec4 color;\n if (lum > threshold && texel.a > 0.0)\n {\n color = vec4(texel.rgb * scale, texel.a * scale);\n }\n else\n {\n color = vec4(0.0);\n }\n gl_FragColor = encodeHDR(color);\n}\n@end\n"; - -var downsampleGLSL = "@export qtek.compositor.downsample\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\nfloat brightness(vec3 c)\n{\n return max(max(c.r, c.g), c.b);\n}\n@import qtek.util.clamp_sample\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n#ifdef ANTI_FLICKER\n vec3 s1 = decodeHDR(clampSample(texture, v_Texcoord + d.xy)).rgb;\n vec3 s2 = decodeHDR(clampSample(texture, v_Texcoord + d.zy)).rgb;\n vec3 s3 = decodeHDR(clampSample(texture, v_Texcoord + d.xw)).rgb;\n vec3 s4 = decodeHDR(clampSample(texture, v_Texcoord + d.zw)).rgb;\n float s1w = 1.0 / (brightness(s1) + 1.0);\n float s2w = 1.0 / (brightness(s2) + 1.0);\n float s3w = 1.0 / (brightness(s3) + 1.0);\n float s4w = 1.0 / (brightness(s4) + 1.0);\n float oneDivideSum = 1.0 / (s1w + s2w + s3w + s4w);\n vec4 color = vec4(\n (s1 * s1w + s2 * s2w + s3 * s3w + s4 * s4w) * oneDivideSum,\n 1.0\n );\n#else\n vec4 color = decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.xw));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.zw));\n color *= 0.25;\n#endif\n gl_FragColor = encodeHDR(color);\n}\n@end"; - -var upsampleGLSL = "\n@export qtek.compositor.upsample\n#define HIGH_QUALITY\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\n@import qtek.util.clamp_sample\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n vec4 s;\n s = decodeHDR(clampSample(texture, v_Texcoord - d.xy));\n s += decodeHDR(clampSample(texture, v_Texcoord - d.wy)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord - d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zw)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord )) * 4.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xw)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.wy)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n gl_FragColor = encodeHDR(s / 16.0);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n vec4 s;\n s = decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xw));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zw));\n gl_FragColor = encodeHDR(s / 4.0);\n#endif\n}\n@end"; - -var hdrGLSL = "@export qtek.compositor.hdr.composite\nuniform sampler2D texture;\n#ifdef BLOOM_ENABLED\nuniform sampler2D bloom;\n#endif\n#ifdef LENSFLARE_ENABLED\nuniform sampler2D lensflare;\nuniform sampler2D lensdirt;\n#endif\n#ifdef LUM_ENABLED\nuniform sampler2D lum;\n#endif\n#ifdef LUT_ENABLED\nuniform sampler2D lut;\n#endif\n#ifdef COLOR_CORRECTION\nuniform float brightness : 0.0;\nuniform float contrast : 1.0;\nuniform float saturation : 1.0;\n#endif\n#ifdef VIGNETTE\nuniform float vignetteDarkness: 1.0;\nuniform float vignetteOffset: 1.0;\n#endif\nuniform float exposure : 1.0;\nuniform float bloomIntensity : 0.25;\nuniform float lensflareIntensity : 1;\nvarying vec2 v_Texcoord;\n@import qtek.util.srgb\nvec3 ACESToneMapping(vec3 color)\n{\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nfloat eyeAdaption(float fLum)\n{\n return mix(0.2, fLum, 0.5);\n}\n#ifdef LUT_ENABLED\nvec3 lutTransform(vec3 color) {\n float blueColor = color.b * 63.0;\n vec2 quad1;\n quad1.y = floor(floor(blueColor) / 8.0);\n quad1.x = floor(blueColor) - (quad1.y * 8.0);\n vec2 quad2;\n quad2.y = floor(ceil(blueColor) / 8.0);\n quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n vec2 texPos1;\n texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.r);\n texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.g);\n vec2 texPos2;\n texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.r);\n texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.g);\n vec4 newColor1 = texture2D(lut, texPos1);\n vec4 newColor2 = texture2D(lut, texPos2);\n vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n return newColor.rgb;\n}\n#endif\n@import qtek.util.rgbm\nvoid main()\n{\n vec4 texel = vec4(0.0);\n vec4 originalTexel = vec4(0.0);\n#ifdef TEXTURE_ENABLED\n texel = decodeHDR(texture2D(texture, v_Texcoord));\n originalTexel = texel;\n#endif\n#ifdef BLOOM_ENABLED\n vec4 bloomTexel = decodeHDR(texture2D(bloom, v_Texcoord));\n texel.rgb += bloomTexel.rgb * bloomIntensity;\n texel.a += bloomTexel.a * bloomIntensity;\n#endif\n#ifdef LENSFLARE_ENABLED\n texel += decodeHDR(texture2D(lensflare, v_Texcoord)) * texture2D(lensdirt, v_Texcoord) * lensflareIntensity;\n#endif\n texel.a = min(texel.a, 1.0);\n#ifdef LUM_ENABLED\n float fLum = texture2D(lum, vec2(0.5, 0.5)).r;\n float adaptedLumDest = 3.0 / (max(0.1, 1.0 + 10.0*eyeAdaption(fLum)));\n float exposureBias = adaptedLumDest * exposure;\n#else\n float exposureBias = exposure;\n#endif\n texel.rgb *= exposureBias;\n texel.rgb = ACESToneMapping(texel.rgb);\n texel = linearTosRGB(texel);\n#ifdef LUT_ENABLED\n texel.rgb = lutTransform(clamp(texel.rgb,vec3(0.0),vec3(1.0)));\n#endif\n#ifdef COLOR_CORRECTION\n texel.rgb = clamp(texel.rgb + vec3(brightness), 0.0, 1.0);\n texel.rgb = clamp((texel.rgb - vec3(0.5))*contrast+vec3(0.5), 0.0, 1.0);\n float lum = dot(texel.rgb, vec3(0.2125, 0.7154, 0.0721));\n texel.rgb = mix(vec3(lum), texel.rgb, saturation);\n#endif\n#ifdef VIGNETTE\n vec2 uv = (v_Texcoord - vec2(0.5)) * vec2(vignetteOffset);\n texel.rgb = mix(texel.rgb, vec3(1.0 - vignetteDarkness), dot(uv, uv));\n#endif\n gl_FragColor = encodeHDR(texel);\n#ifdef DEBUG\n #if DEBUG == 1\n gl_FragColor = encodeHDR(decodeHDR(texture2D(texture, v_Texcoord)));\n #elif DEBUG == 2\n gl_FragColor = encodeHDR(decodeHDR(texture2D(bloom, v_Texcoord)) * bloomIntensity);\n #elif DEBUG == 3\n gl_FragColor = encodeHDR(decodeHDR(texture2D(lensflare, v_Texcoord) * lensflareIntensity));\n #endif\n#endif\n if (originalTexel.a <= 0.01) {\n gl_FragColor.a = dot(gl_FragColor.rgb, vec3(0.2125, 0.7154, 0.0721));\n }\n#ifdef PREMULTIPLY_ALPHA\n gl_FragColor.rgb *= gl_FragColor.a;\n#endif\n}\n@end"; - -var dofEssl = "@export qtek.compositor.dof.coc\nuniform sampler2D depth;\nuniform float zNear: 0.1;\nuniform float zFar: 2000;\nuniform float focalDist: 3;\nuniform float focalRange: 1;\nuniform float focalLength: 30;\nuniform float fstop: 2.8;\nvarying vec2 v_Texcoord;\n@import qtek.util.encode_float\nvoid main()\n{\n float z = texture2D(depth, v_Texcoord).r * 2.0 - 1.0;\n float dist = 2.0 * zNear * zFar / (zFar + zNear - z * (zFar - zNear));\n float aperture = focalLength / fstop;\n float coc;\n float uppper = focalDist + focalRange;\n float lower = focalDist - focalRange;\n if (dist <= uppper && dist >= lower) {\n coc = 0.5;\n }\n else {\n float focalAdjusted = dist > uppper ? uppper : lower;\n coc = abs(aperture * (focalLength * (dist - focalAdjusted)) / (dist * (focalAdjusted - focalLength)));\n coc = clamp(coc, 0.0, 0.4) / 0.4000001;\n if (dist < lower) {\n coc = -coc;\n }\n coc = coc * 0.5 + 0.5;\n }\n gl_FragColor = encodeFloat(coc);\n}\n@end\n@export qtek.compositor.dof.premultiply\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\n@import qtek.util.decode_float\nvoid main() {\n float fCoc = max(abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0), 0.1);\n gl_FragColor = encodeHDR(\n vec4(decodeHDR(texture2D(texture, v_Texcoord)).rgb * fCoc, 1.0)\n );\n}\n@end\n@export qtek.compositor.dof.min_coc\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform vec2 textureSize : [512.0, 512.0];\n@import qtek.util.float\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zy)));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.xw)));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zw)));\n gl_FragColor = encodeFloat(fCoc);\n}\n@end\n@export qtek.compositor.dof.max_coc\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform vec2 textureSize : [512.0, 512.0];\n@import qtek.util.float\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zy)));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.xw)));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zw)));\n gl_FragColor = encodeFloat(fCoc);\n}\n@end\n@export qtek.compositor.dof.coc_upsample\n#define HIGH_QUALITY\nuniform sampler2D coc;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import qtek.util.float\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n float s;\n s = decodeFloat(texture2D(coc, v_Texcoord - d.xy));\n s += decodeFloat(texture2D(coc, v_Texcoord - d.wy)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord - d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zw)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord )) * 4.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xw)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.wy)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n gl_FragColor = encodeFloat(s / 16.0);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n float s;\n s = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xw));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zw));\n gl_FragColor = encodeFloat(s / 4.0);\n#endif\n}\n@end\n@export qtek.compositor.dof.upsample\n#define HIGH_QUALITY\nuniform sampler2D coc;\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\n@import qtek.util.decode_float\nfloat tap(vec2 uv, inout vec4 color, float baseWeight) {\n float weight = abs(decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0) * baseWeight;\n color += decodeHDR(texture2D(texture, uv)) * weight;\n return weight;\n}\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n vec4 color = vec4(0.0);\n float baseWeight = 1.0 / 16.0;\n float w = tap(v_Texcoord - d.xy, color, baseWeight);\n w += tap(v_Texcoord - d.wy, color, baseWeight * 2.0);\n w += tap(v_Texcoord - d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.zw, color, baseWeight * 2.0);\n w += tap(v_Texcoord , color, baseWeight * 4.0);\n w += tap(v_Texcoord + d.xw, color, baseWeight * 2.0);\n w += tap(v_Texcoord + d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.wy, color, baseWeight * 2.0);\n w += tap(v_Texcoord + d.xy, color, baseWeight);\n gl_FragColor = encodeHDR(color / w);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n vec4 color = vec4(0.0);\n float baseWeight = 1.0 / 4.0;\n float w = tap(v_Texcoord + d.xy, color, baseWeight);\n w += tap(v_Texcoord + d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.xw, color, baseWeight);\n w += tap(v_Texcoord + d.zw, color, baseWeight);\n gl_FragColor = encodeHDR(color / w);\n#endif\n}\n@end\n@export qtek.compositor.dof.downsample\nuniform sampler2D texture;\nuniform sampler2D coc;\nuniform vec2 textureSize : [512, 512];\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\n@import qtek.util.decode_float\nfloat tap(vec2 uv, inout vec4 color) {\n float weight = abs(decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0) * 0.25;\n color += decodeHDR(texture2D(texture, uv)) * weight;\n return weight;\n}\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n vec4 color = vec4(0.0);\n float weight = tap(v_Texcoord + d.xy, color);\n weight += tap(v_Texcoord + d.zy, color);\n weight += tap(v_Texcoord + d.xw, color);\n weight += tap(v_Texcoord + d.zw, color);\n color /= weight;\n gl_FragColor = encodeHDR(color);\n}\n@end\n@export qtek.compositor.dof.hexagonal_blur_frag\n@import qtek.util.float\nvec4 doBlur(sampler2D targetTexture, vec2 offset) {\n#ifdef BLUR_COC\n float cocSum = 0.0;\n#else\n vec4 color = vec4(0.0);\n#endif\n float weightSum = 0.0;\n float kernelWeight = 1.0 / float(KERNEL_SIZE);\n for (int i = 0; i < KERNEL_SIZE; i++) {\n vec2 coord = v_Texcoord + offset * float(i);\n float w = kernelWeight;\n#ifdef BLUR_COC\n float fCoc = decodeFloat(texture2D(targetTexture, coord)) * 2.0 - 1.0;\n cocSum += clamp(fCoc, -1.0, 0.0) * w;\n#else\n float fCoc = decodeFloat(texture2D(coc, coord)) * 2.0 - 1.0;\n vec4 texel = texture2D(targetTexture, coord);\n #if !defined(BLUR_NEARFIELD)\n w *= abs(fCoc);\n #endif\n color += decodeHDR(texel) * w;\n#endif\n weightSum += w;\n }\n#ifdef BLUR_COC\n return encodeFloat(clamp(cocSum / weightSum, -1.0, 0.0) * 0.5 + 0.5);\n#else\n return color / weightSum;\n#endif\n}\n@end\n@export qtek.compositor.dof.hexagonal_blur_1\n#define KERNEL_SIZE 5\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import qtek.util.rgbm\n@import qtek.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n gl_FragColor = doBlur(texture, vec2(0.0, offset.y));\n#if !defined(BLUR_COC)\n gl_FragColor = encodeHDR(gl_FragColor);\n#endif\n}\n@end\n@export qtek.compositor.dof.hexagonal_blur_2\n#define KERNEL_SIZE 5\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import qtek.util.rgbm\n@import qtek.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n offset.y /= 2.0;\n gl_FragColor = doBlur(texture, -offset);\n#if !defined(BLUR_COC)\n gl_FragColor = encodeHDR(gl_FragColor);\n#endif\n}\n@end\n@export qtek.compositor.dof.hexagonal_blur_3\n#define KERNEL_SIZE 5\nuniform sampler2D texture1;\nuniform sampler2D texture2;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import qtek.util.rgbm\n@import qtek.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n offset.y /= 2.0;\n vec2 vDownRight = vec2(offset.x, -offset.y);\n vec4 texel1 = doBlur(texture1, -offset);\n vec4 texel2 = doBlur(texture1, vDownRight);\n vec4 texel3 = doBlur(texture2, vDownRight);\n#ifdef BLUR_COC\n float coc1 = decodeFloat(texel1) * 2.0 - 1.0;\n float coc2 = decodeFloat(texel2) * 2.0 - 1.0;\n float coc3 = decodeFloat(texel3) * 2.0 - 1.0;\n gl_FragColor = encodeFloat(\n ((coc1 + coc2 + coc3) / 3.0) * 0.5 + 0.5\n );\n#else\n vec4 color = (texel1 + texel2 + texel3) / 3.0;\n gl_FragColor = encodeHDR(color);\n#endif\n}\n@end\n@export qtek.compositor.dof.composite\n#define DEBUG 0\nuniform sampler2D original;\nuniform sampler2D blurred;\nuniform sampler2D nearfield;\nuniform sampler2D coc;\nuniform sampler2D nearcoc;\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\n@import qtek.util.float\nvoid main()\n{\n vec4 blurredColor = decodeHDR(texture2D(blurred, v_Texcoord));\n vec4 originalColor = decodeHDR(texture2D(original, v_Texcoord));\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord));\n fCoc = abs(fCoc * 2.0 - 1.0);\n float weight = smoothstep(0.0, 1.0, fCoc);\n#ifdef NEARFIELD_ENABLED\n vec4 nearfieldColor = decodeHDR(texture2D(nearfield, v_Texcoord));\n float fNearCoc = decodeFloat(texture2D(nearcoc, v_Texcoord));\n fNearCoc = abs(fNearCoc * 2.0 - 1.0);\n gl_FragColor = encodeHDR(\n mix(\n nearfieldColor, mix(originalColor, blurredColor, weight),\n pow(1.0 - fNearCoc, 4.0)\n )\n );\n#else\n gl_FragColor = encodeHDR(mix(originalColor, blurredColor, weight));\n#endif\n#if DEBUG == 1\n gl_FragColor = vec4(vec3(fCoc), 1.0);\n#elif DEBUG == 2\n gl_FragColor = vec4(vec3(fNearCoc), 1.0);\n#elif DEBUG == 3\n gl_FragColor = encodeHDR(blurredColor);\n#elif DEBUG == 4\n gl_FragColor = encodeHDR(nearfieldColor);\n#endif\n}\n@end"; - -var lensflareEssl = "@export qtek.compositor.lensflare\n#define SAMPLE_NUMBER 8\nuniform sampler2D texture;\nuniform sampler2D lenscolor;\nuniform vec2 textureSize : [512, 512];\nuniform float dispersal : 0.3;\nuniform float haloWidth : 0.4;\nuniform float distortion : 1.0;\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\nvec4 textureDistorted(\n in vec2 texcoord,\n in vec2 direction,\n in vec3 distortion\n) {\n return vec4(\n decodeHDR(texture2D(texture, texcoord + direction * distortion.r)).r,\n decodeHDR(texture2D(texture, texcoord + direction * distortion.g)).g,\n decodeHDR(texture2D(texture, texcoord + direction * distortion.b)).b,\n 1.0\n );\n}\nvoid main()\n{\n vec2 texcoord = -v_Texcoord + vec2(1.0); vec2 textureOffset = 1.0 / textureSize;\n vec2 ghostVec = (vec2(0.5) - texcoord) * dispersal;\n vec2 haloVec = normalize(ghostVec) * haloWidth;\n vec3 distortion = vec3(-textureOffset.x * distortion, 0.0, textureOffset.x * distortion);\n vec4 result = vec4(0.0);\n for (int i = 0; i < SAMPLE_NUMBER; i++)\n {\n vec2 offset = fract(texcoord + ghostVec * float(i));\n float weight = length(vec2(0.5) - offset) / length(vec2(0.5));\n weight = pow(1.0 - weight, 10.0);\n result += textureDistorted(offset, normalize(ghostVec), distortion) * weight;\n }\n result *= texture2D(lenscolor, vec2(length(vec2(0.5) - texcoord)) / length(vec2(0.5)));\n float weight = length(vec2(0.5) - fract(texcoord + haloVec)) / length(vec2(0.5));\n weight = pow(1.0 - weight, 10.0);\n vec2 offset = fract(texcoord + haloVec);\n result += textureDistorted(offset, normalize(ghostVec), distortion) * weight;\n gl_FragColor = result;\n}\n@end"; - -var blendGLSL = "@export qtek.compositor.blend\n#ifdef TEXTURE1_ENABLED\nuniform sampler2D texture1;\nuniform float weight1 : 1.0;\n#endif\n#ifdef TEXTURE2_ENABLED\nuniform sampler2D texture2;\nuniform float weight2 : 1.0;\n#endif\n#ifdef TEXTURE3_ENABLED\nuniform sampler2D texture3;\nuniform float weight3 : 1.0;\n#endif\n#ifdef TEXTURE4_ENABLED\nuniform sampler2D texture4;\nuniform float weight4 : 1.0;\n#endif\n#ifdef TEXTURE5_ENABLED\nuniform sampler2D texture5;\nuniform float weight5 : 1.0;\n#endif\n#ifdef TEXTURE6_ENABLED\nuniform sampler2D texture6;\nuniform float weight6 : 1.0;\n#endif\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\nvoid main()\n{\n vec4 tex = vec4(0.0);\n#ifdef TEXTURE1_ENABLED\n tex += decodeHDR(texture2D(texture1, v_Texcoord)) * weight1;\n#endif\n#ifdef TEXTURE2_ENABLED\n tex += decodeHDR(texture2D(texture2, v_Texcoord)) * weight2;\n#endif\n#ifdef TEXTURE3_ENABLED\n tex += decodeHDR(texture2D(texture3, v_Texcoord)) * weight3;\n#endif\n#ifdef TEXTURE4_ENABLED\n tex += decodeHDR(texture2D(texture4, v_Texcoord)) * weight4;\n#endif\n#ifdef TEXTURE5_ENABLED\n tex += decodeHDR(texture2D(texture5, v_Texcoord)) * weight5;\n#endif\n#ifdef TEXTURE6_ENABLED\n tex += decodeHDR(texture2D(texture6, v_Texcoord)) * weight6;\n#endif\n gl_FragColor = encodeHDR(tex);\n}\n@end"; - -var fxaaGLSL = "@export qtek.compositor.fxaa\nuniform sampler2D texture;\nuniform vec4 viewport : VIEWPORT;\nvarying vec2 v_Texcoord;\n#define FXAA_REDUCE_MIN (1.0/128.0)\n#define FXAA_REDUCE_MUL (1.0/8.0)\n#define FXAA_SPAN_MAX 8.0\n@import qtek.util.rgbm\nvoid main()\n{\n vec2 resolution = 1.0 / viewport.zw;\n vec3 rgbNW = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( -1.0, -1.0 ) ) * resolution ) ).xyz;\n vec3 rgbNE = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( 1.0, -1.0 ) ) * resolution ) ).xyz;\n vec3 rgbSW = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( -1.0, 1.0 ) ) * resolution ) ).xyz;\n vec3 rgbSE = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( 1.0, 1.0 ) ) * resolution ) ).xyz;\n vec4 rgbaM = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution ) );\n vec3 rgbM = rgbaM.xyz;\n float opacity = rgbaM.w;\n vec3 luma = vec3( 0.299, 0.587, 0.114 );\n float lumaNW = dot( rgbNW, luma );\n float lumaNE = dot( rgbNE, luma );\n float lumaSW = dot( rgbSW, luma );\n float lumaSE = dot( rgbSE, luma );\n float lumaM = dot( rgbM, luma );\n float lumaMin = min( lumaM, min( min( lumaNW, lumaNE ), min( lumaSW, lumaSE ) ) );\n float lumaMax = max( lumaM, max( max( lumaNW, lumaNE) , max( lumaSW, lumaSE ) ) );\n vec2 dir;\n dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\n dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));\n float dirReduce = max( ( lumaNW + lumaNE + lumaSW + lumaSE ) * ( 0.25 * FXAA_REDUCE_MUL ), FXAA_REDUCE_MIN );\n float rcpDirMin = 1.0 / ( min( abs( dir.x ), abs( dir.y ) ) + dirReduce );\n dir = min( vec2( FXAA_SPAN_MAX, FXAA_SPAN_MAX),\n max( vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),\n dir * rcpDirMin)) * resolution;\n vec3 rgbA = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * ( 1.0 / 3.0 - 0.5 ) ) ).xyz;\n rgbA += decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * ( 2.0 / 3.0 - 0.5 ) ) ).xyz;\n rgbA *= 0.5;\n vec3 rgbB = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * -0.5 ) ).xyz;\n rgbB += decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * 0.5 ) ).xyz;\n rgbB *= 0.25;\n rgbB += rgbA * 0.5;\n float lumaB = dot( rgbB, luma );\n if ( ( lumaB < lumaMin ) || ( lumaB > lumaMax ) )\n {\n gl_FragColor = vec4( rgbA, opacity );\n }\n else {\n gl_FragColor = vec4( rgbB, opacity );\n }\n}\n@end"; - -var fxaa3Essl = "@export qtek.compositor.fxaa3\nuniform sampler2D texture;\nuniform vec4 viewport : VIEWPORT;\nuniform float subpixel: 0.75;\nuniform float edgeThreshold: 0.125;\nuniform float edgeThresholdMin: 0.0625;\nvarying vec2 v_Texcoord;\n@import qtek.util.rgbm\nfloat FxaaLuma(vec4 rgba) { return rgba.y; }\nvec4 FxaaPixelShader(\n vec2 pos\n ,sampler2D tex\n ,vec2 fxaaQualityRcpFrame\n ,float fxaaQualitySubpix\n ,float fxaaQualityEdgeThreshold\n ,float fxaaQualityEdgeThresholdMin\n) {\n vec2 posM;\n posM.x = pos.x;\n posM.y = pos.y;\n vec4 rgbyM = decodeHDR(texture2D(texture, posM, 0.0));\n float lumaS = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 0.0, 1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaE = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 1.0, 0.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaN = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 0.0,-1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaW = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2(-1.0, 0.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float maxSM = max(lumaS, rgbyM.y);\n float minSM = min(lumaS, rgbyM.y);\n float maxESM = max(lumaE, maxSM);\n float minESM = min(lumaE, minSM);\n float maxWN = max(lumaN, lumaW);\n float minWN = min(lumaN, lumaW);\n float rangeMax = max(maxWN, maxESM);\n float rangeMin = min(minWN, minESM);\n float rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold;\n float range = rangeMax - rangeMin;\n float rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled);\n bool earlyExit = range < rangeMaxClamped;\n if(earlyExit) return rgbyM;\n float lumaNW = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2(-1.0,-1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaSE = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 1.0, 1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaNE = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 1.0,-1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaSW = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2(-1.0, 1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaNS = lumaN + lumaS;\n float lumaWE = lumaW + lumaE;\n float subpixRcpRange = 1.0/range;\n float subpixNSWE = lumaNS + lumaWE;\n float edgeHorz1 = (-2.0 * rgbyM.y) + lumaNS;\n float edgeVert1 = (-2.0 * rgbyM.y) + lumaWE;\n float lumaNESE = lumaNE + lumaSE;\n float lumaNWNE = lumaNW + lumaNE;\n float edgeHorz2 = (-2.0 * lumaE) + lumaNESE;\n float edgeVert2 = (-2.0 * lumaN) + lumaNWNE;\n float lumaNWSW = lumaNW + lumaSW;\n float lumaSWSE = lumaSW + lumaSE;\n float edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2);\n float edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2);\n float edgeHorz3 = (-2.0 * lumaW) + lumaNWSW;\n float edgeVert3 = (-2.0 * lumaS) + lumaSWSE;\n float edgeHorz = abs(edgeHorz3) + edgeHorz4;\n float edgeVert = abs(edgeVert3) + edgeVert4;\n float subpixNWSWNESE = lumaNWSW + lumaNESE;\n float lengthSign = fxaaQualityRcpFrame.x;\n bool horzSpan = edgeHorz >= edgeVert;\n float subpixA = subpixNSWE * 2.0 + subpixNWSWNESE;\n if(!horzSpan) lumaN = lumaW;\n if(!horzSpan) lumaS = lumaE;\n if(horzSpan) lengthSign = fxaaQualityRcpFrame.y;\n float subpixB = (subpixA * (1.0/12.0)) - rgbyM.y;\n float gradientN = lumaN - rgbyM.y;\n float gradientS = lumaS - rgbyM.y;\n float lumaNN = lumaN + rgbyM.y;\n float lumaSS = lumaS + rgbyM.y;\n bool pairN = abs(gradientN) >= abs(gradientS);\n float gradient = max(abs(gradientN), abs(gradientS));\n if(pairN) lengthSign = -lengthSign;\n float subpixC = clamp(abs(subpixB) * subpixRcpRange, 0.0, 1.0);\n vec2 posB;\n posB.x = posM.x;\n posB.y = posM.y;\n vec2 offNP;\n offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;\n offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;\n if(!horzSpan) posB.x += lengthSign * 0.5;\n if( horzSpan) posB.y += lengthSign * 0.5;\n vec2 posN;\n posN.x = posB.x - offNP.x * 1.0;\n posN.y = posB.y - offNP.y * 1.0;\n vec2 posP;\n posP.x = posB.x + offNP.x * 1.0;\n posP.y = posB.y + offNP.y * 1.0;\n float subpixD = ((-2.0)*subpixC) + 3.0;\n float lumaEndN = FxaaLuma(decodeHDR(texture2D(texture, posN, 0.0)));\n float subpixE = subpixC * subpixC;\n float lumaEndP = FxaaLuma(decodeHDR(texture2D(texture, posP, 0.0)));\n if(!pairN) lumaNN = lumaSS;\n float gradientScaled = gradient * 1.0/4.0;\n float lumaMM = rgbyM.y - lumaNN * 0.5;\n float subpixF = subpixD * subpixE;\n bool lumaMLTZero = lumaMM < 0.0;\n lumaEndN -= lumaNN * 0.5;\n lumaEndP -= lumaNN * 0.5;\n bool doneN = abs(lumaEndN) >= gradientScaled;\n bool doneP = abs(lumaEndP) >= gradientScaled;\n if(!doneN) posN.x -= offNP.x * 1.5;\n if(!doneN) posN.y -= offNP.y * 1.5;\n bool doneNP = (!doneN) || (!doneP);\n if(!doneP) posP.x += offNP.x * 1.5;\n if(!doneP) posP.y += offNP.y * 1.5;\n if(doneNP) {\n if(!doneN) lumaEndN = FxaaLuma(decodeHDR(texture2D(texture, posN.xy, 0.0)));\n if(!doneP) lumaEndP = FxaaLuma(decodeHDR(texture2D(texture, posP.xy, 0.0)));\n if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;\n if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;\n doneN = abs(lumaEndN) >= gradientScaled;\n doneP = abs(lumaEndP) >= gradientScaled;\n if(!doneN) posN.x -= offNP.x * 2.0;\n if(!doneN) posN.y -= offNP.y * 2.0;\n doneNP = (!doneN) || (!doneP);\n if(!doneP) posP.x += offNP.x * 2.0;\n if(!doneP) posP.y += offNP.y * 2.0;\n if(doneNP) {\n if(!doneN) lumaEndN = FxaaLuma(decodeHDR(texture2D(texture, posN.xy, 0.0)));\n if(!doneP) lumaEndP = FxaaLuma(decodeHDR(texture2D(texture, posP.xy, 0.0)));\n if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;\n if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;\n doneN = abs(lumaEndN) >= gradientScaled;\n doneP = abs(lumaEndP) >= gradientScaled;\n if(!doneN) posN.x -= offNP.x * 4.0;\n if(!doneN) posN.y -= offNP.y * 4.0;\n doneNP = (!doneN) || (!doneP);\n if(!doneP) posP.x += offNP.x * 4.0;\n if(!doneP) posP.y += offNP.y * 4.0;\n if(doneNP) {\n if(!doneN) lumaEndN = FxaaLuma(decodeHDR(texture2D(texture, posN.xy, 0.0)));\n if(!doneP) lumaEndP = FxaaLuma(decodeHDR(texture2D(texture, posP.xy, 0.0)));\n if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;\n if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;\n doneN = abs(lumaEndN) >= gradientScaled;\n doneP = abs(lumaEndP) >= gradientScaled;\n if(!doneN) posN.x -= offNP.x * 12.0;\n if(!doneN) posN.y -= offNP.y * 12.0;\n doneNP = (!doneN) || (!doneP);\n if(!doneP) posP.x += offNP.x * 12.0;\n if(!doneP) posP.y += offNP.y * 12.0;\n }\n }\n }\n float dstN = posM.x - posN.x;\n float dstP = posP.x - posM.x;\n if(!horzSpan) dstN = posM.y - posN.y;\n if(!horzSpan) dstP = posP.y - posM.y;\n bool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero;\n float spanLength = (dstP + dstN);\n bool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero;\n float spanLengthRcp = 1.0/spanLength;\n bool directionN = dstN < dstP;\n float dst = min(dstN, dstP);\n bool goodSpan = directionN ? goodSpanN : goodSpanP;\n float subpixG = subpixF * subpixF;\n float pixelOffset = (dst * (-spanLengthRcp)) + 0.5;\n float subpixH = subpixG * fxaaQualitySubpix;\n float pixelOffsetGood = goodSpan ? pixelOffset : 0.0;\n float pixelOffsetSubpix = max(pixelOffsetGood, subpixH);\n if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign;\n if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign;\n return vec4(decodeHDR(texture2D(texture, posM, 0.0)).xyz, rgbyM.y);\n}\nvoid main()\n{\n vec4 color = FxaaPixelShader(\n v_Texcoord,\n texture,\n vec2(1.0) / viewport.zw,\n subpixel,\n edgeThreshold,\n edgeThresholdMin\n );\n gl_FragColor = vec4(color.rgb, 1.0);\n}\n@end"; +var skyboxEssl = "@export clay.skybox.vertex\n#define SHADER_NAME skybox\nuniform mat4 world : WORLD;\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\nvarying vec3 v_WorldPosition;\nvoid main()\n{\n v_WorldPosition = (world * vec4(position, 1.0)).xyz;\n gl_Position = worldViewProjection * vec4(position, 1.0);\n}\n@end\n@export clay.skybox.fragment\nuniform mat4 viewInverse : VIEWINVERSE;\nuniform samplerCube environmentMap;\nuniform float lod: 0.0;\nvarying vec3 v_WorldPosition;\n@import clay.util.rgbm\n@import clay.util.srgb\n@import clay.util.ACES\nvoid main()\n{\n vec3 eyePos = viewInverse[3].xyz;\n vec3 viewDirection = normalize(v_WorldPosition - eyePos);\n#ifdef LOD\n vec4 texel = decodeHDR(textureCubeLodEXT(environmentMap, viewDirection, lod));\n#else\n vec4 texel = decodeHDR(textureCube(environmentMap, viewDirection));\n#endif\n#ifdef SRGB_DECODE\n texel = sRGBToLinear(texel);\n#endif\n#ifdef TONEMAPPING\n texel.rgb = ACESToneMapping(texel.rgb);\n#endif\n#ifdef SRGB_ENCODE\n texel = linearTosRGB(texel);\n#endif\n gl_FragColor = encodeHDR(vec4(texel.rgb, 1.0));\n}\n@end"; Shader['import'](lightEssl); Shader['import'](utilEssl); @@ -18395,31 +18968,13 @@ Shader['import'](wireframeEssl); Shader['import'](skyboxEssl); Shader['import'](prezEssl); -library.template('qtek.basic', Shader.source('qtek.basic.vertex'), Shader.source('qtek.basic.fragment')); -library.template('qtek.lambert', Shader.source('qtek.lambert.vertex'), Shader.source('qtek.lambert.fragment')); -library.template('qtek.wireframe', Shader.source('qtek.wireframe.vertex'), Shader.source('qtek.wireframe.fragment')); -library.template('qtek.skybox', Shader.source('qtek.skybox.vertex'), Shader.source('qtek.skybox.fragment')); -library.template('qtek.prez', Shader.source('qtek.prez.vertex'), Shader.source('qtek.prez.fragment')); -library.template('qtek.standard', Shader.source('qtek.standard.vertex'), Shader.source('qtek.standard.fragment')); - - -// Some build in shaders -Shader['import'](coloradjustEssl); -Shader['import'](blurGLSL); -Shader['import'](lumEssl); -Shader['import'](lutEssl); -Shader['import'](vigentteEssl); -Shader['import'](outputGLSL); -Shader['import'](brightGLSL); -Shader['import'](downsampleGLSL); -Shader['import'](upsampleGLSL); -Shader['import'](hdrGLSL); -Shader['import'](dofEssl); -Shader['import'](lensflareEssl); -Shader['import'](blendGLSL); - -Shader['import'](fxaaGLSL); -Shader['import'](fxaa3Essl); +library.template('clay.basic', Shader.source('clay.basic.vertex'), Shader.source('clay.basic.fragment')); +library.template('clay.lambert', Shader.source('clay.lambert.vertex'), Shader.source('clay.lambert.fragment')); +library.template('clay.wireframe', Shader.source('clay.wireframe.vertex'), Shader.source('clay.wireframe.fragment')); +library.template('clay.skybox', Shader.source('clay.skybox.vertex'), Shader.source('clay.skybox.fragment')); +library.template('clay.prez', Shader.source('clay.prez.vertex'), Shader.source('clay.prez.fragment')); +library.template('clay.standard', Shader.source('clay.standard.vertex'), Shader.source('clay.standard.fragment')); +library.template('clay.standardMR', Shader.source('clay.standardMR.vertex'), Shader.source('clay.standardMR.fragment')); /** * glTF Loader @@ -18435,7 +18990,7 @@ var semanticAttributeMap = { 'TEXCOORD_1': 'texcoord1', 'WEIGHTS_0': 'weight', 'JOINTS_0': 'joint', - 'COLOR': 'color' + 'COLOR_0': 'color' }; var ARRAY_CTOR_MAP = { @@ -18492,29 +19047,27 @@ function getAccessorData(json, lib, accessorIdx, isIndices) { } /** - * @typedef {Object} qtek.loader.GLTF.IResult + * @typedef {Object} clay.loader.GLTF.Result * @property {Object} json - * @property {qtek.Scene} scene - * @property {qtek.Node} rootNode - * @property {qtek.Camera[]} cameras - * @property {qtek.Texture[]} textures - * @property {qtek.Material[]} materials - * @property {qtek.Skeleton[]} skeletons - * @property {qtek.Mesh[]} meshes - * @property {qtek.animation.TrackClip[]} clips - * @property {qtek.Node[]} nodes + * @property {clay.Scene} scene + * @property {clay.Node} rootNode + * @property {clay.Camera[]} cameras + * @property {clay.Texture[]} textures + * @property {clay.Material[]} materials + * @property {clay.Skeleton[]} skeletons + * @property {clay.Mesh[]} meshes + * @property {clay.animation.TrackClip[]} clips + * @property {clay.Node[]} nodes */ /** - * @constructor qtek.loader.GLTF - * @extends qtek.core.Base + * @constructor clay.loader.GLTF + * @extends clay.core.Base */ -var GLTFLoader = Base.extend( -/** @lends qtek.loader.GLTF# */ -{ +var GLTFLoader = Base.extend(/** @lends clay.loader.GLTF# */ { /** - * - * @type {qtek.Node} + * + * @type {clay.Node} */ rootNode: null, /** @@ -18537,13 +19090,13 @@ var GLTFLoader = Base.extend( /** * Shader used when creating the materials. - * @type {string} - * @default 'qtek.standard' + * @type {string|clay.Shader} + * @default 'clay.standard' */ - shaderName: 'qtek.standard', + shader: 'clay.standard', /** - * If use {@link qtek.StandardMaterial} + * If use {@link clay.StandardMaterial} * @type {string} */ useStandardMaterial: false, @@ -18580,6 +19133,12 @@ var GLTFLoader = Base.extend( */ textureFlipY: false, + /** + * If convert texture to power-of-two + * @type {boolean} + */ + textureConvertToPOT: false, + shaderLibrary: null }, function () { @@ -18587,7 +19146,7 @@ function () { this.shaderLibrary = library.createLibrary(); } }, -/** @lends qtek.loader.GLTF.prototype */ +/** @lends clay.loader.GLTF.prototype */ { /** * @param {string} url @@ -18623,7 +19182,7 @@ function () { /** * Parse glTF binary * @param {ArrayBuffer} buffer - * @return {qtek.loader.GLTF.IResult} + * @return {clay.loader.GLTF.Result} */ parseBinary: function (buffer) { var header = new Uint32Array(buffer, 0, 4); @@ -18635,9 +19194,9 @@ function () { this.trigger('error', 'Only glTF2.0 is supported.'); return; } - + var dataView = new DataView(buffer, 12); - + var json; var buffers = []; // Read chunks @@ -18678,7 +19237,7 @@ function () { /** * @param {Object} json * @param {ArrayBuffer[]} [buffer] - * @return {qtek.loader.GLTF.IResult} + * @return {clay.loader.GLTF.Result} */ parse: function (json, buffers) { var self = this; @@ -18716,7 +19275,7 @@ function () { util.each(json.buffers, function (bufferInfo, idx) { loading++; var path = bufferInfo.uri; - + self._loadBuffer(path, function (buffer) { lib.buffers[idx] = buffer; checkLoad(); @@ -18733,7 +19292,7 @@ function () { textures: lib.textures, materials: lib.materials, skeletons: lib.skeletons, - meshes: lib.meshes, + meshes: lib.instancedMeshes, clips: lib.clips, nodes: lib.nodes }; @@ -18803,7 +19362,7 @@ function () { if (path && path.match(/^data:(.*?)base64,/)) { return path; } - + var rootPath = this.bufferRootPath; if (rootPath == null) { rootPath = this.rootPath; @@ -18827,6 +19386,15 @@ function () { return util.relative2absolute(path, rootPath); }, + _getShader: function () { + if (typeof this.shader === 'string') { + return this.shaderLibrary.get(this.shader); + } + else if (this.shader instanceof Shader) { + return this.shader; + } + }, + _loadBuffer: function (path, onsuccess, onerror) { request.get({ url: this.resolveBinaryPath(path), @@ -18877,29 +19445,9 @@ function () { lib.skeletons[idx] = skeleton; }, this); - var shaderLib = this.shaderLibrary; - var shaderName = this.shaderName; function enableSkinningForMesh(mesh, skeleton, jointIndices) { mesh.skeleton = skeleton; mesh.joints = jointIndices; - // Make sure meshs with different joints not have same material. - var originalShader = mesh.material.shader; - var material = mesh.material.clone(); - mesh.material = material; - if (material instanceof StandardMaterial) { - material.jointCount = jointIndices.length; - } - else { - material.shader = shaderLib.get( - shaderName, { - textures: originalShader.getEnabledTextures(), - vertexDefines: { - SKINNING: null, - JOINT_COUNT: jointIndices.length - } - } - ); - } } function getJointIndex(joint) { @@ -18939,9 +19487,10 @@ function () { } }); util.defaults(parameters, { - wrapS: Texture.REPEAT, - wrapT: Texture.REPEAT, - flipY: this.textureFlipY + wrapS: Texture$1.REPEAT, + wrapT: Texture$1.REPEAT, + flipY: this.textureFlipY, + convertToPOT: this.textureConvertToPOT }); var target = textureInfo.target || glenum.TEXTURE_2D; @@ -19001,20 +19550,17 @@ function () { }); } else { - var fragmentDefines = { - USE_ROUGHNESS: null, - USE_METALNESS: null - }; - if (materialInfo.doubleSided) { - fragmentDefines.DOUBLE_SIDED = null; - } material = new Material({ name: materialInfo.name, - shader: this.shaderLibrary.get(this.shaderName, { - fragmentDefines: fragmentDefines, - textures: enabledTextures - }) + shader: this._getShader() }); + + material.define('fragment', 'USE_ROUGHNESS'); + material.define('fragment', 'USE_METALNESS'); + + if (materialInfo.doubleSided) { + material.define('fragment', 'DOUBLE_SIDED'); + } } if (uniforms.transparent) { @@ -19116,6 +19662,7 @@ function () { metalness: metallicRoughnessMatInfo.metallicFactor || 0, roughness: metallicRoughnessMatInfo.roughnessFactor || 0, emission: materialInfo.emissiveFactor || [0, 0, 0], + emissionIntensity: 1, alphaCutoff: materialInfo.alphaCutoff || 0 }; if (commonProperties.roughnessMap) { @@ -19136,25 +19683,26 @@ function () { }, commonProperties)); } else { - var fragmentDefines = { - ROUGHNESS_CHANNEL: 1, - METALNESS_CHANNEL: 2, - USE_ROUGHNESS: null, - USE_METALNESS: null - }; + + material = new Material({ + name: materialInfo.name, + shader: this._getShader() + }); + + material.define('fragment', 'USE_ROUGHNESS'); + material.define('fragment', 'USE_METALNESS'); + material.define('fragment', 'ROUGHNESS_CHANNEL', 1); + material.define('fragment', 'METALNESS_CHANNEL', 2); + + material.define('fragment', 'DIFFUSEMAP_ALPHA_ALPHA'); + if (alphaTest) { - fragmentDefines.ALPHA_TEST = null; + material.define('fragment', 'ALPHA_TEST'); } if (materialInfo.doubleSided) { - fragmentDefines.DOUBLE_SIDED = null; + material.define('fragment', 'DOUBLE_SIDED'); } - material = new Material({ - name: materialInfo.name, - shader: this.shaderLibrary.get(this.shaderName, { - fragmentDefines: fragmentDefines, - textures: enabledTextures - }) - }); + material.set(commonProperties); } @@ -19207,6 +19755,7 @@ function () { specularColor: specularGlossinessMatInfo.specularFactor || [1, 1, 1], glossiness: specularGlossinessMatInfo.glossinessFactor || 0, emission: materialInfo.emissiveFactor || [0, 0, 0], + emissionIntensity: 1, alphaCutoff: materialInfo.alphaCutoff == null ? 0.9 : materialInfo.alphaCutoff }; if (commonProperties.glossinessMap) { @@ -19218,22 +19767,21 @@ function () { commonProperties.specularColor = [1, 1, 1]; } - var fragmentDefines = { - GLOSSINESS_CHANNEL: 3 - }; + material = new Material({ + name: materialInfo.name, + shader: this._getShader() + }); + + material.define('fragment', 'GLOSSINESS_CHANNEL', 3); + material.define('fragment', 'DIFFUSEMAP_ALPHA_ALPHA'); + if (alphaTest) { - fragmentDefines.ALPHA_TEST = null; + material.define('fragment', 'ALPHA_TEST'); } if (materialInfo.doubleSided) { - fragmentDefines.DOUBLE_SIDED = null; + material.define('fragment', 'DOUBLE_SIDED'); } - material = new Material({ - name: materialInfo.name, - shader: this.shaderLibrary.get(this.shaderName, { - fragmentDefines: fragmentDefines, - textures: enabledTextures - }) - }); + material.set(commonProperties); if (materialInfo.alphaMode === 'BLEND') { @@ -19303,9 +19851,21 @@ function () { } geometry.attributes[attributeName].value = weightArray; } + else if (semantic === 'COLOR_0' && size === 3) { + var colorArray = new attributeArray.constructor(attributeInfo.count * 4); + for (var i = 0; i < attributeInfo.count; i++) { + var i4 = i * 4, i3 = i * 3; + colorArray[i4] = attributeArray[i3]; + colorArray[i4 + 1] = attributeArray[i3 + 1]; + colorArray[i4 + 2] = attributeArray[i3 + 2]; + colorArray[i4 + 3] = 1; + } + geometry.attributes[attributeName].value = colorArray; + } else { geometry.attributes[attributeName].value = attributeArray; } + var attributeType = 'float'; if (attributeArray instanceof vendor.Uint16Array) { attributeType = 'ushort'; @@ -19339,7 +19899,10 @@ function () { geometry.indices = getAccessorData(json, lib, primitiveInfo.indices, true); if (geometry.vertexCount <= 0xffff && geometry.indices instanceof vendor.Uint32Array) { geometry.indices = new vendor.Uint16Array(geometry.indices); - } + } + if(geometry.indices instanceof vendor.Uint8Array) { + geometry.indices = new vendor.Uint16Array(geometry.indices); + } } var material = lib.materials[primitiveInfo.material]; @@ -19347,7 +19910,7 @@ function () { // Use default material if (!material) { material = new Material({ - shader: this.shaderLibrary.get(self.shaderName) + shader: self._getShader() }); } var mesh = new Mesh({ @@ -19363,12 +19926,15 @@ function () { mesh.geometry.generateVertexNormals(); } if (((material instanceof StandardMaterial) && material.normalMap) - || (material.shader && material.shader.isTextureEnabled('normalMap')) + || (material.isTextureEnabled('normalMap')) ) { if (!mesh.geometry.attributes.tangent.value) { mesh.geometry.generateTangents(); } } + if (mesh.geometry.attributes.color.value) { + mesh.material.define('VERTEX_COLOR'); + } mesh.name = GLTFLoader.generateMeshName(json.meshes, idx, pp); @@ -19385,7 +19951,7 @@ function () { return new Perspective({ name: nodeInfo.name, aspect: perspectiveInfo.aspectRatio, - fov: perspectiveInfo.yfov, + fov: perspectiveInfo.yfov / Math.PI * 180, far: perspectiveInfo.zfar, near: perspectiveInfo.znear }); @@ -19416,6 +19982,8 @@ function () { }); } + lib.instancedMeshes = []; + util.each(json.nodes, function (nodeInfo, idx) { var node; if (nodeInfo.camera != null && this.includeCamera) { @@ -19429,12 +19997,15 @@ function () { // Replace the node with mesh directly node = instanceMesh(primitives[0]); node.setName(nodeInfo.name); + lib.instancedMeshes.push(node); } else { node = new Node(); node.setName(nodeInfo.name); for (var j = 0; j < primitives.length; j++) { - node.add(instanceMesh(primitives[j])); + var newMesh = instanceMesh(primitives[j]); + node.add(newMesh); + lib.instancedMeshes.push(newMesh); } } } @@ -19533,14 +20104,15 @@ function () { track.channels[path] = getAccessorData(json, lib, samplerInfo.output); } + var tracksList = []; + for (var hash in tracks) { + tracksList.push(tracks[hash]); + } var clip = new TrackClip({ name: animationInfo.name, - loop: true + loop: true, + tracks: tracksList }); - for (var hash in tracks) { - clip.addTrack(tracks[hash]); - } - clip.calcLifeFromTracks(); lib.clips.push(clip); }, this); @@ -19563,9 +20135,6 @@ GLTFLoader.generateMeshName = function (meshes, idx, primitiveIdx) { return primitiveIdx === 0 ? meshName : (meshName + '$' + primitiveIdx); }; -/** - * @module echarts/animation/Animator - */ var arraySlice = Array.prototype.slice; function defaultGetter(target, key) { @@ -19585,7 +20154,8 @@ function interpolateArray(p0, p1, percent, out, arrDim) { for (var i = 0; i < len; i++) { out[i] = interpolateNumber(p0[i], p1[i], percent); } - } else { + } + else { var len2 = p0[0].length; for (var i = 0; i < len; i++) { for (var j = 0; j < len2; j++) { @@ -19694,12 +20264,6 @@ function fillArr(arr0, arr1, arrDim) { } } -/** - * @param {Array} arr0 - * @param {Array} arr1 - * @param {number} arrDim - * @return {boolean} - */ function isArraySame(arr0, arr1, arrDim) { if (arr0 === arr1) { return true; @@ -19728,10 +20292,10 @@ function isArraySame(arr0, arr1, arrDim) { return true; } -function createTrackClip(animator, easing, oneTrackDone, keyframes, propName, interpolater) { +function createTrackClip(animator, globalEasing, oneTrackDone, keyframes, propName, interpolater, maxTime) { var getter = animator._getter; var setter = animator._setter; - var useSpline = easing === 'spline'; + var useSpline = globalEasing === 'spline'; var trackLen = keyframes.length; if (!trackLen) { @@ -19752,16 +20316,17 @@ function createTrackClip(animator, easing, oneTrackDone, keyframes, propName, in return a.time - b.time; }); - var trackMaxTime = keyframes[trackLen - 1].time; // Percents of each keyframe var kfPercents = []; // Value of each keyframe var kfValues = []; + // Easing funcs of each keyframe. + var kfEasings = []; var prevValue = keyframes[0].value; var isAllValueEqual = true; for (var i = 0; i < trackLen; i++) { - kfPercents.push(keyframes[i].time / trackMaxTime); + kfPercents.push(keyframes[i].time / maxTime); // Assume value is a color when it is a string var value = keyframes[i].value; @@ -19774,6 +20339,7 @@ function createTrackClip(animator, easing, oneTrackDone, keyframes, propName, in prevValue = value; kfValues.push(value); + kfEasings.push(keyframes[i].easing); } if (isAllValueEqual) { return; @@ -19804,7 +20370,7 @@ function createTrackClip(animator, easing, oneTrackDone, keyframes, propName, in var onframe = function(target, percent) { // Find the range keyframes // kf1-----kf2---------current--------kf3 - // find kf2(i) and kf3(i+1) and do interpolation + // find kf2(i) and kf3(i + 1) and do interpolation if (percent < cachePercent) { // Start from next key start = Math.min(cacheKey + 1, trackLen - 1); @@ -19813,24 +20379,30 @@ function createTrackClip(animator, easing, oneTrackDone, keyframes, propName, in break; } } - i = Math.min(i, trackLen-2); - } else { + i = Math.min(i, trackLen - 2); + } + else { for (i = cacheKey; i < trackLen; i++) { if (kfPercents[i] > percent) { break; } } - i = Math.min(i-1, trackLen-2); + i = Math.min(i - 1, trackLen - 2); } cacheKey = i; cachePercent = percent; - var range = (kfPercents[i+1] - kfPercents[i]); + var range = (kfPercents[i + 1] - kfPercents[i]); if (range === 0) { return; - } else { + } + else { w = (percent - kfPercents[i]) / range; + // Clamp 0 - 1 + w = Math.max(Math.min(1, w), 0); } + w = kfEasings[i + 1](w); + if (useSpline) { p1 = kfValues[i]; p0 = kfValues[i === 0 ? i : i - 1]; @@ -19845,20 +20417,23 @@ function createTrackClip(animator, easing, oneTrackDone, keyframes, propName, in p0, p1, p2, p3, w ) ); - } else if (isValueArray) { + } + else if (isValueArray) { catmullRomInterpolateArray( p0, p1, p2, p3, w, w*w, w*w*w, getter(target, propName), arrDim ); - } else { + } + else { setter( target, propName, catmullRomInterpolate(p0, p1, p2, p3, w, w*w, w*w*w) ); } - } else { + } + else { if (interpolater) { setter( target, @@ -19871,13 +20446,15 @@ function createTrackClip(animator, easing, oneTrackDone, keyframes, propName, in ) ); } + else if (isValueArray) { interpolateArray( kfValues[i], kfValues[i+1], w, getter(target, propName), arrDim ); - } else { + } + else { setter( target, propName, @@ -19889,15 +20466,15 @@ function createTrackClip(animator, easing, oneTrackDone, keyframes, propName, in var clip = new Clip({ target: animator._target, - life: trackMaxTime, + life: maxTime, loop: animator._loop, delay: animator._delay, onframe: onframe, onfinish: oneTrackDone }); - if (easing && easing !== 'spline') { - clip.setEasing(easing); + if (globalEasing && globalEasing !== 'spline') { + clip.setEasing(globalEasing); } return clip; @@ -19905,10 +20482,10 @@ function createTrackClip(animator, easing, oneTrackDone, keyframes, propName, in /** * @description Animator object can only be created by Animation.prototype.animate method. - * After created, we can use {@link qtek.animation.Animator#when} to add all keyframes and {@link qtek.animation.Animator#start} it. + * After created, we can use {@link clay.animation.Animator#when} to add all keyframes and {@link clay.animation.Animator#start} it. * Clips will be automatically created and added to the animation instance which created this deferred object. * - * @constructor qtek.animation.Animator + * @constructor clay.animation.Animator * * @param {Object} target * @param {boolean} loop @@ -19934,6 +20511,14 @@ function Animator(target, loop, getter, setter, interpolater) { this._onframeList = []; this._clipList = []; + + this._maxTime = 0; + + this._lastKFTime = 0; +} + +function noopEasing(w) { + return w; } Animator.prototype = { @@ -19941,12 +20526,17 @@ Animator.prototype = { constructor: Animator, /** - * @param {number} time Keyframe time using millisecond - * @param {Object} props A key-value object. Value can be number, 1d and 2d array - * @return {qtek.animation.Animator} - * @memberOf qtek.animation.Animator.prototype + * @param {number} time Keyframe time using millisecond + * @param {Object} props A key-value object. Value can be number, 1d and 2d array + * @param {string|Function} [easing] + * @return {clay.animation.Animator} + * @memberOf clay.animation.Animator.prototype */ - when: function (time, props) { + when: function (time, props, easing$$1) { + + this._maxTime = Math.max(time, this._maxTime); + + easing$$1 = (typeof easing$$1 === 'function' ? easing$$1 : easing[easing$$1]) || noopEasing; for (var propName in props) { if (!this._tracks[propName]) { this._tracks[propName] = []; @@ -19959,22 +20549,36 @@ Animator.prototype = { time: 0, value: cloneValue( this._getter(this._target, propName) - ) + ), + easing: easing$$1 }); } } this._tracks[propName].push({ time: parseInt(time), - value: props[propName] + value: props[propName], + easing: easing$$1 }); } return this; }, + /** + * @param {number} time During time since last keyframe + * @param {Object} props A key-value object. Value can be number, 1d and 2d array + * @param {string|Function} [easing] + * @return {clay.animation.Animator} + * @memberOf clay.animation.Animator.prototype + */ + then: function (duringTime, props, easing$$1) { + this.when(duringTime + this._lastKFTime, props, easing$$1); + this._lastKFTime += duringTime; + return this; + }, /** * callback when running animation * @param {Function} callback callback have two args, animating target and current percent - * @return {qtek.animation.Animator} - * @memberOf qtek.animation.Animator.prototype + * @return {clay.animation.Animator} + * @memberOf clay.animation.Animator.prototype */ during: function (callback) { this._onframeList.push(callback); @@ -19995,11 +20599,11 @@ Animator.prototype = { }, /** * Start the animation - * @param {string|function} easing - * @return {qtek.animation.Animator} - * @memberOf qtek.animation.Animator.prototype + * @param {string|Function} easing + * @return {clay.animation.Animator} + * @memberOf clay.animation.Animator.prototype */ - start: function (easing) { + start: function (globalEasing) { var self = this; var clipCount = 0; @@ -20012,12 +20616,14 @@ Animator.prototype = { }; var lastClip; + var clipMaxTime = 0; for (var propName in this._tracks) { var clip = createTrackClip( - this, easing, oneTrackDone, - this._tracks[propName], propName, self._interpolater + this, globalEasing, oneTrackDone, + this._tracks[propName], propName, self._interpolater, self._maxTime ); if (clip) { + clipMaxTime = Math.max(clipMaxTime, clip.life); this._clipList.push(clip); clipCount++; @@ -20050,7 +20656,7 @@ Animator.prototype = { /** * Stop the animation - * @memberOf qtek.animation.Animator.prototype + * @memberOf clay.animation.Animator.prototype */ stop: function () { for (var i = 0; i < this._clipList.length; i++) { @@ -20062,8 +20668,8 @@ Animator.prototype = { /** * Delay given milliseconds * @param {number} time - * @return {qtek.animation.Animator} - * @memberOf qtek.animation.Animator.prototype + * @return {clay.animation.Animator} + * @memberOf clay.animation.Animator.prototype */ delay: function (time){ this._delay = time; @@ -20072,8 +20678,8 @@ Animator.prototype = { /** * Callback after animation finished * @param {Function} func - * @return {qtek.animation.Animator} - * @memberOf qtek.animation.Animator.prototype + * @return {clay.animation.Animator} + * @memberOf clay.animation.Animator.prototype */ done: function (func) { if (func) { @@ -20083,28 +20689,30 @@ Animator.prototype = { }, /** * Get all clips created in start method. - * @return {qtek.animation.Clip[]} - * @memberOf qtek.animation.Animator.prototype + * @return {clay.animation.Clip[]} + * @memberOf clay.animation.Animator.prototype */ getClips: function () { return this._clipList; } }; -var requestAnimationFrame$1 = window.requestAnimationFrame - || window.msRequestAnimationFrame - || window.mozRequestAnimationFrame - || window.webkitRequestAnimationFrame +var g = typeof window === 'undefined' ? global : window; + +var requestAnimationFrame$1 = g.requestAnimationFrame + || g.msRequestAnimationFrame + || g.mozRequestAnimationFrame + || g.webkitRequestAnimationFrame || function (func){ setTimeout(func, 16); }; /** * Animation is global timeline that schedule all clips. each frame animation will set the time of clips to current and update the states of clips - * @constructor qtek.animation.Animation - * @extends qtek.core.Base + * @constructor clay.Timeline + * @extends clay.core.Base * * @example - * var animation = new qtek.animation.Animation(); - * var node = new qtek.Node(); + * var animation = new clay.Timeline(); + * var node = new clay.Node(); * animation.animate(node.position) * .when(1000, { * x: 500, @@ -20119,8 +20727,8 @@ var requestAnimationFrame$1 = window.requestAnimationFrame * }) * .start('spline'); */ -var Animation = Base.extend(function () { - return /** @lends qtek.animation.Animation# */{ +var Timeline$1 = Base.extend(function () { + return /** @lends clay.Timeline# */{ /** * stage is an object with render method, each frame if there exists any animating clips, stage.render will be called * @type {Object} @@ -20138,12 +20746,12 @@ var Animation = Base.extend(function () { _pausedTime: 0 }; }, -/** @lends qtek.animation.Animation.prototype */ +/** @lends clay.Timeline.prototype */ { /** * Add animator - * @param {qtek.animate.Animator} animator + * @param {clay.animate.Animator} animator */ addAnimator: function (animator) { animator.animation = this; @@ -20154,7 +20762,7 @@ var Animation = Base.extend(function () { }, /** - * @param {qtek.animation.Clip} clip + * @param {clay.animation.Clip} clip */ addClip: function (clip) { if (this._clips.indexOf(clip) < 0) { @@ -20163,7 +20771,7 @@ var Animation = Base.extend(function () { }, /** - * @param {qtek.animation.Clip} clip + * @param {clay.animation.Clip} clip */ removeClip: function (clip) { var idx = this._clips.indexOf(clip); @@ -20174,7 +20782,7 @@ var Animation = Base.extend(function () { /** * Remove animator - * @param {qtek.animate.Animator} animator + * @param {clay.animate.Animator} animator */ removeAnimator: function (animator) { var clips = animator.getClips(); @@ -20287,14 +20895,14 @@ var Animation = Base.extend(function () { this._clips = []; }, /** - * Create a animator + * Create an animator * @param {Object} target * @param {Object} [options] * @param {boolean} [options.loop] * @param {Function} [options.getter] * @param {Function} [options.setter] * @param {Function} [options.interpolater] - * @return {qtek.animation.Animator} + * @return {clay.animation.Animator} */ animate: function (target, options) { options = options || {}; @@ -20310,22 +20918,24 @@ var Animation = Base.extend(function () { } }); +// Alias + // TODO test -var mat4$7 = glmatrix.mat4; -var vec3$13 = glmatrix.vec3; +var mat4$8 = glmatrix.mat4; +var vec3$12 = glmatrix.vec3; /** - * @namespace qtek.util.mesh + * @namespace clay.util.mesh */ var meshUtil = { /** * Merge multiple meshes to one. * Note that these meshes must have the same material * - * @param {Array.} meshes + * @param {Array.} meshes * @param {boolean} applyWorldTransform - * @return qtek.Mesh - * @memberOf qtek.util.mesh + * @return {clay.Mesh} + * @memberOf clay.util.mesh */ merge: function (meshes, applyWorldTransform) { @@ -20353,7 +20963,7 @@ var meshUtil = { } } - var inverseTransposeMatrix = mat4$7.create(); + var inverseTransposeMatrix = mat4$8.create(); // Initialize the array data and merge bounding box var nVertex = 0; var nFace = 0; @@ -20388,9 +20998,9 @@ var meshUtil = { var nVertex = currentGeo.vertexCount; - var matrix = applyWorldTransform ? mesh.worldTransform._array : mesh.localTransform._array; - mat4$7.invert(inverseTransposeMatrix, matrix); - mat4$7.transpose(inverseTransposeMatrix, inverseTransposeMatrix); + var matrix = applyWorldTransform ? mesh.worldTransform.array : mesh.localTransform.array; + mat4$8.invert(inverseTransposeMatrix, matrix); + mat4$8.transpose(inverseTransposeMatrix, inverseTransposeMatrix); for (var nn = 0; nn < attributeNames.length; nn++) { var name = attributeNames[nn]; @@ -20409,10 +21019,10 @@ var meshUtil = { } // Transform position, normal and tangent if (name === 'position') { - vec3$13.forEach(targetAttr.value, size, offset, count, vec3$13.transformMat4, matrix); + vec3$12.forEach(targetAttr.value, size, offset, count, vec3$12.transformMat4, matrix); } else if (name === 'normal' || name === 'tangent') { - vec3$13.forEach(targetAttr.value, size, offset, count, vec3$13.transformMat4, inverseTransposeMatrix); + vec3$12.forEach(targetAttr.value, size, offset, count, vec3$12.transformMat4, inverseTransposeMatrix); } } @@ -20435,22 +21045,19 @@ var meshUtil = { /** * Split mesh into sub meshes, each mesh will have maxJointNumber joints. - * @param {qtek.Mesh} mesh + * @param {clay.Mesh} mesh * @param {number} maxJointNumber * @param {boolean} inPlace - * @param {qtek.shader.library} [shaderLib] - * @param {string} [shaderType] - * @return {qtek.Node} + * @return {clay.Node} * - * @memberOf qtek.util.mesh + * @memberOf clay.util.mesh */ // FIXME, Have issues on some models - splitByJoints: function (mesh, maxJointNumber, inPlace, shaderLib, shaderType) { + splitByJoints: function (mesh, maxJointNumber, inPlace) { var geometry = mesh.geometry; var skeleton = mesh.skeleton; var material = mesh.material; - var shader = material.shader; var joints = mesh.joints; if (!geometry || !skeleton || !joints.length) { return; @@ -20459,7 +21066,6 @@ var meshUtil = { return mesh; } - var shaders = {}; var indices = geometry.indices; @@ -20547,42 +21153,12 @@ var meshUtil = { var jointReverseMap = bucket.jointReverseMap; var subJointNumber = bucket.joints.length; - var subMat = material.clone(); - if (material instanceof StandardMaterial) { - subMat.jointCount = subJointNumber; - } - else { - var subShader; - if (shaderLib && shaderType) { - var vertexDefines = {}; - for (var name in shader.vertexDefines) { - vertexDefines[name] = shader.vertexDefines[name]; - } - vertexDefines.JOINT_COUNT = subJointNumber; - subShader = shaderLib.get(shaderType, { - textures: shader.getEnabledTextures(), - vertexDefines: vertexDefines, - fragmentDefines: shader.fragmentDefines, - precision: shader.precision - }); - } - else { - subShader = shaders[subJointNumber]; - if (!subShader) { - subShader = shader.clone(); - subShader.define('vertex', 'JOINT_COUNT', subJointNumber); - shaders[subJointNumber] = subShader; - } - } - subMat.attachShader(subShader, true); - } - subMat.name = [material.name, b].join('-'); - var subGeo = new Geometry(); var subMesh = new Mesh({ name: [mesh.name, i].join('-'), - material: subMat, + // DON'T clone material. + material: material, geometry: subGeo, skeleton: skeleton, joints: bucket.joints.slice() @@ -20681,8 +21257,8 @@ var meshUtil = { /** * @constructor - * @alias qtek.async.Task - * @mixes qtek.core.mixin.notifier + * @alias clay.async.Task + * @mixes clay.core.mixin.notifier */ var Task = function() { this._fullfilled = false; @@ -20759,7 +21335,7 @@ function makeRequestTask(url, responseType) { * {url: 'a.json'}, * {url: 'b.bin', responseType: 'arraybuffer'} * ]); - * @return {qtek.async.Task|qtek.async.Task[]} + * @return {clay.async.Task|clay.async.Task[]} */ Task.makeRequestTask = function(url, responseType) { if (typeof url === 'string') { @@ -20784,7 +21360,7 @@ Task.makeRequestTask = function(url, responseType) { } }; /** - * @return {qtek.async.Task} + * @return {clay.async.Task} */ Task.makeTask = function() { return new Task(); @@ -20794,8 +21370,8 @@ util.extend(Task.prototype, notifier); /** * @constructor - * @alias qtek.async.TaskGroup - * @extends qtek.async.Task + * @alias clay.async.TaskGroup + * @extends clay.async.Task */ var TaskGroup = function () { @@ -20815,18 +21391,18 @@ TaskGroup.prototype = new Ctor(); TaskGroup.prototype.constructor = TaskGroup; /** - * Wait for all given tasks successed, task can also be any notifier object which will trigger success and error events. Like {@link qtek.Texture2D}, {@link qtek.TextureCube}, {@link qtek.loader.GLTF}. - * @param {Array.} tasks + * Wait for all given tasks successed, task can also be any notifier object which will trigger success and error events. Like {@link clay.Texture2D}, {@link clay.TextureCube}, {@link clay.loader.GLTF}. + * @param {Array.} tasks * @chainable * @example * // Load texture list * var list = ['a.jpg', 'b.jpg', 'c.jpg'] * var textures = list.map(function (src) { - * var texture = new qtek.Texture2D(); + * var texture = new clay.Texture2D(); * texture.load(src); * return texture; * }); - * var taskGroup = new qtek.async.TaskGroup(); + * var taskGroup = new clay.async.TaskGroup(); * taskGroup.all(textures).success(function () { * // Do some thing after all textures loaded * }); @@ -20879,8 +21455,8 @@ TaskGroup.prototype.all = function (tasks) { }; /** * Wait for all given tasks finished, either successed or failed - * @param {Array.} tasks - * @return {qtek.async.TaskGroup} + * @param {Array.} tasks + * @return {clay.async.TaskGroup} */ TaskGroup.prototype.allSettled = function (tasks) { var count = 0; @@ -21019,14 +21595,14 @@ TaskGroup.prototype.getTaskNumber = function (recursive) { }; /** - * @constructor qtek.geometry.Plane - * @extends qtek.Geometry + * @constructor clay.geometry.Plane + * @extends clay.Geometry * @param {Object} [opt] * @param {number} [opt.widthSegments] * @param {number} [opt.heightSegments] */ var Plane$2 = Geometry.extend( -/** @lends qtek.geometry.Plane# */ +/** @lends clay.geometry.Plane# */ { dynamic: false, /** @@ -21040,7 +21616,7 @@ var Plane$2 = Geometry.extend( }, function() { this.build(); }, -/** @lends qtek.geometry.Plane.prototype */ +/** @lends clay.geometry.Plane.prototype */ { /** * Build plane geometry @@ -21086,35 +21662,35 @@ var Plane$2 = Geometry.extend( } }); -var vec3$14 = glmatrix.vec3; +var vec3$13 = glmatrix.vec3; /** - * @constructor qtek.picking.RayPicking - * @extends qtek.core.Base + * @constructor clay.picking.RayPicking + * @extends clay.core.Base */ var RayPicking = Base.extend( -/** @lends qtek.picking.RayPicking# */ +/** @lends clay.picking.RayPicking# */ { /** * Target scene - * @type {qtek.Scene} + * @type {clay.Scene} */ scene: null, /** * Target camera - * @type {qtek.Camera} + * @type {clay.Camera} */ camera: null, /** * Target renderer - * @type {qtek.Renderer} + * @type {clay.Renderer} */ renderer: null }, function () { this._ray = new Ray(); this._ndc = new Vector2(); }, -/** @lends qtek.picking.RayPicking.prototype */ +/** @lends clay.picking.RayPicking.prototype */ { /** @@ -21122,7 +21698,7 @@ var RayPicking = Base.extend( * @param {number} x Mouse position x * @param {number} y Mouse position y * @param {boolean} [forcePickAll=false] ignore ignorePicking - * @return {qtek.picking.RayPicking~Intersection} + * @return {clay.picking.RayPicking~Intersection} */ pick: function (x, y, forcePickAll) { var out = this.pickAll(x, y, [], forcePickAll); @@ -21135,7 +21711,7 @@ var RayPicking = Base.extend( * @param {number} y Mouse position y * @param {Array} [output] * @param {boolean} [forcePickAll=false] ignore ignorePicking - * @return {Array.} + * @return {Array.} */ pickAll: function (x, y, output, forcePickAll) { this.renderer.screenToNDC(x, y, this._ndc); @@ -21182,7 +21758,7 @@ var RayPicking = Base.extend( var isSkinnedMesh = renderable.isSkinnedMesh(); ray.copy(this._ray); Matrix4.invert(worldInverse, renderable.worldTransform); - + // Skinned mesh will ignore the world transform. if (!isSkinnedMesh) { ray.applyTransform(worldInverse); @@ -21228,7 +21804,7 @@ var RayPicking = Base.extend( return; } if (isSkinnedMesh) { - skinMatricesArray = renderable.skeleton.getSubSkinMatrices(renderable.__GUID__, renderable.joints); + skinMatricesArray = renderable.skeleton.getSubSkinMatrices(renderable.__uid__, renderable.joints); for (var i = 0; i < renderable.joints.length; i++) { skinMatrices[i] = skinMatrices[i] || []; for (var k = 0; k < 16; k++) { @@ -21251,12 +21827,12 @@ var RayPicking = Base.extend( weightAttr.get(i, weight); jointAttr.get(i, joint); weight[3] = 1 - weight[0] - weight[1] - weight[2]; - vec3$14.set(skinnedPos, 0, 0, 0); + vec3$13.set(skinnedPos, 0, 0, 0); for (var k = 0; k < 4; k++) { if (joint[k] >= 0 && weight[k] > 1e-4) { - vec3$14.transformMat4(tmp, pos, skinMatrices[joint[k]]); - vec3$14.scaleAndAdd(skinnedPos, skinnedPos, tmp, weight[k]); - } + vec3$13.transformMat4(tmp, pos, skinMatrices[joint[k]]); + vec3$13.scaleAndAdd(skinnedPos, skinnedPos, tmp, weight[k]); + } } skinnedPositionAttr.set(i, skinnedPos); } @@ -21269,9 +21845,9 @@ var RayPicking = Base.extend( var finalPosAttr = isSkinnedMesh ? geometry.attributes.skinnedPosition : positionAttr; - finalPosAttr.get(i1, v1._array); - finalPosAttr.get(i2, v2._array); - finalPosAttr.get(i3, v3._array); + finalPosAttr.get(i1, v1.array); + finalPosAttr.get(i2, v2.array); + finalPosAttr.get(i3, v3.array); if (cullBack) { point = ray.intersectTriangle(v1, v2, v3, renderable.culling); @@ -21303,10 +21879,10 @@ var RayPicking = Base.extend( }); /** - * @constructor qtek.picking.RayPicking~Intersection - * @param {qtek.math.Vector3} point - * @param {qtek.math.Vector3} pointWorld - * @param {qtek.Node} target + * @constructor clay.picking.RayPicking~Intersection + * @param {clay.Vector3} point + * @param {clay.Vector3} pointWorld + * @param {clay.Node} target * @param {Array.} triangle * @param {number} triangleIndex * @param {number} distance @@ -21314,17 +21890,17 @@ var RayPicking = Base.extend( RayPicking.Intersection = function (point, pointWorld, target, triangle, triangleIndex, distance) { /** * Intersection point in local transform coordinates - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ this.point = point; /** * Intersection point in world transform coordinates - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ this.pointWorld = pointWorld; /** * Intersection scene node - * @type {qtek.Node} + * @type {clay.Node} */ this.target = target; /** @@ -21348,15 +21924,15 @@ var isPowerOfTwo$1 = mathUtil.isPowerOfTwo; var targetList = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; /** - * @constructor qtek.TextureCube - * @extends qtek.Texture + * @constructor clay.TextureCube + * @extends clay.Texture * * @example * ... - * var mat = new qtek.Material({ - * shader: qtek.shader.library.get('qtek.phong', 'environmentMap') + * var mat = new clay.Material({ + * shader: clay.shader.library.get('clay.phong', 'environmentMap') * }); - * var envMap = new qtek.TextureCube(); + * var envMap = new clay.TextureCube(); * envMap.load({ * 'px': 'assets/textures/sky/px.jpg', * 'nx': 'assets/textures/sky/nx.jpg' @@ -21374,8 +21950,16 @@ var targetList = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; * }); * }); */ -var TextureCube = Texture.extend(function () { - return /** @lends qtek.TextureCube# */{ +var TextureCube = Texture$1.extend(function () { + return /** @lends clay.TextureCube# */{ + + /** + * @type {boolean} + * @default false + */ + // PENDING cubemap should not flipY in default. + // flipY: false, + /** * @type {Object} * @property {?HTMLImageElement|HTMLCanvasElemnet} px @@ -21418,6 +22002,9 @@ var TextureCube = Texture.extend(function () { mipmaps: [] }; }, { + + textureType: 'textureCube', + update: function (renderer) { var _gl = renderer.gl; _gl.bindTexture(_gl.TEXTURE_CUBE_MAP, this._cache.get('webgl_texture')); @@ -21481,8 +22068,8 @@ var TextureCube = Texture.extend(function () { }, /** - * @param {qtek.Renderer} renderer - * @memberOf qtek.TextureCube.prototype + * @param {clay.Renderer} renderer + * @memberOf clay.TextureCube.prototype */ generateMipmap: function (renderer) { var _gl = renderer.gl; @@ -21612,11 +22199,11 @@ var GL_RENDERBUFFER = glenum.RENDERBUFFER; var GL_DEPTH_ATTACHMENT = glenum.DEPTH_ATTACHMENT; var GL_COLOR_ATTACHMENT0 = glenum.COLOR_ATTACHMENT0; /** - * @constructor qtek.FrameBuffer - * @extends qtek.core.Base + * @constructor clay.FrameBuffer + * @extends clay.core.Base */ var FrameBuffer = Base.extend( -/** @lends qtek.FrameBuffer# */ +/** @lends clay.FrameBuffer# */ { /** * If use depth buffer @@ -21642,7 +22229,7 @@ var FrameBuffer = Base.extend( this._textures = {}; }, -/**@lends qtek.FrameBuffer.prototype. */ +/**@lends clay.FrameBuffer.prototype. */ { /** * Get attached texture width @@ -21663,7 +22250,7 @@ var FrameBuffer = Base.extend( /** * Bind the framebuffer to given renderer before rendering - * @param {qtek.Renderer} renderer + * @param {clay.Renderer} renderer */ bind: function (renderer) { @@ -21747,7 +22334,7 @@ var FrameBuffer = Base.extend( /** * Unbind the frame buffer after rendering - * @param {qtek.Renderer} renderer + * @param {clay.Renderer} renderer */ unbind: function (renderer) { // Remove status record on renderer @@ -21758,7 +22345,7 @@ var FrameBuffer = Base.extend( _gl.bindFramebuffer(GL_FRAMEBUFFER, null); this._boundRenderer = null; - this._cache.use(renderer.__GUID__); + this._cache.use(renderer.__uid__); var viewport = this._cache.get('viewport'); // Reset viewport; if (viewport) { @@ -21778,8 +22365,8 @@ var FrameBuffer = Base.extend( var texture = obj.texture; // FIXME some texture format can't generate mipmap if (!texture.NPOT && texture.useMipmap - && texture.minFilter === Texture.LINEAR_MIPMAP_LINEAR) { - var target = texture instanceof TextureCube ? glenum.TEXTURE_CUBE_MAP : glenum.TEXTURE_2D; + && texture.minFilter === Texture$1.LINEAR_MIPMAP_LINEAR) { + var target = texture.textureType === 'textureCube' ? glenum.TEXTURE_CUBE_MAP : glenum.TEXTURE_2D; _gl.bindTexture(target, texture.getWebGLTexture(renderer)); _gl.generateMipmap(target); _gl.bindTexture(target, null); @@ -21788,7 +22375,7 @@ var FrameBuffer = Base.extend( } }, - + // 0x8CD5, 36053, FRAMEBUFFER_COMPLETE // 0x8CD6, 36054, FRAMEBUFFER_INCOMPLETE_ATTACHMENT // 0x8CD7, 36055, FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT @@ -21800,7 +22387,7 @@ var FrameBuffer = Base.extend( _getFrameBufferGL: function (renderer) { var cache = this._cache; - cache.use(renderer.__GUID__); + cache.use(renderer.__uid__); if (cache.miss(KEY_FRAMEBUFFER)) { cache.put(KEY_FRAMEBUFFER, renderer.gl.createFramebuffer()); @@ -21811,7 +22398,7 @@ var FrameBuffer = Base.extend( /** * Attach a texture(RTT) to the framebuffer - * @param {qtek.Texture} texture + * @param {clay.Texture} texture * @param {number} [attachment=gl.COLOR_ATTACHMENT0] * @param {number} [target=gl.TEXTURE_2D] */ @@ -21834,7 +22421,7 @@ var FrameBuffer = Base.extend( if (_gl) { var cache = this._cache; - cache.use(boundRenderer.__GUID__); + cache.use(boundRenderer.__uid__); attachedTextures = cache.get('attached_textures'); } @@ -21949,7 +22536,7 @@ var FrameBuffer = Base.extend( this._textures[attachment] = null; if (this._boundRenderer) { var cache = this._cache; - cache.use(this._boundRenderer.__GUID__); + cache.use(this._boundRenderer.__uid__); this._doDetach(this._boundRenderer.gl, attachment, target); } }, @@ -21962,7 +22549,7 @@ var FrameBuffer = Base.extend( var _gl = renderer.gl; var cache = this._cache; - cache.use(renderer.__GUID__); + cache.use(renderer.__uid__); var renderBuffer = cache.get(KEY_RENDERBUFFER); if (renderBuffer) { @@ -21972,7 +22559,7 @@ var FrameBuffer = Base.extend( if (frameBuffer) { _gl.deleteFramebuffer(frameBuffer); } - cache.deleteContext(renderer.__GUID__); + cache.deleteContext(renderer.__uid__); // Clear cache for reusing this._textures = {}; @@ -21990,20 +22577,20 @@ var targets = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; /** * Pass rendering scene to a environment cube map * - * @constructor qtek.prePass.EnvironmentMap - * @extends qtek.core.Base + * @constructor clay.prePass.EnvironmentMap + * @extends clay.core.Base * @example * // Example of car reflection - * var envMap = new qtek.TextureCube({ + * var envMap = new clay.TextureCube({ * width: 256, * height: 256 * }); - * var envPass = new qtek.prePass.EnvironmentMap({ + * var envPass = new clay.prePass.EnvironmentMap({ * position: car.position, * texture: envMap * }); * var carBody = car.getChildByName('body'); - * carBody.material.shader.enableTexture('environmentMap'); + * carBody.material.enableTexture('environmentMap'); * carBody.material.set('environmentMap', envMap); * ... * animation.on('frame', function(frameTime) { @@ -22012,35 +22599,35 @@ var targets = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; * }); */ var EnvironmentMapPass = Base.extend(function() { - var ret = { + var ret = /** @lends clay.prePass.EnvironmentMap# */ { /** * Camera position - * @type {qtek.math.Vector3} - * @memberOf qtek.prePass.EnvironmentMap# + * @type {clay.Vector3} + * @memberOf clay.prePass.EnvironmentMap# */ position: new Vector3(), /** * Camera far plane * @type {number} - * @memberOf qtek.prePass.EnvironmentMap# + * @memberOf clay.prePass.EnvironmentMap# */ far: 1000, /** * Camera near plane * @type {number} - * @memberOf qtek.prePass.EnvironmentMap# + * @memberOf clay.prePass.EnvironmentMap# */ near: 0.1, /** * Environment cube map - * @type {qtek.TextureCube} - * @memberOf qtek.prePass.EnvironmentMap# + * @type {clay.TextureCube} + * @memberOf clay.prePass.EnvironmentMap# */ texture: null, /** * Used if you wan't have shadow in environment map - * @type {qtek.prePass.ShadowMap} + * @type {clay.prePass.ShadowMap} */ shadowMapPass: null, }; @@ -22063,17 +22650,17 @@ var EnvironmentMapPass = Base.extend(function() { ret._frameBuffer = new FrameBuffer(); return ret; -}, { +}, /** @lends clay.prePass.EnvironmentMap# */ { /** * @param {string} target - * @return {qtek.Camera} + * @return {clay.Camera} */ getCamera: function (target) { return this._cameras[target]; }, /** - * @param {qtek.Renderer} renderer - * @param {qtek.Scene} scene + * @param {clay.Renderer} renderer + * @param {clay.Scene} scene * @param {boolean} [notUpdateScene=false] */ render: function(renderer, scene, notUpdateScene) { @@ -22115,7 +22702,7 @@ var EnvironmentMapPass = Base.extend(function() { } }, /** - * @param {qtek.Renderer} renderer + * @param {clay.Renderer} renderer */ dispose: function (renderer) { this._frameBuffer.dispose(renderer); @@ -22123,8 +22710,8 @@ var EnvironmentMapPass = Base.extend(function() { }); /** - * @constructor qtek.geometry.Sphere - * @extends qtek.Geometry + * @constructor clay.geometry.Sphere + * @extends clay.Geometry * @param {Object} [opt] * @param {number} [widthSegments] * @param {number} [heightSegments] @@ -22134,14 +22721,12 @@ var EnvironmentMapPass = Base.extend(function() { * @param {number} [thetaLength] * @param {number} [radius] */ -var Sphere = Geometry.extend( -/** @lends qtek.geometry.Sphere# */ -{ +var Sphere = Geometry.extend(/** @lends clay.geometry.Sphere# */ { dynamic: false, /** * @type {number} */ - widthSegments: 20, + widthSegments: 40, /** * @type {number} */ @@ -22173,7 +22758,7 @@ var Sphere = Geometry.extend( }, function() { this.build(); }, -/** @lends qtek.geometry.Sphere.prototype */ +/** @lends clay.geometry.Sphere.prototype */ { /** * Build sphere geometry @@ -22259,25 +22844,23 @@ var Sphere = Geometry.extend( } }); -Shader.import(basicEssl); +var skydomeGLSL = "@export clay.skydome.vertex\n#define SHADER_NAME skydome\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec2 texcoord : TEXCOORD_0;\nattribute vec3 position : POSITION;\nvarying vec2 v_Texcoord;\nvoid main()\n{\n gl_Position = worldViewProjection * vec4(position, 1.0);\n v_Texcoord = texcoord;\n}\n@end\n@export clay.skydome.fragment\nuniform sampler2D environmentMap;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.srgb\n@import clay.util.ACES\nvoid main()\n{\n vec4 texel = decodeHDR(texture2D(environmentMap, v_Texcoord));\n#ifdef SRGB_DECODE\n texel = sRGBToLinear(texel);\n#endif\n#ifdef TONEMAPPING\n texel.rgb = ACESToneMapping(texel.rgb);\n#endif\n#ifdef SRGB_ENCODE\n texel = linearTosRGB(texel);\n#endif\n gl_FragColor = encodeHDR(vec4(texel.rgb, 1.0));\n}\n@end"; + +Shader.import(skydomeGLSL); /** - * @constructor qtek.plugin.Skydome + * @constructor clay.plugin.Skydome * * @example - * var skyTex = new qtek.Texture2D(); + * var skyTex = new clay.Texture2D(); * skyTex.load('assets/textures/sky.jpg'); - * var skydome = new qtek.plugin.Skydome({ + * var skydome = new clay.plugin.Skydome({ * scene: scene * }); * skydome.material.set('diffuseMap', skyTex); - */ +*/ var Skydome = Mesh.extend(function () { - var skydomeShader = new Shader({ - vertex: Shader.source('qtek.basic.vertex'), - fragment: Shader.source('qtek.basic.fragment') - }); - skydomeShader.enableTexture('diffuseMap'); + var skydomeShader = new Shader(Shader.source('clay.skydome.vertex'), Shader.source('clay.skydome.fragment')); var material = new Material({ shader: skydomeShader, @@ -22286,8 +22869,8 @@ var Skydome = Mesh.extend(function () { return { /** - * @type {qtek.Scene} - * @memberOf qtek.plugin.Skydome# + * @type {clay.Scene} + * @memberOf clay.plugin.Skydome# */ scene: null, @@ -22315,23 +22898,26 @@ var Skydome = Mesh.extend(function () { }, { /** * Attach the skybox to the scene - * @param {qtek.Scene} scene - * @memberOf qtek.plugin.Skydome.prototype + * @param {clay.Scene} scene + * @memberOf clay.plugin.Skydome.prototype */ attachScene: function (scene) { if (this.scene) { this.detachScene(); } + scene.skydome = this; + this.scene = scene; scene.on('beforerender', this._beforeRenderScene, this); }, /** * Detach from scene - * @memberOf qtek.plugin.Skydome.prototype + * @memberOf clay.plugin.Skydome.prototype */ detachScene: function () { if (this.scene) { this.scene.off('beforerender', this._beforeRenderScene); + this.scene.skydome = null; } this.scene = null; }, @@ -22339,21 +22925,20 @@ var Skydome = Mesh.extend(function () { _beforeRenderScene: function (renderer, scene, camera) { this.position.copy(camera.getWorldPosition()); this.update(); - renderer.renderQueue([this], camera); + renderer.renderPass([this], camera); }, setEnvironmentMap: function (envMap) { - this.material.set('diffuseMap', envMap); + this.material.set('environmentMap', envMap); }, getEnvironmentMap: function () { - return this.material.get('diffuseMap'); + return this.material.get('environmentMap'); }, dispose: function (renderer) { this.detachScene(); this.geometry.dispose(renderer); - this.material.dispose(renderer); } }); @@ -22376,7 +22961,7 @@ var headerLengthInt = 31; // The header length in 32 bit ints var FOURCC_DXT1 = fourCCToInt32('DXT1'); var FOURCC_DXT3 = fourCCToInt32('DXT3'); var FOURCC_DXT5 = fourCCToInt32('DXT5'); - // Offsets into the header array +// Offsets into the header array var off_magic = 0; var off_size = 1; @@ -22409,15 +22994,15 @@ var ret = { switch(fourCC) { case FOURCC_DXT1: blockBytes = 8; - internalFormat = Texture.COMPRESSED_RGB_S3TC_DXT1_EXT; + internalFormat = Texture$1.COMPRESSED_RGB_S3TC_DXT1_EXT; break; case FOURCC_DXT3: blockBytes = 16; - internalFormat = Texture.COMPRESSED_RGBA_S3TC_DXT3_EXT; + internalFormat = Texture$1.COMPRESSED_RGBA_S3TC_DXT3_EXT; break; case FOURCC_DXT5: blockBytes = 16; - internalFormat = Texture.COMPRESSED_RGBA_S3TC_DXT5_EXT; + internalFormat = Texture$1.COMPRESSED_RGBA_S3TC_DXT5_EXT; break; default: return null; @@ -22435,9 +23020,9 @@ var ret = { var _width = width; var _height = height; textures[f] = new Texture2D({ - width : _width, - height : _height, - format : internalFormat + width: _width, + height: _height, + format: internalFormat }); var mipmaps = []; for (var i = 0; i < mipmapCount; i++) { @@ -22634,7 +23219,7 @@ var ret$1 = { texture.height = height; texture.pixels = pixels; // HALF_FLOAT can't use Float32Array - texture.type = Texture.FLOAT; + texture.type = Texture$1.FLOAT; return texture; }, @@ -22644,7 +23229,7 @@ var ret$1 = { }; /** - * @alias qtek.util.texture + * @alias clay.util.texture */ var textureUtil = { /** @@ -22652,7 +23237,7 @@ var textureUtil = { * @param {object} [option] * @param {Function} [onsuccess] * @param {Function} [onerror] - * @return {qtek.Texture} + * @return {clay.Texture} */ loadTexture: function (path, option, onsuccess, onerror) { var texture; @@ -22668,7 +23253,8 @@ var textureUtil = { if (path.match(/.hdr$/) || option.fileType === 'hdr') { texture = new Texture2D({ width: 0, - height: 0 + height: 0, + sRGB: false }); textureUtil._fetchTexture( path, @@ -22703,8 +23289,8 @@ var textureUtil = { texture.error(onerror); } } - else if (typeof(path) == 'object' && typeof(path.px) !== 'undefined') { - var texture = new TextureCube(); + else if (typeof path === 'object' && typeof(path.px) !== 'undefined') { + texture = new TextureCube(); texture.load(path); texture.success(onsuccess); texture.error(onerror); @@ -22714,9 +23300,9 @@ var textureUtil = { /** * Load a panorama texture and render it to a cube map - * @param {qtek.Renderer} renderer + * @param {clay.Renderer} renderer * @param {string} path - * @param {qtek.TextureCube} cubeMap + * @param {clay.TextureCube} cubeMap * @param {object} [option] * @param {boolean} [option.encodeRGBM] * @param {number} [option.exposure] @@ -22746,9 +23332,9 @@ var textureUtil = { /** * Render a panorama texture to a cube map - * @param {qtek.Renderer} renderer - * @param {qtek.Texture2D} panoramaMap - * @param {qtek.TextureCube} cubeMap + * @param {clay.Renderer} renderer + * @param {clay.Texture2D} panoramaMap + * @param {clay.TextureCube} cubeMap * @param {Object} option * @param {boolean} [option.encodeRGBM] */ @@ -22757,13 +23343,16 @@ var textureUtil = { var skydome = new Skydome({ scene: new Scene() }); - skydome.material.set('diffuseMap', panoramaMap); + skydome.setEnvironmentMap(panoramaMap); option = option || {}; if (option.encodeRGBM) { - skydome.material.shader.define('fragment', 'RGBM_ENCODE'); + skydome.material.define('fragment', 'RGBM_ENCODE'); } + // Share sRGB + cubeMap.sRGB = panoramaMap.sRGB; + environmentMapPass.texture = cubeMap; environmentMapPass.render(renderer, skydome.scene); environmentMapPass.texture = null; @@ -22802,369 +23391,147 @@ var textureUtil = { if (i % (width * 4) === 0) { // left edge x1 = srcData.data[i]; - x2 = srcData.data[i + 4]; - } - else if (i % (width * 4) === (width - 1) * 4) { - // right edge - x1 = srcData.data[i - 4]; - x2 = srcData.data[i]; - } - else { - x1 = srcData.data[i - 4]; - x2 = srcData.data[i + 4]; - } - - if (i < width * 4) { - // top edge - y1 = srcData.data[i]; - y2 = srcData.data[i + width * 4]; - } - else if (i > width * (height - 1) * 4) { - // bottom edge - y1 = srcData.data[i - width * 4]; - y2 = srcData.data[i]; - } - else { - y1 = srcData.data[i - width * 4]; - y2 = srcData.data[i + width * 4]; - } - - dstData.data[i] = (x1 - x2) + 127; - dstData.data[i + 1] = (y1 - y2) + 127; - dstData.data[i + 2] = 255; - dstData.data[i + 3] = 255; - } - ctx.putImageData(dstData, 0, 0); - return canvas; - }, - - /** - * Convert height map to normal map - * @param {HTMLImageElement|HTMLCanvasElement} image - * @param {boolean} [checkBump=false] - * @param {number} [threshold=20] - * @return {HTMLCanvasElement} - */ - isHeightImage: function (img, downScaleSize, threshold) { - if (!img || !img.width || !img.height) { - return false; - } - - var canvas = document.createElement('canvas'); - var ctx = canvas.getContext('2d'); - var size = downScaleSize || 32; - threshold = threshold || 20; - canvas.width = canvas.height = size; - ctx.drawImage(img, 0, 0, size, size); - var srcData = ctx.getImageData(0, 0, size, size); - for (var i = 0; i < srcData.data.length; i += 4) { - var r = srcData.data[i]; - var g = srcData.data[i + 1]; - var b = srcData.data[i + 2]; - var diff = Math.abs(r - g) + Math.abs(g - b); - if (diff > threshold) { - return false; - } - } - return true; - }, - - _fetchTexture: function (path, onsuccess, onerror) { - request.get({ - url: path, - responseType: 'arraybuffer', - onload: onsuccess, - onerror: onerror - }); - }, - - /** - * Create a chessboard texture - * @param {number} [size] - * @param {number} [unitSize] - * @param {string} [color1] - * @param {string} [color2] - * @return {qtek.Texture2D} - */ - createChessboard: function (size, unitSize, color1, color2) { - size = size || 512; - unitSize = unitSize || 64; - color1 = color1 || 'black'; - color2 = color2 || 'white'; - - var repeat = Math.ceil(size / unitSize); - - var canvas = document.createElement('canvas'); - canvas.width = size; - canvas.height = size; - var ctx = canvas.getContext('2d'); - ctx.fillStyle = color2; - ctx.fillRect(0, 0, size, size); - - ctx.fillStyle = color1; - for (var i = 0; i < repeat; i++) { - for (var j = 0; j < repeat; j++) { - var isFill = j % 2 ? (i % 2) : (i % 2 - 1); - if (isFill) { - ctx.fillRect(i * unitSize, j * unitSize, unitSize, unitSize); - } - } - } - - var texture = new Texture2D({ - image: canvas, - anisotropic: 8 - }); - - return texture; - }, - - /** - * Create a blank pure color 1x1 texture - * @param {string} color - * @return {qtek.Texture2D} - */ - createBlank: function (color) { - var canvas = document.createElement('canvas'); - canvas.width = 1; - canvas.height = 1; - var ctx = canvas.getContext('2d'); - ctx.fillStyle = color; - ctx.fillRect(0, 0, 1, 1); - - var texture = new Texture2D({ - image: canvas - }); - - return texture; - } -}; - -/** - * @constructor qtek.light.Spot - * @extends qtek.Light - */ -var SpotLight = Light.extend( -/**@lends qtek.light.Spot */ -{ - /** - * @type {number} - */ - range: 20, - /** - * @type {number} - */ - umbraAngle: 30, - /** - * @type {number} - */ - penumbraAngle: 45, - /** - * @type {number} - */ - falloffFactor: 2.0, - /** - * @type {number} - */ - shadowBias: 0.0002, - /** - * @type {number} - */ - shadowSlopeScale: 2.0 -},{ - - type: 'SPOT_LIGHT', - - uniformTemplates: { - spotLightPosition: { - type: '3f', - value: function (instance) { - return instance.getWorldPosition()._array; - } - }, - spotLightRange: { - type: '1f', - value: function (instance) { - return instance.range; - } - }, - spotLightUmbraAngleCosine: { - type: '1f', - value: function (instance) { - return Math.cos(instance.umbraAngle * Math.PI / 180); - } - }, - spotLightPenumbraAngleCosine: { - type: '1f', - value: function (instance) { - return Math.cos(instance.penumbraAngle * Math.PI / 180); - } - }, - spotLightFalloffFactor: { - type: '1f', - value: function (instance) { - return instance.falloffFactor; - } - }, - spotLightDirection: { - type: '3f', - value: function (instance) { - instance.__dir = instance.__dir || new Vector3(); - // Direction is target to eye - return instance.__dir.copy(instance.worldTransform.z).negate()._array; - } - }, - spotLightColor: { - type: '3f', - value: function (instance) { - var color = instance.color; - var intensity = instance.intensity; - return [color[0] * intensity, color[1] * intensity, color[2] * intensity]; - } - } - }, - /** - * @return {qtek.light.Spot} - * @memberOf qtek.light.Spot.prototype - */ - clone: function () { - var light = Light.prototype.clone.call(this); - light.range = this.range; - light.umbraAngle = this.umbraAngle; - light.penumbraAngle = this.penumbraAngle; - light.falloffFactor = this.falloffFactor; - light.shadowBias = this.shadowBias; - light.shadowSlopeScale = this.shadowSlopeScale; - return light; - } -}); - -/** - * @constructor qtek.light.Directional - * @extends qtek.Light - * - * @example - * var light = new qtek.light.Directional({ - * intensity: 0.5, - * color: [1.0, 0.0, 0.0] - * }); - * light.position.set(10, 10, 10); - * light.lookAt(qtek.math.Vector3.ZERO); - * scene.add(light); - */ -var DirectionalLight = Light.extend( -/** @lends qtek.light.Directional# */ -{ - /** - * @type {number} - */ - shadowBias: 0.001, - /** - * @type {number} - */ - shadowSlopeScale: 2.0, - /** - * Shadow cascade. - * Use PSSM technique when it is larger than 1 and have a unique directional light in scene. - * @type {number} - */ - shadowCascade: 1, - - /** - * Available when shadowCascade is larger than 1 and have a unique directional light in scene. - * @type {number} - */ - cascadeSplitLogFactor: 0.2 -}, { - - type: 'DIRECTIONAL_LIGHT', + x2 = srcData.data[i + 4]; + } + else if (i % (width * 4) === (width - 1) * 4) { + // right edge + x1 = srcData.data[i - 4]; + x2 = srcData.data[i]; + } + else { + x1 = srcData.data[i - 4]; + x2 = srcData.data[i + 4]; + } - uniformTemplates: { - directionalLightDirection: { - type: '3f', - value: function (instance) { - instance.__dir = instance.__dir || new Vector3(); - // Direction is target to eye - return instance.__dir.copy(instance.worldTransform.z).normalize().negate()._array; + if (i < width * 4) { + // top edge + y1 = srcData.data[i]; + y2 = srcData.data[i + width * 4]; } - }, - directionalLightColor: { - type: '3f', - value: function (instance) { - var color = instance.color; - var intensity = instance.intensity; - return [color[0] * intensity, color[1] * intensity, color[2] * intensity]; + else if (i > width * (height - 1) * 4) { + // bottom edge + y1 = srcData.data[i - width * 4]; + y2 = srcData.data[i]; } + else { + y1 = srcData.data[i - width * 4]; + y2 = srcData.data[i + width * 4]; + } + + dstData.data[i] = (x1 - x2) + 127; + dstData.data[i + 1] = (y1 - y2) + 127; + dstData.data[i + 2] = 255; + dstData.data[i + 3] = 255; } + ctx.putImageData(dstData, 0, 0); + return canvas; }, - /** - * @return {qtek.light.Directional} - * @memberOf qtek.light.Directional.prototype - */ - clone: function () { - var light = Light.prototype.clone.call(this); - light.shadowBias = this.shadowBias; - light.shadowSlopeScale = this.shadowSlopeScale; - return light; - } -}); -/** - * @constructor qtek.light.Point - * @extends qtek.Light - */ -var PointLight = Light.extend( -/** @lends qtek.light.Point# */ -{ /** - * @type {number} + * Convert height map to normal map + * @param {HTMLImageElement|HTMLCanvasElement} image + * @param {boolean} [checkBump=false] + * @param {number} [threshold=20] + * @return {HTMLCanvasElement} */ - range: 100, + isHeightImage: function (img, downScaleSize, threshold) { + if (!img || !img.width || !img.height) { + return false; + } + + var canvas = document.createElement('canvas'); + var ctx = canvas.getContext('2d'); + var size = downScaleSize || 32; + threshold = threshold || 20; + canvas.width = canvas.height = size; + ctx.drawImage(img, 0, 0, size, size); + var srcData = ctx.getImageData(0, 0, size, size); + for (var i = 0; i < srcData.data.length; i += 4) { + var r = srcData.data[i]; + var g = srcData.data[i + 1]; + var b = srcData.data[i + 2]; + var diff = Math.abs(r - g) + Math.abs(g - b); + if (diff > threshold) { + return false; + } + } + return true; + }, + + _fetchTexture: function (path, onsuccess, onerror) { + request.get({ + url: path, + responseType: 'arraybuffer', + onload: onsuccess, + onerror: onerror + }); + }, /** - * @type {number} + * Create a chessboard texture + * @param {number} [size] + * @param {number} [unitSize] + * @param {string} [color1] + * @param {string} [color2] + * @return {clay.Texture2D} */ - castShadow: false -}, { + createChessboard: function (size, unitSize, color1, color2) { + size = size || 512; + unitSize = unitSize || 64; + color1 = color1 || 'black'; + color2 = color2 || 'white'; - type: 'POINT_LIGHT', + var repeat = Math.ceil(size / unitSize); - uniformTemplates: { - pointLightPosition: { - type: '3f', - value: function(instance) { - return instance.getWorldPosition()._array; - } - }, - pointLightRange: { - type: '1f', - value: function(instance) { - return instance.range; - } - }, - pointLightColor: { - type: '3f', - value: function(instance) { - var color = instance.color, - intensity = instance.intensity; - return [ color[0]*intensity, color[1]*intensity, color[2]*intensity ]; + var canvas = document.createElement('canvas'); + canvas.width = size; + canvas.height = size; + var ctx = canvas.getContext('2d'); + ctx.fillStyle = color2; + ctx.fillRect(0, 0, size, size); + + ctx.fillStyle = color1; + for (var i = 0; i < repeat; i++) { + for (var j = 0; j < repeat; j++) { + var isFill = j % 2 ? (i % 2) : (i % 2 - 1); + if (isFill) { + ctx.fillRect(i * unitSize, j * unitSize, unitSize, unitSize); + } } } + + var texture = new Texture2D({ + image: canvas, + anisotropic: 8 + }); + + return texture; }, + /** - * @return {qtek.light.Point} - * @memberOf qtek.light.Point.prototype + * Create a blank pure color 1x1 texture + * @param {string} color + * @return {clay.Texture2D} */ - clone: function() { - var light = Light.prototype.clone.call(this); - light.range = this.range; - return light; + createBlank: function (color) { + var canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + var ctx = canvas.getContext('2d'); + ctx.fillStyle = color; + ctx.fillRect(0, 0, 1, 1); + + var texture = new Texture2D({ + image: canvas + }); + + return texture; } -}); +}; -var vertexEssl = "\n@export qtek.compositor.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\nvarying vec2 v_Texcoord;\nvoid main()\n{\n v_Texcoord = texcoord;\n gl_Position = worldViewProjection * vec4(position, 1.0);\n}\n@end"; +var vertexGlsl = "\n@export clay.compositor.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\nvarying vec2 v_Texcoord;\nvoid main()\n{\n v_Texcoord = texcoord;\n gl_Position = worldViewProjection * vec4(position, 1.0);\n}\n@end"; -Shader['import'](vertexEssl); +Shader['import'](vertexGlsl); var planeGeo = new Plane$2(); var mesh = new Mesh({ @@ -23174,11 +23541,11 @@ var mesh = new Mesh({ var camera = new Orthographic(); /** - * @constructor qtek.compositor.Pass - * @extends qtek.core.Base + * @constructor clay.compositor.Pass + * @extends clay.core.Base */ var Pass = Base.extend(function () { - return /** @lends qtek.compositor.Pass# */ { + return /** @lends clay.compositor.Pass# */ { /** * Fragment shader string * @type {string} @@ -23192,7 +23559,7 @@ var Pass = Base.extend(function () { outputs : null, /** - * @type {qtek.Material} + * @type {clay.Material} */ material : null, @@ -23213,29 +23580,23 @@ var Pass = Base.extend(function () { }; }, function() { - var shader = new Shader({ - vertex : Shader.source('qtek.compositor.vertex'), - fragment : this.fragment - }); + var shader = new Shader(Shader.source('clay.compositor.vertex'), this.fragment); var material = new Material({ - shader : shader + shader: shader }); - shader.enableTexturesAll(); + material.enableTexturesAll(); this.material = material; }, -/** @lends qtek.compositor.Pass.prototype */ +/** @lends clay.compositor.Pass.prototype */ { /** * @param {string} name * @param {} value */ setUniform : function(name, value) { - var uniform = this.material.uniforms[name]; - if (uniform) { - uniform.value = value; - } + this.material.setUniform(name, value); }, /** * @param {string} name @@ -23248,7 +23609,7 @@ var Pass = Base.extend(function () { } }, /** - * @param {qtek.Texture} texture + * @param {clay.Texture} texture * @param {number} attachment */ attachOutput : function(texture, attachment) { @@ -23259,7 +23620,7 @@ var Pass = Base.extend(function () { this.outputs[attachment] = texture; }, /** - * @param {qtek.Texture} texture + * @param {clay.Texture} texture */ detachOutput : function(texture) { for (var attachment in this.outputs) { @@ -23289,8 +23650,8 @@ var Pass = Base.extend(function () { frameBuffer.unbind(renderer); }, /** - * @param {qtek.Renderer} renderer - * @param {qtek.FrameBuffer} [frameBuffer] + * @param {clay.Renderer} renderer + * @param {clay.FrameBuffer} [frameBuffer] */ render : function(renderer, frameBuffer) { @@ -23355,15 +23716,13 @@ var Pass = Base.extend(function () { */ renderQuad: function (renderer) { mesh.material = this.material; - renderer.renderQueue([mesh], camera); + renderer.renderPass([mesh], camera); }, /** - * @param {qtek.Renderer} renderer + * @param {clay.Renderer} renderer */ - dispose: function (renderer) { - this.material.dispose(renderer); - } + dispose: function (renderer) {} }); var TexturePool = function () { @@ -23470,10 +23829,9 @@ function isPowerOfTwo$2(width, height) { (height & (height-1)) === 0; } -var shadowmapEssl = "@export qtek.sm.depth.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\n#ifdef SHADOW_TRANSPARENT\nattribute vec2 texcoord : TEXCOORD_0;\n#endif\n@import qtek.chunk.skinning_header\nvarying vec4 v_ViewPosition;\n#ifdef SHADOW_TRANSPARENT\nvarying vec2 v_Texcoord;\n#endif\nvoid main(){\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import qtek.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n v_ViewPosition = worldViewProjection * vec4(skinnedPosition, 1.0);\n gl_Position = v_ViewPosition;\n#ifdef SHADOW_TRANSPARENT\n v_Texcoord = texcoord;\n#endif\n}\n@end\n@export qtek.sm.depth.fragment\nvarying vec4 v_ViewPosition;\n#ifdef SHADOW_TRANSPARENT\nvarying vec2 v_Texcoord;\n#endif\nuniform float bias : 0.001;\nuniform float slopeScale : 1.0;\n#ifdef SHADOW_TRANSPARENT\nuniform sampler2D transparentMap;\n#endif\n@import qtek.util.encode_float\nvoid main(){\n float depth = v_ViewPosition.z / v_ViewPosition.w;\n#ifdef USE_VSM\n depth = depth * 0.5 + 0.5;\n float moment1 = depth;\n float moment2 = depth * depth;\n float dx = dFdx(depth);\n float dy = dFdy(depth);\n moment2 += 0.25*(dx*dx+dy*dy);\n gl_FragColor = vec4(moment1, moment2, 0.0, 1.0);\n#else\n float dx = dFdx(depth);\n float dy = dFdy(depth);\n depth += sqrt(dx*dx + dy*dy) * slopeScale + bias;\n#ifdef SHADOW_TRANSPARENT\n if (texture2D(transparentMap, v_Texcoord).a <= 0.1) {\n gl_FragColor = encodeFloat(0.9999);\n return;\n }\n#endif\n gl_FragColor = encodeFloat(depth * 0.5 + 0.5);\n#endif\n}\n@end\n@export qtek.sm.debug_depth\nuniform sampler2D depthMap;\nvarying vec2 v_Texcoord;\n@import qtek.util.decode_float\nvoid main() {\n vec4 tex = texture2D(depthMap, v_Texcoord);\n#ifdef USE_VSM\n gl_FragColor = vec4(tex.rgb, 1.0);\n#else\n float depth = decodeFloat(tex);\n gl_FragColor = vec4(depth, depth, depth, 1.0);\n#endif\n}\n@end\n@export qtek.sm.distance.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 world : WORLD;\nattribute vec3 position : POSITION;\n@import qtek.chunk.skinning_header\nvarying vec3 v_WorldPosition;\nvoid main (){\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import qtek.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition , 1.0);\n v_WorldPosition = (world * vec4(skinnedPosition, 1.0)).xyz;\n}\n@end\n@export qtek.sm.distance.fragment\nuniform vec3 lightPosition;\nuniform float range : 100;\nvarying vec3 v_WorldPosition;\n@import qtek.util.encode_float\nvoid main(){\n float dist = distance(lightPosition, v_WorldPosition);\n#ifdef USE_VSM\n gl_FragColor = vec4(dist, dist * dist, 0.0, 0.0);\n#else\n dist = dist / range;\n gl_FragColor = encodeFloat(dist);\n#endif\n}\n@end\n@export qtek.plugin.shadow_map_common\n@import qtek.util.decode_float\nfloat tapShadowMap(sampler2D map, vec2 uv, float z){\n vec4 tex = texture2D(map, uv);\n return step(z, decodeFloat(tex) * 2.0 - 1.0);\n}\nfloat pcf(sampler2D map, vec2 uv, float z, float textureSize, vec2 scale) {\n float shadowContrib = tapShadowMap(map, uv, z);\n vec2 offset = vec2(1.0 / textureSize) * scale;\n#ifdef PCF_KERNEL_SIZE\n for (int _idx_ = 0; _idx_ < PCF_KERNEL_SIZE; _idx_++) {{\n shadowContrib += tapShadowMap(map, uv + offset * pcfKernel[_idx_], z);\n }}\n return shadowContrib / float(PCF_KERNEL_SIZE + 1);\n#else\n shadowContrib += tapShadowMap(map, uv+vec2(offset.x, 0.0), z);\n shadowContrib += tapShadowMap(map, uv+vec2(offset.x, offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(-offset.x, offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(0.0, offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(-offset.x, 0.0), z);\n shadowContrib += tapShadowMap(map, uv+vec2(-offset.x, -offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(offset.x, -offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(0.0, -offset.y), z);\n return shadowContrib / 9.0;\n#endif\n}\nfloat pcf(sampler2D map, vec2 uv, float z, float textureSize) {\n return pcf(map, uv, z, textureSize, vec2(1.0));\n}\nfloat chebyshevUpperBound(vec2 moments, float z){\n float p = 0.0;\n z = z * 0.5 + 0.5;\n if (z <= moments.x) {\n p = 1.0;\n }\n float variance = moments.y - moments.x * moments.x;\n variance = max(variance, 0.0000001);\n float mD = moments.x - z;\n float pMax = variance / (variance + mD * mD);\n pMax = clamp((pMax-0.4)/(1.0-0.4), 0.0, 1.0);\n return max(p, pMax);\n}\nfloat computeShadowContrib(\n sampler2D map, mat4 lightVPM, vec3 position, float textureSize, vec2 scale, vec2 offset\n) {\n vec4 posInLightSpace = lightVPM * vec4(position, 1.0);\n posInLightSpace.xyz /= posInLightSpace.w;\n float z = posInLightSpace.z;\n if(all(greaterThan(posInLightSpace.xyz, vec3(-0.99, -0.99, -1.0))) &&\n all(lessThan(posInLightSpace.xyz, vec3(0.99, 0.99, 1.0)))){\n vec2 uv = (posInLightSpace.xy+1.0) / 2.0;\n #ifdef USE_VSM\n vec2 moments = texture2D(map, uv * scale + offset).xy;\n return chebyshevUpperBound(moments, z);\n #else\n return pcf(map, uv * scale + offset, z, textureSize, scale);\n #endif\n }\n return 1.0;\n}\nfloat computeShadowContrib(sampler2D map, mat4 lightVPM, vec3 position, float textureSize) {\n return computeShadowContrib(map, lightVPM, position, textureSize, vec2(1.0), vec2(0.0));\n}\nfloat computeShadowContribOmni(samplerCube map, vec3 direction, float range)\n{\n float dist = length(direction);\n vec4 shadowTex = textureCube(map, direction);\n#ifdef USE_VSM\n vec2 moments = shadowTex.xy;\n float variance = moments.y - moments.x * moments.x;\n float mD = moments.x - dist;\n float p = variance / (variance + mD * mD);\n if(moments.x + 0.001 < dist){\n return clamp(p, 0.0, 1.0);\n }else{\n return 1.0;\n }\n#else\n return step(dist, (decodeFloat(shadowTex) + 0.0002) * range);\n#endif\n}\n@end\n@export qtek.plugin.compute_shadow_map\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT) || defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT) || defined(POINT_LIGHT_SHADOWMAP_COUNT)\n#ifdef SPOT_LIGHT_SHADOWMAP_COUNT\nuniform sampler2D spotLightShadowMaps[SPOT_LIGHT_SHADOWMAP_COUNT];\nuniform mat4 spotLightMatrices[SPOT_LIGHT_SHADOWMAP_COUNT];\nuniform float spotLightShadowMapSizes[SPOT_LIGHT_SHADOWMAP_COUNT];\n#endif\n#ifdef DIRECTIONAL_LIGHT_SHADOWMAP_COUNT\n#if defined(SHADOW_CASCADE)\nuniform sampler2D directionalLightShadowMaps[1];\nuniform mat4 directionalLightMatrices[SHADOW_CASCADE];\nuniform float directionalLightShadowMapSizes[1];\nuniform float shadowCascadeClipsNear[SHADOW_CASCADE];\nuniform float shadowCascadeClipsFar[SHADOW_CASCADE];\n#else\nuniform sampler2D directionalLightShadowMaps[DIRECTIONAL_LIGHT_SHADOWMAP_COUNT];\nuniform mat4 directionalLightMatrices[DIRECTIONAL_LIGHT_SHADOWMAP_COUNT];\nuniform float directionalLightShadowMapSizes[DIRECTIONAL_LIGHT_SHADOWMAP_COUNT];\n#endif\n#endif\n#ifdef POINT_LIGHT_SHADOWMAP_COUNT\nuniform samplerCube pointLightShadowMaps[POINT_LIGHT_SHADOWMAP_COUNT];\nuniform float pointLightShadowMapSizes[POINT_LIGHT_SHADOWMAP_COUNT];\n#endif\nuniform bool shadowEnabled : true;\n#ifdef PCF_KERNEL_SIZE\nuniform vec2 pcfKernel[PCF_KERNEL_SIZE];\n#endif\n@import qtek.plugin.shadow_map_common\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\nvoid computeShadowOfSpotLights(vec3 position, inout float shadowContribs[SPOT_LIGHT_COUNT] ) {\n float shadowContrib;\n for(int _idx_ = 0; _idx_ < SPOT_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n shadowContrib = computeShadowContrib(\n spotLightShadowMaps[_idx_], spotLightMatrices[_idx_], position,\n spotLightShadowMapSizes[_idx_]\n );\n shadowContribs[_idx_] = shadowContrib;\n }}\n for(int _idx_ = SPOT_LIGHT_SHADOWMAP_COUNT; _idx_ < SPOT_LIGHT_COUNT; _idx_++){{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n#ifdef SHADOW_CASCADE\nvoid computeShadowOfDirectionalLights(vec3 position, inout float shadowContribs[DIRECTIONAL_LIGHT_COUNT]){\n float depth = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far)\n / (gl_DepthRange.far - gl_DepthRange.near);\n float shadowContrib;\n shadowContribs[0] = 1.0;\n for (int _idx_ = 0; _idx_ < SHADOW_CASCADE; _idx_++) {{\n if (\n depth >= shadowCascadeClipsNear[_idx_] &&\n depth <= shadowCascadeClipsFar[_idx_]\n ) {\n shadowContrib = computeShadowContrib(\n directionalLightShadowMaps[0], directionalLightMatrices[_idx_], position,\n directionalLightShadowMapSizes[0],\n vec2(1.0 / float(SHADOW_CASCADE), 1.0),\n vec2(float(_idx_) / float(SHADOW_CASCADE), 0.0)\n );\n shadowContribs[0] = shadowContrib;\n }\n }}\n for(int _idx_ = DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#else\nvoid computeShadowOfDirectionalLights(vec3 position, inout float shadowContribs[DIRECTIONAL_LIGHT_COUNT]){\n float shadowContrib;\n for(int _idx_ = 0; _idx_ < DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n shadowContrib = computeShadowContrib(\n directionalLightShadowMaps[_idx_], directionalLightMatrices[_idx_], position,\n directionalLightShadowMapSizes[_idx_]\n );\n shadowContribs[_idx_] = shadowContrib;\n }}\n for(int _idx_ = DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#endif\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\nvoid computeShadowOfPointLights(vec3 position, inout float shadowContribs[POINT_LIGHT_COUNT] ){\n vec3 lightPosition;\n vec3 direction;\n for(int _idx_ = 0; _idx_ < POINT_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n lightPosition = pointLightPosition[_idx_];\n direction = position - lightPosition;\n shadowContribs[_idx_] = computeShadowContribOmni(pointLightShadowMaps[_idx_], direction, pointLightRange[_idx_]);\n }}\n for(int _idx_ = POINT_LIGHT_SHADOWMAP_COUNT; _idx_ < POINT_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#endif\n@end"; +var shadowmapEssl = "@export clay.sm.depth.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\n#ifdef SHADOW_TRANSPARENT\nattribute vec2 texcoord : TEXCOORD_0;\n#endif\n@import clay.chunk.skinning_header\nvarying vec4 v_ViewPosition;\n#ifdef SHADOW_TRANSPARENT\nvarying vec2 v_Texcoord;\n#endif\nvoid main(){\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n v_ViewPosition = worldViewProjection * vec4(skinnedPosition, 1.0);\n gl_Position = v_ViewPosition;\n#ifdef SHADOW_TRANSPARENT\n v_Texcoord = texcoord;\n#endif\n}\n@end\n@export clay.sm.depth.fragment\nvarying vec4 v_ViewPosition;\n#ifdef SHADOW_TRANSPARENT\nvarying vec2 v_Texcoord;\n#endif\nuniform float bias : 0.001;\nuniform float slopeScale : 1.0;\n#ifdef SHADOW_TRANSPARENT\nuniform sampler2D transparentMap;\n#endif\n@import clay.util.encode_float\nvoid main(){\n float depth = v_ViewPosition.z / v_ViewPosition.w;\n#ifdef USE_VSM\n depth = depth * 0.5 + 0.5;\n float moment1 = depth;\n float moment2 = depth * depth;\n float dx = dFdx(depth);\n float dy = dFdy(depth);\n moment2 += 0.25*(dx*dx+dy*dy);\n gl_FragColor = vec4(moment1, moment2, 0.0, 1.0);\n#else\n float dx = dFdx(depth);\n float dy = dFdy(depth);\n depth += sqrt(dx*dx + dy*dy) * slopeScale + bias;\n#ifdef SHADOW_TRANSPARENT\n if (texture2D(transparentMap, v_Texcoord).a <= 0.1) {\n gl_FragColor = encodeFloat(0.9999);\n return;\n }\n#endif\n gl_FragColor = encodeFloat(depth * 0.5 + 0.5);\n#endif\n}\n@end\n@export clay.sm.debug_depth\nuniform sampler2D depthMap;\nvarying vec2 v_Texcoord;\n@import clay.util.decode_float\nvoid main() {\n vec4 tex = texture2D(depthMap, v_Texcoord);\n#ifdef USE_VSM\n gl_FragColor = vec4(tex.rgb, 1.0);\n#else\n float depth = decodeFloat(tex);\n gl_FragColor = vec4(depth, depth, depth, 1.0);\n#endif\n}\n@end\n@export clay.sm.distance.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 world : WORLD;\nattribute vec3 position : POSITION;\n@import clay.chunk.skinning_header\nvarying vec3 v_WorldPosition;\nvoid main (){\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition , 1.0);\n v_WorldPosition = (world * vec4(skinnedPosition, 1.0)).xyz;\n}\n@end\n@export clay.sm.distance.fragment\nuniform vec3 lightPosition;\nuniform float range : 100;\nvarying vec3 v_WorldPosition;\n@import clay.util.encode_float\nvoid main(){\n float dist = distance(lightPosition, v_WorldPosition);\n#ifdef USE_VSM\n gl_FragColor = vec4(dist, dist * dist, 0.0, 0.0);\n#else\n dist = dist / range;\n gl_FragColor = encodeFloat(dist);\n#endif\n}\n@end\n@export clay.plugin.shadow_map_common\n@import clay.util.decode_float\nfloat tapShadowMap(sampler2D map, vec2 uv, float z){\n vec4 tex = texture2D(map, uv);\n return step(z, decodeFloat(tex) * 2.0 - 1.0);\n}\nfloat pcf(sampler2D map, vec2 uv, float z, float textureSize, vec2 scale) {\n float shadowContrib = tapShadowMap(map, uv, z);\n vec2 offset = vec2(1.0 / textureSize) * scale;\n#ifdef PCF_KERNEL_SIZE\n for (int _idx_ = 0; _idx_ < PCF_KERNEL_SIZE; _idx_++) {{\n shadowContrib += tapShadowMap(map, uv + offset * pcfKernel[_idx_], z);\n }}\n return shadowContrib / float(PCF_KERNEL_SIZE + 1);\n#else\n shadowContrib += tapShadowMap(map, uv+vec2(offset.x, 0.0), z);\n shadowContrib += tapShadowMap(map, uv+vec2(offset.x, offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(-offset.x, offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(0.0, offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(-offset.x, 0.0), z);\n shadowContrib += tapShadowMap(map, uv+vec2(-offset.x, -offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(offset.x, -offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(0.0, -offset.y), z);\n return shadowContrib / 9.0;\n#endif\n}\nfloat pcf(sampler2D map, vec2 uv, float z, float textureSize) {\n return pcf(map, uv, z, textureSize, vec2(1.0));\n}\nfloat chebyshevUpperBound(vec2 moments, float z){\n float p = 0.0;\n z = z * 0.5 + 0.5;\n if (z <= moments.x) {\n p = 1.0;\n }\n float variance = moments.y - moments.x * moments.x;\n variance = max(variance, 0.0000001);\n float mD = moments.x - z;\n float pMax = variance / (variance + mD * mD);\n pMax = clamp((pMax-0.4)/(1.0-0.4), 0.0, 1.0);\n return max(p, pMax);\n}\nfloat computeShadowContrib(\n sampler2D map, mat4 lightVPM, vec3 position, float textureSize, vec2 scale, vec2 offset\n) {\n vec4 posInLightSpace = lightVPM * vec4(position, 1.0);\n posInLightSpace.xyz /= posInLightSpace.w;\n float z = posInLightSpace.z;\n if(all(greaterThan(posInLightSpace.xyz, vec3(-0.99, -0.99, -1.0))) &&\n all(lessThan(posInLightSpace.xyz, vec3(0.99, 0.99, 1.0)))){\n vec2 uv = (posInLightSpace.xy+1.0) / 2.0;\n #ifdef USE_VSM\n vec2 moments = texture2D(map, uv * scale + offset).xy;\n return chebyshevUpperBound(moments, z);\n #else\n return pcf(map, uv * scale + offset, z, textureSize, scale);\n #endif\n }\n return 1.0;\n}\nfloat computeShadowContrib(sampler2D map, mat4 lightVPM, vec3 position, float textureSize) {\n return computeShadowContrib(map, lightVPM, position, textureSize, vec2(1.0), vec2(0.0));\n}\nfloat computeShadowContribOmni(samplerCube map, vec3 direction, float range)\n{\n float dist = length(direction);\n vec4 shadowTex = textureCube(map, direction);\n#ifdef USE_VSM\n vec2 moments = shadowTex.xy;\n float variance = moments.y - moments.x * moments.x;\n float mD = moments.x - dist;\n float p = variance / (variance + mD * mD);\n if(moments.x + 0.001 < dist){\n return clamp(p, 0.0, 1.0);\n }else{\n return 1.0;\n }\n#else\n return step(dist, (decodeFloat(shadowTex) + 0.0002) * range);\n#endif\n}\n@end\n@export clay.plugin.compute_shadow_map\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT) || defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT) || defined(POINT_LIGHT_SHADOWMAP_COUNT)\n#ifdef SPOT_LIGHT_SHADOWMAP_COUNT\nuniform sampler2D spotLightShadowMaps[SPOT_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\nuniform mat4 spotLightMatrices[SPOT_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\nuniform float spotLightShadowMapSizes[SPOT_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\n#endif\n#ifdef DIRECTIONAL_LIGHT_SHADOWMAP_COUNT\n#if defined(SHADOW_CASCADE)\nuniform sampler2D directionalLightShadowMaps[1]:unconfigurable;\nuniform mat4 directionalLightMatrices[SHADOW_CASCADE]:unconfigurable;\nuniform float directionalLightShadowMapSizes[1]:unconfigurable;\nuniform float shadowCascadeClipsNear[SHADOW_CASCADE]:unconfigurable;\nuniform float shadowCascadeClipsFar[SHADOW_CASCADE]:unconfigurable;\n#else\nuniform sampler2D directionalLightShadowMaps[DIRECTIONAL_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\nuniform mat4 directionalLightMatrices[DIRECTIONAL_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\nuniform float directionalLightShadowMapSizes[DIRECTIONAL_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\n#endif\n#endif\n#ifdef POINT_LIGHT_SHADOWMAP_COUNT\nuniform samplerCube pointLightShadowMaps[POINT_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\n#endif\nuniform bool shadowEnabled : true;\n#ifdef PCF_KERNEL_SIZE\nuniform vec2 pcfKernel[PCF_KERNEL_SIZE];\n#endif\n@import clay.plugin.shadow_map_common\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\nvoid computeShadowOfSpotLights(vec3 position, inout float shadowContribs[SPOT_LIGHT_COUNT] ) {\n float shadowContrib;\n for(int _idx_ = 0; _idx_ < SPOT_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n shadowContrib = computeShadowContrib(\n spotLightShadowMaps[_idx_], spotLightMatrices[_idx_], position,\n spotLightShadowMapSizes[_idx_]\n );\n shadowContribs[_idx_] = shadowContrib;\n }}\n for(int _idx_ = SPOT_LIGHT_SHADOWMAP_COUNT; _idx_ < SPOT_LIGHT_COUNT; _idx_++){{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n#ifdef SHADOW_CASCADE\nvoid computeShadowOfDirectionalLights(vec3 position, inout float shadowContribs[DIRECTIONAL_LIGHT_COUNT]){\n float depth = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far)\n / (gl_DepthRange.far - gl_DepthRange.near);\n float shadowContrib;\n shadowContribs[0] = 1.0;\n for (int _idx_ = 0; _idx_ < SHADOW_CASCADE; _idx_++) {{\n if (\n depth >= shadowCascadeClipsNear[_idx_] &&\n depth <= shadowCascadeClipsFar[_idx_]\n ) {\n shadowContrib = computeShadowContrib(\n directionalLightShadowMaps[0], directionalLightMatrices[_idx_], position,\n directionalLightShadowMapSizes[0],\n vec2(1.0 / float(SHADOW_CASCADE), 1.0),\n vec2(float(_idx_) / float(SHADOW_CASCADE), 0.0)\n );\n shadowContribs[0] = shadowContrib;\n }\n }}\n for(int _idx_ = DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#else\nvoid computeShadowOfDirectionalLights(vec3 position, inout float shadowContribs[DIRECTIONAL_LIGHT_COUNT]){\n float shadowContrib;\n for(int _idx_ = 0; _idx_ < DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n shadowContrib = computeShadowContrib(\n directionalLightShadowMaps[_idx_], directionalLightMatrices[_idx_], position,\n directionalLightShadowMapSizes[_idx_]\n );\n shadowContribs[_idx_] = shadowContrib;\n }}\n for(int _idx_ = DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#endif\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\nvoid computeShadowOfPointLights(vec3 position, inout float shadowContribs[POINT_LIGHT_COUNT] ){\n vec3 lightPosition;\n vec3 direction;\n for(int _idx_ = 0; _idx_ < POINT_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n lightPosition = pointLightPosition[_idx_];\n direction = position - lightPosition;\n shadowContribs[_idx_] = computeShadowContribOmni(pointLightShadowMaps[_idx_], direction, pointLightRange[_idx_]);\n }}\n for(int _idx_ = POINT_LIGHT_SHADOWMAP_COUNT; _idx_ < POINT_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#endif\n@end"; -var mat4$8 = glmatrix.mat4; -var vec3$15 = glmatrix.vec3; +var mat4$9 = glmatrix.mat4; var targets$1 = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; @@ -23482,11 +23840,11 @@ Shader['import'](shadowmapEssl); /** * Pass rendering shadow map. * - * @constructor qtek.prePass.ShadowMap - * @extends qtek.core.Base + * @constructor clay.prePass.ShadowMap + * @extends clay.core.Base * @example - * var shadowMapPass = new qtek.prePass.ShadowMap({ - * softShadow: qtek.prePass.ShadowMap.VSM + * var shadowMapPass = new clay.prePass.ShadowMap({ + * softShadow: clay.prePass.ShadowMap.VSM * }); * ... * animation.on('frame', function (frameTime) { @@ -23495,10 +23853,10 @@ Shader['import'](shadowmapEssl); * }); */ var ShadowMapPass = Base.extend(function () { - return /** @lends qtek.prePass.ShadowMap# */ { + return /** @lends clay.prePass.ShadowMap# */ { /** * Soft shadow technique. - * Can be {@link qtek.prePass.ShadowMap.PCF} or {@link qtek.prePass.ShadowMap.VSM} + * Can be {@link clay.prePass.ShadowMap.PCF} or {@link clay.prePass.ShadowMap.VSM} * @type {number} */ softShadow: ShadowMapPass.PCF, @@ -23522,7 +23880,7 @@ var ShadowMapPass = Base.extend(function () { 0, -1 ]), - precision: 'mediump', + precision: 'highp', _lastRenderNotCastShadow: false, @@ -23535,26 +23893,24 @@ var ShadowMapPass = Base.extend(function () { 'SPOT_LIGHT': 0 }, - _meshMaterials: {}, _depthMaterials: {}, - _depthShaders: {}, _distanceMaterials: {}, - _opaqueCasters: [], _receivers: [], _lightsCastShadow: [], _lightCameras: {}, + _lightMaterials: {}, _texturePool: new TexturePool() }; }, function () { // Gaussian filter pass for VSM this._gaussianPassH = new Pass({ - fragment: Shader.source('qtek.compositor.gaussian_blur') + fragment: Shader.source('clay.compositor.gaussian_blur') }); this._gaussianPassV = new Pass({ - fragment: Shader.source('qtek.compositor.gaussian_blur') + fragment: Shader.source('clay.compositor.gaussian_blur') }); this._gaussianPassH.setUniform('blurSize', this.shadowBlur); this._gaussianPassH.setUniform('blurDir', 0.0); @@ -23562,18 +23918,21 @@ var ShadowMapPass = Base.extend(function () { this._gaussianPassV.setUniform('blurDir', 1.0); this._outputDepthPass = new Pass({ - fragment: Shader.source('qtek.sm.debug_depth') + fragment: Shader.source('clay.sm.debug_depth') }); }, { /** * Render scene to shadow textures - * @param {qtek.Renderer} renderer - * @param {qtek.Scene} scene - * @param {qtek.Camera} sceneCamera + * @param {clay.Renderer} renderer + * @param {clay.Scene} scene + * @param {clay.Camera} sceneCamera * @param {boolean} [notUpdateScene=false] - * @memberOf qtek.prePass.ShadowMap.prototype + * @memberOf clay.prePass.ShadowMap.prototype */ render: function (renderer, scene, sceneCamera, notUpdateScene) { + if (!sceneCamera) { + sceneCamera = scene.getMainCamera(); + } this.trigger('beforerender', this, renderer, scene, sceneCamera); this._renderShadowPass(renderer, scene, sceneCamera, notUpdateScene); this.trigger('afterrender', this, renderer, scene, sceneCamera); @@ -23581,9 +23940,9 @@ var ShadowMapPass = Base.extend(function () { /** * Debug rendering of shadow textures - * @param {qtek.Renderer} renderer + * @param {clay.Renderer} renderer * @param {number} size - * @memberOf qtek.prePass.ShadowMap.prototype + * @memberOf clay.prePass.ShadowMap.prototype */ renderDebug: function (renderer, size) { renderer.saveClear(); @@ -23592,10 +23951,10 @@ var ShadowMapPass = Base.extend(function () { var width = size || viewport.width / 4; var height = width; if (this.softShadow === ShadowMapPass.VSM) { - this._outputDepthPass.material.shader.define('fragment', 'USE_VSM'); + this._outputDepthPass.material.define('fragment', 'USE_VSM'); } else { - this._outputDepthPass.material.shader.undefine('fragment', 'USE_VSM'); + this._outputDepthPass.material.undefine('fragment', 'USE_VSM'); } for (var name in this._textures) { var texture = this._textures[name]; @@ -23608,134 +23967,7 @@ var ShadowMapPass = Base.extend(function () { renderer.restoreClear(); }, - _bindDepthMaterial: function (casters, bias, slopeScale) { - for (var i = 0; i < casters.length; i++) { - var mesh = casters[i]; - var isShadowTransparent = mesh.material.shadowTransparentMap instanceof Texture2D; - var transparentMap = mesh.material.shadowTransparentMap; - var nJoints = mesh.joints && mesh.joints.length; - var matHashKey; - var shaderHashKey; - if (isShadowTransparent) { - matHashKey = nJoints + '-' + transparentMap.__GUID__; - shaderHashKey = nJoints + '-t'; - } - else { - matHashKey = nJoints; - shaderHashKey = nJoints; - } - if (mesh.useSkinMatricesTexture) { - matHashKey += '-s'; - shaderHashKey += '-s'; - } - // Use custom shadow depth material - var depthMaterial = mesh.shadowDepthMaterial || this._depthMaterials[matHashKey]; - var depthShader = mesh.shadowDepthMaterial ? mesh.shadowDepthMaterial.shader : this._depthShaders[shaderHashKey]; - - if (mesh.material !== depthMaterial) { // Not binded yet - if (!depthShader) { - depthShader = new Shader({ - vertex: Shader.source('qtek.sm.depth.vertex'), - fragment: Shader.source('qtek.sm.depth.fragment'), - precision: this.precision - }); - if (nJoints > 0) { - depthShader.define('vertex', 'SKINNING'); - depthShader.define('vertex', 'JOINT_COUNT', nJoints); - } - if (isShadowTransparent) { - depthShader.define('both', 'SHADOW_TRANSPARENT'); - } - if (mesh.useSkinMatricesTexture) { - depthShader.define('vertex', 'USE_SKIN_MATRICES_TEXTURE'); - } - this._depthShaders[shaderHashKey] = depthShader; - } - if (!depthMaterial) { - // Skinned mesh - depthMaterial = new Material({ - shader: depthShader - }); - this._depthMaterials[matHashKey] = depthMaterial; - } - - mesh.material = depthMaterial; - - if (this.softShadow === ShadowMapPass.VSM) { - depthShader.define('fragment', 'USE_VSM'); - } - else { - depthShader.undefine('fragment', 'USE_VSM'); - } - - depthMaterial.setUniform('bias', bias); - depthMaterial.setUniform('slopeScale', slopeScale); - if (isShadowTransparent) { - depthMaterial.set('shadowTransparentMap', transparentMap); - } - } - } - }, - - _bindDistanceMaterial: function (casters, light) { - var lightPosition = light.getWorldPosition()._array; - for (var i = 0; i < casters.length; i++) { - var mesh = casters[i]; - var nJoints = mesh.joints && mesh.joints.length; - var distanceMaterial = this._distanceMaterials[nJoints]; - if (mesh.material !== distanceMaterial) { - if (!distanceMaterial) { - // Skinned mesh - distanceMaterial = new Material({ - shader: new Shader({ - vertex: Shader.source('qtek.sm.distance.vertex'), - fragment: Shader.source('qtek.sm.distance.fragment'), - precision: this.precision - }) - }); - if (nJoints > 0) { - distanceMaterial.shader.define('vertex', 'SKINNING'); - distanceMaterial.shader.define('vertex', 'JOINT_COUNT', nJoints); - } - this._distanceMaterials[nJoints] = distanceMaterial; - } - mesh.material = distanceMaterial; - - if (this.softShadow === ShadowMapPass.VSM) { - distanceMaterial.shader.define('fragment', 'USE_VSM'); - } - else { - distanceMaterial.shader.undefine('fragment', 'USE_VSM'); - } - } - - distanceMaterial.set('lightPosition', lightPosition); - distanceMaterial.set('range', light.range); - } - }, - - saveMaterial: function (casters) { - for (var i = 0; i < casters.length; i++) { - var mesh = casters[i]; - this._meshMaterials[mesh.__GUID__] = mesh.material; - } - }, - - restoreMaterial: function (casters) { - for (var i = 0; i < casters.length; i++) { - var mesh = casters[i]; - var material = this._meshMaterials[mesh.__GUID__]; - // In case restoreMaterial when no shadowMap is rendered - if (material) { - mesh.material = material; - } - } - }, - - _updateCasterAndReceiver: function (renderer, mesh) { - if (mesh.castShadow) { - this._opaqueCasters.push(mesh); - } + _updateReceivers: function (renderer, mesh) { if (mesh.receiveShadow) { this._receivers.push(mesh); mesh.material.set('shadowEnabled', 1); @@ -23746,38 +23978,33 @@ var ShadowMapPass = Base.extend(function () { mesh.material.set('shadowEnabled', 0); } - if (!mesh.material.shader && mesh.material.updateShader) { - mesh.material.updateShader(renderer); - } - var shader = mesh.material.shader; if (this.softShadow === ShadowMapPass.VSM) { - shader.define('fragment', 'USE_VSM'); - shader.undefine('fragment', 'PCF_KERNEL_SIZE'); + mesh.material.define('fragment', 'USE_VSM'); + mesh.material.undefine('fragment', 'PCF_KERNEL_SIZE'); } else { - shader.undefine('fragment', 'USE_VSM'); + mesh.material.undefine('fragment', 'USE_VSM'); var kernelPCF = this.kernelPCF; if (kernelPCF && kernelPCF.length) { - shader.define('fragment', 'PCF_KERNEL_SIZE', kernelPCF.length / 2); + mesh.material.define('fragment', 'PCF_KERNEL_SIZE', kernelPCF.length / 2); } else { - shader.undefine('fragment', 'PCF_KERNEL_SIZE'); + mesh.material.undefine('fragment', 'PCF_KERNEL_SIZE'); } } }, _update: function (renderer, scene) { - for (var i = 0; i < scene.opaqueQueue.length; i++) { - this._updateCasterAndReceiver(renderer, scene.opaqueQueue[i]); - } - for (var i = 0; i < scene.transparentQueue.length; i++) { - // TODO Transparent object receive shadow will be very slow - // in stealth demo, still not find the reason - this._updateCasterAndReceiver(renderer, scene.transparentQueue[i]); - } + var self = this; + scene.traverse(function (renderable) { + if (renderable.isRenderable()) { + self._updateReceivers(renderer, renderable); + } + }); + for (var i = 0; i < scene.lights.length; i++) { var light = scene.lights[i]; - if (light.castShadow) { + if (light.castShadow && !light.invisible) { this._lightsCastShadow.push(light); } } @@ -23789,7 +24016,6 @@ var ShadowMapPass = Base.extend(function () { this._shadowMapNumber[name] = 0; } this._lightsCastShadow.length = 0; - this._opaqueCasters.length = 0; this._receivers.length = 0; var _gl = renderer.gl; @@ -23798,9 +24024,10 @@ var ShadowMapPass = Base.extend(function () { scene.update(); } if (sceneCamera) { - sceneCamera.update(); + sceneCamera.update(); } + scene.updateLights(); this._update(renderer, scene); // Needs to update the receivers again if shadows come from 1 to 0. @@ -23827,25 +24054,22 @@ var ShadowMapPass = Base.extend(function () { var shadowCascadeClips = []; var pointLightShadowMaps = []; - this.saveMaterial(this._opaqueCasters); - var dirLightHasCascade; // Create textures for shadow map for (var i = 0; i < this._lightsCastShadow.length; i++) { var light = this._lightsCastShadow[i]; - if (light instanceof DirectionalLight) { + if (light.type === 'DIRECTIONAL_LIGHT') { if (dirLightHasCascade) { - console.warn('Only one dire light supported with shadow cascade'); + console.warn('Only one direectional light supported with shadow cascade'); + continue; + } + if (light.shadowCascade > 4) { + console.warn('Support at most 4 cascade'); continue; } if (light.shadowCascade > 1) { dirLightHasCascade = light; - - if (light.shadowCascade > 4) { - console.warn('Support at most 4 cascade'); - continue; - } } this.renderDirectionalLightShadow( @@ -23853,106 +24077,96 @@ var ShadowMapPass = Base.extend(function () { scene, sceneCamera, light, - this._opaqueCasters, shadowCascadeClips, directionalLightMatrices, directionalLightShadowMaps ); } - else if (light instanceof SpotLight) { + else if (light.type === 'SPOT_LIGHT') { this.renderSpotLightShadow( renderer, + scene, light, - this._opaqueCasters, spotLightMatrices, spotLightShadowMaps ); } - else if (light instanceof PointLight) { + else if (light.type === 'POINT_LIGHT') { this.renderPointLightShadow( renderer, + scene, light, - this._opaqueCasters, pointLightShadowMaps ); } this._shadowMapNumber[light.type]++; } - this.restoreMaterial(this._opaqueCasters); - - var shadowCascadeClipsNear = shadowCascadeClips.slice(); - var shadowCascadeClipsFar = shadowCascadeClips.slice(); - shadowCascadeClipsNear.pop(); - shadowCascadeClipsFar.shift(); - // Iterate from far to near - shadowCascadeClipsNear.reverse(); - shadowCascadeClipsFar.reverse(); - // directionalLightShadowMaps.reverse(); - directionalLightMatrices.reverse(); - - function getSize(texture) { - return texture.height; + for (var lightType in this._shadowMapNumber) { + var number = this._shadowMapNumber[lightType]; + var key = lightType + '_SHADOWMAP_COUNT'; + for (var i = 0; i < this._receivers.length; i++) { + var mesh = this._receivers[i]; + var material = mesh.material; + if (material.fragmentDefines[key] !== number) { + if (number > 0) { + material.define('fragment', key, number); + } + else if (material.isDefined('fragment', key)) { + material.undefine('fragment', key); + } + } + } } - var spotLightShadowMapSizes = spotLightShadowMaps.map(getSize); - var directionalLightShadowMapSizes = directionalLightShadowMaps.map(getSize); - - var shadowDefineUpdatedShader = {}; - for (var i = 0; i < this._receivers.length; i++) { var mesh = this._receivers[i]; var material = mesh.material; - - var shader = material.shader; - - if (!shadowDefineUpdatedShader[shader.__GUID__]) { - var shaderNeedsUpdate = false; - for (var lightType in this._shadowMapNumber) { - var number = this._shadowMapNumber[lightType]; - var key = lightType + '_SHADOWMAP_COUNT'; - - if (shader.fragmentDefines[key] !== number) { - if (number > 0) { - shader.fragmentDefines[key] = number; - shaderNeedsUpdate = true; - } - else if (shader.isDefined('fragment', key)) { - shader.undefine('fragment', key); - shaderNeedsUpdate = true; - } - } - } - if (shaderNeedsUpdate) { - shader.dirty(); - } - if (dirLightHasCascade) { - shader.define('fragment', 'SHADOW_CASCADE', dirLightHasCascade.shadowCascade); - } - else { - shader.undefine('fragment', 'SHADOW_CASCADE'); - } - shadowDefineUpdatedShader[shader.__GUID__] = true; - } - - if (spotLightShadowMaps.length > 0) { - material.setUniform('spotLightShadowMaps', spotLightShadowMaps); - material.setUniform('spotLightMatrices', spotLightMatrices); - material.setUniform('spotLightShadowMapSizes', spotLightShadowMapSizes); + if (dirLightHasCascade) { + material.define('fragment', 'SHADOW_CASCADE', dirLightHasCascade.shadowCascade); } - if (directionalLightShadowMaps.length > 0) { - material.setUniform('directionalLightShadowMaps', directionalLightShadowMaps); - if (dirLightHasCascade) { - material.setUniform('shadowCascadeClipsNear', shadowCascadeClipsNear); - material.setUniform('shadowCascadeClipsFar', shadowCascadeClipsFar); - } - material.setUniform('directionalLightMatrices', directionalLightMatrices); - material.setUniform('directionalLightShadowMapSizes', directionalLightShadowMapSizes); + else { + material.undefine('fragment', 'SHADOW_CASCADE'); } - if (pointLightShadowMaps.length > 0) { - material.setUniform('pointLightShadowMaps', pointLightShadowMaps); + } + + var shadowUniforms = scene.shadowUniforms; + + function getSize(texture) { + return texture.height; + } + if (directionalLightShadowMaps.length > 0) { + var directionalLightShadowMapSizes = directionalLightShadowMaps.map(getSize); + shadowUniforms.directionalLightShadowMaps = { value: directionalLightShadowMaps, type: 'tv' }; + shadowUniforms.directionalLightMatrices = { value: directionalLightMatrices, type: 'm4v' }; + shadowUniforms.directionalLightShadowMapSizes = { value: directionalLightShadowMapSizes, type: '1fv' }; + if (dirLightHasCascade) { + var shadowCascadeClipsNear = shadowCascadeClips.slice(); + var shadowCascadeClipsFar = shadowCascadeClips.slice(); + shadowCascadeClipsNear.pop(); + shadowCascadeClipsFar.shift(); + + // Iterate from far to near + shadowCascadeClipsNear.reverse(); + shadowCascadeClipsFar.reverse(); + // directionalLightShadowMaps.reverse(); + directionalLightMatrices.reverse(); + shadowUniforms.shadowCascadeClipsNear = { value: shadowCascadeClipsNear, type: '1fv' }; + shadowUniforms.shadowCascadeClipsFar = { value: shadowCascadeClipsFar, type: '1fv' }; } } + + if (spotLightShadowMaps.length > 0) { + var spotLightShadowMapSizes = spotLightShadowMaps.map(getSize); + var shadowUniforms = scene.shadowUniforms; + shadowUniforms.spotLightShadowMaps = { value: spotLightShadowMaps, type: 'tv' }; + shadowUniforms.spotLightMatrices = { value: spotLightMatrices, type: 'm4v' }; + shadowUniforms.spotLightShadowMapSizes = { value: spotLightShadowMapSizes, type: '1fv' }; + } + + if (pointLightShadowMaps.length > 0) { + shadowUniforms.pointLightShadowMaps = { value: pointLightShadowMaps, type: 'tv' }; + } }, renderDirectionalLightShadow: (function () { @@ -23965,12 +24179,18 @@ var ShadowMapPass = Base.extend(function () { var lightViewProjMatrix = new Matrix4(); var lightProjMatrix = new Matrix4(); - return function (renderer, scene, sceneCamera, light, casters, shadowCascadeClips, directionalLightMatrices, directionalLightShadowMaps) { - - var shadowBias = light.shadowBias; - this._bindDepthMaterial(casters, shadowBias, light.shadowSlopeScale); + return function (renderer, scene, sceneCamera, light, shadowCascadeClips, directionalLightMatrices, directionalLightShadowMaps) { - casters.sort(Renderer.opaqueSortFunc); + var defaultShadowMaterial = this._getDepthMaterial(light); + var passConfig = { + getMaterial: function (renderable) { + return renderable.shadowDepthMaterial || defaultShadowMaterial; + }, + ifRender: function (renderable) { + return renderable.castShadow; + }, + sortCompare: Renderer.opaqueSortCompare + }; // First frame if (!scene.viewBoundingBoxLastFrame.isFinite()) { @@ -23985,11 +24205,11 @@ var ShadowMapPass = Base.extend(function () { var lightCamera = this._getDirectionalLightCamera(light, scene, sceneCamera); - var lvpMat4Arr = lightViewProjMatrix._array; + var lvpMat4Arr = lightViewProjMatrix.array; lightProjMatrix.copy(lightCamera.projectionMatrix); - mat4$8.invert(lightViewMatrix._array, lightCamera.worldTransform._array); - mat4$8.multiply(lightViewMatrix._array, lightViewMatrix._array, sceneCamera.worldTransform._array); - mat4$8.multiply(lvpMat4Arr, lightProjMatrix._array, lightViewMatrix._array); + mat4$9.invert(lightViewMatrix.array, lightCamera.worldTransform.array); + mat4$9.multiply(lightViewMatrix.array, lightViewMatrix.array, sceneCamera.worldTransform.array); + mat4$9.multiply(lvpMat4Arr, lightProjMatrix.array, lightViewMatrix.array); var clipPlanes = []; var isPerspective = sceneCamera instanceof Perspective; @@ -24018,11 +24238,11 @@ var ShadowMapPass = Base.extend(function () { var nearPlane = clipPlanes[i]; var farPlane = clipPlanes[i + 1]; if (isPerspective) { - mat4$8.perspective(splitProjMatrix._array, sceneCamera.fov / 180 * Math.PI, sceneCamera.aspect, nearPlane, farPlane); + mat4$9.perspective(splitProjMatrix.array, sceneCamera.fov / 180 * Math.PI, sceneCamera.aspect, nearPlane, farPlane); } else { - mat4$8.ortho( - splitProjMatrix._array, + mat4$9.ortho( + splitProjMatrix.array, sceneCamera.left, sceneCamera.right, sceneCamera.bottom, sceneCamera.top, nearPlane, farPlane ); @@ -24030,8 +24250,8 @@ var ShadowMapPass = Base.extend(function () { splitFrustum.setFromProjection(splitProjMatrix); splitFrustum.getTransformedBoundingBox(cropBBox, lightViewMatrix); cropBBox.applyProjection(lightProjMatrix); - var _min = cropBBox.min._array; - var _max = cropBBox.max._array; + var _min = cropBBox.min.array; + var _max = cropBBox.max.array; _min[0] = Math.max(_min[0], -1); _min[1] = Math.max(_min[1], -1); _max[0] = Math.min(_max[0], 1); @@ -24044,13 +24264,8 @@ var ShadowMapPass = Base.extend(function () { // Reversed, left to right => far to near renderer.setViewport((light.shadowCascade - i - 1) * shadowSize, 0, shadowSize, shadowSize, 1); - // Set bias seperately for each cascade - // TODO Simply divide 1.5 ? - for (var key in this._depthMaterials) { - this._depthMaterials[key].set('shadowBias', shadowBias); - } - - renderer.renderQueue(casters, lightCamera); + var renderList = scene.updateRenderList(lightCamera); + renderer.renderPass(renderList.opaque, lightCamera, passConfig); // Filter for VSM if (this.softShadow === ShadowMapPass.VSM) { @@ -24061,7 +24276,7 @@ var ShadowMapPass = Base.extend(function () { matrix.copy(lightCamera.viewMatrix) .multiplyLeft(lightCamera.projectionMatrix); - directionalLightMatrices.push(matrix._array); + directionalLightMatrices.push(matrix.array); lightCamera.projectionMatrix.copy(lightProjMatrix); } @@ -24072,13 +24287,10 @@ var ShadowMapPass = Base.extend(function () { }; })(), - renderSpotLightShadow: function (renderer, light, casters, spotLightMatrices, spotLightShadowMaps) { - - this._bindDepthMaterial(casters, light.shadowBias, light.shadowSlopeScale); - casters.sort(Renderer.opaqueSortFunc); + renderSpotLightShadow: function (renderer, scene, light, spotLightMatrices, spotLightShadowMaps) { var texture = this._getTexture(light); - var camera = this._getSpotLightCamera(light); + var lightCamera = this._getSpotLightCamera(light); var _gl = renderer.gl; this._frameBuffer.attach(texture); @@ -24086,7 +24298,19 @@ var ShadowMapPass = Base.extend(function () { _gl.clear(_gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT); - renderer.renderQueue(casters, camera); + var defaultShadowMaterial = this._getDepthMaterial(light); + var passConfig = { + getMaterial: function (renderable) { + return renderable.shadowDepthMaterial || defaultShadowMaterial; + }, + ifRender: function (renderable) { + return renderable.castShadow; + }, + sortCompare: Renderer.opaqueSortCompare + }; + + var renderList = scene.updateRenderList(lightCamera); + renderer.renderPass(renderList.opaque, lightCamera, passConfig); this._frameBuffer.unbind(renderer); @@ -24096,20 +24320,92 @@ var ShadowMapPass = Base.extend(function () { } var matrix = new Matrix4(); - matrix.copy(camera.worldTransform) + matrix.copy(lightCamera.worldTransform) .invert() - .multiplyLeft(camera.projectionMatrix); + .multiplyLeft(lightCamera.projectionMatrix); spotLightShadowMaps.push(texture); - spotLightMatrices.push(matrix._array); + spotLightMatrices.push(matrix.array); }, - renderPointLightShadow: function (renderer, light, casters, pointLightShadowMaps) { + renderPointLightShadow: function (renderer, scene, light, pointLightShadowMaps) { var texture = this._getTexture(light); var _gl = renderer.gl; pointLightShadowMaps.push(texture); - this._bindDistanceMaterial(casters, light); + var defaultShadowMaterial = this._getDepthMaterial(light); + var passConfig = { + getMaterial: function (renderable) { + return renderable.shadowDepthMaterial || defaultShadowMaterial; + }, + sortCompare: Renderer.opaqueSortCompare + }; + + var renderListEachSide = { + px: [], py: [], pz: [], nx: [], ny: [], nz: [] + }; + var bbox = new BoundingBox(); + var lightWorldPosition = light.getWorldPosition().array; + var lightBBox = new BoundingBox(); + var range = light.range; + lightBBox.min.setArray(lightWorldPosition); + lightBBox.max.setArray(lightWorldPosition); + var extent = new Vector3(range, range, range); + lightBBox.max.add(extent); + lightBBox.min.sub(extent); + + var targetsNeedRender = { px: false, py: false, pz: false, nx: false, ny: false, nz: false }; + scene.traverse(function (renderable) { + if (renderable.isRenderable() && renderable.castShadow) { + var geometry = renderable.geometry; + if (!geometry.boundingBox) { + for (var i = 0; i < targets$1.length; i++) { + renderListEachSide[targets$1[i]].push(renderable); + } + return; + } + bbox.transformFrom(geometry.boundingBox, renderable.worldTransform); + if (!bbox.intersectBoundingBox(lightBBox)) { + return; + } + + bbox.updateVertices(); + for (var i = 0; i < targets$1.length; i++) { + targetsNeedRender[targets$1[i]] = false; + } + for (var i = 0; i < 8; i++) { + var vtx = bbox.vertices[i]; + var x = vtx[0] - lightWorldPosition[0]; + var y = vtx[1] - lightWorldPosition[1]; + var z = vtx[2] - lightWorldPosition[2]; + var absx = Math.abs(x); + var absy = Math.abs(y); + var absz = Math.abs(z); + if (absx > absy) { + if (absx > absz) { + targetsNeedRender[x > 0 ? 'px' : 'nx'] = true; + } + else { + targetsNeedRender[z > 0 ? 'pz' : 'nz'] = true; + } + } + else { + if (absy > absz) { + targetsNeedRender[y > 0 ? 'py' : 'ny'] = true; + } + else { + targetsNeedRender[z > 0 ? 'pz' : 'nz'] = true; + } + } + } + for (var i = 0; i < targets$1.length; i++) { + if (targetsNeedRender[targets$1[i]]) { + renderListEachSide[targets$1[i]].push(renderable); + } + } + } + }); + for (var i = 0; i < 6; i++) { var target = targets$1[i]; var camera = this._getPointLightCamera(light, target); @@ -24118,18 +24414,51 @@ var ShadowMapPass = Base.extend(function () { this._frameBuffer.bind(renderer); _gl.clear(_gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT); - renderer.renderQueue(casters, camera); + renderer.renderPass(renderListEachSide[target], camera, passConfig); } - this._frameBuffer.unbind(renderer); + + this._frameBuffer.unbind(renderer); + }, + + _getDepthMaterial: function (light) { + var shadowMaterial = this._lightMaterials[light.__uid__]; + var isPointLight = light.type === 'POINT_LIGHT'; + if (!shadowMaterial) { + var shaderPrefix = isPointLight ? 'clay.sm.distance.' : 'clay.sm.depth.'; + shadowMaterial = new Material({ + precision: this.precision, + shader: new Shader(Shader.source(shaderPrefix + 'vertex'), Shader.source(shaderPrefix + 'fragment')) + }); + + this._lightMaterials[light.__uid__] = shadowMaterial; + } + if (light.shadowSlopeScale != null) { + shadowMaterial.setUniform('slopeScale', light.shadowSlopeScale); + } + if (light.shadowBias != null) { + shadowMaterial.setUniform('bias', light.shadowBias); + } + if (this.softShadow === ShadowMapPass.VSM) { + shadowMaterial.define('fragment', 'USE_VSM'); + } + else { + shadowMaterial.undefine('fragment', 'USE_VSM'); + } + + if (isPointLight) { + shadowMaterial.set('lightPosition', light.getWorldPosition().array); + shadowMaterial.set('range', light.range); + } + + return shadowMaterial; }, _gaussianFilter: function (renderer, texture, size) { var parameter = { width: size, height: size, - type: Texture.FLOAT + type: Texture$1.FLOAT }; - var _gl = renderer.gl; var tmpTexture = this._texturePool.get(parameter); this._frameBuffer.attach(tmpTexture); @@ -24148,12 +24477,12 @@ var ShadowMapPass = Base.extend(function () { }, _getTexture: function (light, cascade) { - var key = light.__GUID__; + var key = light.__uid__; var texture = this._textures[key]; var resolution = light.shadowResolution || 512; cascade = cascade || 1; if (!texture) { - if (light instanceof PointLight) { + if (light.type === 'POINT_LIGHT') { texture = new TextureCube(); } else { @@ -24164,7 +24493,7 @@ var ShadowMapPass = Base.extend(function () { texture.width = resolution * cascade; texture.height = resolution; if (this.softShadow === ShadowMapPass.VSM) { - texture.type = Texture.FLOAT; + texture.type = Texture$1.FLOAT; texture.anisotropic = 4; } else { @@ -24250,8 +24579,8 @@ var ShadowMapPass = Base.extend(function () { lightViewBBox.copy(sceneViewBoundingBox).applyTransform(lightViewMatrix); - var min = lightViewBBox.min._array; - var max = lightViewBBox.max._array; + var min = lightViewBBox.min.array; + var max = lightViewBBox.max.array; // Move camera to adjust the near to 0 camera.position.set((min[0] + max[0]) / 2, (min[1] + max[1]) / 2, max[2]) @@ -24285,28 +24614,19 @@ var ShadowMapPass = Base.extend(function () { camera.far = light.range; camera.worldTransform.copy(light.worldTransform); camera.updateProjectionMatrix(); - mat4$8.invert(camera.viewMatrix._array, camera.worldTransform._array); + mat4$9.invert(camera.viewMatrix.array, camera.worldTransform.array); return camera; }, /** - * @param {qtek.Renderer|WebGLRenderingContext} [renderer] - * @memberOf qtek.prePass.ShadowMap.prototype + * @param {clay.Renderer|WebGLRenderingContext} [renderer] + * @memberOf clay.prePass.ShadowMap.prototype */ // PENDING Renderer or WebGLRenderingContext dispose: function (renderer) { var _gl = renderer.gl || renderer; - for (var guid in this._depthMaterials) { - var mat = this._depthMaterials[guid]; - mat.dispose(_gl); - } - for (var guid in this._distanceMaterials) { - var mat = this._distanceMaterials[guid]; - mat.dispose(_gl); - } - if (this._frameBuffer) { this._frameBuffer.dispose(_gl); } @@ -24331,30 +24651,28 @@ var ShadowMapPass = Base.extend(function () { for (var i = 0; i < this._receivers.length; i++) { var mesh = this._receivers[i]; // Mesh may be disposed - if (mesh.material && mesh.material.shader) { + if (mesh.material) { var material = mesh.material; - var shader = material.shader; - shader.undefine('fragment', 'POINT_LIGHT_SHADOW_COUNT'); - shader.undefine('fragment', 'DIRECTIONAL_LIGHT_SHADOW_COUNT'); - shader.undefine('fragment', 'AMBIENT_LIGHT_SHADOW_COUNT'); + material.undefine('fragment', 'POINT_LIGHT_SHADOW_COUNT'); + material.undefine('fragment', 'DIRECTIONAL_LIGHT_SHADOW_COUNT'); + material.undefine('fragment', 'AMBIENT_LIGHT_SHADOW_COUNT'); material.set('shadowEnabled', 0); } } - this._opaqueCasters = []; this._receivers = []; this._lightsCastShadow = []; } }); /** - * @name qtek.prePass.ShadowMap.VSM + * @name clay.prePass.ShadowMap.VSM * @type {number} */ ShadowMapPass.VSM = 1; /** - * @name qtek.prePass.ShadowMap.PCF + * @name clay.prePass.ShadowMap.PCF * @type {number} */ ShadowMapPass.PCF = 2; @@ -24365,12 +24683,12 @@ ShadowMapPass.PCF = 2; /** * Node of graph based post processing. * - * @constructor qtek.compositor.Node - * @extends qtek.core.Base + * @constructor clay.compositor.CompositorNode + * @extends clay.core.Base * */ -var Node$2 = Base.extend(function () { - return /** @lends qtek.compositor.Node# */ { +var CompositorNode = Base.extend(function () { + return /** @lends clay.compositor.CompositorNode# */ { /** * @type {string} */ @@ -24413,7 +24731,7 @@ var Node$2 = Base.extend(function () { _compositor: null }; }, -/** @lends qtek.compositor.Node.prototype */ +/** @lends clay.compositor.CompositorNode.prototype */ { // TODO Remove parameter function callback @@ -24553,8 +24871,7 @@ var Node$2 = Base.extend(function () { }); // Enabled the pin texture in shader - var shader = this.pass.material.shader; - shader.enableTexture(inputPinName); + this.pass.material.enableTexture(inputPinName); }, clear: function () { @@ -24604,18 +24921,18 @@ var Node$2 = Base.extend(function () { }); /** - * @constructor qtek.compositor.Graph - * @extends qtek.core.Base + * @constructor clay.compositor.Graph + * @extends clay.core.Base */ var Graph = Base.extend(function () { - return /** @lends qtek.compositor.Graph# */ { + return /** @lends clay.compositor.Graph# */ { /** - * @type {Array.} + * @type {Array.} */ nodes: [] }; }, -/** @lends qtek.compositor.Graph.prototype */ +/** @lends clay.compositor.Graph.prototype */ { /** @@ -24625,7 +24942,7 @@ var Graph = Base.extend(function () { this._dirty = true; }, /** - * @param {qtek.compositor.Node} node + * @param {clay.compositor.CompositorNode} node */ addNode: function (node) { @@ -24638,7 +24955,7 @@ var Graph = Base.extend(function () { this._dirty = true; }, /** - * @param {qtek.compositor.Node|string} node + * @param {clay.compositor.CompositorNode|string} node */ removeNode: function (node) { if (typeof node === 'string') { @@ -24652,7 +24969,7 @@ var Graph = Base.extend(function () { }, /** * @param {string} name - * @return {qtek.compositor.Node} + * @return {clay.compositor.CompositorNode} */ getNodeByName: function (name) { for (var i = 0; i < this.nodes.length; i++) { @@ -24704,7 +25021,7 @@ var Graph = Base.extend(function () { findPin: function (input) { var node; // Try to take input as a directly a node - if (typeof input === 'string' || input instanceof Node$2) { + if (typeof input === 'string' || input instanceof CompositorNode) { input = { node: input }; @@ -24742,8 +25059,8 @@ var Graph = Base.extend(function () { /** * Compositor provide graph based post processing * - * @constructor qtek.compositor.Compositor - * @extends qtek.compositor.Graph + * @constructor clay.compositor.Compositor + * @extends clay.compositor.Graph * */ var Compositor = Graph.extend(function() { @@ -24758,14 +25075,14 @@ var Compositor = Graph.extend(function() { }) }; }, -/** @lends qtek.compositor.Compositor.prototype */ +/** @lends clay.compositor.Compositor.prototype */ { addNode: function(node) { Graph.prototype.addNode.call(this, node); node._compositor = this; }, /** - * @param {qtek.Renderer} renderer + * @param {clay.Renderer} renderer */ render: function(renderer, frameBuffer) { if (this._dirty) { @@ -24813,7 +25130,7 @@ var Compositor = Graph.extend(function() { /** * Dispose compositor - * @param {qtek.Renderer} renderer + * @param {clay.Renderer} renderer */ dispose: function (renderer) { this._texturePool.clear(renderer); @@ -24821,19 +25138,19 @@ var Compositor = Graph.extend(function() { }); /** - * @constructor qtek.compositor.SceneNode - * @extends qtek.compositor.Node + * @constructor clay.compositor.SceneNode + * @extends clay.compositor.CompositorNode */ -var SceneNode = Node$2.extend( -/** @lends qtek.compositor.SceneNode# */ +var SceneNode = CompositorNode.extend( +/** @lends clay.compositor.SceneNode# */ { name: 'scene', /** - * @type {qtek.Scene} + * @type {clay.Scene} */ scene: null, /** - * @type {qtek.Camera} + * @type {clay.Camera} */ camera: null, /** @@ -24911,13 +25228,13 @@ var SceneNode = Node$2.extend( }); /** - * @constructor qtek.compositor.TextureNode - * @extends qtek.compositor.Node + * @constructor clay.compositor.TextureNode + * @extends clay.compositor.CompositorNode */ -var TextureNode = Node$2.extend(function() { - return /** @lends qtek.compositor.TextureNode# */ { +var TextureNode = CompositorNode.extend(function() { + return /** @lends clay.compositor.TextureNode# */ { /** - * @type {qtek.Texture2D} + * @type {clay.Texture2D} */ texture: null, @@ -24947,13 +25264,13 @@ var TextureNode = Node$2.extend(function() { /** * Filter node * - * @constructor qtek.compositor.FilterNode - * @extends qtek.compositor.Node + * @constructor clay.compositor.FilterNode + * @extends clay.compositor.CompositorNode * * @example - var node = new qtek.compositor.Node({ + var node = new clay.compositor.FilterNode({ name: 'fxaa', - shader: qtek.Shader.source('qtek.compositor.fxaa'), + shader: clay.Shader.source('clay.compositor.fxaa'), inputs: { texture: { node: 'scene', @@ -24963,9 +25280,9 @@ var TextureNode = Node$2.extend(function() { // Multiple outputs is preserved for MRT support in WebGL2.0 outputs: { color: { - attachment: qtek.FrameBuffer.COLOR_ATTACHMENT0 + attachment: clay.FrameBuffer.COLOR_ATTACHMENT0 parameters: { - format: qtek.Texture.RGBA, + format: clay.Texture.RGBA, width: 512, height: 512 }, @@ -24978,8 +25295,8 @@ var TextureNode = Node$2.extend(function() { }); * */ -var FilterNode = Node$2.extend(function () { - return /** @lends qtek.compositor.Node# */ { +var FilterNode = CompositorNode.extend(function () { + return /** @lends clay.compositor.FilterNode# */ { /** * @type {string} */ @@ -25023,7 +25340,7 @@ var FilterNode = Node$2.extend(function () { outputLinks: {}, /** - * @type {qtek.compositor.Pass} + * @type {clay.compositor.Pass} */ pass: null, @@ -25048,10 +25365,10 @@ var FilterNode = Node$2.extend(function () { }); this.pass = pass; }, -/** @lends qtek.compositor.Node.prototype */ +/** @lends clay.compositor.FilterNode.prototype */ { /** - * @param {qtek.Renderer} renderer + * @param {clay.Renderer} renderer */ render: function (renderer, frameBuffer) { this.trigger('beforerender', renderer); @@ -25185,30 +25502,30 @@ var FilterNode = Node$2.extend(function () { this.setParameter(name, obj[name]); } }, + // /** + // * Set shader code + // * @param {string} shaderStr + // */ + // setShader: function (shaderStr) { + // var material = this.pass.material; + // material.shader.setFragment(shaderStr); + // material.attachShader(material.shader, true); + // }, /** - * Set shader code - * @param {string} shaderStr - */ - setShader: function (shaderStr) { - var material = this.pass.material; - material.shader.setFragment(shaderStr); - material.attachShader(material.shader, true); - }, - /** - * Proxy of pass.material.shader.define('fragment', xxx); + * Proxy of pass.material.define('fragment', xxx); * @param {string} symbol * @param {number} [val] */ - shaderDefine: function (symbol, val) { - this.pass.material.shader.define('fragment', symbol, val); + define: function (symbol, val) { + this.pass.material.define('fragment', symbol, val); }, /** - * Proxy of pass.material.shader.undefine('fragment', xxx) + * Proxy of pass.material.undefine('fragment', xxx) * @param {string} symbol */ - shaderUndefine: function (symbol) { - this.pass.material.shader.undefine('fragment', symbol); + undefine: function (symbol) { + this.pass.material.undefine('fragment', symbol); }, removeReference: function (outputName) { @@ -25229,413 +25546,297 @@ var FilterNode = Node$2.extend(function () { } }, - link: function (inputPinName, fromNode, fromPinName) { + clear: function () { + CompositorNode.prototype.clear.call(this); - // The relationship from output pin to input pin is one-on-multiple - this.inputLinks[inputPinName] = { - node: fromNode, - pin: fromPinName - }; - if (!fromNode.outputLinks[fromPinName]) { - fromNode.outputLinks[fromPinName] = []; - } - fromNode.outputLinks[ fromPinName ].push({ - node: this, - pin: inputPinName - }); + // Default disable all texture + this.pass.material.disableTexturesAll(); + } +}); - // Enabled the pin texture in shader - var shader = this.pass.material.shader; - shader.enableTexture(inputPinName); - }, +var coloradjustEssl = "@export clay.compositor.coloradjust\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float brightness : 0.0;\nuniform float contrast : 1.0;\nuniform float exposure : 0.0;\nuniform float gamma : 1.0;\nuniform float saturation : 1.0;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = clamp(tex.rgb + vec3(brightness), 0.0, 1.0);\n color = clamp( (color-vec3(0.5))*contrast+vec3(0.5), 0.0, 1.0);\n color = clamp( color * pow(2.0, exposure), 0.0, 1.0);\n color = clamp( pow(color, vec3(gamma)), 0.0, 1.0);\n float luminance = dot( color, w );\n color = mix(vec3(luminance), color, saturation);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.brightness\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float brightness : 0.0;\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = tex.rgb + vec3(brightness);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.contrast\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float contrast : 1.0;\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = (tex.rgb-vec3(0.5))*contrast+vec3(0.5);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.exposure\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float exposure : 0.0;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = tex.rgb * pow(2.0, exposure);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.gamma\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float gamma : 1.0;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = pow(tex.rgb, vec3(gamma));\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.saturation\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float saturation : 1.0;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = tex.rgb;\n float luminance = dot(color, w);\n color = mix(vec3(luminance), color, saturation);\n gl_FragColor = vec4(color, tex.a);\n}\n@end"; - clear: function () { - Node$2.prototype.clear.call(this); +var blurEssl = "@export clay.compositor.kernel.gaussian_9\nfloat gaussianKernel[9];\ngaussianKernel[0] = 0.07;\ngaussianKernel[1] = 0.09;\ngaussianKernel[2] = 0.12;\ngaussianKernel[3] = 0.14;\ngaussianKernel[4] = 0.16;\ngaussianKernel[5] = 0.14;\ngaussianKernel[6] = 0.12;\ngaussianKernel[7] = 0.09;\ngaussianKernel[8] = 0.07;\n@end\n@export clay.compositor.kernel.gaussian_13\nfloat gaussianKernel[13];\ngaussianKernel[0] = 0.02;\ngaussianKernel[1] = 0.03;\ngaussianKernel[2] = 0.06;\ngaussianKernel[3] = 0.08;\ngaussianKernel[4] = 0.11;\ngaussianKernel[5] = 0.13;\ngaussianKernel[6] = 0.14;\ngaussianKernel[7] = 0.13;\ngaussianKernel[8] = 0.11;\ngaussianKernel[9] = 0.08;\ngaussianKernel[10] = 0.06;\ngaussianKernel[11] = 0.03;\ngaussianKernel[12] = 0.02;\n@end\n@export clay.compositor.gaussian_blur\n#define SHADER_NAME gaussian_blur\nuniform sampler2D texture;varying vec2 v_Texcoord;\nuniform float blurSize : 2.0;\nuniform vec2 textureSize : [512.0, 512.0];\nuniform float blurDir : 0.0;\n@import clay.util.rgbm\n@import clay.util.clamp_sample\nvoid main (void)\n{\n @import clay.compositor.kernel.gaussian_9\n vec2 off = blurSize / textureSize;\n off *= vec2(1.0 - blurDir, blurDir);\n vec4 sum = vec4(0.0);\n float weightAll = 0.0;\n for (int i = 0; i < 9; i++) {\n float w = gaussianKernel[i];\n vec4 texel = decodeHDR(clampSample(texture, v_Texcoord + float(i - 4) * off));\n sum += texel * w;\n weightAll += w;\n }\n gl_FragColor = encodeHDR(sum / max(weightAll, 0.01));\n}\n@end\n"; - var shader = this.pass.material.shader; - // Default disable all texture - shader.disableTexturesAll(); - }, +var lumEssl = "@export clay.compositor.hdr.log_lum\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\n@import clay.util.rgbm\nvoid main()\n{\n vec4 tex = decodeHDR(texture2D(texture, v_Texcoord));\n float luminance = dot(tex.rgb, w);\n luminance = log(luminance + 0.001);\n gl_FragColor = encodeHDR(vec4(vec3(luminance), 1.0));\n}\n@end\n@export clay.compositor.hdr.lum_adaption\nvarying vec2 v_Texcoord;\nuniform sampler2D adaptedLum;\nuniform sampler2D currentLum;\nuniform float frameTime : 0.02;\n@import clay.util.rgbm\nvoid main()\n{\n float fAdaptedLum = decodeHDR(texture2D(adaptedLum, vec2(0.5, 0.5))).r;\n float fCurrentLum = exp(encodeHDR(texture2D(currentLum, vec2(0.5, 0.5))).r);\n fAdaptedLum += (fCurrentLum - fAdaptedLum) * (1.0 - pow(0.98, 30.0 * frameTime));\n gl_FragColor = encodeHDR(vec4(vec3(fAdaptedLum), 1.0));\n}\n@end\n@export clay.compositor.lum\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord );\n float luminance = dot(tex.rgb, w);\n gl_FragColor = vec4(vec3(luminance), 1.0);\n}\n@end"; - updateReference: function (outputName) { - if (!this._rendering) { - this._rendering = true; - for (var inputName in this.inputLinks) { - var link = this.inputLinks[inputName]; - link.node.updateReference(link.pin); - } - this._rendering = false; - } - if (outputName) { - this._outputReferences[outputName] ++; - } - }, +var lutEssl = "\n@export clay.compositor.lut\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform sampler2D lookup;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n float blueColor = tex.b * 63.0;\n vec2 quad1;\n quad1.y = floor(floor(blueColor) / 8.0);\n quad1.x = floor(blueColor) - (quad1.y * 8.0);\n vec2 quad2;\n quad2.y = floor(ceil(blueColor) / 8.0);\n quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n vec2 texPos1;\n texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.r);\n texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.g);\n vec2 texPos2;\n texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.r);\n texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.g);\n vec4 newColor1 = texture2D(lookup, texPos1);\n vec4 newColor2 = texture2D(lookup, texPos2);\n vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n gl_FragColor = vec4(newColor.rgb, tex.w);\n}\n@end"; - beforeFrame: function () { - this._rendered = false; +var vigentteEssl = "@export clay.compositor.vignette\n#define OUTPUT_ALPHA\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float darkness: 1;\nuniform float offset: 1;\n@import clay.util.rgbm\nvoid main()\n{\n vec4 texel = decodeHDR(texture2D(texture, v_Texcoord));\n gl_FragColor.rgb = texel.rgb;\n vec2 uv = (v_Texcoord - vec2(0.5)) * vec2(offset);\n gl_FragColor = encodeHDR(vec4(mix(texel.rgb, vec3(1.0 - darkness), dot(uv, uv)), texel.a));\n}\n@end"; - for (var name in this.outputLinks) { - this._outputReferences[name] = 0; - } - }, +var outputEssl = "@export clay.compositor.output\n#define OUTPUT_ALPHA\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\n@import clay.util.rgbm\nvoid main()\n{\n vec4 tex = decodeHDR(texture2D(texture, v_Texcoord));\n gl_FragColor.rgb = tex.rgb;\n#ifdef OUTPUT_ALPHA\n gl_FragColor.a = tex.a;\n#else\n gl_FragColor.a = 1.0;\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n#ifdef PREMULTIPLY_ALPHA\n gl_FragColor.rgb *= gl_FragColor.a;\n#endif\n}\n@end"; - afterFrame: function () { - // Put back all the textures to pool - for (var name in this.outputLinks) { - if (this._outputReferences[name] > 0) { - var outputInfo = this.outputs[name]; - if (outputInfo.keepLastFrame) { - if (this._prevOutputTextures[name]) { - this._compositor.releaseTexture(this._prevOutputTextures[name]); - } - this._prevOutputTextures[name] = this._outputTextures[name]; - } - else { - this._compositor.releaseTexture(this._outputTextures[name]); - } - } - } - } -}); +var brightEssl = "@export clay.compositor.bright\nuniform sampler2D texture;\nuniform float threshold : 1;\nuniform float scale : 1.0;\nuniform vec2 textureSize: [512, 512];\nvarying vec2 v_Texcoord;\nconst vec3 lumWeight = vec3(0.2125, 0.7154, 0.0721);\n@import clay.util.rgbm\nvec4 median(vec4 a, vec4 b, vec4 c)\n{\n return a + b + c - min(min(a, b), c) - max(max(a, b), c);\n}\nvoid main()\n{\n vec4 texel = decodeHDR(texture2D(texture, v_Texcoord));\n#ifdef ANTI_FLICKER\n vec3 d = 1.0 / textureSize.xyx * vec3(1.0, 1.0, 0.0);\n vec4 s1 = decodeHDR(texture2D(texture, v_Texcoord - d.xz));\n vec4 s2 = decodeHDR(texture2D(texture, v_Texcoord + d.xz));\n vec4 s3 = decodeHDR(texture2D(texture, v_Texcoord - d.zy));\n vec4 s4 = decodeHDR(texture2D(texture, v_Texcoord + d.zy));\n texel = median(median(texel, s1, s2), s3, s4);\n#endif\n float lum = dot(texel.rgb , lumWeight);\n vec4 color;\n if (lum > threshold && texel.a > 0.0)\n {\n color = vec4(texel.rgb * scale, texel.a * scale);\n }\n else\n {\n color = vec4(0.0);\n }\n gl_FragColor = encodeHDR(color);\n}\n@end\n"; -var shaderSourceReg = /#source\((.*?)\)/; -var urlReg = /#url\((.*?)\)/; +var downsampleEssl = "@export clay.compositor.downsample\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\nfloat brightness(vec3 c)\n{\n return max(max(c.r, c.g), c.b);\n}\n@import clay.util.clamp_sample\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n#ifdef ANTI_FLICKER\n vec3 s1 = decodeHDR(clampSample(texture, v_Texcoord + d.xy)).rgb;\n vec3 s2 = decodeHDR(clampSample(texture, v_Texcoord + d.zy)).rgb;\n vec3 s3 = decodeHDR(clampSample(texture, v_Texcoord + d.xw)).rgb;\n vec3 s4 = decodeHDR(clampSample(texture, v_Texcoord + d.zw)).rgb;\n float s1w = 1.0 / (brightness(s1) + 1.0);\n float s2w = 1.0 / (brightness(s2) + 1.0);\n float s3w = 1.0 / (brightness(s3) + 1.0);\n float s4w = 1.0 / (brightness(s4) + 1.0);\n float oneDivideSum = 1.0 / (s1w + s2w + s3w + s4w);\n vec4 color = vec4(\n (s1 * s1w + s2 * s2w + s3 * s3w + s4 * s4w) * oneDivideSum,\n 1.0\n );\n#else\n vec4 color = decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.xw));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.zw));\n color *= 0.25;\n#endif\n gl_FragColor = encodeHDR(color);\n}\n@end"; -/** - * @constructor qtek.loader.FX - * @extends qtek.core.Base - */ -var FXLoader = Base.extend( -/** @lends qtek.loader.FX# */ -{ - /** - * @type {string} - */ - rootPath: '', - /** - * @type {string} - */ - textureRootPath: '', - /** - * @type {string} - */ - shaderRootPath: '', +var upsampleEssl = "\n@export clay.compositor.upsample\n#define HIGH_QUALITY\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.clamp_sample\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n vec4 s;\n s = decodeHDR(clampSample(texture, v_Texcoord - d.xy));\n s += decodeHDR(clampSample(texture, v_Texcoord - d.wy)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord - d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zw)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord )) * 4.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xw)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.wy)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n gl_FragColor = encodeHDR(s / 16.0);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n vec4 s;\n s = decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xw));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zw));\n gl_FragColor = encodeHDR(s / 4.0);\n#endif\n}\n@end"; - /** - * @type {qtek.Scene} - */ - scene: null, +var hdrEssl = "@export clay.compositor.hdr.composite\nuniform sampler2D texture;\n#ifdef BLOOM_ENABLED\nuniform sampler2D bloom;\n#endif\n#ifdef LENSFLARE_ENABLED\nuniform sampler2D lensflare;\nuniform sampler2D lensdirt;\n#endif\n#ifdef LUM_ENABLED\nuniform sampler2D lum;\n#endif\n#ifdef LUT_ENABLED\nuniform sampler2D lut;\n#endif\n#ifdef COLOR_CORRECTION\nuniform float brightness : 0.0;\nuniform float contrast : 1.0;\nuniform float saturation : 1.0;\n#endif\n#ifdef VIGNETTE\nuniform float vignetteDarkness: 1.0;\nuniform float vignetteOffset: 1.0;\n#endif\nuniform float exposure : 1.0;\nuniform float bloomIntensity : 0.25;\nuniform float lensflareIntensity : 1;\nvarying vec2 v_Texcoord;\n@import clay.util.srgb\nvec3 ACESToneMapping(vec3 color)\n{\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nfloat eyeAdaption(float fLum)\n{\n return mix(0.2, fLum, 0.5);\n}\n#ifdef LUT_ENABLED\nvec3 lutTransform(vec3 color) {\n float blueColor = color.b * 63.0;\n vec2 quad1;\n quad1.y = floor(floor(blueColor) / 8.0);\n quad1.x = floor(blueColor) - (quad1.y * 8.0);\n vec2 quad2;\n quad2.y = floor(ceil(blueColor) / 8.0);\n quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n vec2 texPos1;\n texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.r);\n texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.g);\n vec2 texPos2;\n texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.r);\n texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.g);\n vec4 newColor1 = texture2D(lut, texPos1);\n vec4 newColor2 = texture2D(lut, texPos2);\n vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n return newColor.rgb;\n}\n#endif\n@import clay.util.rgbm\nvoid main()\n{\n vec4 texel = vec4(0.0);\n vec4 originalTexel = vec4(0.0);\n#ifdef TEXTURE_ENABLED\n texel = decodeHDR(texture2D(texture, v_Texcoord));\n originalTexel = texel;\n#endif\n#ifdef BLOOM_ENABLED\n vec4 bloomTexel = decodeHDR(texture2D(bloom, v_Texcoord));\n texel.rgb += bloomTexel.rgb * bloomIntensity;\n texel.a += bloomTexel.a * bloomIntensity;\n#endif\n#ifdef LENSFLARE_ENABLED\n texel += decodeHDR(texture2D(lensflare, v_Texcoord)) * texture2D(lensdirt, v_Texcoord) * lensflareIntensity;\n#endif\n texel.a = min(texel.a, 1.0);\n#ifdef LUM_ENABLED\n float fLum = texture2D(lum, vec2(0.5, 0.5)).r;\n float adaptedLumDest = 3.0 / (max(0.1, 1.0 + 10.0*eyeAdaption(fLum)));\n float exposureBias = adaptedLumDest * exposure;\n#else\n float exposureBias = exposure;\n#endif\n texel.rgb *= exposureBias;\n texel.rgb = ACESToneMapping(texel.rgb);\n texel = linearTosRGB(texel);\n#ifdef LUT_ENABLED\n texel.rgb = lutTransform(clamp(texel.rgb,vec3(0.0),vec3(1.0)));\n#endif\n#ifdef COLOR_CORRECTION\n texel.rgb = clamp(texel.rgb + vec3(brightness), 0.0, 1.0);\n texel.rgb = clamp((texel.rgb - vec3(0.5))*contrast+vec3(0.5), 0.0, 1.0);\n float lum = dot(texel.rgb, vec3(0.2125, 0.7154, 0.0721));\n texel.rgb = mix(vec3(lum), texel.rgb, saturation);\n#endif\n#ifdef VIGNETTE\n vec2 uv = (v_Texcoord - vec2(0.5)) * vec2(vignetteOffset);\n texel.rgb = mix(texel.rgb, vec3(1.0 - vignetteDarkness), dot(uv, uv));\n#endif\n gl_FragColor = encodeHDR(texel);\n#ifdef DEBUG\n #if DEBUG == 1\n gl_FragColor = encodeHDR(decodeHDR(texture2D(texture, v_Texcoord)));\n #elif DEBUG == 2\n gl_FragColor = encodeHDR(decodeHDR(texture2D(bloom, v_Texcoord)) * bloomIntensity);\n #elif DEBUG == 3\n gl_FragColor = encodeHDR(decodeHDR(texture2D(lensflare, v_Texcoord) * lensflareIntensity));\n #endif\n#endif\n if (originalTexel.a <= 0.01 && gl_FragColor.a > 1e-5) {\n gl_FragColor.a = dot(gl_FragColor.rgb, vec3(0.2125, 0.7154, 0.0721));\n }\n#ifdef PREMULTIPLY_ALPHA\n gl_FragColor.rgb *= gl_FragColor.a;\n#endif\n}\n@end"; - /** - * @type {qtek.Camera} - */ - camera: null -}, -/** @lends qtek.loader.FX.prototype */ -{ - /** - * @param {string} url - */ - load: function(url) { - var self = this; +var dofEssl = "@export clay.compositor.dof.coc\nuniform sampler2D depth;\nuniform float zNear: 0.1;\nuniform float zFar: 2000;\nuniform float focalDist: 3;\nuniform float focalRange: 1;\nuniform float focalLength: 30;\nuniform float fstop: 2.8;\nvarying vec2 v_Texcoord;\n@import clay.util.encode_float\nvoid main()\n{\n float z = texture2D(depth, v_Texcoord).r * 2.0 - 1.0;\n float dist = 2.0 * zNear * zFar / (zFar + zNear - z * (zFar - zNear));\n float aperture = focalLength / fstop;\n float coc;\n float uppper = focalDist + focalRange;\n float lower = focalDist - focalRange;\n if (dist <= uppper && dist >= lower) {\n coc = 0.5;\n }\n else {\n float focalAdjusted = dist > uppper ? uppper : lower;\n coc = abs(aperture * (focalLength * (dist - focalAdjusted)) / (dist * (focalAdjusted - focalLength)));\n coc = clamp(coc, 0.0, 0.4) / 0.4000001;\n if (dist < lower) {\n coc = -coc;\n }\n coc = coc * 0.5 + 0.5;\n }\n gl_FragColor = encodeFloat(coc);\n}\n@end\n@export clay.compositor.dof.premultiply\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.decode_float\nvoid main() {\n float fCoc = max(abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0), 0.1);\n gl_FragColor = encodeHDR(\n vec4(decodeHDR(texture2D(texture, v_Texcoord)).rgb * fCoc, 1.0)\n );\n}\n@end\n@export clay.compositor.dof.min_coc\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.float\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zy)));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.xw)));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zw)));\n gl_FragColor = encodeFloat(fCoc);\n}\n@end\n@export clay.compositor.dof.max_coc\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.float\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zy)));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.xw)));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zw)));\n gl_FragColor = encodeFloat(fCoc);\n}\n@end\n@export clay.compositor.dof.coc_upsample\n#define HIGH_QUALITY\nuniform sampler2D coc;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import clay.util.float\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n float s;\n s = decodeFloat(texture2D(coc, v_Texcoord - d.xy));\n s += decodeFloat(texture2D(coc, v_Texcoord - d.wy)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord - d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zw)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord )) * 4.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xw)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.wy)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n gl_FragColor = encodeFloat(s / 16.0);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n float s;\n s = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xw));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zw));\n gl_FragColor = encodeFloat(s / 4.0);\n#endif\n}\n@end\n@export clay.compositor.dof.upsample\n#define HIGH_QUALITY\nuniform sampler2D coc;\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.decode_float\nfloat tap(vec2 uv, inout vec4 color, float baseWeight) {\n float weight = abs(decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0) * baseWeight;\n color += decodeHDR(texture2D(texture, uv)) * weight;\n return weight;\n}\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n vec4 color = vec4(0.0);\n float baseWeight = 1.0 / 16.0;\n float w = tap(v_Texcoord - d.xy, color, baseWeight);\n w += tap(v_Texcoord - d.wy, color, baseWeight * 2.0);\n w += tap(v_Texcoord - d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.zw, color, baseWeight * 2.0);\n w += tap(v_Texcoord , color, baseWeight * 4.0);\n w += tap(v_Texcoord + d.xw, color, baseWeight * 2.0);\n w += tap(v_Texcoord + d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.wy, color, baseWeight * 2.0);\n w += tap(v_Texcoord + d.xy, color, baseWeight);\n gl_FragColor = encodeHDR(color / w);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n vec4 color = vec4(0.0);\n float baseWeight = 1.0 / 4.0;\n float w = tap(v_Texcoord + d.xy, color, baseWeight);\n w += tap(v_Texcoord + d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.xw, color, baseWeight);\n w += tap(v_Texcoord + d.zw, color, baseWeight);\n gl_FragColor = encodeHDR(color / w);\n#endif\n}\n@end\n@export clay.compositor.dof.downsample\nuniform sampler2D texture;\nuniform sampler2D coc;\nuniform vec2 textureSize : [512, 512];\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.decode_float\nfloat tap(vec2 uv, inout vec4 color) {\n float weight = abs(decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0) * 0.25;\n color += decodeHDR(texture2D(texture, uv)) * weight;\n return weight;\n}\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n vec4 color = vec4(0.0);\n float weight = tap(v_Texcoord + d.xy, color);\n weight += tap(v_Texcoord + d.zy, color);\n weight += tap(v_Texcoord + d.xw, color);\n weight += tap(v_Texcoord + d.zw, color);\n color /= weight;\n gl_FragColor = encodeHDR(color);\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_frag\n@import clay.util.float\nvec4 doBlur(sampler2D targetTexture, vec2 offset) {\n#ifdef BLUR_COC\n float cocSum = 0.0;\n#else\n vec4 color = vec4(0.0);\n#endif\n float weightSum = 0.0;\n float kernelWeight = 1.0 / float(KERNEL_SIZE);\n for (int i = 0; i < KERNEL_SIZE; i++) {\n vec2 coord = v_Texcoord + offset * float(i);\n float w = kernelWeight;\n#ifdef BLUR_COC\n float fCoc = decodeFloat(texture2D(targetTexture, coord)) * 2.0 - 1.0;\n cocSum += clamp(fCoc, -1.0, 0.0) * w;\n#else\n float fCoc = decodeFloat(texture2D(coc, coord)) * 2.0 - 1.0;\n vec4 texel = texture2D(targetTexture, coord);\n #if !defined(BLUR_NEARFIELD)\n w *= abs(fCoc);\n #endif\n color += decodeHDR(texel) * w;\n#endif\n weightSum += w;\n }\n#ifdef BLUR_COC\n return encodeFloat(clamp(cocSum / weightSum, -1.0, 0.0) * 0.5 + 0.5);\n#else\n return color / weightSum;\n#endif\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_1\n#define KERNEL_SIZE 5\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.rgbm\n@import clay.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n gl_FragColor = doBlur(texture, vec2(0.0, offset.y));\n#if !defined(BLUR_COC)\n gl_FragColor = encodeHDR(gl_FragColor);\n#endif\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_2\n#define KERNEL_SIZE 5\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.rgbm\n@import clay.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n offset.y /= 2.0;\n gl_FragColor = doBlur(texture, -offset);\n#if !defined(BLUR_COC)\n gl_FragColor = encodeHDR(gl_FragColor);\n#endif\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_3\n#define KERNEL_SIZE 5\nuniform sampler2D texture1;\nuniform sampler2D texture2;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.rgbm\n@import clay.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n offset.y /= 2.0;\n vec2 vDownRight = vec2(offset.x, -offset.y);\n vec4 texel1 = doBlur(texture1, -offset);\n vec4 texel2 = doBlur(texture1, vDownRight);\n vec4 texel3 = doBlur(texture2, vDownRight);\n#ifdef BLUR_COC\n float coc1 = decodeFloat(texel1) * 2.0 - 1.0;\n float coc2 = decodeFloat(texel2) * 2.0 - 1.0;\n float coc3 = decodeFloat(texel3) * 2.0 - 1.0;\n gl_FragColor = encodeFloat(\n ((coc1 + coc2 + coc3) / 3.0) * 0.5 + 0.5\n );\n#else\n vec4 color = (texel1 + texel2 + texel3) / 3.0;\n gl_FragColor = encodeHDR(color);\n#endif\n}\n@end\n@export clay.compositor.dof.composite\n#define DEBUG 0\nuniform sampler2D original;\nuniform sampler2D blurred;\nuniform sampler2D nearfield;\nuniform sampler2D coc;\nuniform sampler2D nearcoc;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.float\nvoid main()\n{\n vec4 blurredColor = decodeHDR(texture2D(blurred, v_Texcoord));\n vec4 originalColor = decodeHDR(texture2D(original, v_Texcoord));\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord));\n fCoc = abs(fCoc * 2.0 - 1.0);\n float weight = smoothstep(0.0, 1.0, fCoc);\n#ifdef NEARFIELD_ENABLED\n vec4 nearfieldColor = decodeHDR(texture2D(nearfield, v_Texcoord));\n float fNearCoc = decodeFloat(texture2D(nearcoc, v_Texcoord));\n fNearCoc = abs(fNearCoc * 2.0 - 1.0);\n gl_FragColor = encodeHDR(\n mix(\n nearfieldColor, mix(originalColor, blurredColor, weight),\n pow(1.0 - fNearCoc, 4.0)\n )\n );\n#else\n gl_FragColor = encodeHDR(mix(originalColor, blurredColor, weight));\n#endif\n#if DEBUG == 1\n gl_FragColor = vec4(vec3(fCoc), 1.0);\n#elif DEBUG == 2\n gl_FragColor = vec4(vec3(fNearCoc), 1.0);\n#elif DEBUG == 3\n gl_FragColor = encodeHDR(blurredColor);\n#elif DEBUG == 4\n gl_FragColor = encodeHDR(nearfieldColor);\n#endif\n}\n@end"; - if (!this.rootPath) { - this.rootPath = url.slice(0, url.lastIndexOf('/')); - } +var lensflareEssl = "@export clay.compositor.lensflare\n#define SAMPLE_NUMBER 8\nuniform sampler2D texture;\nuniform sampler2D lenscolor;\nuniform vec2 textureSize : [512, 512];\nuniform float dispersal : 0.3;\nuniform float haloWidth : 0.4;\nuniform float distortion : 1.0;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\nvec4 textureDistorted(\n in vec2 texcoord,\n in vec2 direction,\n in vec3 distortion\n) {\n return vec4(\n decodeHDR(texture2D(texture, texcoord + direction * distortion.r)).r,\n decodeHDR(texture2D(texture, texcoord + direction * distortion.g)).g,\n decodeHDR(texture2D(texture, texcoord + direction * distortion.b)).b,\n 1.0\n );\n}\nvoid main()\n{\n vec2 texcoord = -v_Texcoord + vec2(1.0); vec2 textureOffset = 1.0 / textureSize;\n vec2 ghostVec = (vec2(0.5) - texcoord) * dispersal;\n vec2 haloVec = normalize(ghostVec) * haloWidth;\n vec3 distortion = vec3(-textureOffset.x * distortion, 0.0, textureOffset.x * distortion);\n vec4 result = vec4(0.0);\n for (int i = 0; i < SAMPLE_NUMBER; i++)\n {\n vec2 offset = fract(texcoord + ghostVec * float(i));\n float weight = length(vec2(0.5) - offset) / length(vec2(0.5));\n weight = pow(1.0 - weight, 10.0);\n result += textureDistorted(offset, normalize(ghostVec), distortion) * weight;\n }\n result *= texture2D(lenscolor, vec2(length(vec2(0.5) - texcoord)) / length(vec2(0.5)));\n float weight = length(vec2(0.5) - fract(texcoord + haloVec)) / length(vec2(0.5));\n weight = pow(1.0 - weight, 10.0);\n vec2 offset = fract(texcoord + haloVec);\n result += textureDistorted(offset, normalize(ghostVec), distortion) * weight;\n gl_FragColor = result;\n}\n@end"; - request.get({ - url: url, - onprogress: function(percent, loaded, total) { - self.trigger('progress', percent, loaded, total); - }, - onerror: function(e) { - self.trigger('error', e); - }, - responseType: 'text', - onload: function(data) { - self.parse(JSON.parse(data)); - } - }); - }, +var blendEssl = "@export clay.compositor.blend\n#define SHADER_NAME blend\n#ifdef TEXTURE1_ENABLED\nuniform sampler2D texture1;\nuniform float weight1 : 1.0;\n#endif\n#ifdef TEXTURE2_ENABLED\nuniform sampler2D texture2;\nuniform float weight2 : 1.0;\n#endif\n#ifdef TEXTURE3_ENABLED\nuniform sampler2D texture3;\nuniform float weight3 : 1.0;\n#endif\n#ifdef TEXTURE4_ENABLED\nuniform sampler2D texture4;\nuniform float weight4 : 1.0;\n#endif\n#ifdef TEXTURE5_ENABLED\nuniform sampler2D texture5;\nuniform float weight5 : 1.0;\n#endif\n#ifdef TEXTURE6_ENABLED\nuniform sampler2D texture6;\nuniform float weight6 : 1.0;\n#endif\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\nvoid main()\n{\n vec4 tex = vec4(0.0);\n#ifdef TEXTURE1_ENABLED\n tex += decodeHDR(texture2D(texture1, v_Texcoord)) * weight1;\n#endif\n#ifdef TEXTURE2_ENABLED\n tex += decodeHDR(texture2D(texture2, v_Texcoord)) * weight2;\n#endif\n#ifdef TEXTURE3_ENABLED\n tex += decodeHDR(texture2D(texture3, v_Texcoord)) * weight3;\n#endif\n#ifdef TEXTURE4_ENABLED\n tex += decodeHDR(texture2D(texture4, v_Texcoord)) * weight4;\n#endif\n#ifdef TEXTURE5_ENABLED\n tex += decodeHDR(texture2D(texture5, v_Texcoord)) * weight5;\n#endif\n#ifdef TEXTURE6_ENABLED\n tex += decodeHDR(texture2D(texture6, v_Texcoord)) * weight6;\n#endif\n gl_FragColor = encodeHDR(tex);\n}\n@end"; - /** - * @param {Object} json - * @return {qtek.compositor.Compositor} - */ - parse: function(json) { - var self = this; - var compositor = new Compositor(); +var fxaaEssl = "@export clay.compositor.fxaa\nuniform sampler2D texture;\nuniform vec4 viewport : VIEWPORT;\nvarying vec2 v_Texcoord;\n#define FXAA_REDUCE_MIN (1.0/128.0)\n#define FXAA_REDUCE_MUL (1.0/8.0)\n#define FXAA_SPAN_MAX 8.0\n@import clay.util.rgbm\nvoid main()\n{\n vec2 resolution = 1.0 / viewport.zw;\n vec3 rgbNW = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( -1.0, -1.0 ) ) * resolution ) ).xyz;\n vec3 rgbNE = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( 1.0, -1.0 ) ) * resolution ) ).xyz;\n vec3 rgbSW = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( -1.0, 1.0 ) ) * resolution ) ).xyz;\n vec3 rgbSE = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( 1.0, 1.0 ) ) * resolution ) ).xyz;\n vec4 rgbaM = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution ) );\n vec3 rgbM = rgbaM.xyz;\n float opacity = rgbaM.w;\n vec3 luma = vec3( 0.299, 0.587, 0.114 );\n float lumaNW = dot( rgbNW, luma );\n float lumaNE = dot( rgbNE, luma );\n float lumaSW = dot( rgbSW, luma );\n float lumaSE = dot( rgbSE, luma );\n float lumaM = dot( rgbM, luma );\n float lumaMin = min( lumaM, min( min( lumaNW, lumaNE ), min( lumaSW, lumaSE ) ) );\n float lumaMax = max( lumaM, max( max( lumaNW, lumaNE) , max( lumaSW, lumaSE ) ) );\n vec2 dir;\n dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\n dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));\n float dirReduce = max( ( lumaNW + lumaNE + lumaSW + lumaSE ) * ( 0.25 * FXAA_REDUCE_MUL ), FXAA_REDUCE_MIN );\n float rcpDirMin = 1.0 / ( min( abs( dir.x ), abs( dir.y ) ) + dirReduce );\n dir = min( vec2( FXAA_SPAN_MAX, FXAA_SPAN_MAX),\n max( vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),\n dir * rcpDirMin)) * resolution;\n vec3 rgbA = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * ( 1.0 / 3.0 - 0.5 ) ) ).xyz;\n rgbA += decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * ( 2.0 / 3.0 - 0.5 ) ) ).xyz;\n rgbA *= 0.5;\n vec3 rgbB = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * -0.5 ) ).xyz;\n rgbB += decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * 0.5 ) ).xyz;\n rgbB *= 0.25;\n rgbB += rgbA * 0.5;\n float lumaB = dot( rgbB, luma );\n if ( ( lumaB < lumaMin ) || ( lumaB > lumaMax ) )\n {\n gl_FragColor = vec4( rgbA, opacity );\n }\n else {\n gl_FragColor = vec4( rgbB, opacity );\n }\n}\n@end"; - var lib = { - textures: {}, - shaders: {}, - parameters: {} - }; - var afterLoad = function(shaderLib, textureLib) { - for (var i = 0; i < json.nodes.length; i++) { - var nodeInfo = json.nodes[i]; - var node = self._createNode(nodeInfo, lib); - if (node) { - compositor.addNode(node); - } - } +// import fxaa3Essl from './source/compositor/fxaa3.glsl.js'; - self.trigger('success', compositor); - }; +// Some build in shaders +Shader['import'](coloradjustEssl); +Shader['import'](blurEssl); +Shader['import'](lumEssl); +Shader['import'](lutEssl); +Shader['import'](vigentteEssl); +Shader['import'](outputEssl); +Shader['import'](brightEssl); +Shader['import'](downsampleEssl); +Shader['import'](upsampleEssl); +Shader['import'](hdrEssl); +Shader['import'](dofEssl); +Shader['import'](lensflareEssl); +Shader['import'](blendEssl); - for (var name in json.parameters) { - var paramInfo = json.parameters[name]; - lib.parameters[name] = this._convertParameter(paramInfo); - } - this._loadShaders(json, function(shaderLib) { - // TODO load texture asynchronous - self._loadTextures(json, lib, function(textureLib) { - lib.textures = textureLib; - lib.shaders = shaderLib; - afterLoad(); - }); - }); +Shader['import'](fxaaEssl); +// Shader['import'](fxaa3Essl); - return compositor; - }, +var shaderSourceReg = /^#source\((.*?)\)/; - _createNode: function(nodeInfo, lib) { - var type = nodeInfo.type || 'filter'; - var shaderSource; - var inputs; - var outputs; +/** + * @name clay.createCompositor + * @function + * @param {Object} json + * @param {Object} [opts] + * @return {clay.compositor.Compositor} + */ +function createCompositor$1(json, opts) { + var compositor = new Compositor(); + opts = opts || {}; - if (type === 'filter') { - var shaderExp = nodeInfo.shader.trim(); - var res = shaderSourceReg.exec(shaderExp); - if (res) { - shaderSource = Shader.source(res[1].trim()); - } - else if (shaderExp.charAt(0) === '#') { - shaderSource = lib.shaders[shaderExp.substr(1)]; - } - if (!shaderSource) { - shaderSource = shaderExp; - } - if (!shaderSource) { - return; + var lib = { + textures: {}, + parameters: {} + }; + var afterLoad = function(shaderLib, textureLib) { + for (var i = 0; i < json.nodes.length; i++) { + var nodeInfo = json.nodes[i]; + var node = createNode(nodeInfo, lib, opts); + if (node) { + compositor.addNode(node); } } + }; - if (nodeInfo.inputs) { - inputs = {}; - for (var name in nodeInfo.inputs) { - if (typeof nodeInfo.inputs[name] === 'string') { - inputs[name] = nodeInfo.inputs[name]; - } - else { - inputs[name] = { - node: nodeInfo.inputs[name].node, - pin: nodeInfo.inputs[name].pin - }; - } - } - } - if (nodeInfo.outputs) { - outputs = {}; - for (var name in nodeInfo.outputs) { - var outputInfo = nodeInfo.outputs[name]; - outputs[name] = {}; - if (outputInfo.attachment != null) { - outputs[name].attachment = outputInfo.attachment; - } - if (outputInfo.keepLastFrame != null) { - outputs[name].keepLastFrame = outputInfo.keepLastFrame; - } - if (outputInfo.outputLastFrame != null) { - outputs[name].outputLastFrame = outputInfo.outputLastFrame; - } - if (typeof(outputInfo.parameters) === 'string') { - var paramExp = outputInfo.parameters; - if (paramExp.charAt(0) === '#') { - outputs[name].parameters = lib.parameters[paramExp.substr(1)]; - } - } - else if (outputInfo.parameters) { - outputs[name].parameters = this._convertParameter(outputInfo.parameters); - } - } + for (var name in json.parameters) { + var paramInfo = json.parameters[name]; + lib.parameters[name] = convertParameter(paramInfo); + } + // TODO load texture asynchronous + loadTextures(json, lib, opts, function(textureLib) { + lib.textures = textureLib; + afterLoad(); + }); + + return compositor; +} + +function createNode(nodeInfo, lib, opts) { + var type = nodeInfo.type || 'filter'; + var shaderSource; + var inputs; + var outputs; + + if (type === 'filter') { + var shaderExp = nodeInfo.shader.trim(); + var res = shaderSourceReg.exec(shaderExp); + if (res) { + shaderSource = Shader.source(res[1].trim()); } - var node; - if (type === 'scene') { - node = new SceneNode({ - name: nodeInfo.name, - scene: this.scene, - camera: this.camera, - outputs: outputs - }); + else if (shaderExp.charAt(0) === '#') { + shaderSource = lib.shaders[shaderExp.substr(1)]; } - else if (type === 'texture') { - node = new TextureNode({ - name: nodeInfo.name, - outputs: outputs - }); + if (!shaderSource) { + shaderSource = shaderExp; } - // Default is filter - else { - node = new FilterNode({ - name: nodeInfo.name, - shader: shaderSource, - inputs: inputs, - outputs: outputs - }); + if (!shaderSource) { + return; } - if (node) { - if (nodeInfo.parameters) { - for (var name in nodeInfo.parameters) { - var val = nodeInfo.parameters[name]; - if (typeof(val) === 'string') { - val = val.trim(); - if (val.charAt(0) === '#') { - val = lib.textures[val.substr(1)]; - } - else { - node.on( - 'beforerender', createSizeSetHandler( - name, tryConvertExpr(val) - ) - ); - } - } - node.setParameter(name, val); - } + } + + if (nodeInfo.inputs) { + inputs = {}; + for (var name in nodeInfo.inputs) { + if (typeof nodeInfo.inputs[name] === 'string') { + inputs[name] = nodeInfo.inputs[name]; } - if (nodeInfo.defines && node.pass) { - for (var name in nodeInfo.defines) { - var val = nodeInfo.defines[name]; - node.pass.material.shader.define('fragment', name, val); - } + else { + inputs[name] = { + node: nodeInfo.inputs[name].node, + pin: nodeInfo.inputs[name].pin + }; } } - return node; - }, - - _convertParameter: function(paramInfo) { - var param = {}; - if (!paramInfo) { - return param; + } + if (nodeInfo.outputs) { + outputs = {}; + for (var name in nodeInfo.outputs) { + var outputInfo = nodeInfo.outputs[name]; + outputs[name] = {}; + if (outputInfo.attachment != null) { + outputs[name].attachment = outputInfo.attachment; + } + if (outputInfo.keepLastFrame != null) { + outputs[name].keepLastFrame = outputInfo.keepLastFrame; + } + if (outputInfo.outputLastFrame != null) { + outputs[name].outputLastFrame = outputInfo.outputLastFrame; + } + if (outputInfo.parameters) { + outputs[name].parameters = convertParameter(outputInfo.parameters); + } } - ['type', 'minFilter', 'magFilter', 'wrapS', 'wrapT', 'flipY', 'useMipmap'] - .forEach(function(name) { - var val = paramInfo[name]; - if (val != null) { - // Convert string to enum - if (typeof val === 'string') { - val = Texture[val]; - } - param[name] = val; - } - }); - ['width', 'height'] - .forEach(function(name) { - if (paramInfo[name] != null) { - var val = paramInfo[name]; - if (typeof val === 'string') { - val = val.trim(); - param[name] = createSizeParser( - name, tryConvertExpr(val) - ); + } + var node; + if (type === 'scene') { + node = new SceneNode({ + name: nodeInfo.name, + scene: opts.scene, + camera: opts.camera, + outputs: outputs + }); + } + else if (type === 'texture') { + node = new TextureNode({ + name: nodeInfo.name, + outputs: outputs + }); + } + // Default is filter + else { + node = new FilterNode({ + name: nodeInfo.name, + shader: shaderSource, + inputs: inputs, + outputs: outputs + }); + } + if (node) { + if (nodeInfo.parameters) { + for (var name in nodeInfo.parameters) { + var val = nodeInfo.parameters[name]; + if (typeof(val) === 'string') { + val = val.trim(); + if (val.charAt(0) === '#') { + val = lib.textures[val.substr(1)]; } else { - param[name] = val; + node.on( + 'beforerender', createSizeSetHandler( + name, tryConvertExpr(val) + ) + ); } } - }); - if (paramInfo.useMipmap != null) { - param.useMipmap = paramInfo.useMipmap; + node.setParameter(name, val); + } } - return param; - }, - - _loadShaders: function(json, callback) { - if (!json.shaders) { - callback({}); - return; + if (nodeInfo.defines && node.pass) { + for (var name in nodeInfo.defines) { + var val = nodeInfo.defines[name]; + node.pass.material.define('fragment', name, val); + } } - var shaders = {}; - var loading = 0; - var cbd = false; - var shaderRootPath = this.shaderRootPath || this.rootPath; - util.each(json.shaders, function(shaderExp, name) { - var res = urlReg.exec(shaderExp); - if (res) { - var path = res[1]; - path = util.relative2absolute(path, shaderRootPath); - loading++; - request.get({ - url: path, - onload: function(shaderSource) { - shaders[name] = shaderSource; - Shader['import'](shaderSource); - loading--; - if (loading === 0) { - callback(shaders); - cbd = true; - } - } - }); + } + return node; +} + +function convertParameter(paramInfo) { + var param = {}; + if (!paramInfo) { + return param; + } + ['type', 'minFilter', 'magFilter', 'wrapS', 'wrapT', 'flipY', 'useMipmap'] + .forEach(function(name) { + var val = paramInfo[name]; + if (val != null) { + // Convert string to enum + if (typeof val === 'string') { + val = Texture$1[val]; + } + param[name] = val; } - else { - shaders[name] = shaderExp; - // Try import shader - Shader['import'](shaderExp); + }); + ['width', 'height'] + .forEach(function(name) { + if (paramInfo[name] != null) { + var val = paramInfo[name]; + if (typeof val === 'string') { + val = val.trim(); + param[name] = createSizeParser( + name, tryConvertExpr(val) + ); + } + else { + param[name] = val; + } } - }, this); - if (loading === 0 && !cbd) { - callback(shaders); - } - }, + }); + if (paramInfo.useMipmap != null) { + param.useMipmap = paramInfo.useMipmap; + } + return param; +} - _loadTextures: function(json, lib, callback) { - if (!json.textures) { - callback({}); - return; - } - var textures = {}; - var loading = 0; +function loadTextures(json, lib, opts, callback) { + if (!json.textures) { + callback({}); + return; + } + var textures = {}; + var loading = 0; - var cbd = false; - var textureRootPath = this.textureRootPath || this.rootPath; - util.each(json.textures, function(textureInfo, name) { - var texture; - var path = textureInfo.path; - var parameters = this._convertParameter(textureInfo.parameters); - if (Array.isArray(path) && path.length === 6) { + var cbd = false; + var textureRootPath = opts.textureRootPath; + util.each(json.textures, function(textureInfo, name) { + var texture; + var path = textureInfo.path; + var parameters = convertParameter(textureInfo.parameters); + if (Array.isArray(path) && path.length === 6) { + if (textureRootPath) { path = path.map(function(item) { return util.relative2absolute(item, textureRootPath); }); - texture = new TextureCube(parameters); } - else if(typeof path === 'string') { + texture = new TextureCube(parameters); + } + else if(typeof path === 'string') { + if (textureRootPath) { path = util.relative2absolute(path, textureRootPath); - texture = new Texture2D(parameters); - } - else { - return; } + texture = new Texture2D(parameters); + } + else { + return; + } - texture.load(path); - loading++; - texture.once('success', function() { - textures[name] = texture; - loading--; - if (loading === 0) { - callback(textures); - cbd = true; - } - }); - }, this); + texture.load(path); + loading++; + texture.once('success', function() { + textures[name] = texture; + loading--; + if (loading === 0) { + callback(textures); + cbd = true; + } + }); + }); - if (loading === 0 && !cbd) { - callback(textures); - } + if (loading === 0 && !cbd) { + callback(textures); } -}); +} function createSizeSetHandler(name, exprFunc) { return function (renderer) { @@ -25675,6 +25876,8 @@ function tryConvertExpr(string) { } } +// Alias + // Generate halton sequence // https://en.wikipedia.org/wiki/Halton_sequence function halton(index, base) { @@ -25690,7 +25893,7 @@ function halton(index, base) { return result; } -var SSAOGLSLCode = "@export ecgl.ssao.estimate\n\n#define SHADER_NAME SSAO\n\nuniform sampler2D depthTex;\n\nuniform sampler2D normalTex;\n\nuniform sampler2D noiseTex;\n\nuniform vec2 depthTexSize;\n\nuniform vec2 noiseTexSize;\n\nuniform mat4 projection;\n\nuniform mat4 projectionInv;\n\nuniform mat4 viewInverseTranspose;\n\nuniform vec3 kernel[KERNEL_SIZE];\n\nuniform float radius : 1;\n\nuniform float power : 1;\n\nuniform float bias: 0.01;\n\nuniform float intensity: 1.0;\n\nvarying vec2 v_Texcoord;\n\nfloat ssaoEstimator(in vec3 originPos, in vec3 N, in mat3 kernelBasis) {\n float occlusion = 0.0;\n\n for (int i = 0; i < KERNEL_SIZE; i++) {\n vec3 samplePos = kernel[i];\n#ifdef NORMALTEX_ENABLED\n samplePos = kernelBasis * samplePos;\n#endif\n samplePos = samplePos * radius + originPos;\n\n vec4 texCoord = projection * vec4(samplePos, 1.0);\n texCoord.xy /= texCoord.w;\n texCoord.xy = texCoord.xy * 0.5 + 0.5;\n\n vec4 depthTexel = texture2D(depthTex, texCoord.xy);\n float z = depthTexel.r * 2.0 - 1.0;\n#ifdef ALCHEMY\n vec4 projectedPos = vec4(texCoord.xy * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * projectedPos;\n p4.xyz /= p4.w;\n vec3 cDir = p4.xyz - originPos;\n\n float vv = dot(cDir, cDir);\n float vn = dot(cDir, N);\n\n float radius2 = radius * radius;\n\n vn = max(vn + p4.z * bias, 0.0);\n float f = max(radius2 - vv, 0.0) / radius2;\n occlusion += f * f * f * max(vn / (0.01 + vv), 0.0);\n#else\n if (projection[3][3] == 0.0) {\n z = projection[3][2] / (z * projection[2][3] - projection[2][2]);\n }\n else {\n z = (z - projection[3][2]) / projection[2][2];\n }\n float factor = step(samplePos.z, z - bias);\n float rangeCheck = smoothstep(0.0, 1.0, radius / abs(originPos.z - z));\n occlusion += rangeCheck * factor;\n#endif\n }\n#ifdef NORMALTEX_ENABLED\n occlusion = 1.0 - occlusion / float(KERNEL_SIZE);\n#else\n occlusion = 1.0 - clamp((occlusion / float(KERNEL_SIZE) - 0.6) * 2.5, 0.0, 1.0);\n#endif\n return pow(occlusion, power);\n}\n\nvoid main()\n{\n\n vec4 depthTexel = texture2D(depthTex, v_Texcoord);\n\n#ifdef NORMALTEX_ENABLED\n vec4 tex = texture2D(normalTex, v_Texcoord);\n if (dot(tex.rgb, tex.rgb) == 0.0) {\n gl_FragColor = vec4(1.0);\n return;\n }\n vec3 N = tex.rgb * 2.0 - 1.0;\n N = (viewInverseTranspose * vec4(N, 0.0)).xyz;\n\n vec2 noiseTexCoord = depthTexSize / vec2(noiseTexSize) * v_Texcoord;\n vec3 rvec = texture2D(noiseTex, noiseTexCoord).rgb * 2.0 - 1.0;\n vec3 T = normalize(rvec - N * dot(rvec, N));\n vec3 BT = normalize(cross(N, T));\n mat3 kernelBasis = mat3(T, BT, N);\n#else\n if (depthTexel.r > 0.99999) {\n gl_FragColor = vec4(1.0);\n return;\n }\n mat3 kernelBasis;\n#endif\n\n float z = depthTexel.r * 2.0 - 1.0;\n\n vec4 projectedPos = vec4(v_Texcoord * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * projectedPos;\n\n vec3 position = p4.xyz / p4.w;\n\n float ao = ssaoEstimator(position, N, kernelBasis);\n ao = clamp(1.0 - (1.0 - ao) * intensity, 0.0, 1.0);\n gl_FragColor = vec4(vec3(ao), 1.0);\n}\n\n@end\n\n\n@export ecgl.ssao.blur\n#define SHADER_NAME SSAO_BLUR\n\nuniform sampler2D ssaoTexture;\n\n#ifdef NORMALTEX_ENABLED\nuniform sampler2D normalTex;\n#endif\n\nvarying vec2 v_Texcoord;\n\nuniform vec2 textureSize;\nuniform float blurSize : 1.0;\n\nuniform int direction: 0.0;\n\n#ifdef DEPTHTEX_ENABLED\nuniform sampler2D depthTex;\nuniform mat4 projection;\nuniform float depthRange : 0.05;\n\nfloat getLinearDepth(vec2 coord)\n{\n float depth = texture2D(depthTex, coord).r * 2.0 - 1.0;\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n}\n#endif\n\nvoid main()\n{\n @import qtek.compositor.kernel.gaussian_9\n\n vec2 off = vec2(0.0);\n if (direction == 0) {\n off[0] = blurSize / textureSize.x;\n }\n else {\n off[1] = blurSize / textureSize.y;\n }\n\n vec2 coord = v_Texcoord;\n\n float sum = 0.0;\n float weightAll = 0.0;\n\n#ifdef NORMALTEX_ENABLED\n vec3 centerNormal = texture2D(normalTex, v_Texcoord).rgb * 2.0 - 1.0;\n#endif\n#if defined(DEPTHTEX_ENABLED)\n float centerDepth = getLinearDepth(v_Texcoord);\n#endif\n\n for (int i = 0; i < 9; i++) {\n vec2 coord = clamp(v_Texcoord + vec2(float(i) - 4.0) * off, vec2(0.0), vec2(1.0));\n\n float w = gaussianKernel[i];\n#ifdef NORMALTEX_ENABLED\n vec3 normal = texture2D(normalTex, coord).rgb * 2.0 - 1.0;\n w *= clamp(dot(normal, centerNormal), 0.0, 1.0);\n#endif\n#ifdef DEPTHTEX_ENABLED\n float d = getLinearDepth(coord);\n w *= (1.0 - smoothstep(abs(centerDepth - d) / depthRange, 0.0, 1.0));\n#endif\n\n weightAll += w;\n sum += texture2D(ssaoTexture, coord).r * w;\n }\n\n gl_FragColor = vec4(vec3(sum / weightAll), 1.0);\n}\n\n@end\n"; +var SSAOGLSLCode = "@export ecgl.ssao.estimate\n\n#define SHADER_NAME SSAO\n\nuniform sampler2D depthTex;\n\nuniform sampler2D normalTex;\n\nuniform sampler2D noiseTex;\n\nuniform vec2 depthTexSize;\n\nuniform vec2 noiseTexSize;\n\nuniform mat4 projection;\n\nuniform mat4 projectionInv;\n\nuniform mat4 viewInverseTranspose;\n\nuniform vec3 kernel[KERNEL_SIZE];\n\nuniform float radius : 1;\n\nuniform float power : 1;\n\nuniform float bias: 0.01;\n\nuniform float intensity: 1.0;\n\nvarying vec2 v_Texcoord;\n\nfloat ssaoEstimator(in vec3 originPos, in vec3 N, in mat3 kernelBasis) {\n float occlusion = 0.0;\n\n for (int i = 0; i < KERNEL_SIZE; i++) {\n vec3 samplePos = kernel[i];\n#ifdef NORMALTEX_ENABLED\n samplePos = kernelBasis * samplePos;\n#endif\n samplePos = samplePos * radius + originPos;\n\n vec4 texCoord = projection * vec4(samplePos, 1.0);\n texCoord.xy /= texCoord.w;\n texCoord.xy = texCoord.xy * 0.5 + 0.5;\n\n vec4 depthTexel = texture2D(depthTex, texCoord.xy);\n float z = depthTexel.r * 2.0 - 1.0;\n#ifdef ALCHEMY\n vec4 projectedPos = vec4(texCoord.xy * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * projectedPos;\n p4.xyz /= p4.w;\n vec3 cDir = p4.xyz - originPos;\n\n float vv = dot(cDir, cDir);\n float vn = dot(cDir, N);\n\n float radius2 = radius * radius;\n\n vn = max(vn + p4.z * bias, 0.0);\n float f = max(radius2 - vv, 0.0) / radius2;\n occlusion += f * f * f * max(vn / (0.01 + vv), 0.0);\n#else\n if (projection[3][3] == 0.0) {\n z = projection[3][2] / (z * projection[2][3] - projection[2][2]);\n }\n else {\n z = (z - projection[3][2]) / projection[2][2];\n }\n float factor = step(samplePos.z, z - bias);\n float rangeCheck = smoothstep(0.0, 1.0, radius / abs(originPos.z - z));\n occlusion += rangeCheck * factor;\n#endif\n }\n#ifdef NORMALTEX_ENABLED\n occlusion = 1.0 - occlusion / float(KERNEL_SIZE);\n#else\n occlusion = 1.0 - clamp((occlusion / float(KERNEL_SIZE) - 0.6) * 2.5, 0.0, 1.0);\n#endif\n return pow(occlusion, power);\n}\n\nvoid main()\n{\n\n vec4 depthTexel = texture2D(depthTex, v_Texcoord);\n\n#ifdef NORMALTEX_ENABLED\n vec4 tex = texture2D(normalTex, v_Texcoord);\n if (dot(tex.rgb, tex.rgb) == 0.0) {\n gl_FragColor = vec4(1.0);\n return;\n }\n vec3 N = tex.rgb * 2.0 - 1.0;\n N = (viewInverseTranspose * vec4(N, 0.0)).xyz;\n\n vec2 noiseTexCoord = depthTexSize / vec2(noiseTexSize) * v_Texcoord;\n vec3 rvec = texture2D(noiseTex, noiseTexCoord).rgb * 2.0 - 1.0;\n vec3 T = normalize(rvec - N * dot(rvec, N));\n vec3 BT = normalize(cross(N, T));\n mat3 kernelBasis = mat3(T, BT, N);\n#else\n if (depthTexel.r > 0.99999) {\n gl_FragColor = vec4(1.0);\n return;\n }\n mat3 kernelBasis;\n#endif\n\n float z = depthTexel.r * 2.0 - 1.0;\n\n vec4 projectedPos = vec4(v_Texcoord * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * projectedPos;\n\n vec3 position = p4.xyz / p4.w;\n\n float ao = ssaoEstimator(position, N, kernelBasis);\n ao = clamp(1.0 - (1.0 - ao) * intensity, 0.0, 1.0);\n gl_FragColor = vec4(vec3(ao), 1.0);\n}\n\n@end\n\n\n@export ecgl.ssao.blur\n#define SHADER_NAME SSAO_BLUR\n\nuniform sampler2D ssaoTexture;\n\n#ifdef NORMALTEX_ENABLED\nuniform sampler2D normalTex;\n#endif\n\nvarying vec2 v_Texcoord;\n\nuniform vec2 textureSize;\nuniform float blurSize : 1.0;\n\nuniform int direction: 0.0;\n\n#ifdef DEPTHTEX_ENABLED\nuniform sampler2D depthTex;\nuniform mat4 projection;\nuniform float depthRange : 0.05;\n\nfloat getLinearDepth(vec2 coord)\n{\n float depth = texture2D(depthTex, coord).r * 2.0 - 1.0;\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n}\n#endif\n\nvoid main()\n{\n float kernel[5];\n kernel[0] = 0.122581;\n kernel[1] = 0.233062;\n kernel[2] = 0.288713;\n kernel[3] = 0.233062;\n kernel[4] = 0.122581;\n\n vec2 off = vec2(0.0);\n if (direction == 0) {\n off[0] = blurSize / textureSize.x;\n }\n else {\n off[1] = blurSize / textureSize.y;\n }\n\n vec2 coord = v_Texcoord;\n\n float sum = 0.0;\n float weightAll = 0.0;\n\n#ifdef NORMALTEX_ENABLED\n vec3 centerNormal = texture2D(normalTex, v_Texcoord).rgb * 2.0 - 1.0;\n#endif\n#if defined(DEPTHTEX_ENABLED)\n float centerDepth = getLinearDepth(v_Texcoord);\n#endif\n\n for (int i = 0; i < 5; i++) {\n vec2 coord = clamp(v_Texcoord + vec2(float(i) - 2.0) * off, vec2(0.0), vec2(1.0));\n\n float w = kernel[i];\n#ifdef NORMALTEX_ENABLED\n vec3 normal = texture2D(normalTex, coord).rgb * 2.0 - 1.0;\n w *= clamp(dot(normal, centerNormal), 0.0, 1.0);\n#endif\n#ifdef DEPTHTEX_ENABLED\n float d = getLinearDepth(coord);\n w *= (1.0 - smoothstep(abs(centerDepth - d) / depthRange, 0.0, 1.0));\n#endif\n\n weightAll += w;\n sum += texture2D(ssaoTexture, coord).r * w;\n }\n\n gl_FragColor = vec4(vec3(sum / weightAll), 1.0);\n}\n@end\n"; Shader.import(SSAOGLSLCode); @@ -25714,8 +25917,8 @@ function generateNoiseData(size) { function generateNoiseTexture(size) { return new Texture2D({ pixels: generateNoiseData(size), - wrapS: Texture.REPEAT, - wrapT: Texture.REPEAT, + wrapS: Texture$1.REPEAT, + wrapT: Texture$1.REPEAT, width: size, height: size }); @@ -25749,7 +25952,7 @@ function SSAOPass(opt) { fragment: Shader.source('ecgl.ssao.blur') }); this._framebuffer = new FrameBuffer(); - + this._ssaoTexture = new Texture2D(); this._blurTexture = new Texture2D(); @@ -25766,11 +25969,11 @@ function SSAOPass(opt) { } if (!this._normalTex) { - this._ssaoPass.material.shader.disableTexture('normalTex'); - this._blurPass.material.shader.disableTexture('normalTex'); + this._ssaoPass.material.disableTexture('normalTex'); + this._blurPass.material.disableTexture('normalTex'); } if (!this._depthTex) { - this._blurPass.material.shader.disableTexture('depthTex'); + this._blurPass.material.disableTexture('depthTex'); } this._blurPass.material.setUniform('normalTex', this._normalTex); @@ -25783,7 +25986,7 @@ SSAOPass.prototype.setDepthTexture = function (depthTex) { SSAOPass.prototype.setNormalTexture = function (normalTex) { this._normalTex = normalTex; - this._ssaoPass.material.shader[normalTex ? 'enableTexture' : 'disableTexture']('normalTex'); + this._ssaoPass.material[normalTex ? 'enableTexture' : 'disableTexture']('normalTex'); // Switch between hemisphere and shere kernel. this.setKernelSize(this._kernelSize); }; @@ -25805,9 +26008,9 @@ SSAOPass.prototype.update = function (renderer, camera, frame) { var viewInverseTranspose = new Matrix4(); Matrix4.transpose(viewInverseTranspose, camera.worldTransform); - ssaoPass.setUniform('projection', camera.projectionMatrix._array); - ssaoPass.setUniform('projectionInv', camera.invProjectionMatrix._array); - ssaoPass.setUniform('viewInverseTranspose', viewInverseTranspose._array); + ssaoPass.setUniform('projection', camera.projectionMatrix.array); + ssaoPass.setUniform('projectionInv', camera.invProjectionMatrix.array); + ssaoPass.setUniform('viewInverseTranspose', viewInverseTranspose.array); var ssaoTexture = this._ssaoTexture; var blurTexture = this._blurTexture; @@ -25824,7 +26027,7 @@ SSAOPass.prototype.update = function (renderer, camera, frame) { ssaoPass.render(renderer); blurPass.setUniform('textureSize', [width, height]); - blurPass.setUniform('projection', camera.projectionMatrix._array); + blurPass.setUniform('projection', camera.projectionMatrix.array); this._framebuffer.attach(blurTexture); blurPass.setUniform('direction', 0); blurPass.setUniform('ssaoTexture', ssaoTexture); @@ -25863,7 +26066,7 @@ SSAOPass.prototype.setParameter = function (name, val) { SSAOPass.prototype.setKernelSize = function (size) { this._kernelSize = size; - this._ssaoPass.material.shader.define('fragment', 'KERNEL_SIZE', size); + this._ssaoPass.material.define('fragment', 'KERNEL_SIZE', size); this._kernels = this._kernels || []; for (var i = 0; i < 30; i++) { this._kernels[i] = generateKernel(size, i * size, !!this._normalTex); @@ -25890,1452 +26093,1523 @@ SSAOPass.prototype.dispose = function (renderer) { this._ssaoTexture.dispose(renderer); }; -var SSRGLSLCode = "@export ecgl.ssr.main\n\n#define MAX_ITERATION 20;\n\nuniform sampler2D sourceTexture;\nuniform sampler2D gBufferTexture1;\nuniform sampler2D gBufferTexture2;\n\nuniform mat4 projection;\nuniform mat4 projectionInv;\nuniform mat4 viewInverseTranspose;\n\nuniform float maxRayDistance: 50;\n\nuniform float pixelStride: 16;\nuniform float pixelStrideZCutoff: 50; \nuniform float screenEdgeFadeStart: 0.9; \nuniform float eyeFadeStart : 0.2; uniform float eyeFadeEnd: 0.8; \nuniform float minGlossiness: 0.2; uniform float zThicknessThreshold: 10;\n\nuniform float nearZ;\nuniform vec2 viewportSize : VIEWPORT_SIZE;\n\nuniform float jitterOffset: 0;\n\nvarying vec2 v_Texcoord;\n\n#ifdef DEPTH_DECODE\n@import qtek.util.decode_float\n#endif\n\nfloat fetchDepth(sampler2D depthTexture, vec2 uv)\n{\n vec4 depthTexel = texture2D(depthTexture, uv);\n return depthTexel.r * 2.0 - 1.0;\n}\n\nfloat linearDepth(float depth)\n{\n if (projection[3][3] == 0.0) {\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n }\n else {\n return (depth - projection[3][2]) / projection[2][2];\n }\n}\n\nbool rayIntersectDepth(float rayZNear, float rayZFar, vec2 hitPixel)\n{\n if (rayZFar > rayZNear)\n {\n float t = rayZFar; rayZFar = rayZNear; rayZNear = t;\n }\n float cameraZ = linearDepth(fetchDepth(gBufferTexture2, hitPixel));\n return rayZFar <= cameraZ && rayZNear >= cameraZ - zThicknessThreshold;\n}\n\n\nbool traceScreenSpaceRay(\n vec3 rayOrigin, vec3 rayDir, float jitter,\n out vec2 hitPixel, out vec3 hitPoint, out float iterationCount\n)\n{\n float rayLength = ((rayOrigin.z + rayDir.z * maxRayDistance) > -nearZ)\n ? (-nearZ - rayOrigin.z) / rayDir.z : maxRayDistance;\n\n vec3 rayEnd = rayOrigin + rayDir * rayLength;\n\n vec4 H0 = projection * vec4(rayOrigin, 1.0);\n vec4 H1 = projection * vec4(rayEnd, 1.0);\n\n float k0 = 1.0 / H0.w, k1 = 1.0 / H1.w;\n\n vec3 Q0 = rayOrigin * k0, Q1 = rayEnd * k1;\n\n vec2 P0 = (H0.xy * k0 * 0.5 + 0.5) * viewportSize;\n vec2 P1 = (H1.xy * k1 * 0.5 + 0.5) * viewportSize;\n\n P1 += dot(P1 - P0, P1 - P0) < 0.0001 ? 0.01 : 0.0;\n vec2 delta = P1 - P0;\n\n bool permute = false;\n if (abs(delta.x) < abs(delta.y)) {\n permute = true;\n delta = delta.yx;\n P0 = P0.yx;\n P1 = P1.yx;\n }\n float stepDir = sign(delta.x);\n float invdx = stepDir / delta.x;\n\n vec3 dQ = (Q1 - Q0) * invdx;\n float dk = (k1 - k0) * invdx;\n\n vec2 dP = vec2(stepDir, delta.y * invdx);\n\n float strideScaler = 1.0 - min(1.0, -rayOrigin.z / pixelStrideZCutoff);\n float pixStride = 1.0 + strideScaler * pixelStride;\n\n dP *= pixStride; dQ *= pixStride; dk *= pixStride;\n\n vec4 pqk = vec4(P0, Q0.z, k0);\n vec4 dPQK = vec4(dP, dQ.z, dk);\n\n pqk += dPQK * jitter;\n float rayZFar = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);\n float rayZNear;\n\n bool intersect = false;\n\n vec2 texelSize = 1.0 / viewportSize;\n\n iterationCount = 0.0;\n\n for (int i = 0; i < MAX_ITERATION; i++)\n {\n pqk += dPQK;\n\n rayZNear = rayZFar;\n rayZFar = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);\n\n hitPixel = permute ? pqk.yx : pqk.xy;\n hitPixel *= texelSize;\n\n intersect = rayIntersectDepth(rayZNear, rayZFar, hitPixel);\n\n iterationCount += 1.0;\n\n if (intersect) {\n break;\n }\n }\n\n\n Q0.xy += dQ.xy * iterationCount;\n Q0.z = pqk.z;\n hitPoint = Q0 / pqk.w;\n\n return intersect;\n}\n\nfloat calculateAlpha(\n float iterationCount, float reflectivity,\n vec2 hitPixel, vec3 hitPoint, float dist, vec3 rayDir\n)\n{\n float alpha = clamp(reflectivity, 0.0, 1.0);\n alpha *= 1.0 - (iterationCount / float(MAX_ITERATION));\n vec2 hitPixelNDC = hitPixel * 2.0 - 1.0;\n float maxDimension = min(1.0, max(abs(hitPixelNDC.x), abs(hitPixelNDC.y)));\n alpha *= 1.0 - max(0.0, maxDimension - screenEdgeFadeStart) / (1.0 - screenEdgeFadeStart);\n\n float _eyeFadeStart = eyeFadeStart;\n float _eyeFadeEnd = eyeFadeEnd;\n if (_eyeFadeStart > _eyeFadeEnd) {\n float tmp = _eyeFadeEnd;\n _eyeFadeEnd = _eyeFadeStart;\n _eyeFadeStart = tmp;\n }\n\n float eyeDir = clamp(rayDir.z, _eyeFadeStart, _eyeFadeEnd);\n alpha *= 1.0 - (eyeDir - _eyeFadeStart) / (_eyeFadeEnd - _eyeFadeStart);\n\n alpha *= 1.0 - clamp(dist / maxRayDistance, 0.0, 1.0);\n\n return alpha;\n}\n\n@import qtek.util.rand\n\n@import qtek.util.rgbm\n\nvoid main()\n{\n vec4 normalAndGloss = texture2D(gBufferTexture1, v_Texcoord);\n\n if (dot(normalAndGloss.rgb, vec3(1.0)) == 0.0) {\n discard;\n }\n\n float g = normalAndGloss.a;\n if (g <= minGlossiness) {\n discard;\n }\n\n float reflectivity = (g - minGlossiness) / (1.0 - minGlossiness);\n\n vec3 N = normalAndGloss.rgb * 2.0 - 1.0;\n N = normalize((viewInverseTranspose * vec4(N, 0.0)).xyz);\n\n vec4 projectedPos = vec4(v_Texcoord * 2.0 - 1.0, fetchDepth(gBufferTexture2, v_Texcoord), 1.0);\n vec4 pos = projectionInv * projectedPos;\n vec3 rayOrigin = pos.xyz / pos.w;\n\n vec3 rayDir = normalize(reflect(normalize(rayOrigin), N));\n vec2 hitPixel;\n vec3 hitPoint;\n float iterationCount;\n\n vec2 uv2 = v_Texcoord * viewportSize;\n float jitter = rand(fract(v_Texcoord + jitterOffset));\n\n bool intersect = traceScreenSpaceRay(rayOrigin, rayDir, jitter, hitPixel, hitPoint, iterationCount);\n\n float dist = distance(rayOrigin, hitPoint);\n\n float alpha = calculateAlpha(iterationCount, reflectivity, hitPixel, hitPoint, dist, rayDir) * float(intersect);\n\n vec3 hitNormal = texture2D(gBufferTexture1, hitPixel).rgb * 2.0 - 1.0;\n hitNormal = normalize((viewInverseTranspose * vec4(hitNormal, 0.0)).xyz);\n\n if (dot(hitNormal, rayDir) >= 0.0) {\n discard;\n }\n\n \n if (!intersect) {\n discard;\n }\n vec4 color = decodeHDR(texture2D(sourceTexture, hitPixel));\n gl_FragColor = encodeHDR(vec4(color.rgb * alpha, color.a));\n}\n@end\n\n@export ecgl.ssr.blur\n\nuniform sampler2D texture;\nuniform sampler2D gBufferTexture1;\n\nvarying vec2 v_Texcoord;\n\nuniform vec2 textureSize;\nuniform float blurSize : 4.0;\n\n#ifdef BLEND\n #ifdef SSAOTEX_ENABLED\nuniform sampler2D ssaoTex;\n #endif\nuniform sampler2D sourceTexture;\n#endif\n\n@import qtek.util.rgbm\n\n\nvoid main()\n{\n @import qtek.compositor.kernel.gaussian_13\n\n vec4 centerNTexel = texture2D(gBufferTexture1, v_Texcoord);\n float g = centerNTexel.a;\n float maxBlurSize = clamp(1.0 - g + 0.1, 0.0, 1.0) * blurSize;\n#ifdef VERTICAL\n vec2 off = vec2(0.0, maxBlurSize / textureSize.y);\n#else\n vec2 off = vec2(maxBlurSize / textureSize.x, 0.0);\n#endif\n\n vec2 coord = v_Texcoord;\n\n vec4 sum = vec4(0.0);\n float weightAll = 0.0;\n\n vec3 cN = centerNTexel.rgb * 2.0 - 1.0;\n for (int i = 0; i < 13; i++) {\n vec2 coord = clamp((float(i) - 6.0) * off + v_Texcoord, vec2(0.0), vec2(1.0));\n float w = gaussianKernel[i] * clamp(dot(cN, texture2D(gBufferTexture1, coord).rgb * 2.0 - 1.0), 0.0, 1.0);\n weightAll += w;\n sum += decodeHDR(texture2D(texture, coord)) * w;\n }\n\n#ifdef BLEND\n\n float aoFactor = 1.0;\n #ifdef SSAOTEX_ENABLED\n aoFactor = texture2D(ssaoTex, v_Texcoord).r;\n #endif\n gl_FragColor = encodeHDR(\n sum / weightAll * aoFactor + decodeHDR(texture2D(sourceTexture, v_Texcoord))\n );\n#else\n gl_FragColor = encodeHDR(sum / weightAll);\n#endif\n}\n\n@end"; - -Shader.import(SSRGLSLCode); - -function SSRPass(opt) { - opt = opt || {}; - - this._ssrPass = new Pass({ - fragment: Shader.source('ecgl.ssr.main'), - clearColor: [0, 0, 0, 0] - }); - this._blurPass1 = new Pass({ - fragment: Shader.source('ecgl.ssr.blur'), - clearColor: [0, 0, 0, 0] - }); - this._blurPass2 = new Pass({ - fragment: Shader.source('ecgl.ssr.blur'), - clearColor: [0, 0, 0, 0] - }); - - this._ssrPass.setUniform('gBufferTexture1', opt.normalTexture); - this._ssrPass.setUniform('gBufferTexture2', opt.depthTexture); - - this._blurPass1.setUniform('gBufferTexture1', opt.normalTexture); - this._blurPass2.setUniform('gBufferTexture1', opt.normalTexture); - - this._blurPass2.material.shader.define('fragment', 'VERTICAL'); - this._blurPass2.material.shader.define('fragment', 'BLEND'); - - this._texture1 = new Texture2D({ - type: Texture.HALF_FLOAT - }); - this._texture2 = new Texture2D({ - type: Texture.HALF_FLOAT - }); - - this._frameBuffer = new FrameBuffer(); -} - -SSRPass.prototype.update = function (renderer, camera, sourceTexture, frame) { - var width = renderer.getWidth(); - var height = renderer.getHeight(); - var texture1 = this._texture1; - var texture2 = this._texture2; - texture1.width = texture2.width = width; - texture1.height = texture2.height = height; - var frameBuffer = this._frameBuffer; - - var ssrPass = this._ssrPass; - var blurPass1 = this._blurPass1; - var blurPass2 = this._blurPass2; - - var viewInverseTranspose = new Matrix4(); - Matrix4.transpose(viewInverseTranspose, camera.worldTransform); - - ssrPass.setUniform('sourceTexture', sourceTexture); - ssrPass.setUniform('projection', camera.projectionMatrix._array); - ssrPass.setUniform('projectionInv', camera.invProjectionMatrix._array); - ssrPass.setUniform('viewInverseTranspose', viewInverseTranspose._array); - ssrPass.setUniform('nearZ', camera.near); - ssrPass.setUniform('jitterOffset', frame / 30); - - var textureSize = [width, height]; - - blurPass1.setUniform('textureSize', textureSize); - blurPass2.setUniform('textureSize', textureSize); - blurPass2.setUniform('sourceTexture', sourceTexture); - - frameBuffer.attach(texture2); - frameBuffer.bind(renderer); - ssrPass.render(renderer); - - frameBuffer.attach(texture1); - blurPass1.setUniform('texture', texture2); - blurPass1.render(renderer); - - frameBuffer.attach(texture2); - blurPass2.setUniform('texture', texture1); - blurPass2.render(renderer); - frameBuffer.unbind(renderer); -}; - -SSRPass.prototype.getTargetTexture = function () { - return this._texture2; -}; - -SSRPass.prototype.setParameter = function (name, val) { - if (name === 'maxIteration') { - this._ssrPass.material.shader.define('fragment', 'MAX_ITERATION', val); - } - else { - this._ssrPass.setUniform(name, val); - } -}; - -SSRPass.prototype.setSSAOTexture = function (texture) { - var blendPass = this._blurPass2; - if (texture) { - blendPass.material.shader.enableTexture('ssaoTex'); - blendPass.material.set('ssaoTex', texture); - } - else { - blendPass.material.shader.disableTexture('ssaoTex'); - } -}; - -SSRPass.prototype.dispose = function (renderer) { - this._texture1.dispose(renderer); - this._texture2.dispose(renderer); - this._frameBuffer.dispose(renderer); +SSAOPass.prototype.isFinished = function (frame) { + return frame > 30; }; -// Based on https://bl.ocks.org/mbostock/19168c663618b707158 - -var poissonKernel = [ -0.0, 0.0, --0.321585265978, -0.154972575841, -0.458126042375, 0.188473391593, -0.842080129861, 0.527766490688, -0.147304551086, -0.659453822776, --0.331943915203, -0.940619700594, -0.0479226680259, 0.54812163202, -0.701581552186, -0.709825561388, --0.295436780218, 0.940589268233, --0.901489676764, 0.237713156085, -0.973570876096, -0.109899459384, --0.866792314779, -0.451805525005, -0.330975007087, 0.800048655954, --0.344275183665, 0.381779221166, --0.386139432542, -0.437418421534, --0.576478634965, -0.0148463392551, -0.385798197415, -0.262426961053, --0.666302061145, 0.682427250835, --0.628010632582, -0.732836215494, -0.10163141741, -0.987658134403, -0.711995289051, -0.320024291314, -0.0296005138058, 0.950296523438, -0.0130612307608, -0.351024443122, --0.879596633704, -0.10478487883, -0.435712737232, 0.504254490347, -0.779203817497, 0.206477676721, -0.388264289969, -0.896736162545, --0.153106280781, -0.629203242522, --0.245517550697, 0.657969239148, -0.126830499058, 0.26862328493, --0.634888119007, -0.302301223431, -0.617074219636, 0.779817204925 -]; - -var gbufferEssl = "@export qtek.deferred.gbuffer.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat;\nuniform vec2 uvOffset;\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\n#ifdef FIRST_PASS\nattribute vec3 normal : NORMAL;\n#endif\n@import qtek.chunk.skinning_header\n#ifdef FIRST_PASS\nvarying vec3 v_Normal;\nattribute vec4 tangent : TANGENT;\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\nvarying vec3 v_WorldPosition;\n#endif\nvarying vec2 v_Texcoord;\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef FIRST_PASS\n vec3 skinnedNormal = normal;\n vec3 skinnedTangent = tangent.xyz;\n bool hasTangent = dot(tangent, tangent) > 0.0;\n#endif\n#ifdef SKINNING\n @import qtek.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n #ifdef FIRST_PASS\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n if (hasTangent) {\n skinnedTangent = (skinMatrixWS * vec4(tangent.xyz, 0.0)).xyz;\n }\n #endif\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n#ifdef FIRST_PASS\n v_Normal = normalize((worldInverseTranspose * vec4(skinnedNormal, 0.0)).xyz);\n if (hasTangent) {\n v_Tangent = normalize((worldInverseTranspose * vec4(skinnedTangent, 0.0)).xyz);\n v_Bitangent = normalize(cross(v_Normal, v_Tangent) * tangent.w);\n }\n v_WorldPosition = (world * vec4(skinnedPosition, 1.0)).xyz;\n#endif\n}\n@end\n@export qtek.deferred.gbuffer1.fragment\nuniform mat4 viewInverse : VIEWINVERSE;\nuniform float glossiness;\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nuniform sampler2D normalMap;\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\nuniform sampler2D roughGlossMap;\nuniform bool useRoughGlossMap;\nuniform bool useRoughness;\nuniform bool doubleSided;\nuniform int roughGlossChannel: 0;\nfloat indexingTexel(in vec4 texel, in int idx) {\n if (idx == 3) return texel.a;\n else if (idx == 1) return texel.g;\n else if (idx == 2) return texel.b;\n else return texel.r;\n}\nvoid main()\n{\n vec3 N = v_Normal;\n if (doubleSided) {\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = eyePos - v_WorldPosition;\n if (dot(N, V) < 0.0) {\n N = -N;\n }\n }\n if (dot(v_Tangent, v_Tangent) > 0.0) {\n vec3 normalTexel = texture2D(normalMap, v_Texcoord).xyz;\n if (dot(normalTexel, normalTexel) > 0.0) { N = normalTexel * 2.0 - 1.0;\n mat3 tbn = mat3(v_Tangent, v_Bitangent, v_Normal);\n N = normalize(tbn * N);\n }\n }\n gl_FragColor.rgb = (N + 1.0) * 0.5;\n float g = glossiness;\n if (useRoughGlossMap) {\n float g2 = indexingTexel(texture2D(roughGlossMap, v_Texcoord), roughGlossChannel);\n if (useRoughness) {\n g2 = 1.0 - g2;\n }\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n }\n gl_FragColor.a = g;\n}\n@end\n@export qtek.deferred.gbuffer2.fragment\nuniform sampler2D diffuseMap;\nuniform sampler2D metalnessMap;\nuniform vec3 color;\nuniform float metalness;\nuniform bool useMetalnessMap;\nuniform bool linear;\nvarying vec2 v_Texcoord;\n@import qtek.util.srgb\nvoid main ()\n{\n float m = metalness;\n if (useMetalnessMap) {\n vec4 metalnessTexel = texture2D(metalnessMap, v_Texcoord);\n m = clamp(metalnessTexel.r + (m * 2.0 - 1.0), 0.0, 1.0);\n }\n vec4 texel = texture2D(diffuseMap, v_Texcoord);\n if (linear) {\n texel = sRGBToLinear(texel);\n }\n gl_FragColor.rgb = texel.rgb * color;\n gl_FragColor.a = m;\n}\n@end\n@export qtek.deferred.gbuffer.debug\n@import qtek.deferred.chunk.light_head\nuniform int debug: 0;\nvoid main ()\n{\n @import qtek.deferred.chunk.gbuffer_read\n if (debug == 0) {\n gl_FragColor = vec4(N, 1.0);\n }\n else if (debug == 1) {\n gl_FragColor = vec4(vec3(z), 1.0);\n }\n else if (debug == 2) {\n gl_FragColor = vec4(position, 1.0);\n }\n else if (debug == 3) {\n gl_FragColor = vec4(vec3(glossiness), 1.0);\n }\n else if (debug == 4) {\n gl_FragColor = vec4(vec3(metalness), 1.0);\n }\n else {\n gl_FragColor = vec4(albedo, 1.0);\n }\n}\n@end"; - -var chunkEssl = "@export qtek.deferred.chunk.light_head\nuniform sampler2D gBufferTexture1;\nuniform sampler2D gBufferTexture2;\nuniform sampler2D gBufferTexture3;\nuniform vec2 windowSize: WINDOW_SIZE;\nuniform vec4 viewport: VIEWPORT;\nuniform mat4 viewProjectionInv;\n#ifdef DEPTH_ENCODED\n@import qtek.util.decode_float\n#endif\n@end\n@export qtek.deferred.chunk.gbuffer_read\n vec2 uv = gl_FragCoord.xy / windowSize;\n vec2 uv2 = (gl_FragCoord.xy - viewport.xy) / viewport.zw;\n vec4 texel1 = texture2D(gBufferTexture1, uv);\n vec4 texel3 = texture2D(gBufferTexture3, uv);\n if (dot(texel1.rgb, vec3(1.0)) == 0.0) {\n discard;\n }\n float glossiness = texel1.a;\n float metalness = texel3.a;\n vec3 N = texel1.rgb * 2.0 - 1.0;\n float z = texture2D(gBufferTexture2, uv).r * 2.0 - 1.0;\n vec2 xy = uv2 * 2.0 - 1.0;\n vec4 projectedPos = vec4(xy, z, 1.0);\n vec4 p4 = viewProjectionInv * projectedPos;\n vec3 position = p4.xyz / p4.w;\n vec3 albedo = texel3.rgb;\n vec3 diffuseColor = albedo * (1.0 - metalness);\n vec3 specularColor = mix(vec3(0.04), albedo, metalness);\n@end\n@export qtek.deferred.chunk.light_equation\nfloat D_Phong(in float g, in float ndh) {\n float a = pow(8192.0, g);\n return (a + 2.0) / 8.0 * pow(ndh, a);\n}\nfloat D_GGX(in float g, in float ndh) {\n float r = 1.0 - g;\n float a = r * r;\n float tmp = ndh * ndh * (a - 1.0) + 1.0;\n return a / (3.1415926 * tmp * tmp);\n}\nvec3 F_Schlick(in float ndv, vec3 spec) {\n return spec + (1.0 - spec) * pow(1.0 - ndv, 5.0);\n}\nvec3 lightEquation(\n in vec3 lightColor, in vec3 diffuseColor, in vec3 specularColor,\n in float ndl, in float ndh, in float ndv, in float g\n)\n{\n return ndl * lightColor\n * (diffuseColor + D_Phong(g, ndh) * F_Schlick(ndv, specularColor));\n}\n@end"; - -Shader.import(gbufferEssl); -Shader.import(chunkEssl); - -function createFillCanvas(color) { - var canvas = document.createElement('canvas'); - canvas.width = canvas.height = 1; - var ctx = canvas.getContext('2d'); - ctx.fillStyle = color || '#000'; - ctx.fillRect(0, 0, 1, 1); - - return canvas; -} - -function attachTextureToSlot(renderer, shader, symbol, texture, slot) { - var gl = renderer.gl; - shader.setUniform(gl, '1i', symbol, slot); - - gl.activeTexture(gl.TEXTURE0 + slot); - // Maybe texture is not loaded yet; - if (texture.isRenderable()) { - texture.bind(renderer); - } - else { - // Bind texture to null - texture.unbind(renderer); - } -} - -// TODO Use globalShader insteadof globalMaterial? -function getBeforeRenderHook1 (gl, defaultNormalMap, defaultRoughnessMap) { - - var previousNormalMap; - var previousRougGlossMap; - var previousRenderable; +var planeMatrix = new Matrix4(); - return function (renderable, prevMaterial, prevShader) { - // Material not change - if (previousRenderable && previousRenderable.__standardMat === renderable.__standardMat) { - return; - } +/** + * @constructor clay.geometry.Cube + * @extends clay.Geometry + * @param {Object} [opt] + * @param {number} [opt.widthSegments] + * @param {number} [opt.heightSegments] + * @param {number} [opt.depthSegments] + * @param {boolean} [opt.inside] + */ +var Cube = Geometry.extend( +/**@lends clay.geometry.Cube# */ +{ + dynamic: false, + /** + * @type {number} + */ + widthSegments: 1, + /** + * @type {number} + */ + heightSegments: 1, + /** + * @type {number} + */ + depthSegments: 1, + /** + * @type {boolean} + */ + inside: false +}, function() { + this.build(); +}, +/** @lends clay.geometry.Cube.prototype */ +{ + /** + * Build cube geometry + */ + build: function() { - var standardMaterial = renderable.__standardMat; - var gBufferMat = renderable.material; + var planes = { + 'px': createPlane('px', this.depthSegments, this.heightSegments), + 'nx': createPlane('nx', this.depthSegments, this.heightSegments), + 'py': createPlane('py', this.widthSegments, this.depthSegments), + 'ny': createPlane('ny', this.widthSegments, this.depthSegments), + 'pz': createPlane('pz', this.widthSegments, this.heightSegments), + 'nz': createPlane('nz', this.widthSegments, this.heightSegments), + }; - var glossiness; - var roughGlossMap; - var useRoughnessWorkflow = standardMaterial.shader.isDefined('fragment', 'USE_ROUGHNESS'); - var doubleSided = standardMaterial.shader.isDefined('fragment', 'DOUBLE_SIDED'); - var roughGlossChannel; - if (useRoughnessWorkflow) { - glossiness = 1.0 - standardMaterial.get('roughness'); - roughGlossMap = standardMaterial.get('roughnessMap'); - roughGlossChannel = standardMaterial.shader.getDefine('fragment', 'ROUGHNESS_CHANNEL'); - } - else { - glossiness = standardMaterial.get('glossiness'); - roughGlossMap = standardMaterial.get('glossinessMap'); - roughGlossChannel = standardMaterial.shader.getDefine('fragment', 'GLOSSINESS_CHANNEL'); + var attrList = ['position', 'texcoord0', 'normal']; + var vertexNumber = 0; + var faceNumber = 0; + for (var pos in planes) { + vertexNumber += planes[pos].vertexCount; + faceNumber += planes[pos].indices.length; } - var useRoughGlossMap = !!roughGlossMap; - - var normalMap = standardMaterial.get('normalMap') || defaultNormalMap; - var uvRepeat = standardMaterial.get('uvRepeat'); - var uvOffset = standardMaterial.get('uvOffset'); - - roughGlossMap = roughGlossMap || defaultRoughnessMap; - - if (prevMaterial !== gBufferMat) { - gBufferMat.set('glossiness', glossiness); - gBufferMat.set('normalMap', normalMap); - gBufferMat.set('roughGlossMap', roughGlossMap); - gBufferMat.set('useRoughGlossMap', +useRoughGlossMap); - gBufferMat.set('useRoughness', +useRoughnessWorkflow); - gBufferMat.set('doubleSided', +doubleSided); - gBufferMat.set('roughGlossChannel', +roughGlossChannel || 0); - gBufferMat.set('uvRepeat', uvRepeat); - gBufferMat.set('uvOffset', uvOffset); + for (var k = 0; k < attrList.length; k++) { + this.attributes[attrList[k]].init(vertexNumber); } - else { - gBufferMat.shader.setUniform( - gl, '1f', 'glossiness', glossiness - ); - - if (previousNormalMap !== normalMap) { - attachTextureToSlot(this, gBufferMat.shader, 'normalMap', normalMap, 0); - } - if (previousRougGlossMap !== roughGlossMap) { - attachTextureToSlot(this, gBufferMat.shader, 'roughGlossMap', roughGlossMap, 1); - } - gBufferMat.shader.setUniform(gl, '1i', 'useRoughGlossMap', +useRoughGlossMap); - gBufferMat.shader.setUniform(gl, '1i', 'useRoughness', +useRoughnessWorkflow); - gBufferMat.shader.setUniform(gl, '1i', 'doubleSided', +doubleSided); - gBufferMat.shader.setUniform(gl, '1i', 'roughGlossChannel', +roughGlossChannel || 0); - if (uvRepeat != null) { - gBufferMat.shader.setUniform(gl, '2f', 'uvRepeat', uvRepeat); + this.indices = new vendor.Uint16Array(faceNumber); + var faceOffset = 0; + var vertexOffset = 0; + for (var pos in planes) { + var plane = planes[pos]; + for (var k = 0; k < attrList.length; k++) { + var attrName = attrList[k]; + var attrArray = plane.attributes[attrName].value; + var attrSize = plane.attributes[attrName].size; + var isNormal = attrName === 'normal'; + for (var i = 0; i < attrArray.length; i++) { + var value = attrArray[i]; + if (this.inside && isNormal) { + value = -value; + } + this.attributes[attrName].value[i + attrSize * vertexOffset] = value; + } } - if (uvOffset != null) { - gBufferMat.shader.setUniform(gl, '2f', 'uvOffset', uvOffset); + var len = plane.indices.length; + for (var i = 0; i < plane.indices.length; i++) { + this.indices[i + faceOffset] = vertexOffset + plane.indices[this.inside ? (len - i - 1) : i]; } + faceOffset += plane.indices.length; + vertexOffset += plane.vertexCount; } - previousNormalMap = normalMap; - previousRougGlossMap = roughGlossMap; + this.boundingBox = new BoundingBox(); + this.boundingBox.max.set(1, 1, 1); + this.boundingBox.min.set(-1, -1, -1); + } +}); - previousRenderable = renderable; - }; -} +function createPlane(pos, widthSegments, heightSegments) { -function getBeforeRenderHook2(gl, defaultDiffuseMap, defaultMetalnessMap) { - var previousDiffuseMap; - var previousRenderable; - var previousMetalnessMap; + planeMatrix.identity(); - return function (renderable, prevMaterial, prevShader) { - // Material not change - if (previousRenderable && previousRenderable.__standardMat === renderable.__standardMat) { - return; - } + var plane = new Plane$2({ + widthSegments: widthSegments, + heightSegments: heightSegments + }); - var standardMaterial = renderable.__standardMat; - var gBufferMat = renderable.material; + switch(pos) { + case 'px': + Matrix4.translate(planeMatrix, planeMatrix, Vector3.POSITIVE_X); + Matrix4.rotateY(planeMatrix, planeMatrix, Math.PI / 2); + break; + case 'nx': + Matrix4.translate(planeMatrix, planeMatrix, Vector3.NEGATIVE_X); + Matrix4.rotateY(planeMatrix, planeMatrix, -Math.PI / 2); + break; + case 'py': + Matrix4.translate(planeMatrix, planeMatrix, Vector3.POSITIVE_Y); + Matrix4.rotateX(planeMatrix, planeMatrix, -Math.PI / 2); + break; + case 'ny': + Matrix4.translate(planeMatrix, planeMatrix, Vector3.NEGATIVE_Y); + Matrix4.rotateX(planeMatrix, planeMatrix, Math.PI / 2); + break; + case 'pz': + Matrix4.translate(planeMatrix, planeMatrix, Vector3.POSITIVE_Z); + break; + case 'nz': + Matrix4.translate(planeMatrix, planeMatrix, Vector3.NEGATIVE_Z); + Matrix4.rotateY(planeMatrix, planeMatrix, Math.PI); + break; + } + plane.applyTransform(planeMatrix); + return plane; +} - var color = standardMaterial.get('color'); - var metalness = standardMaterial.get('metalness'); +// TODO Should not derived from mesh? +Shader.import(skyboxEssl); +/** + * @constructor clay.plugin.Skybox + * + * @example + * var skyTex = new clay.TextureCube(); + * skyTex.load({ + * 'px': 'assets/textures/sky/px.jpg', + * 'nx': 'assets/textures/sky/nx.jpg' + * 'py': 'assets/textures/sky/py.jpg' + * 'ny': 'assets/textures/sky/ny.jpg' + * 'pz': 'assets/textures/sky/pz.jpg' + * 'nz': 'assets/textures/sky/nz.jpg' + * }); + * var skybox = new clay.plugin.Skybox({ + * scene: scene + * }); + * skybox.material.set('environmentMap', skyTex); + */ +var Skybox = Mesh.extend(function () { - var diffuseMap = standardMaterial.get('diffuseMap'); - var metalnessMap = standardMaterial.get('metalnessMap'); + var skyboxShader = new Shader({ + vertex: Shader.source('clay.skybox.vertex'), + fragment: Shader.source('clay.skybox.fragment') + }); + var material = new Material({ + shader: skyboxShader, + depthMask: false + }); - var uvRepeat = standardMaterial.get('uvRepeat'); - var uvOffset = standardMaterial.get('uvOffset'); + return { + /** + * @type {clay.Scene} + * @memberOf clay.plugin.Skybox.prototype + */ + scene: null, - var useMetalnessMap = !!metalnessMap; + geometry: new Cube(), - diffuseMap = diffuseMap || defaultDiffuseMap; - metalnessMap = metalnessMap || defaultMetalnessMap; + material: material, - if (prevMaterial !== gBufferMat) { - gBufferMat.set('color', color); - gBufferMat.set('metalness', metalness); - gBufferMat.set('diffuseMap', diffuseMap); - gBufferMat.set('metalnessMap', metalnessMap); - gBufferMat.set('useMetalnessMap', +useMetalnessMap); - gBufferMat.set('uvRepeat', uvRepeat); - gBufferMat.set('uvOffset', uvOffset); + environmentMap: null, - gBufferMat.set('linear', +standardMaterial.linear); + culling: false + }; +}, function () { + var scene = this.scene; + if (scene) { + this.attachScene(scene); + } + if (this.environmentMap) { + this.setEnvironmentMap(this.environmentMap); + } +}, /** @lends clay.plugin.Skybox# */ { + /** + * Attach the skybox to the scene + * @param {clay.Scene} scene + */ + attachScene: function (scene) { + if (this.scene) { + this.detachScene(); } - else { - gBufferMat.shader.setUniform( - gl, '1f', 'metalness', metalness - ); - - gBufferMat.shader.setUniform(gl, '3f', 'color', color); - if (previousDiffuseMap !== diffuseMap) { - attachTextureToSlot(this, gBufferMat.shader, 'diffuseMap', diffuseMap, 0); - } - if (previousMetalnessMap !== metalnessMap) { - attachTextureToSlot(this, gBufferMat.shader, 'metalnessMap', metalnessMap, 1); - } - gBufferMat.shader.setUniform(gl, '1i', 'useMetalnessMap', +useMetalnessMap); - gBufferMat.shader.setUniform(gl, '2f', 'uvRepeat', uvRepeat); - gBufferMat.shader.setUniform(gl, '2f', 'uvOffset', uvOffset); + scene.skybox = this; - gBufferMat.shader.setUniform(gl, '1i', 'linear', +standardMaterial.linear); + this.scene = scene; + scene.on('beforerender', this._beforeRenderScene, this); + }, + /** + * Detach from scene + */ + detachScene: function () { + if (this.scene) { + this.scene.off('beforerender', this._beforeRenderScene); + this.scene.skybox = null; } + this.scene = null; + }, - previousDiffuseMap = diffuseMap; - previousMetalnessMap = metalnessMap; + /** + * Dispose skybox + * @param {clay.Renderer} renderer + */ + dispose: function (renderer) { + this.detachScene(); + this.geometry.dispose(renderer); + }, + /** + * Set environment map + * @param {clay.TextureCube} envMap + */ + setEnvironmentMap: function (envMap) { + this.material.set('environmentMap', envMap); + }, + /** + * Get environment map + * @return {clay.TextureCube} + */ + getEnvironmentMap: function () { + return this.material.get('environmentMap'); + }, - previousRenderable = renderable; - }; -} + _beforeRenderScene: function(renderer, scene, camera) { + this.renderSkybox(renderer, camera); + }, -/** - * GBuffer is provided for deferred rendering and SSAO, SSR pass. - * It will do two passes rendering to three target textures. See - * + {@link qtek.deferred.GBuffer#getTargetTexture1} - * + {@link qtek.deferred.GBuffer#getTargetTexture2} - * + {@link qtek.deferred.GBuffer#getTargetTexture3} - * @constructor - * @alias qtek.deferred.GBuffer - * @extends qtek.core.Base - */ -var GBuffer = Base.extend(function () { + renderSkybox: function (renderer, camera) { + this.position.copy(camera.getWorldPosition()); + this.update(); + // Don't remember to disable blend + renderer.gl.disable(renderer.gl.BLEND); + if (this.material.get('lod') > 0) { + this.material.define('fragment', 'LOD'); + } + else { + this.material.undefine('fragment', 'LOD'); + } + renderer.renderPass([this], camera); + } +}); - return { +var integrateBRDFShaderCode = "#define SAMPLE_NUMBER 1024\n#define PI 3.14159265358979\nuniform sampler2D normalDistribution;\nuniform vec2 viewportSize : [512, 256];\nconst vec3 N = vec3(0.0, 0.0, 1.0);\nconst float fSampleNumber = float(SAMPLE_NUMBER);\nvec3 importanceSampleNormal(float i, float roughness, vec3 N) {\n vec3 H = texture2D(normalDistribution, vec2(roughness, i)).rgb;\n vec3 upVector = abs(N.y) > 0.999 ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);\n vec3 tangentX = normalize(cross(N, upVector));\n vec3 tangentZ = cross(N, tangentX);\n return normalize(tangentX * H.x + N * H.y + tangentZ * H.z);\n}\nfloat G_Smith(float roughness, float NoV, float NoL) {\n float k = roughness * roughness / 2.0;\n float G1V = NoV / (NoV * (1.0 - k) + k);\n float G1L = NoL / (NoL * (1.0 - k) + k);\n return G1L * G1V;\n}\nvoid main() {\n vec2 uv = gl_FragCoord.xy / viewportSize;\n float NoV = uv.x;\n float roughness = uv.y;\n vec3 V;\n V.x = sqrt(1.0 - NoV * NoV);\n V.y = 0.0;\n V.z = NoV;\n float A = 0.0;\n float B = 0.0;\n for (int i = 0; i < SAMPLE_NUMBER; i++) {\n vec3 H = importanceSampleNormal(float(i) / fSampleNumber, roughness, N);\n vec3 L = reflect(-V, H);\n float NoL = clamp(L.z, 0.0, 1.0);\n float NoH = clamp(H.z, 0.0, 1.0);\n float VoH = clamp(dot(V, H), 0.0, 1.0);\n if (NoL > 0.0) {\n float G = G_Smith(roughness, NoV, NoL);\n float G_Vis = G * VoH / (NoH * NoV);\n float Fc = pow(1.0 - VoH, 5.0);\n A += (1.0 - Fc) * G_Vis;\n B += Fc * G_Vis;\n }\n }\n gl_FragColor = vec4(vec2(A, B) / fSampleNumber, 0.0, 1.0);\n}\n"; - enableTargetTexture1: true, +var prefilterFragCode = "#define SHADER_NAME prefilter\n#define SAMPLE_NUMBER 1024\n#define PI 3.14159265358979\nuniform mat4 viewInverse : VIEWINVERSE;\nuniform samplerCube environmentMap;\nuniform sampler2D normalDistribution;\nuniform float roughness : 0.5;\nuniform int maxSampleNumber: 1024\nvarying vec2 v_Texcoord;\nvarying vec3 v_WorldPosition;\n@import clay.util.rgbm\nvec3 importanceSampleNormal(float i, float roughness, vec3 N) {\n vec3 H = texture2D(normalDistribution, vec2(roughness, i)).rgb;\n vec3 upVector = abs(N.y) > 0.999 ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);\n vec3 tangentX = normalize(cross(N, upVector));\n vec3 tangentZ = cross(N, tangentX);\n return normalize(tangentX * H.x + N * H.y + tangentZ * H.z);\n}\nvoid main() {\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = normalize(v_WorldPosition - eyePos);\n vec3 N = V;\n vec3 prefilteredColor = vec3(0.0);\n float totalWeight = 0.0;\n float fMaxSampleNumber = float(maxSampleNumber);\n for (int i = 0; i < SAMPLE_NUMBER; i++) {\n if (i > maxSampleNumber) {\n break;\n }\n vec3 H = importanceSampleNormal(float(i) / fMaxSampleNumber, roughness, N);\n vec3 L = reflect(-V, H);\n float NoL = clamp(dot(N, L), 0.0, 1.0);\n if (NoL > 0.0) {\n prefilteredColor += decodeHDR(textureCube(environmentMap, L)).rgb * NoL;\n totalWeight += NoL;\n }\n }\n gl_FragColor = encodeHDR(vec4(prefilteredColor / totalWeight, 1.0));\n}\n"; + +// Cubemap prefilter utility +// http://www.unrealengine.com/files/downloads/2013SiggraphPresentationsNotes.pdf +// http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html +var cubemapUtil = {}; - enableTargetTexture2: true, +var targets$2 = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; - enableTargetTexture3: true, +/** + * @name clay.util.cubemap.prefilterEnvironmentMap + * @param {clay.Renderer} renderer + * @param {clay.Texture} envMap + * @param {Object} [textureOpts] + * @param {number} [textureOpts.width=64] + * @param {number} [textureOpts.height=64] + * @param {number} [textureOpts.type] + * @param {boolean} [textureOpts.encodeRGBM=false] + * @param {boolean} [textureOpts.decodeRGBM=false] + * @param {clay.Texture2D} [normalDistribution] + * @param {clay.Texture2D} [brdfLookup] + */ +cubemapUtil.prefilterEnvironmentMap = function ( + renderer, envMap, textureOpts, normalDistribution, brdfLookup +) { + // Not create other renderer, it is easy having issue of cross reference of resources like framebuffer + // PENDING preserveDrawingBuffer? + if (!brdfLookup || !normalDistribution) { + normalDistribution = cubemapUtil.generateNormalDistribution(); + brdfLookup = cubemapUtil.integrateBRDF(renderer, normalDistribution); + } + textureOpts = textureOpts || {}; - _renderQueue: [], - // - R: normal.x - // - G: normal.y - // - B: normal.z - // - A: glossiness - _gBufferTex1: new Texture2D({ - minFilter: Texture.NEAREST, - magFilter: Texture.NEAREST, - // PENDING - type: Texture.HALF_FLOAT - }), + var width = textureOpts.width || 64; + var height = textureOpts.height || 64; - // - R: depth - _gBufferTex2: new Texture2D({ - minFilter: Texture.NEAREST, - magFilter: Texture.NEAREST, - // format: Texture.DEPTH_COMPONENT, - // type: Texture.UNSIGNED_INT + var textureType = textureOpts.type || envMap.type; - format: Texture.DEPTH_STENCIL, - type: Texture.UNSIGNED_INT_24_8_WEBGL - }), + // Use same type with given envMap + var prefilteredCubeMap = new TextureCube({ + width: width, + height: height, + type: textureType, + flipY: false, + mipmaps: [] + }); - // - R: albedo.r - // - G: albedo.g - // - B: albedo.b - // - A: metalness - _gBufferTex3: new Texture2D({ - minFilter: Texture.NEAREST, - magFilter: Texture.NEAREST - }), + if (!prefilteredCubeMap.isPowerOfTwo()) { + console.warn('Width and height must be power of two to enable mipmap.'); + } - _defaultNormalMap: new Texture2D({ - image: createFillCanvas('#000') - }), - _defaultRoughnessMap: new Texture2D({ - image: createFillCanvas('#fff') - }), - _defaultMetalnessMap: new Texture2D({ - image: createFillCanvas('#fff') - }), - _defaultDiffuseMap: new Texture2D({ - image: createFillCanvas('#fff') - }), + var size = Math.min(width, height); + var mipmapNum = Math.log(size) / Math.log(2) + 1; - _frameBuffer: new FrameBuffer(), + var prefilterMaterial = new Material({ + shader: new Shader({ + vertex: Shader.source('clay.skybox.vertex'), + fragment: prefilterFragCode + }) + }); + prefilterMaterial.set('normalDistribution', normalDistribution); - _gBufferMaterials: {}, + textureOpts.encodeRGBM && prefilterMaterial.define('fragment', 'RGBM_ENCODE'); + textureOpts.decodeRGBM && prefilterMaterial.define('fragment', 'RGBM_DECODE'); - _debugPass: new Pass({ - fragment: Shader.source('qtek.deferred.gbuffer.debug') - }) - }; -}, /** @lends qtek.deferred.GBuffer# */{ + var dummyScene = new Scene(); + var skyEnv; - /** - * Set G Buffer size. - * @param {number} width - * @param {number} height - */ - resize: function (width, height) { - if (this._gBufferTex1.width === width - && this._gBufferTex1.height === height - ) { - return; - } - this._gBufferTex1.width = width; - this._gBufferTex1.height = height; + if (envMap.textureType === 'texture2D') { + // Convert panorama to cubemap + var envCubemap = new TextureCube({ + width: width, + height: height, + // FIXME FLOAT type will cause GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT error on iOS + type: textureType === Texture$1.FLOAT ? + Texture$1.HALF_FLOAT : textureType + }); + textureUtil.panoramaToCubeMap(renderer, envMap, envCubemap, { + // PENDING encodeRGBM so it can be decoded as RGBM + encodeRGBM: textureOpts.decodeRGBM + }); + envMap = envCubemap; + } + skyEnv = new Skybox({ + scene: dummyScene, + material: prefilterMaterial + }); + skyEnv.material.set('environmentMap', envMap); - this._gBufferTex2.width = width; - this._gBufferTex2.height = height; + var envMapPass = new EnvironmentMapPass({ + texture: prefilteredCubeMap + }); - this._gBufferTex3.width = width; - this._gBufferTex3.height = height; - }, + // Force to be UNSIGNED_BYTE + if (textureOpts.encodeRGBM) { + textureType = prefilteredCubeMap.type = Texture$1.UNSIGNED_BYTE; + } - // TODO is dpr needed? - setViewport: function (x, y, width, height, dpr) { - var viewport; - if (typeof x === 'object') { - viewport = x; - } - else { - viewport = { - x: x, y: y, - width: width, height: height, - devicePixelRatio: dpr || 1 - }; + var renderTargetTmp = new Texture2D({ + width: width, + height: height, + type: textureType + }); + var frameBuffer = new FrameBuffer({ + depthBuffer: false + }); + var ArrayCtor = vendor[textureType === Texture$1.UNSIGNED_BYTE ? 'Uint8Array' : 'Float32Array']; + for (var i = 0; i < mipmapNum; i++) { + // console.time('prefilter'); + prefilteredCubeMap.mipmaps[i] = { + pixels: {} + }; + skyEnv.material.set('roughness', i / (targets$2.length - 1)); + var maxSampleNumber = renderTargetTmp.width * renderTargetTmp.height; + if (renderTargetTmp.width >= 32) { + maxSampleNumber /= 4; } - this._frameBuffer.viewport = viewport; - }, + skyEnv.material.set('maxSampleNumber', Math.min(maxSampleNumber, 1024)); - getViewport: function () { - if (this._frameBuffer.viewport) { - return this._frameBuffer.viewport; - } - else { - return { - x: 0, y: 0, - width: this._gBufferTex1.width, - height: this._gBufferTex1.height, - devicePixelRatio: 1 - }; - } - }, + // Tweak fov + // http://the-witness.net/news/2012/02/seamless-cube-map-filtering/ + var n = renderTargetTmp.width; + var fov = 2 * Math.atan(n / (n - 0.5)) / Math.PI * 180; - /** - * Update G Buffer - * @param {qtek.Renderer} renderer - * @param {qtek.Scene} scene - * @param {qtek.camera.Perspective} camera - */ - update: function (renderer, scene, camera) { + for (var j = 0; j < targets$2.length; j++) { + var pixels = new ArrayCtor(renderTargetTmp.width * renderTargetTmp.height * 4); + frameBuffer.attach(renderTargetTmp); + frameBuffer.bind(renderer); - var gl = renderer.gl; + var camera = envMapPass.getCamera(targets$2[j]); + camera.fov = fov; + renderer.render(dummyScene, camera); + renderer.gl.readPixels( + 0, 0, renderTargetTmp.width, renderTargetTmp.height, + Texture$1.RGBA, textureType, pixels + ); - var frameBuffer = this._frameBuffer; - var viewport = frameBuffer.viewport; - var opaqueQueue = scene.opaqueQueue; - var transparentQueue = scene.transparentQueue; - var oldBeforeRender = renderer.beforeRenderObject; + // var canvas = document.createElement('canvas'); + // var ctx = canvas.getContext('2d'); + // canvas.width = renderTargetTmp.width; + // canvas.height = renderTargetTmp.height; + // var imageData = ctx.createImageData(renderTargetTmp.width, renderTargetTmp.height); + // for (var k = 0; k < pixels.length; k++) { + // imageData.data[k] = pixels[k]; + // } + // ctx.putImageData(imageData, 0, 0); + // document.body.appendChild(canvas); - // StandardMaterial needs updateShader method so shader can be created on demand. - for (var i = 0; i < opaqueQueue.length; i++) { - var material = opaqueQueue[i].material; - material.updateShader && material.updateShader(renderer); - } - for (var i = 0; i < transparentQueue.length; i++) { - var material = transparentQueue[i].material; - material.updateShader && material.updateShader(renderer); + frameBuffer.unbind(renderer); + prefilteredCubeMap.mipmaps[i].pixels[targets$2[j]] = pixels; } - opaqueQueue.sort(Renderer.opaqueSortFunc); - transparentQueue.sort(Renderer.transparentSortFunc); + renderTargetTmp.width /= 2; + renderTargetTmp.height /= 2; + renderTargetTmp.dirty(); + // console.timeEnd('prefilter'); + } - var offset = 0; - var renderQueue = this._renderQueue; - for (var i = 0; i < opaqueQueue.length; i++) { - if (!opaqueQueue[i].ignoreGBuffer) { - renderQueue[offset++] = opaqueQueue[i]; - } - } - for (var i = 0; i < transparentQueue.length; i++) { - if (!transparentQueue[i].ignoreGBuffer) { - renderQueue[offset++] = transparentQueue[i]; - } - } - renderQueue.length = offset; + frameBuffer.dispose(renderer); + renderTargetTmp.dispose(renderer); + skyEnv.dispose(renderer); + // Remove gpu resource allucated in renderer + normalDistribution.dispose(renderer); + // renderer.dispose(); - gl.clearColor(0, 0, 0, 0); - gl.depthMask(true); - gl.colorMask(true, true, true, true); - gl.disable(gl.BLEND); + return { + environmentMap: prefilteredCubeMap, + brdfLookup: brdfLookup, + normalDistribution: normalDistribution, + maxMipmapLevel: mipmapNum + }; +}; - var enableTargetTexture1 = this.enableTargetTexture1; - var enableTargetTexture2 = this.enableTargetTexture2; - var enableTargetTexture3 = this.enableTargetTexture3; - if (!enableTargetTexture1 && !enableTargetTexture3) { - console.warn('Can\'t disable targetTexture1 targetTexture3 both'); - enableTargetTexture1 = true; - } +cubemapUtil.integrateBRDF = function (renderer, normalDistribution) { + normalDistribution = normalDistribution || cubemapUtil.generateNormalDistribution(); + var framebuffer = new FrameBuffer({ + depthBuffer: false + }); + var pass = new Pass({ + fragment: integrateBRDFShaderCode + }); + + var texture = new Texture2D({ + width: 512, + height: 256, + type: Texture$1.HALF_FLOAT, + wrapS: Texture$1.CLAMP_TO_EDGE, + wrapT: Texture$1.CLAMP_TO_EDGE, + minFilter: Texture$1.NEAREST, + magFilter: Texture$1.NEAREST, + useMipmap: false + }); + pass.setUniform('normalDistribution', normalDistribution); + pass.setUniform('viewportSize', [512, 256]); + pass.attachOutput(texture); + pass.render(renderer, framebuffer); + + // FIXME Only chrome and firefox can readPixels with float type. + // framebuffer.bind(renderer); + // var pixels = new Float32Array(512 * 256 * 4); + // renderer.gl.readPixels( + // 0, 0, texture.width, texture.height, + // Texture.RGBA, Texture.FLOAT, pixels + // ); + // texture.pixels = pixels; + // texture.flipY = false; + // texture.dirty(); + // framebuffer.unbind(renderer); - if (enableTargetTexture2) { - frameBuffer.attach(this._gBufferTex2, renderer.gl.DEPTH_STENCIL_ATTACHMENT); - } + framebuffer.dispose(renderer); - // PENDING, scene.boundingBoxLastFrame needs be updated if have shadow - renderer.bindSceneRendering(scene); - if (enableTargetTexture1) { - // Pass 1 - frameBuffer.attach(this._gBufferTex1); - frameBuffer.bind(renderer); + return texture; +}; - if (viewport) { - var dpr = viewport.devicePixelRatio; - // use scissor to make sure only clear the viewport - gl.enable(gl.SCISSOR_TEST); - gl.scissor(viewport.x * dpr, viewport.y * dpr, viewport.width * dpr, viewport.height * dpr); - } - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - if (viewport) { - gl.disable(gl.SCISSOR_TEST); - } +cubemapUtil.generateNormalDistribution = function (roughnessLevels, sampleSize) { - this._resetGBufferMaterials(); + // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + // GLSL not support bit operation, use lookup instead + // V -> i / N, U -> roughness + var roughnessLevels = roughnessLevels || 256; + var sampleSize = sampleSize || 1024; - this._replaceGBufferMat(renderQueue, 1); + var normalDistribution = new Texture2D({ + width: roughnessLevels, + height: sampleSize, + type: Texture$1.FLOAT, + minFilter: Texture$1.NEAREST, + magFilter: Texture$1.NEAREST, + wrapS: Texture$1.CLAMP_TO_EDGE, + wrapT: Texture$1.CLAMP_TO_EDGE, + useMipmap: false + }); + var pixels = new Float32Array(sampleSize * roughnessLevels * 4); + var tmp = []; - // FIXME Use MRT if possible - // Pass 1 - renderer.beforeRenderObject = getBeforeRenderHook1( - gl, - this._defaultNormalMap, - this._defaultRoughnessMap - ); - renderer.renderQueue(renderQueue, camera); + // function sortFunc(a, b) { + // return Math.abs(b) - Math.abs(a); + // } + for (var j = 0; j < roughnessLevels; j++) { + var roughness = j / roughnessLevels; + var a = roughness * roughness; + + for (var i = 0; i < sampleSize; i++) { + // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators + // http://stackoverflow.com/questions/1908492/unsigned-integer-in-javascript + // http://stackoverflow.com/questions/1822350/what-is-the-javascript-operator-and-how-do-you-use-it + var y = (i << 16 | i >>> 16) >>> 0; + y = ((y & 1431655765) << 1 | (y & 2863311530) >>> 1) >>> 0; + y = ((y & 858993459) << 2 | (y & 3435973836) >>> 2) >>> 0; + y = ((y & 252645135) << 4 | (y & 4042322160) >>> 4) >>> 0; + y = (((y & 16711935) << 8 | (y & 4278255360) >>> 8) >>> 0) / 4294967296; + // CDF + var cosTheta = Math.sqrt((1 - y) / (1 + (a * a - 1.0) * y)); + tmp[i] = cosTheta; } - if (enableTargetTexture3) { - // Pass 2 - frameBuffer.attach(this._gBufferTex3); - frameBuffer.bind(renderer); + for (var i = 0; i < sampleSize; i++) { + var offset = (i * roughnessLevels + j) * 4; + var cosTheta = tmp[i]; + var sinTheta = Math.sqrt(1.0 - cosTheta * cosTheta); + var x = i / sampleSize; + var phi = 2.0 * Math.PI * x; + pixels[offset] = sinTheta * Math.cos(phi); + pixels[offset + 1] = cosTheta; + pixels[offset + 2] = sinTheta * Math.sin(phi); + pixels[offset + 3] = 1.0; + } + } + normalDistribution.pixels = pixels; - if (viewport) { - var dpr = viewport.devicePixelRatio; - // use scissor to make sure only clear the viewport - gl.enable(gl.SCISSOR_TEST); - gl.scissor(viewport.x * dpr, viewport.y * dpr, viewport.width * dpr, viewport.height * dpr); - } - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - if (viewport) { - gl.disable(gl.SCISSOR_TEST); - } + return normalDistribution; +}; - this._replaceGBufferMat(renderQueue, 2); - renderer.beforeRenderObject = getBeforeRenderHook2( - gl, - this._defaultDiffuseMap, - this._defaultMetalnessMap - ); - renderer.renderQueue(renderQueue, camera); +var SSRGLSLCode = "@export ecgl.ssr.main\n\n#define SHADER_NAME SSR\n#define MAX_ITERATION 20;\n#define SAMPLE_PER_FRAME 5;\n#define TOTAL_SAMPLES 128;\n\nuniform sampler2D sourceTexture;\nuniform sampler2D gBufferTexture1;\nuniform sampler2D gBufferTexture2;\nuniform sampler2D gBufferTexture3;\nuniform samplerCube specularCubemap;\nuniform float specularIntensity: 1;\n\nuniform mat4 projection;\nuniform mat4 projectionInv;\nuniform mat4 toViewSpace;\nuniform mat4 toWorldSpace;\n\nuniform float maxRayDistance: 200;\n\nuniform float pixelStride: 16;\nuniform float pixelStrideZCutoff: 50; \nuniform float screenEdgeFadeStart: 0.9; \nuniform float eyeFadeStart : 0.2; uniform float eyeFadeEnd: 0.8; \nuniform float minGlossiness: 0.2; uniform float zThicknessThreshold: 1;\n\nuniform float nearZ;\nuniform vec2 viewportSize : VIEWPORT_SIZE;\n\nuniform float jitterOffset: 0;\n\nvarying vec2 v_Texcoord;\n\n#ifdef DEPTH_DECODE\n@import clay.util.decode_float\n#endif\n\n#ifdef PHYSICALLY_CORRECT\nuniform sampler2D normalDistribution;\nuniform float sampleOffset: 0;\nuniform vec2 normalDistributionSize;\n\nvec3 transformNormal(vec3 H, vec3 N) {\n vec3 upVector = N.y > 0.999 ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);\n vec3 tangentX = normalize(cross(N, upVector));\n vec3 tangentZ = cross(N, tangentX);\n return normalize(tangentX * H.x + N * H.y + tangentZ * H.z);\n}\nvec3 importanceSampleNormalGGX(float i, float roughness, vec3 N) {\n float p = fract((i + sampleOffset) / float(TOTAL_SAMPLES));\n vec3 H = texture2D(normalDistribution,vec2(roughness, p)).rgb;\n return transformNormal(H, N);\n}\nfloat G_Smith(float g, float ndv, float ndl) {\n float roughness = 1.0 - g;\n float k = roughness * roughness / 2.0;\n float G1V = ndv / (ndv * (1.0 - k) + k);\n float G1L = ndl / (ndl * (1.0 - k) + k);\n return G1L * G1V;\n}\nvec3 F_Schlick(float ndv, vec3 spec) {\n return spec + (1.0 - spec) * pow(1.0 - ndv, 5.0);\n}\n#endif\n\nfloat fetchDepth(sampler2D depthTexture, vec2 uv)\n{\n vec4 depthTexel = texture2D(depthTexture, uv);\n return depthTexel.r * 2.0 - 1.0;\n}\n\nfloat linearDepth(float depth)\n{\n if (projection[3][3] == 0.0) {\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n }\n else {\n return (depth - projection[3][2]) / projection[2][2];\n }\n}\n\nbool rayIntersectDepth(float rayZNear, float rayZFar, vec2 hitPixel)\n{\n if (rayZFar > rayZNear)\n {\n float t = rayZFar; rayZFar = rayZNear; rayZNear = t;\n }\n float cameraZ = linearDepth(fetchDepth(gBufferTexture2, hitPixel));\n return rayZFar <= cameraZ && rayZNear >= cameraZ - zThicknessThreshold;\n}\n\n\nbool traceScreenSpaceRay(\n vec3 rayOrigin, vec3 rayDir, float jitter,\n out vec2 hitPixel, out vec3 hitPoint, out float iterationCount\n)\n{\n float rayLength = ((rayOrigin.z + rayDir.z * maxRayDistance) > -nearZ)\n ? (-nearZ - rayOrigin.z) / rayDir.z : maxRayDistance;\n\n vec3 rayEnd = rayOrigin + rayDir * rayLength;\n\n vec4 H0 = projection * vec4(rayOrigin, 1.0);\n vec4 H1 = projection * vec4(rayEnd, 1.0);\n\n float k0 = 1.0 / H0.w, k1 = 1.0 / H1.w;\n\n vec3 Q0 = rayOrigin * k0, Q1 = rayEnd * k1;\n\n vec2 P0 = (H0.xy * k0 * 0.5 + 0.5) * viewportSize;\n vec2 P1 = (H1.xy * k1 * 0.5 + 0.5) * viewportSize;\n\n P1 += dot(P1 - P0, P1 - P0) < 0.0001 ? 0.01 : 0.0;\n vec2 delta = P1 - P0;\n\n bool permute = false;\n if (abs(delta.x) < abs(delta.y)) {\n permute = true;\n delta = delta.yx;\n P0 = P0.yx;\n P1 = P1.yx;\n }\n float stepDir = sign(delta.x);\n float invdx = stepDir / delta.x;\n\n vec3 dQ = (Q1 - Q0) * invdx;\n float dk = (k1 - k0) * invdx;\n\n vec2 dP = vec2(stepDir, delta.y * invdx);\n\n float strideScaler = 1.0 - min(1.0, -rayOrigin.z / pixelStrideZCutoff);\n float pixStride = 1.0 + strideScaler * pixelStride;\n\n dP *= pixStride; dQ *= pixStride; dk *= pixStride;\n\n vec4 pqk = vec4(P0, Q0.z, k0);\n vec4 dPQK = vec4(dP, dQ.z, dk);\n\n pqk += dPQK * jitter;\n float rayZFar = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);\n float rayZNear;\n\n bool intersect = false;\n\n vec2 texelSize = 1.0 / viewportSize;\n\n iterationCount = 0.0;\n\n for (int i = 0; i < MAX_ITERATION; i++)\n {\n pqk += dPQK;\n\n rayZNear = rayZFar;\n rayZFar = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);\n\n hitPixel = permute ? pqk.yx : pqk.xy;\n hitPixel *= texelSize;\n\n intersect = rayIntersectDepth(rayZNear, rayZFar, hitPixel);\n\n iterationCount += 1.0;\n\n dPQK *= 1.2;\n\n if (intersect) {\n break;\n }\n }\n\n Q0.xy += dQ.xy * iterationCount;\n Q0.z = pqk.z;\n hitPoint = Q0 / pqk.w;\n\n return intersect;\n}\n\nfloat calculateAlpha(\n float iterationCount, float reflectivity,\n vec2 hitPixel, vec3 hitPoint, float dist, vec3 rayDir\n)\n{\n float alpha = clamp(reflectivity, 0.0, 1.0);\n alpha *= 1.0 - (iterationCount / float(MAX_ITERATION));\n vec2 hitPixelNDC = hitPixel * 2.0 - 1.0;\n float maxDimension = min(1.0, max(abs(hitPixelNDC.x), abs(hitPixelNDC.y)));\n alpha *= 1.0 - max(0.0, maxDimension - screenEdgeFadeStart) / (1.0 - screenEdgeFadeStart);\n\n float _eyeFadeStart = eyeFadeStart;\n float _eyeFadeEnd = eyeFadeEnd;\n if (_eyeFadeStart > _eyeFadeEnd) {\n float tmp = _eyeFadeEnd;\n _eyeFadeEnd = _eyeFadeStart;\n _eyeFadeStart = tmp;\n }\n\n float eyeDir = clamp(rayDir.z, _eyeFadeStart, _eyeFadeEnd);\n alpha *= 1.0 - (eyeDir - _eyeFadeStart) / (_eyeFadeEnd - _eyeFadeStart);\n\n alpha *= 1.0 - clamp(dist / maxRayDistance, 0.0, 1.0);\n\n return alpha;\n}\n\n@import clay.util.rand\n\n@import clay.util.rgbm\n\nvoid main()\n{\n vec4 normalAndGloss = texture2D(gBufferTexture1, v_Texcoord);\n\n if (dot(normalAndGloss.rgb, vec3(1.0)) == 0.0) {\n discard;\n }\n\n float g = normalAndGloss.a;\n#if !defined(PHYSICALLY_CORRECT)\n if (g <= minGlossiness) {\n discard;\n }\n#endif\n\n float reflectivity = (g - minGlossiness) / (1.0 - minGlossiness);\n\n vec3 N = normalize(normalAndGloss.rgb * 2.0 - 1.0);\n N = normalize((toViewSpace * vec4(N, 0.0)).xyz);\n\n vec4 projectedPos = vec4(v_Texcoord * 2.0 - 1.0, fetchDepth(gBufferTexture2, v_Texcoord), 1.0);\n vec4 pos = projectionInv * projectedPos;\n vec3 rayOrigin = pos.xyz / pos.w;\n vec3 V = -normalize(rayOrigin);\n\n float ndv = clamp(dot(N, V), 0.0, 1.0);\n float iterationCount;\n float jitter = rand(fract(v_Texcoord + jitterOffset));\n\n#ifdef PHYSICALLY_CORRECT\n vec4 color = vec4(vec3(0.0), 1.0);\n vec4 albedoMetalness = texture2D(gBufferTexture3, v_Texcoord);\n vec3 albedo = albedoMetalness.rgb;\n float m = albedoMetalness.a;\n vec3 diffuseColor = albedo * (1.0 - m);\n vec3 spec = mix(vec3(0.04), albedo, m);\n\n float jitter2 = rand(fract(v_Texcoord)) * float(TOTAL_SAMPLES);\n\n for (int i = 0; i < SAMPLE_PER_FRAME; i++) {\n vec3 H = importanceSampleNormalGGX(float(i) + jitter2, 1.0 - g, N);\n vec3 rayDir = normalize(reflect(-V, H));\n#else\n vec3 rayDir = normalize(reflect(-V, N));\n#endif\n vec2 hitPixel;\n vec3 hitPoint;\n\n bool intersect = traceScreenSpaceRay(rayOrigin, rayDir, jitter, hitPixel, hitPoint, iterationCount);\n\n float dist = distance(rayOrigin, hitPoint);\n\n vec3 hitNormal = texture2D(gBufferTexture1, hitPixel).rgb * 2.0 - 1.0;\n hitNormal = normalize((toViewSpace * vec4(hitNormal, 0.0)).xyz);\n#ifdef PHYSICALLY_CORRECT\n float ndl = clamp(dot(N, rayDir), 0.0, 1.0);\n float vdh = clamp(dot(V, H), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n vec3 litTexel = vec3(0.0);\n if (dot(hitNormal, rayDir) < 0.0 && intersect) {\n litTexel = texture2D(sourceTexture, hitPixel).rgb;\n litTexel *= pow(clamp(1.0 - dist / 200.0, 0.0, 1.0), 3.0);\n\n }\n else {\n #ifdef SPECULARCUBEMAP_ENABLED\n vec3 rayDirW = normalize(toWorldSpace * vec4(rayDir, 0.0)).rgb;\n litTexel = RGBMDecode(textureCubeLodEXT(specularCubemap, rayDirW, 0.0), 8.12).rgb * specularIntensity;\n#endif\n }\n color.rgb += ndl * litTexel * (\n F_Schlick(ndl, spec) * G_Smith(g, ndv, ndl) * vdh / (ndh * ndv + 0.001)\n );\n }\n color.rgb /= float(SAMPLE_PER_FRAME);\n#else\n #if !defined(SPECULARCUBEMAP_ENABLED)\n if (dot(hitNormal, rayDir) >= 0.0) {\n discard;\n }\n if (!intersect) {\n discard;\n }\n#endif\n float alpha = clamp(calculateAlpha(iterationCount, reflectivity, hitPixel, hitPoint, dist, rayDir), 0.0, 1.0);\n vec4 color = texture2D(sourceTexture, hitPixel);\n color.rgb *= alpha;\n\n#ifdef SPECULARCUBEMAP_ENABLED\n vec3 rayDirW = normalize(toWorldSpace * vec4(rayDir, 0.0)).rgb;\n alpha = alpha * (intersect ? 1.0 : 0.0);\n float bias = (1.0 -g) * 5.0;\n color.rgb += (1.0 - alpha) * RGBMDecode(textureCubeLodEXT(specularCubemap, rayDirW, bias), 8.12).rgb * specularIntensity;\n#endif\n\n#endif\n\n gl_FragColor = encodeHDR(color);\n}\n@end\n\n@export ecgl.ssr.blur\n\nuniform sampler2D texture;\nuniform sampler2D gBufferTexture1;\nuniform sampler2D gBufferTexture2;\nuniform mat4 projection;\nuniform float depthRange : 0.05;\n\nvarying vec2 v_Texcoord;\n\nuniform vec2 textureSize;\nuniform float blurSize : 1.0;\n\n#ifdef BLEND\n #ifdef SSAOTEX_ENABLED\nuniform sampler2D ssaoTex;\n #endif\nuniform sampler2D sourceTexture;\n#endif\n\nfloat getLinearDepth(vec2 coord)\n{\n float depth = texture2D(gBufferTexture2, coord).r * 2.0 - 1.0;\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n}\n\n@import clay.util.rgbm\n\n\nvoid main()\n{\n @import clay.compositor.kernel.gaussian_9\n\n vec4 centerNTexel = texture2D(gBufferTexture1, v_Texcoord);\n float g = centerNTexel.a;\n float maxBlurSize = clamp(1.0 - g, 0.0, 1.0) * blurSize;\n#ifdef VERTICAL\n vec2 off = vec2(0.0, maxBlurSize / textureSize.y);\n#else\n vec2 off = vec2(maxBlurSize / textureSize.x, 0.0);\n#endif\n\n vec2 coord = v_Texcoord;\n\n vec4 sum = vec4(0.0);\n float weightAll = 0.0;\n\n vec3 cN = centerNTexel.rgb * 2.0 - 1.0;\n float cD = getLinearDepth(v_Texcoord);\n for (int i = 0; i < 9; i++) {\n vec2 coord = clamp((float(i) - 4.0) * off + v_Texcoord, vec2(0.0), vec2(1.0));\n float w = gaussianKernel[i]\n * clamp(dot(cN, texture2D(gBufferTexture1, coord).rgb * 2.0 - 1.0), 0.0, 1.0);\n float d = getLinearDepth(coord);\n w *= (1.0 - smoothstep(abs(cD - d) / depthRange, 0.0, 1.0));\n\n weightAll += w;\n sum += decodeHDR(texture2D(texture, coord)) * w;\n }\n\n#ifdef BLEND\n float aoFactor = 1.0;\n #ifdef SSAOTEX_ENABLED\n aoFactor = texture2D(ssaoTex, v_Texcoord).r;\n #endif\n gl_FragColor = encodeHDR(\n sum / weightAll * aoFactor + decodeHDR(texture2D(sourceTexture, v_Texcoord))\n );\n#else\n gl_FragColor = encodeHDR(sum / weightAll);\n#endif\n}\n\n@end"; - } +Shader.import(SSRGLSLCode); - renderer.bindSceneRendering(null); +// function generateNormals(size, offset, hemisphere) { +// var kernel = new Float32Array(size * 3); +// offset = offset || 0; +// for (var i = 0; i < size; i++) { +// var phi = halton(i + offset, 2) * (hemisphere ? 1 : 2) * Math.PI / 2; +// var theta = halton(i + offset, 3) * 2 * Math.PI; +// var x = Math.cos(theta) * Math.sin(phi); +// var y = Math.sin(theta) * Math.sin(phi); +// var z = Math.cos(phi); +// kernel[i * 3] = x; +// kernel[i * 3 + 1] = y; +// kernel[i * 3 + 2] = z; +// } +// return kernel; +// } - renderer.beforeRenderObject = oldBeforeRender; - this._cleanGBufferMaterials(renderer); - this._restoreMaterial(renderQueue); +function SSRPass(opt) { + opt = opt || {}; - frameBuffer.unbind(renderer); - }, + this._ssrPass = new Pass({ + fragment: Shader.source('ecgl.ssr.main'), + clearColor: [0, 0, 0, 0] + }); + this._blurPass1 = new Pass({ + fragment: Shader.source('ecgl.ssr.blur'), + clearColor: [0, 0, 0, 0] + }); + this._blurPass2 = new Pass({ + fragment: Shader.source('ecgl.ssr.blur'), + clearColor: [0, 0, 0, 0] + }); + this._blendPass = new Pass({ + fragment: Shader.source('clay.compositor.blend') + }); + this._blendPass.material.disableTexturesAll(); + this._blendPass.material.enableTexture(['texture1', 'texture2']); - renderDebug: function (renderer, camera, type, viewport) { - var debugTypes = { - normal: 0, - depth: 1, - position: 2, - glossiness: 3, - metalness: 4, - albedo: 5 - }; - if (debugTypes[type] == null) { - console.warn('Unkown type "' + type + '"'); - // Default use normal - type = 'normal'; - } + this._ssrPass.setUniform('gBufferTexture1', opt.normalTexture); + this._ssrPass.setUniform('gBufferTexture2', opt.depthTexture); + this._ssrPass.setUniform('gBufferTexture3', opt.albedoTexture); - renderer.saveClear(); - renderer.saveViewport(); - renderer.clearBit = renderer.gl.DEPTH_BUFFER_BIT; + this._blurPass1.setUniform('gBufferTexture1', opt.normalTexture); + this._blurPass1.setUniform('gBufferTexture2', opt.depthTexture); - if (viewport) { - renderer.setViewport(viewport); - } - var viewProjectionInv = new Matrix4(); - Matrix4.multiply(viewProjectionInv, camera.worldTransform, camera.invProjectionMatrix); + this._blurPass2.setUniform('gBufferTexture1', opt.normalTexture); + this._blurPass2.setUniform('gBufferTexture2', opt.depthTexture); - var debugPass = this._debugPass; - debugPass.setUniform('viewportSize', [renderer.getWidth(), renderer.getHeight()]); - debugPass.setUniform('gBufferTexture1', this._gBufferTex1); - debugPass.setUniform('gBufferTexture2', this._gBufferTex2); - debugPass.setUniform('gBufferTexture3', this._gBufferTex3); - debugPass.setUniform('debug', debugTypes[type]); - debugPass.setUniform('viewProjectionInv', viewProjectionInv._array); - debugPass.render(renderer); + this._blurPass2.material.define('fragment', 'VERTICAL'); + this._blurPass2.material.define('fragment', 'BLEND'); - renderer.restoreViewport(); - renderer.restoreClear(); - }, + this._ssrTexture = new Texture2D({ + type: Texture$1.HALF_FLOAT + }); + this._texture2 = new Texture2D({ + type: Texture$1.HALF_FLOAT + }); + this._texture3 = new Texture2D({ + type: Texture$1.HALF_FLOAT + }); + this._prevTexture = new Texture2D({ + type: Texture$1.HALF_FLOAT + }); + this._currentTexture = new Texture2D({ + type: Texture$1.HALF_FLOAT + }); - /** - * Get first target texture. - * Channel storage: - * + R: normal.x * 0.5 + 0.5 - * + G: normal.y * 0.5 + 0.5 - * + B: normal.z * 0.5 + 0.5 - * + A: glossiness - * @return {qtek.Texture2D} - */ - getTargetTexture1: function () { - return this._gBufferTex1; - }, + this._frameBuffer = new FrameBuffer({ + depthBuffer: false + }); - /** - * Get second target texture. - * Channel storage: - * + R: depth - * @return {qtek.Texture2D} - */ - getTargetTexture2: function () { - return this._gBufferTex2; - }, + this._normalDistribution = null; - /** - * Get third target texture. - * Channel storage: - * + R: albedo.r - * + G: albedo.g - * + B: albedo.b - * + A: metalness - * @return {qtek.Texture2D} - */ - getTargetTexture3: function () { - return this._gBufferTex3; - }, + this._totalSamples = 256; + this._samplePerFrame = 4; - _getMaterial: function (nJoints) { - var gBufferMaterials = this._gBufferMaterials; - var obj = gBufferMaterials[nJoints]; - if (!obj) { - var mat1 = new Material({ - shader: new Shader({ - vertex: Shader.source('qtek.deferred.gbuffer.vertex'), - fragment: Shader.source('qtek.deferred.gbuffer1.fragment') - }) - }); - var mat2 = new Material({ - shader: new Shader({ - vertex: Shader.source('qtek.deferred.gbuffer.vertex'), - fragment: Shader.source('qtek.deferred.gbuffer2.fragment') - }) - }); - mat1.shader.define('vertex', 'FIRST_PASS'); + this._ssrPass.material.define('fragment', 'SAMPLE_PER_FRAME', this._samplePerFrame); + this._ssrPass.material.define('fragment', 'TOTAL_SAMPLES', this._totalSamples); - if (nJoints > 0) { - mat1.shader.define('vertex', 'SKINNING'); - mat1.shader.define('vertex', 'JOINT_COUNT', nJoints); - mat2.shader.define('vertex', 'SKINNING'); - mat2.shader.define('vertex', 'JOINT_COUNT', nJoints); - } + this._downScale = 1; +} - obj = { - material1: mat1, - material2: mat2 - }; +SSRPass.prototype.setAmbientCubemap = function (specularCubemap, specularIntensity) { + this._ssrPass.material.set('specularCubemap', specularCubemap); + this._ssrPass.material.set('specularIntensity', specularIntensity); - gBufferMaterials[nJoints] = obj; - } - obj.used = true; + var enableSpecularMap = specularCubemap && specularIntensity; + this._ssrPass.material[enableSpecularMap ? 'enableTexture' : 'disableTexture']('specularCubemap'); +}; - return obj; - }, +SSRPass.prototype.update = function (renderer, camera, sourceTexture, frame) { + var width = renderer.getWidth(); + var height = renderer.getHeight(); + var ssrTexture = this._ssrTexture; + var texture2 = this._texture2; + var texture3 = this._texture3; + ssrTexture.width = this._prevTexture.width = this._currentTexture.width = width / this._downScale; + ssrTexture.height = this._prevTexture.height = this._currentTexture.height = height / this._downScale; - _resetGBufferMaterials: function () { - for (var key in this._gBufferMaterials) { - this._gBufferMaterials[key].used = false; - } - }, + texture2.width = texture3.width = width; + texture2.height = texture3.height = height; - _cleanGBufferMaterials: function (renderer) { - for (var key in this._gBufferMaterials) { - var obj = this._gBufferMaterials[key]; - if (!obj.used) { - obj.material1.dispose(renderer); - obj.material2.dispose(renderer); - } - } - }, + var frameBuffer = this._frameBuffer; - _replaceGBufferMat: function (queue, pass) { - for (var i = 0; i < queue.length; i++) { - var renderable = queue[i]; + var ssrPass = this._ssrPass; + var blurPass1 = this._blurPass1; + var blurPass2 = this._blurPass2; + var blendPass = this._blendPass; - if (pass === 1) { - renderable.__standardMat = renderable.material; - } + var toViewSpace = new Matrix4(); + var toWorldSpace = new Matrix4(); + Matrix4.transpose(toViewSpace, camera.worldTransform); + Matrix4.transpose(toWorldSpace, camera.viewMatrix); - var matObj = this._getMaterial( - renderable.joints ? renderable.joints.length : 0, - false - ); - renderable.material = pass === 1 ? matObj.material1 : matObj.material2; - } - }, + ssrPass.setUniform('sourceTexture', sourceTexture); + ssrPass.setUniform('projection', camera.projectionMatrix.array); + ssrPass.setUniform('projectionInv', camera.invProjectionMatrix.array); + ssrPass.setUniform('toViewSpace', toViewSpace.array); + ssrPass.setUniform('toWorldSpace', toWorldSpace.array); + ssrPass.setUniform('nearZ', camera.near); - _restoreMaterial: function (queue) { - for (var i = 0; i < queue.length; i++) { - var renderable = queue[i]; + var percent = frame / this._totalSamples * this._samplePerFrame; + ssrPass.setUniform('jitterOffset', percent); + ssrPass.setUniform('sampleOffset', frame * this._samplePerFrame); + // ssrPass.setUniform('lambertNormals', this._diffuseSampleNormals[frame % this._totalSamples]); - if (renderable.__standardMat) { - renderable.material = renderable.__standardMat; - } - } - }, + blurPass1.setUniform('textureSize', [ssrTexture.width, ssrTexture.height]); + blurPass2.setUniform('textureSize', [width, height]); + blurPass2.setUniform('sourceTexture', sourceTexture); + blurPass1.setUniform('projection', camera.projectionMatrix.array); + blurPass2.setUniform('projection', camera.projectionMatrix.array); - /** - * @param {qtek.Renderer} renderer - */ - dispose: function (renderer) { - for (var name in this._gBufferMaterials) { - var matObj = this._gBufferMaterials[name]; - matObj.material1.dispose(renderer); - matObj.material2.dispose(renderer); - } - } -}); + frameBuffer.attach(ssrTexture); + frameBuffer.bind(renderer); + ssrPass.render(renderer); -// Simple LRU cache use doubly linked list -// @module zrender/core/LRU + if (this._physicallyCorrect) { + frameBuffer.attach(this._currentTexture); + blendPass.setUniform('texture1', this._prevTexture); + blendPass.setUniform('texture2', ssrTexture); + blendPass.material.set({ + 'weight1': frame >= 1 ? 0.95 : 0, + 'weight2': frame >= 1 ? 0.05 : 1 + // weight1: frame >= 1 ? 1 : 0, + // weight2: 1 + }); + blendPass.render(renderer); + } -/** - * Simple double linked list. Compared with array, it has O(1) remove operation. - * @constructor - */ -var LinkedList = function () { + frameBuffer.attach(texture2); + blurPass1.setUniform('texture', this._physicallyCorrect ? this._currentTexture : ssrTexture); + blurPass1.render(renderer); - /** - * @type {module:zrender/core/LRU~Entry} - */ - this.head = null; + frameBuffer.attach(texture3); + blurPass2.setUniform('texture', texture2); + blurPass2.render(renderer); + frameBuffer.unbind(renderer); - /** - * @type {module:zrender/core/LRU~Entry} - */ - this.tail = null; + if (this._physicallyCorrect) { + var tmp = this._prevTexture; + this._prevTexture = this._currentTexture; + this._currentTexture = tmp; + } +}; - this._len = 0; +SSRPass.prototype.getTargetTexture = function () { + return this._texture3; }; -var linkedListProto = LinkedList.prototype; -/** - * Insert a new value at the tail - * @param {} val - * @return {module:zrender/core/LRU~Entry} - */ -linkedListProto.insert = function (val) { - var entry = new Entry(val); - this.insertEntry(entry); - return entry; +SSRPass.prototype.setParameter = function (name, val) { + if (name === 'maxIteration') { + this._ssrPass.material.define('fragment', 'MAX_ITERATION', val); + } + else { + this._ssrPass.setUniform(name, val); + } }; -/** - * Insert an entry at the tail - * @param {module:zrender/core/LRU~Entry} entry - */ -linkedListProto.insertEntry = function (entry) { - if (!this.head) { - this.head = this.tail = entry; +SSRPass.prototype.setPhysicallyCorrect = function (isPhysicallyCorrect) { + if (isPhysicallyCorrect) { + if (!this._normalDistribution) { + this._normalDistribution = cubemapUtil.generateNormalDistribution(64, this._totalSamples); + } + this._ssrPass.material.define('fragment', 'PHYSICALLY_CORRECT'); + this._ssrPass.material.set('normalDistribution', this._normalDistribution); + this._ssrPass.material.set('normalDistributionSize', [64, this._totalSamples]); } else { - this.tail.next = entry; - entry.prev = this.tail; - entry.next = null; - this.tail = entry; + this._ssrPass.material.undefine('fragment', 'PHYSICALLY_CORRECT'); } - this._len++; + + this._physicallyCorrect = isPhysicallyCorrect; }; -/** - * Remove entry. - * @param {module:zrender/core/LRU~Entry} entry - */ -linkedListProto.remove = function (entry) { - var prev = entry.prev; - var next = entry.next; - if (prev) { - prev.next = next; +SSRPass.prototype.setSSAOTexture = function (texture) { + var blendPass = this._blurPass2; + if (texture) { + blendPass.material.enableTexture('ssaoTex'); + blendPass.material.set('ssaoTex', texture); } else { - // Is head - this.head = next; + blendPass.material.disableTexture('ssaoTex'); } - if (next) { - next.prev = prev; +}; + +SSRPass.prototype.isFinished = function (frame) { + if (this._physicallyCorrect) { + return frame > (this._totalSamples / this._samplePerFrame); } else { - // Is tail - this.tail = prev; + return true; } - entry.next = entry.prev = null; - this._len--; }; -/** - * @return {number} - */ -linkedListProto.len = function () { - return this._len; +SSRPass.prototype.dispose = function (renderer) { + this._ssrTexture.dispose(renderer); + this._texture2.dispose(renderer); + this._texture3.dispose(renderer); + this._prevTexture.dispose(renderer); + this._currentTexture.dispose(renderer); + this._frameBuffer.dispose(renderer); }; -/** - * Clear list - */ -linkedListProto.clear = function () { - this.head = this.tail = null; - this._len = 0; -}; +// Based on https://bl.ocks.org/mbostock/19168c663618b707158 -/** - * @constructor - * @param {} val - */ -var Entry = function (val) { - /** - * @type {} - */ - this.value = val; +var poissonKernel = [ +0.0, 0.0, +-0.321585265978, -0.154972575841, +0.458126042375, 0.188473391593, +0.842080129861, 0.527766490688, +0.147304551086, -0.659453822776, +-0.331943915203, -0.940619700594, +0.0479226680259, 0.54812163202, +0.701581552186, -0.709825561388, +-0.295436780218, 0.940589268233, +-0.901489676764, 0.237713156085, +0.973570876096, -0.109899459384, +-0.866792314779, -0.451805525005, +0.330975007087, 0.800048655954, +-0.344275183665, 0.381779221166, +-0.386139432542, -0.437418421534, +-0.576478634965, -0.0148463392551, +0.385798197415, -0.262426961053, +-0.666302061145, 0.682427250835, +-0.628010632582, -0.732836215494, +0.10163141741, -0.987658134403, +0.711995289051, -0.320024291314, +0.0296005138058, 0.950296523438, +0.0130612307608, -0.351024443122, +-0.879596633704, -0.10478487883, +0.435712737232, 0.504254490347, +0.779203817497, 0.206477676721, +0.388264289969, -0.896736162545, +-0.153106280781, -0.629203242522, +-0.245517550697, 0.657969239148, +0.126830499058, 0.26862328493, +-0.634888119007, -0.302301223431, +0.617074219636, 0.779817204925 +]; - /** - * @type {module:zrender/core/LRU~Entry} - */ - this.next; +var gbufferEssl = "@export clay.deferred.gbuffer.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat;\nuniform vec2 uvOffset;\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\n#ifdef FIRST_PASS\nattribute vec3 normal : NORMAL;\n#endif\n@import clay.chunk.skinning_header\n#ifdef FIRST_PASS\nvarying vec3 v_Normal;\nattribute vec4 tangent : TANGENT;\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\nvarying vec3 v_WorldPosition;\n#endif\nvarying vec2 v_Texcoord;\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef FIRST_PASS\n vec3 skinnedNormal = normal;\n vec3 skinnedTangent = tangent.xyz;\n bool hasTangent = dot(tangent, tangent) > 0.0;\n#endif\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n #ifdef FIRST_PASS\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n if (hasTangent) {\n skinnedTangent = (skinMatrixWS * vec4(tangent.xyz, 0.0)).xyz;\n }\n #endif\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n#ifdef FIRST_PASS\n v_Normal = normalize((worldInverseTranspose * vec4(skinnedNormal, 0.0)).xyz);\n if (hasTangent) {\n v_Tangent = normalize((worldInverseTranspose * vec4(skinnedTangent, 0.0)).xyz);\n v_Bitangent = normalize(cross(v_Normal, v_Tangent) * tangent.w);\n }\n v_WorldPosition = (world * vec4(skinnedPosition, 1.0)).xyz;\n#endif\n}\n@end\n@export clay.deferred.gbuffer1.fragment\nuniform mat4 viewInverse : VIEWINVERSE;\nuniform float glossiness;\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nuniform sampler2D normalMap;\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\nuniform sampler2D roughGlossMap;\nuniform bool useRoughGlossMap;\nuniform bool useRoughness;\nuniform bool doubleSided;\nuniform int roughGlossChannel: 0;\nfloat indexingTexel(in vec4 texel, in int idx) {\n if (idx == 3) return texel.a;\n else if (idx == 1) return texel.g;\n else if (idx == 2) return texel.b;\n else return texel.r;\n}\nvoid main()\n{\n vec3 N = v_Normal;\n if (doubleSided) {\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = eyePos - v_WorldPosition;\n if (dot(N, V) < 0.0) {\n N = -N;\n }\n }\n if (dot(v_Tangent, v_Tangent) > 0.0) {\n vec3 normalTexel = texture2D(normalMap, v_Texcoord).xyz;\n if (dot(normalTexel, normalTexel) > 0.0) { N = normalTexel * 2.0 - 1.0;\n mat3 tbn = mat3(v_Tangent, v_Bitangent, v_Normal);\n N = normalize(tbn * N);\n }\n }\n gl_FragColor.rgb = (N + 1.0) * 0.5;\n float g = glossiness;\n if (useRoughGlossMap) {\n float g2 = indexingTexel(texture2D(roughGlossMap, v_Texcoord), roughGlossChannel);\n if (useRoughness) {\n g2 = 1.0 - g2;\n }\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n }\n gl_FragColor.a = g + 0.005;\n}\n@end\n@export clay.deferred.gbuffer2.fragment\nuniform sampler2D diffuseMap;\nuniform sampler2D metalnessMap;\nuniform vec3 color;\nuniform float metalness;\nuniform bool useMetalnessMap;\nuniform bool linear;\nvarying vec2 v_Texcoord;\n@import clay.util.srgb\nvoid main ()\n{\n float m = metalness;\n if (useMetalnessMap) {\n vec4 metalnessTexel = texture2D(metalnessMap, v_Texcoord);\n m = clamp(metalnessTexel.r + (m * 2.0 - 1.0), 0.0, 1.0);\n }\n vec4 texel = texture2D(diffuseMap, v_Texcoord);\n if (linear) {\n texel = sRGBToLinear(texel);\n }\n gl_FragColor.rgb = texel.rgb * color;\n gl_FragColor.a = m + 0.005;\n}\n@end\n@export clay.deferred.gbuffer.debug\n@import clay.deferred.chunk.light_head\nuniform int debug: 0;\nvoid main ()\n{\n @import clay.deferred.chunk.gbuffer_read\n if (debug == 0) {\n gl_FragColor = vec4(N, 1.0);\n }\n else if (debug == 1) {\n gl_FragColor = vec4(vec3(z), 1.0);\n }\n else if (debug == 2) {\n gl_FragColor = vec4(position, 1.0);\n }\n else if (debug == 3) {\n gl_FragColor = vec4(vec3(glossiness), 1.0);\n }\n else if (debug == 4) {\n gl_FragColor = vec4(vec3(metalness), 1.0);\n }\n else {\n gl_FragColor = vec4(albedo, 1.0);\n }\n}\n@end"; - /** - * @type {module:zrender/core/LRU~Entry} - */ - this.prev; -}; +var chunkEssl = "@export clay.deferred.chunk.light_head\nuniform sampler2D gBufferTexture1;\nuniform sampler2D gBufferTexture2;\nuniform sampler2D gBufferTexture3;\nuniform vec2 windowSize: WINDOW_SIZE;\nuniform vec4 viewport: VIEWPORT;\nuniform mat4 viewProjectionInv;\n#ifdef DEPTH_ENCODED\n@import clay.util.decode_float\n#endif\n@end\n@export clay.deferred.chunk.gbuffer_read\n vec2 uv = gl_FragCoord.xy / windowSize;\n vec2 uv2 = (gl_FragCoord.xy - viewport.xy) / viewport.zw;\n vec4 texel1 = texture2D(gBufferTexture1, uv);\n vec4 texel3 = texture2D(gBufferTexture3, uv);\n if (dot(texel1.rgb, vec3(1.0)) == 0.0) {\n discard;\n }\n float glossiness = texel1.a;\n float metalness = texel3.a;\n vec3 N = texel1.rgb * 2.0 - 1.0;\n float z = texture2D(gBufferTexture2, uv).r * 2.0 - 1.0;\n vec2 xy = uv2 * 2.0 - 1.0;\n vec4 projectedPos = vec4(xy, z, 1.0);\n vec4 p4 = viewProjectionInv * projectedPos;\n vec3 position = p4.xyz / p4.w;\n vec3 albedo = texel3.rgb;\n vec3 diffuseColor = albedo * (1.0 - metalness);\n vec3 specularColor = mix(vec3(0.04), albedo, metalness);\n@end\n@export clay.deferred.chunk.light_equation\nfloat D_Phong(in float g, in float ndh) {\n float a = pow(8192.0, g);\n return (a + 2.0) / 8.0 * pow(ndh, a);\n}\nfloat D_GGX(in float g, in float ndh) {\n float r = 1.0 - g;\n float a = r * r;\n float tmp = ndh * ndh * (a - 1.0) + 1.0;\n return a / (3.1415926 * tmp * tmp);\n}\nvec3 F_Schlick(in float ndv, vec3 spec) {\n return spec + (1.0 - spec) * pow(1.0 - ndv, 5.0);\n}\nvec3 lightEquation(\n in vec3 lightColor, in vec3 diffuseColor, in vec3 specularColor,\n in float ndl, in float ndh, in float ndv, in float g\n)\n{\n return ndl * lightColor\n * (diffuseColor + D_Phong(g, ndh) * F_Schlick(ndv, specularColor));\n}\n@end"; -/** - * LRU Cache - * @constructor - * @alias module:zrender/core/LRU - */ -var LRU = function (maxSize) { +Shader.import(gbufferEssl); +Shader.import(chunkEssl); - this._list = new LinkedList(); +function createFillCanvas(color) { + var canvas = document.createElement('canvas'); + canvas.width = canvas.height = 1; + var ctx = canvas.getContext('2d'); + ctx.fillStyle = color || '#000'; + ctx.fillRect(0, 0, 1, 1); - this._map = {}; + return canvas; +} - this._maxSize = maxSize || 10; +function attachTextureToSlot(renderer, program, symbol, texture, slot) { + var gl = renderer.gl; + program.setUniform(gl, '1i', symbol, slot); - this._lastRemovedEntry = null; -}; + gl.activeTexture(gl.TEXTURE0 + slot); + // Maybe texture is not loaded yet; + if (texture.isRenderable()) { + texture.bind(renderer); + } + else { + // Bind texture to null + texture.unbind(renderer); + } +} -var LRUProto = LRU.prototype; +// TODO Use globalShader insteadof globalMaterial? +function getBeforeRenderHook1 (gl, defaultNormalMap, defaultRoughnessMap) { -/** - * @param {string} key - * @param {} value - * @return {} Removed value - */ -LRUProto.put = function (key, value) { - var list = this._list; - var map = this._map; - var removed = null; - if (map[key] == null) { - var len = list.len(); - // Reuse last removed entry - var entry = this._lastRemovedEntry; + var previousNormalMap; + var previousRougGlossMap; + var previousRenderable; - if (len >= this._maxSize && len > 0) { - // Remove the least recently used - var leastUsedEntry = list.head; - list.remove(leastUsedEntry); - delete map[leastUsedEntry.key]; + return function (renderable, gBufferMat, prevMaterial) { + // Material not change + if (previousRenderable && previousRenderable.material === renderable.material) { + return; + } - removed = leastUsedEntry.value; - this._lastRemovedEntry = leastUsedEntry; + var standardMaterial = renderable.material; + var program = renderable.__program; + + var glossiness; + var roughGlossMap; + var useRoughnessWorkflow = standardMaterial.isDefined('fragment', 'USE_ROUGHNESS'); + var doubleSided = standardMaterial.isDefined('fragment', 'DOUBLE_SIDED'); + var roughGlossChannel; + if (useRoughnessWorkflow) { + glossiness = 1.0 - standardMaterial.get('roughness'); + roughGlossMap = standardMaterial.get('roughnessMap'); + roughGlossChannel = standardMaterial.getDefine('fragment', 'ROUGHNESS_CHANNEL'); + } + else { + glossiness = standardMaterial.get('glossiness'); + roughGlossMap = standardMaterial.get('glossinessMap'); + roughGlossChannel = standardMaterial.getDefine('fragment', 'GLOSSINESS_CHANNEL'); } + var useRoughGlossMap = !!roughGlossMap; - if (entry) { - entry.value = value; + var normalMap = standardMaterial.get('normalMap') || defaultNormalMap; + var uvRepeat = standardMaterial.get('uvRepeat'); + var uvOffset = standardMaterial.get('uvOffset'); + + roughGlossMap = roughGlossMap || defaultRoughnessMap; + + if (prevMaterial !== gBufferMat) { + gBufferMat.set('glossiness', glossiness); + gBufferMat.set('normalMap', normalMap); + gBufferMat.set('roughGlossMap', roughGlossMap); + gBufferMat.set('useRoughGlossMap', +useRoughGlossMap); + gBufferMat.set('useRoughness', +useRoughnessWorkflow); + gBufferMat.set('doubleSided', +doubleSided); + gBufferMat.set('roughGlossChannel', +roughGlossChannel || 0); + gBufferMat.set('uvRepeat', uvRepeat); + gBufferMat.set('uvOffset', uvOffset); } else { - entry = new Entry(value); + program.setUniform( + gl, '1f', 'glossiness', glossiness + ); + + if (previousNormalMap !== normalMap) { + attachTextureToSlot(this, program, 'normalMap', normalMap, 0); + } + if (previousRougGlossMap !== roughGlossMap) { + attachTextureToSlot(this, program, 'roughGlossMap', roughGlossMap, 1); + } + program.setUniform(gl, '1i', 'useRoughGlossMap', +useRoughGlossMap); + program.setUniform(gl, '1i', 'useRoughness', +useRoughnessWorkflow); + program.setUniform(gl, '1i', 'doubleSided', +doubleSided); + program.setUniform(gl, '1i', 'roughGlossChannel', +roughGlossChannel || 0); + if (uvRepeat != null) { + program.setUniform(gl, '2f', 'uvRepeat', uvRepeat); + } + if (uvOffset != null) { + program.setUniform(gl, '2f', 'uvOffset', uvOffset); + } } - entry.key = key; - list.insertEntry(entry); - map[key] = entry; - } - return removed; -}; + previousNormalMap = normalMap; + previousRougGlossMap = roughGlossMap; + + previousRenderable = renderable; + }; +} + +function getBeforeRenderHook2(gl, defaultDiffuseMap, defaultMetalnessMap) { + var previousDiffuseMap; + var previousRenderable; + var previousMetalnessMap; + + return function (renderable, gBufferMat, prevMaterial) { + // Material not change + if (previousRenderable && previousRenderable.material === renderable.material) { + return; + } + + var program = renderable.__program; + var standardMaterial = renderable.material; + + var color = standardMaterial.get('color'); + var metalness = standardMaterial.get('metalness'); + + var diffuseMap = standardMaterial.get('diffuseMap'); + var metalnessMap = standardMaterial.get('metalnessMap'); + + var uvRepeat = standardMaterial.get('uvRepeat'); + var uvOffset = standardMaterial.get('uvOffset'); + + var useMetalnessMap = !!metalnessMap; + + diffuseMap = diffuseMap || defaultDiffuseMap; + metalnessMap = metalnessMap || defaultMetalnessMap; + + if (prevMaterial !== gBufferMat) { + gBufferMat.set('color', color); + gBufferMat.set('metalness', metalness); + gBufferMat.set('diffuseMap', diffuseMap); + gBufferMat.set('metalnessMap', metalnessMap); + gBufferMat.set('useMetalnessMap', +useMetalnessMap); + gBufferMat.set('uvRepeat', uvRepeat); + gBufferMat.set('uvOffset', uvOffset); + // TODO + gBufferMat.set('linear', +standardMaterial.linear || 0); + } + else { + program.setUniform(gl, '1f', 'metalness', metalness); + + program.setUniform(gl, '3f', 'color', color); + if (previousDiffuseMap !== diffuseMap) { + attachTextureToSlot(this, program, 'diffuseMap', diffuseMap, 0); + } + if (previousMetalnessMap !== metalnessMap) { + attachTextureToSlot(this, program, 'metalnessMap', metalnessMap, 1); + } + program.setUniform(gl, '1i', 'useMetalnessMap', +useMetalnessMap); + program.setUniform(gl, '2f', 'uvRepeat', uvRepeat); + program.setUniform(gl, '2f', 'uvOffset', uvOffset); + + program.setUniform(gl, '1i', 'linear', +standardMaterial.linear || 0); + } + + previousDiffuseMap = diffuseMap; + previousMetalnessMap = metalnessMap; + + previousRenderable = renderable; + }; +} /** - * @param {string} key - * @return {} + * GBuffer is provided for deferred rendering and SSAO, SSR pass. + * It will do two passes rendering to three target textures. See + * + {@link clay.deferred.GBuffer#getTargetTexture1} + * + {@link clay.deferred.GBuffer#getTargetTexture2} + * + {@link clay.deferred.GBuffer#getTargetTexture3} + * @constructor + * @alias clay.deferred.GBuffer + * @extends clay.core.Base */ -LRUProto.get = function (key) { - var entry = this._map[key]; - var list = this._list; - if (entry != null) { - // Put the latest used entry in the tail - if (entry !== list.tail) { - list.remove(entry); - list.insertEntry(entry); - } +var GBuffer = Base.extend(function () { - return entry.value; - } -}; + return { -/** - * Clear the cache - */ -LRUProto.clear = function () { - this._list.clear(); - this._map = {}; -}; + enableTargetTexture1: true, -var planeMatrix = new Matrix4(); + enableTargetTexture2: true, -/** - * @constructor qtek.geometry.Cube - * @extends qtek.Geometry - * @param {Object} [opt] - * @param {number} [opt.widthSegments] - * @param {number} [opt.heightSegments] - * @param {number} [opt.depthSegments] - * @param {boolean} [opt.inside] - */ -var Cube = Geometry.extend( -/**@lends qtek.geometry.Cube# */ -{ - dynamic: false, - /** - * @type {number} - */ - widthSegments: 1, - /** - * @type {number} - */ - heightSegments: 1, - /** - * @type {number} - */ - depthSegments: 1, - /** - * @type {boolean} - */ - inside: false -}, function() { - this.build(); -}, -/** @lends qtek.geometry.Cube.prototype */ -{ - /** - * Build cube geometry - */ - build: function() { + enableTargetTexture3: true, - var planes = { - 'px': createPlane('px', this.depthSegments, this.heightSegments), - 'nx': createPlane('nx', this.depthSegments, this.heightSegments), - 'py': createPlane('py', this.widthSegments, this.depthSegments), - 'ny': createPlane('ny', this.widthSegments, this.depthSegments), - 'pz': createPlane('pz', this.widthSegments, this.heightSegments), - 'nz': createPlane('nz', this.widthSegments, this.heightSegments), - }; + renderTransparent: false, - var attrList = ['position', 'texcoord0', 'normal']; - var vertexNumber = 0; - var faceNumber = 0; - for (var pos in planes) { - vertexNumber += planes[pos].vertexCount; - faceNumber += planes[pos].indices.length; - } - for (var k = 0; k < attrList.length; k++) { - this.attributes[attrList[k]].init(vertexNumber); - } - this.indices = new vendor.Uint16Array(faceNumber); - var faceOffset = 0; - var vertexOffset = 0; - for (var pos in planes) { - var plane = planes[pos]; - for (var k = 0; k < attrList.length; k++) { - var attrName = attrList[k]; - var attrArray = plane.attributes[attrName].value; - var attrSize = plane.attributes[attrName].size; - var isNormal = attrName === 'normal'; - for (var i = 0; i < attrArray.length; i++) { - var value = attrArray[i]; - if (this.inside && isNormal) { - value = -value; - } - this.attributes[attrName].value[i + attrSize * vertexOffset] = value; - } - } - for (var i = 0; i < plane.indices.length; i++) { - this.indices[i + faceOffset] = vertexOffset + plane.indices[i]; + _gBufferRenderList: [], + // - R: normal.x + // - G: normal.y + // - B: normal.z + // - A: glossiness + _gBufferTex1: new Texture2D({ + minFilter: Texture$1.NEAREST, + magFilter: Texture$1.NEAREST, + // PENDING + type: Texture$1.HALF_FLOAT + }), + + // - R: depth + _gBufferTex2: new Texture2D({ + minFilter: Texture$1.NEAREST, + magFilter: Texture$1.NEAREST, + // format: Texture.DEPTH_COMPONENT, + // type: Texture.UNSIGNED_INT + + format: Texture$1.DEPTH_STENCIL, + type: Texture$1.UNSIGNED_INT_24_8_WEBGL + }), + + // - R: albedo.r + // - G: albedo.g + // - B: albedo.b + // - A: metalness + _gBufferTex3: new Texture2D({ + minFilter: Texture$1.NEAREST, + magFilter: Texture$1.NEAREST + }), + + _defaultNormalMap: new Texture2D({ + image: createFillCanvas('#000') + }), + _defaultRoughnessMap: new Texture2D({ + image: createFillCanvas('#fff') + }), + _defaultMetalnessMap: new Texture2D({ + image: createFillCanvas('#fff') + }), + _defaultDiffuseMap: new Texture2D({ + image: createFillCanvas('#fff') + }), + + _frameBuffer: new FrameBuffer(), + + _gBufferMaterial1: new Material({ + shader: new Shader( + Shader.source('clay.deferred.gbuffer.vertex'), + Shader.source('clay.deferred.gbuffer1.fragment') + ), + vertexDefines: { + FIRST_PASS: null + }, + fragmentDefines: { + FIRST_PASS: null } - faceOffset += plane.indices.length; - vertexOffset += plane.vertexCount; - } + }), + _gBufferMaterial2: new Material({ + shader: new Shader( + Shader.source('clay.deferred.gbuffer.vertex'), + Shader.source('clay.deferred.gbuffer2.fragment') + ) + }), - this.boundingBox = new BoundingBox(); - this.boundingBox.max.set(1, 1, 1); - this.boundingBox.min.set(-1, -1, -1); - } -}); + _debugPass: new Pass({ + fragment: Shader.source('clay.deferred.gbuffer.debug') + }) + }; +}, /** @lends clay.deferred.GBuffer# */{ -function createPlane(pos, widthSegments, heightSegments) { + /** + * Set G Buffer size. + * @param {number} width + * @param {number} height + */ + resize: function (width, height) { + if (this._gBufferTex1.width === width + && this._gBufferTex1.height === height + ) { + return; + } + this._gBufferTex1.width = width; + this._gBufferTex1.height = height; - planeMatrix.identity(); + this._gBufferTex2.width = width; + this._gBufferTex2.height = height; - var plane = new Plane$2({ - widthSegments: widthSegments, - heightSegments: heightSegments - }); + this._gBufferTex3.width = width; + this._gBufferTex3.height = height; + }, - switch(pos) { - case 'px': - Matrix4.translate(planeMatrix, planeMatrix, Vector3.POSITIVE_X); - Matrix4.rotateY(planeMatrix, planeMatrix, Math.PI / 2); - break; - case 'nx': - Matrix4.translate(planeMatrix, planeMatrix, Vector3.NEGATIVE_X); - Matrix4.rotateY(planeMatrix, planeMatrix, -Math.PI / 2); - break; - case 'py': - Matrix4.translate(planeMatrix, planeMatrix, Vector3.POSITIVE_Y); - Matrix4.rotateX(planeMatrix, planeMatrix, -Math.PI / 2); - break; - case 'ny': - Matrix4.translate(planeMatrix, planeMatrix, Vector3.NEGATIVE_Y); - Matrix4.rotateX(planeMatrix, planeMatrix, Math.PI / 2); - break; - case 'pz': - Matrix4.translate(planeMatrix, planeMatrix, Vector3.POSITIVE_Z); - break; - case 'nz': - Matrix4.translate(planeMatrix, planeMatrix, Vector3.NEGATIVE_Z); - Matrix4.rotateY(planeMatrix, planeMatrix, Math.PI); - break; - } - plane.applyTransform(planeMatrix); - return plane; -} + // TODO is dpr needed? + setViewport: function (x, y, width, height, dpr) { + var viewport; + if (typeof x === 'object') { + viewport = x; + } + else { + viewport = { + x: x, y: y, + width: width, height: height, + devicePixelRatio: dpr || 1 + }; + } + this._frameBuffer.viewport = viewport; + }, -// TODO Should not derived from mesh? -Shader.import(skyboxEssl); -/** - * @constructor qtek.plugin.Skybox - * - * @example - * var skyTex = new qtek.TextureCube(); - * skyTex.load({ - * 'px': 'assets/textures/sky/px.jpg', - * 'nx': 'assets/textures/sky/nx.jpg' - * 'py': 'assets/textures/sky/py.jpg' - * 'ny': 'assets/textures/sky/ny.jpg' - * 'pz': 'assets/textures/sky/pz.jpg' - * 'nz': 'assets/textures/sky/nz.jpg' - * }); - * var skybox = new qtek.plugin.Skybox({ - * scene: scene - * }); - * skybox.material.set('environmentMap', skyTex); - */ -var Skybox = Mesh.extend(function () { + getViewport: function () { + if (this._frameBuffer.viewport) { + return this._frameBuffer.viewport; + } + else { + return { + x: 0, y: 0, + width: this._gBufferTex1.width, + height: this._gBufferTex1.height, + devicePixelRatio: 1 + }; + } + }, - var skyboxShader = new Shader({ - vertex: Shader.source('qtek.skybox.vertex'), - fragment: Shader.source('qtek.skybox.fragment') - }); - var material = new Material({ - shader: skyboxShader, - depthMask: false - }); + /** + * Update G Buffer + * @param {clay.Renderer} renderer + * @param {clay.Scene} scene + * @param {clay.camera.Perspective} camera + */ + update: function (renderer, scene, camera) { - return { - /** - * @type {qtek.Scene} - * @memberOf qtek.plugin.Skybox.prototype - */ - scene: null, + var gl = renderer.gl; - geometry: new Cube(), + var frameBuffer = this._frameBuffer; + var viewport = frameBuffer.viewport; - material: material, + var renderList = scene.updateRenderList(camera); - environmentMap: null, + var opaqueList = renderList.opaque; + var transparentList = renderList.transparent; - culling: false - }; -}, function () { - var scene = this.scene; - if (scene) { - this.attachScene(scene); - } - if (this.environmentMap) { - this.setEnvironmentMap(this.environmentMap); - } -}, { - /** - * Attach the skybox to the scene - * @param {qtek.Scene} scene - * @memberOf qtek.plugin.Skybox.prototype - */ - attachScene: function (scene) { - if (this.scene) { - this.detachScene(); + var offset = 0; + var gBufferRenderList = this._gBufferRenderList; + for (var i = 0; i < opaqueList.length; i++) { + if (!opaqueList[i].ignoreGBuffer) { + gBufferRenderList[offset++] = opaqueList[i]; + } } - this.scene = scene; - scene.on('beforerender', this._beforeRenderScene, this); - }, - /** - * Detach from scene - * @memberOf qtek.plugin.Skybox.prototype - */ - detachScene: function () { - if (this.scene) { - this.scene.off('beforerender', this._beforeRenderScene); + if (this.renderTransparent) { + for (var i = 0; i < transparentList.length; i++) { + if (!transparentList[i].ignoreGBuffer) { + gBufferRenderList[offset++] = transparentList[i]; + } + } } - this.scene = null; - }, - - /** - * Dispose skybox - * @param {qtek.Renderer} renderer - */ - dispose: function (renderer) { - this.detachScene(); - this.geometry.dispose(renderer); - this.material.dispose(renderer); - }, + gBufferRenderList.length = offset; - setEnvironmentMap: function (envMap) { - this.material.set('environmentMap', envMap); - }, + gl.clearColor(0, 0, 0, 0); + gl.depthMask(true); + gl.colorMask(true, true, true, true); + gl.disable(gl.BLEND); - getEnvironmentMap: function () { - return this.material.get('environmentMap'); - }, + var enableTargetTexture1 = this.enableTargetTexture1; + var enableTargetTexture2 = this.enableTargetTexture2; + var enableTargetTexture3 = this.enableTargetTexture3; + if (!enableTargetTexture1 && !enableTargetTexture3) { + console.warn('Can\'t disable targetTexture1 targetTexture3 both'); + enableTargetTexture1 = true; + } - _beforeRenderScene: function(renderer, scene, camera) { - this.renderSkybox(renderer, camera); - }, + if (enableTargetTexture2) { + frameBuffer.attach(this._gBufferTex2, renderer.gl.DEPTH_STENCIL_ATTACHMENT); + } - renderSkybox: function (renderer, camera) { - this.position.copy(camera.getWorldPosition()); - this.update(); - // Don't remember to disable blend - renderer.gl.disable(renderer.gl.BLEND); - renderer.renderQueue([this], camera); - } -}); + // PENDING, scene.boundingBoxLastFrame needs be updated if have shadow + renderer.bindSceneRendering(scene); + if (enableTargetTexture1) { + // Pass 1 + frameBuffer.attach(this._gBufferTex1); + frameBuffer.bind(renderer); -var integrateBRDFShaderCode = "#define SAMPLE_NUMBER 1024\n#define PI 3.14159265358979\nuniform sampler2D normalDistribution;\nuniform vec2 viewportSize : [512, 256];\nconst vec3 N = vec3(0.0, 0.0, 1.0);\nconst float fSampleNumber = float(SAMPLE_NUMBER);\nvec3 importanceSampleNormal(float i, float roughness, vec3 N) {\n vec3 H = texture2D(normalDistribution, vec2(roughness, i)).rgb;\n vec3 upVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);\n vec3 tangentX = normalize(cross(upVector, N));\n vec3 tangentY = cross(N, tangentX);\n return tangentX * H.x + tangentY * H.y + N * H.z;\n}\nfloat G_Smith(float roughness, float NoV, float NoL) {\n float k = roughness * roughness / 2.0;\n float G1V = NoV / (NoV * (1.0 - k) + k);\n float G1L = NoL / (NoL * (1.0 - k) + k);\n return G1L * G1V;\n}\nvoid main() {\n vec2 uv = gl_FragCoord.xy / viewportSize;\n float NoV = uv.x;\n float roughness = uv.y;\n vec3 V;\n V.x = sqrt(1.0 - NoV * NoV);\n V.y = 0.0;\n V.z = NoV;\n float A = 0.0;\n float B = 0.0;\n for (int i = 0; i < SAMPLE_NUMBER; i++) {\n vec3 H = importanceSampleNormal(float(i) / fSampleNumber, roughness, N);\n vec3 L = reflect(-V, H);\n float NoL = clamp(L.z, 0.0, 1.0);\n float NoH = clamp(H.z, 0.0, 1.0);\n float VoH = clamp(dot(V, H), 0.0, 1.0);\n if (NoL > 0.0) {\n float G = G_Smith(roughness, NoV, NoL);\n float G_Vis = G * VoH / (NoH * NoV);\n float Fc = pow(1.0 - VoH, 5.0);\n A += (1.0 - Fc) * G_Vis;\n B += Fc * G_Vis;\n }\n }\n gl_FragColor = vec4(vec2(A, B) / fSampleNumber, 0.0, 1.0);\n}\n"; + if (viewport) { + var dpr = viewport.devicePixelRatio; + // use scissor to make sure only clear the viewport + gl.enable(gl.SCISSOR_TEST); + gl.scissor(viewport.x * dpr, viewport.y * dpr, viewport.width * dpr, viewport.height * dpr); + } + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + if (viewport) { + gl.disable(gl.SCISSOR_TEST); + } + var gBufferMaterial1 = this._gBufferMaterial1; + var passConfig = { + getMaterial: function () { + return gBufferMaterial1; + }, + beforeRender: getBeforeRenderHook1(gl, this._defaultNormalMap, this._defaultRoughnessMap), + sortCompare: renderer.opaqueSortCompare + }; + // FIXME Use MRT if possible + renderer.renderPass(gBufferRenderList, camera, passConfig); -var prefilterFragCode = "#define SAMPLE_NUMBER 1024\n#define PI 3.14159265358979\nuniform mat4 viewInverse : VIEWINVERSE;\nuniform samplerCube environmentMap;\nuniform sampler2D normalDistribution;\nuniform float roughness : 0.5;\nvarying vec2 v_Texcoord;\nvarying vec3 v_WorldPosition;\nconst float fSampleNumber = float(SAMPLE_NUMBER);\n@import qtek.util.rgbm\nvec3 importanceSampleNormal(float i, float roughness, vec3 N) {\n vec3 H = texture2D(normalDistribution, vec2(roughness, i)).rgb;\n vec3 upVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);\n vec3 tangentX = normalize(cross(upVector, N));\n vec3 tangentY = cross(N, tangentX);\n return tangentX * H.x + tangentY * H.y + N * H.z;\n}\nvoid main() {\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = normalize(v_WorldPosition - eyePos);\n vec3 N = V;\n vec3 R = V;\n vec3 prefilteredColor = vec3(0.0);\n float totalWeight = 0.0;\n for (int i = 0; i < SAMPLE_NUMBER; i++) {\n vec3 H = importanceSampleNormal(float(i) / fSampleNumber, roughness, N);\n vec3 L = reflect(-V, H);\n float NoL = clamp(dot(N, L), 0.0, 1.0);\n if (NoL > 0.0) {\n prefilteredColor += decodeHDR(textureCube(environmentMap, L)).rgb * NoL;\n totalWeight += NoL;\n }\n }\n gl_FragColor = encodeHDR(vec4(prefilteredColor / totalWeight, 1.0));\n}\n"; + } + if (enableTargetTexture3) { -// Cubemap prefilter utility -// http://www.unrealengine.com/files/downloads/2013SiggraphPresentationsNotes.pdf -// http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html -var cubemapUtil = {}; + // Pass 2 + frameBuffer.attach(this._gBufferTex3); + frameBuffer.bind(renderer); -var targets$2 = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; + if (viewport) { + var dpr = viewport.devicePixelRatio; + // use scissor to make sure only clear the viewport + gl.enable(gl.SCISSOR_TEST); + gl.scissor(viewport.x * dpr, viewport.y * dpr, viewport.width * dpr, viewport.height * dpr); + } + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + if (viewport) { + gl.disable(gl.SCISSOR_TEST); + } -/** - * @name qtek.util.cubemap.prefilterEnvironmentMap - * @param {qtek.Renderer} renderer - * @param {qtek.Texture} envMap - * @param {Object} [textureOpts] - * @param {number} [textureOpts.width=64] - * @param {number} [textureOpts.height=64] - * @param {number} [textureOpts.type] - * @param {boolean} [textureOpts.encodeRGBM=false] - * @param {boolean} [textureOpts.decodeRGBM=false] - * @param {qtek.Texture2D} [normalDistribution] - * @param {qtek.Texture2D} [brdfLookup] - */ -cubemapUtil.prefilterEnvironmentMap = function ( - renderer, envMap, textureOpts, normalDistribution, brdfLookup -) { - // Not create other renderer, it is easy having issue of cross reference of resources like framebuffer - // PENDING preserveDrawingBuffer? - if (!brdfLookup || !normalDistribution) { - normalDistribution = cubemapUtil.generateNormalDistribution(); - brdfLookup = cubemapUtil.integrateBRDF(renderer, normalDistribution); - } - textureOpts = textureOpts || {}; + var gBufferMaterial2 = this._gBufferMaterial2; + var passConfig = { + getMaterial: function () { + return gBufferMaterial2; + }, + beforeRender: getBeforeRenderHook2(gl, this._defaultDiffuseMap, this._defaultMetalnessMap), + sortCompare: renderer.opaqueSortCompare + }; + renderer.renderPass(gBufferRenderList, camera, passConfig); + } - var width = textureOpts.width || 64; - var height = textureOpts.height || 64; + renderer.bindSceneRendering(null); + frameBuffer.unbind(renderer); + }, - var textureType = textureOpts.type || envMap.type; + renderDebug: function (renderer, camera, type, viewport) { + var debugTypes = { + normal: 0, + depth: 1, + position: 2, + glossiness: 3, + metalness: 4, + albedo: 5 + }; + if (debugTypes[type] == null) { + console.warn('Unkown type "' + type + '"'); + // Default use normal + type = 'normal'; + } - // Use same type with given envMap - var prefilteredCubeMap = new TextureCube({ - width: width, - height: height, - type: textureType, - flipY: false, - mipmaps: [] - }); + renderer.saveClear(); + renderer.saveViewport(); + renderer.clearBit = renderer.gl.DEPTH_BUFFER_BIT; - if (!prefilteredCubeMap.isPowerOfTwo()) { - console.warn('Width and height must be power of two to enable mipmap.'); - } + if (viewport) { + renderer.setViewport(viewport); + } + var viewProjectionInv = new Matrix4(); + Matrix4.multiply(viewProjectionInv, camera.worldTransform, camera.invProjectionMatrix); - var size = Math.min(width, height); - var mipmapNum = Math.log(size) / Math.log(2) + 1; + var debugPass = this._debugPass; + debugPass.setUniform('viewportSize', [renderer.getWidth(), renderer.getHeight()]); + debugPass.setUniform('gBufferTexture1', this._gBufferTex1); + debugPass.setUniform('gBufferTexture2', this._gBufferTex2); + debugPass.setUniform('gBufferTexture3', this._gBufferTex3); + debugPass.setUniform('debug', debugTypes[type]); + debugPass.setUniform('viewProjectionInv', viewProjectionInv.array); + debugPass.render(renderer); - var prefilterMaterial = new Material({ - shader: new Shader({ - vertex: Shader.source('qtek.skybox.vertex'), - fragment: prefilterFragCode - }) - }); - prefilterMaterial.set('normalDistribution', normalDistribution); + renderer.restoreViewport(); + renderer.restoreClear(); + }, - textureOpts.encodeRGBM && prefilterMaterial.shader.define('fragment', 'RGBM_ENCODE'); - textureOpts.decodeRGBM && prefilterMaterial.shader.define('fragment', 'RGBM_DECODE'); + /** + * Get first target texture. + * Channel storage: + * + R: normal.x * 0.5 + 0.5 + * + G: normal.y * 0.5 + 0.5 + * + B: normal.z * 0.5 + 0.5 + * + A: glossiness + * @return {clay.Texture2D} + */ + getTargetTexture1: function () { + return this._gBufferTex1; + }, - var dummyScene = new Scene(); - var skyEnv; + /** + * Get second target texture. + * Channel storage: + * + R: depth + * @return {clay.Texture2D} + */ + getTargetTexture2: function () { + return this._gBufferTex2; + }, - if (envMap instanceof Texture2D) { - // Convert panorama to cubemap - var envCubemap = new TextureCube({ - width: width, - height: height, - // FIXME FLOAT type will cause GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT error on iOS - type: textureType === Texture.FLOAT ? - Texture.HALF_FLOAT : textureType - }); - textureUtil.panoramaToCubeMap(renderer, envMap, envCubemap, { - // PENDING encodeRGBM so it can be decoded as RGBM - encodeRGBM: textureOpts.decodeRGBM - }); - envMap = envCubemap; - } - skyEnv = new Skybox({ - scene: dummyScene, - material: prefilterMaterial - }); - skyEnv.material.set('environmentMap', envMap); + /** + * Get third target texture. + * Channel storage: + * + R: albedo.r + * + G: albedo.g + * + B: albedo.b + * + A: metalness + * @return {clay.Texture2D} + */ + getTargetTexture3: function () { + return this._gBufferTex3; + }, - var envMapPass = new EnvironmentMapPass({ - texture: prefilteredCubeMap - }); - // Force to be UNSIGNED_BYTE - if (textureOpts.encodeRGBM) { - textureType = prefilteredCubeMap.type = Texture.UNSIGNED_BYTE; + /** + * @param {clay.Renderer} renderer + */ + dispose: function (renderer) { } +}); - var renderTargetTmp = new Texture2D({ - width: width, - height: height, - type: textureType - }); - var frameBuffer = new FrameBuffer({ - depthBuffer: false - }); - var ArrayCtor = vendor[textureType === Texture.UNSIGNED_BYTE ? 'Uint8Array' : 'Float32Array']; - for (var i = 0; i < mipmapNum; i++) { - prefilteredCubeMap.mipmaps[i] = { - pixels: {} - }; - skyEnv.material.set('roughness', i / (targets$2.length - 1)); +// Simple LRU cache use doubly linked list +// @module zrender/core/LRU - // Tweak fov - // http://the-witness.net/news/2012/02/seamless-cube-map-filtering/ - var n = renderTargetTmp.width; - var fov = 2 * Math.atan(n / (n - 0.5)) / Math.PI * 180; +/** + * Simple double linked list. Compared with array, it has O(1) remove operation. + * @constructor + */ +var LinkedList$2 = function () { - for (var j = 0; j < targets$2.length; j++) { - var pixels = new ArrayCtor(renderTargetTmp.width * renderTargetTmp.height * 4); - frameBuffer.attach(renderTargetTmp); - frameBuffer.bind(renderer); + /** + * @type {module:zrender/core/LRU~Entry} + */ + this.head = null; - var camera = envMapPass.getCamera(targets$2[j]); - camera.fov = fov; - renderer.render(dummyScene, camera); - renderer.gl.readPixels( - 0, 0, renderTargetTmp.width, renderTargetTmp.height, - Texture.RGBA, textureType, pixels - ); + /** + * @type {module:zrender/core/LRU~Entry} + */ + this.tail = null; - // var canvas = document.createElement('canvas'); - // var ctx = canvas.getContext('2d'); - // canvas.width = renderTargetTmp.width; - // canvas.height = renderTargetTmp.height; - // var imageData = ctx.createImageData(renderTargetTmp.width, renderTargetTmp.height); - // for (var k = 0; k < pixels.length; k++) { - // imageData.data[k] = pixels[k]; - // } - // ctx.putImageData(imageData, 0, 0); - // document.body.appendChild(canvas); + this._len = 0; +}; - frameBuffer.unbind(renderer); - prefilteredCubeMap.mipmaps[i].pixels[targets$2[j]] = pixels; - } +var linkedListProto = LinkedList$2.prototype; +/** + * Insert a new value at the tail + * @param {} val + * @return {module:zrender/core/LRU~Entry} + */ +linkedListProto.insert = function (val) { + var entry = new Entry(val); + this.insertEntry(entry); + return entry; +}; - renderTargetTmp.width /= 2; - renderTargetTmp.height /= 2; - renderTargetTmp.dirty(); +/** + * Insert an entry at the tail + * @param {module:zrender/core/LRU~Entry} entry + */ +linkedListProto.insertEntry = function (entry) { + if (!this.head) { + this.head = this.tail = entry; + } + else { + this.tail.next = entry; + entry.prev = this.tail; + entry.next = null; + this.tail = entry; } + this._len++; +}; - frameBuffer.dispose(renderer); - renderTargetTmp.dispose(renderer); - skyEnv.dispose(renderer); - // Remove gpu resource allucated in renderer - normalDistribution.dispose(renderer); +/** + * Remove entry. + * @param {module:zrender/core/LRU~Entry} entry + */ +linkedListProto.remove = function (entry) { + var prev = entry.prev; + var next = entry.next; + if (prev) { + prev.next = next; + } + else { + // Is head + this.head = next; + } + if (next) { + next.prev = prev; + } + else { + // Is tail + this.tail = prev; + } + entry.next = entry.prev = null; + this._len--; +}; - // renderer.dispose(); +/** + * @return {number} + */ +linkedListProto.len = function () { + return this._len; +}; - return { - environmentMap: prefilteredCubeMap, - brdfLookup: brdfLookup, - normalDistribution: normalDistribution, - maxMipmapLevel: mipmapNum - }; +/** + * Clear list + */ +linkedListProto.clear = function () { + this.head = this.tail = null; + this._len = 0; }; -cubemapUtil.integrateBRDF = function (renderer, normalDistribution) { - normalDistribution = normalDistribution || cubemapUtil.generateNormalDistribution(); - var framebuffer = new FrameBuffer({ - depthBuffer: false - }); - var pass = new Pass({ - fragment: integrateBRDFShaderCode - }); +/** + * @constructor + * @param {} val + */ +var Entry = function (val) { + /** + * @type {} + */ + this.value = val; - var texture = new Texture2D({ - width: 512, - height: 256, - type: Texture.HALF_FLOAT, - minFilter: Texture.NEAREST, - magFilter: Texture.NEAREST, - useMipmap: false - }); - pass.setUniform('normalDistribution', normalDistribution); - pass.setUniform('viewportSize', [512, 256]); - pass.attachOutput(texture); - pass.render(renderer, framebuffer); + /** + * @type {module:zrender/core/LRU~Entry} + */ + this.next; - // FIXME Only chrome and firefox can readPixels with float type. - // framebuffer.bind(renderer); - // var pixels = new Float32Array(512 * 256 * 4); - // renderer.gl.readPixels( - // 0, 0, texture.width, texture.height, - // Texture.RGBA, Texture.FLOAT, pixels - // ); - // texture.pixels = pixels; - // texture.flipY = false; - // texture.dirty(); - // framebuffer.unbind(renderer); + /** + * @type {module:zrender/core/LRU~Entry} + */ + this.prev; +}; - framebuffer.dispose(renderer); +/** + * LRU Cache + * @constructor + * @alias module:zrender/core/LRU + */ +var LRU$1 = function (maxSize) { - return texture; + this._list = new LinkedList$2(); + + this._map = {}; + + this._maxSize = maxSize || 10; + + this._lastRemovedEntry = null; }; -cubemapUtil.generateNormalDistribution = function (roughnessLevels, sampleSize) { +var LRUProto = LRU$1.prototype; - // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html - // GLSL not support bit operation, use lookup instead - // V -> i / N, U -> roughness - var roughnessLevels = roughnessLevels || 256; - var sampleSize = sampleSize || 1024; +/** + * @param {string} key + * @param {} value + * @return {} Removed value + */ +LRUProto.put = function (key, value) { + var list = this._list; + var map = this._map; + var removed = null; + if (map[key] == null) { + var len = list.len(); + // Reuse last removed entry + var entry = this._lastRemovedEntry; - var normalDistribution = new Texture2D({ - width: roughnessLevels, - height: sampleSize, - type: Texture.FLOAT, - minFilter: Texture.NEAREST, - magFilter: Texture.NEAREST, - useMipmap: false - }); - var pixels = new Float32Array(sampleSize * roughnessLevels * 4); - for (var i = 0; i < sampleSize; i++) { - var x = i / sampleSize; - // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators - // http://stackoverflow.com/questions/1908492/unsigned-integer-in-javascript - // http://stackoverflow.com/questions/1822350/what-is-the-javascript-operator-and-how-do-you-use-it - var y = (i << 16 | i >>> 16) >>> 0; - y = ((y & 1431655765) << 1 | (y & 2863311530) >>> 1) >>> 0; - y = ((y & 858993459) << 2 | (y & 3435973836) >>> 2) >>> 0; - y = ((y & 252645135) << 4 | (y & 4042322160) >>> 4) >>> 0; - y = (((y & 16711935) << 8 | (y & 4278255360) >>> 8) >>> 0) / 4294967296; - - for (var j = 0; j < roughnessLevels; j++) { - var roughness = j / roughnessLevels; - var a = roughness * roughness; - var phi = 2.0 * Math.PI * x; - // CDF - var cosTheta = Math.sqrt((1 - y) / (1 + (a * a - 1.0) * y)); - var sinTheta = Math.sqrt(1.0 - cosTheta * cosTheta); - var offset = (i * roughnessLevels + j) * 4; - pixels[offset] = sinTheta * Math.cos(phi); - pixels[offset + 1] = sinTheta * Math.sin(phi); - pixels[offset + 2] = cosTheta; - pixels[offset + 3] = 1.0; + if (len >= this._maxSize && len > 0) { + // Remove the least recently used + var leastUsedEntry = list.head; + list.remove(leastUsedEntry); + delete map[leastUsedEntry.key]; + + removed = leastUsedEntry.value; + this._lastRemovedEntry = leastUsedEntry; + } + + if (entry) { + entry.value = value; + } + else { + entry = new Entry(value); + } + entry.key = key; + list.insertEntry(entry); + map[key] = entry; + } + + return removed; +}; + +/** + * @param {string} key + * @return {} + */ +LRUProto.get = function (key) { + var entry = this._map[key]; + var list = this._list; + if (entry != null) { + // Put the latest used entry in the tail + if (entry !== list.tail) { + list.remove(entry); + list.insertEntry(entry); } + + return entry.value; } - normalDistribution.pixels = pixels; +}; - return normalDistribution; +/** + * Clear the cache + */ +LRUProto.clear = function () { + this._list.clear(); + this._map = {}; }; // https://docs.unrealengine.com/latest/INT/Engine/Rendering/LightingAndShadows/AmbientCubemap/ /** * Ambient cubemap light provides specular parts of Image Based Lighting. * Which is a basic requirement for Physically Based Rendering - * @constructor qtek.light.AmbientCubemap - * @extends qtek.Light + * @constructor clay.light.AmbientCubemap + * @extends clay.Light */ var AmbientCubemapLight = Light.extend({ /** - * @type {qtek.TextureCube} + * @type {clay.TextureCube} + * @memberOf clay.light.AmbientCubemap# */ cubemap: null, @@ -27347,13 +27621,13 @@ var AmbientCubemapLight = Light.extend({ _normalDistribution: null, _brdfLookup: null -}, { +}, /** @lends clay.light.AmbientCubemap# */ { type: 'AMBIENT_CUBEMAP_LIGHT', /** * Do prefitering the cubemap - * @param {qtek.Renderer} renderer + * @param {clay.Renderer} renderer * @param {number} [size=32] */ prefilter: function (renderer, size) { @@ -27404,26 +27678,26 @@ var AmbientCubemapLight = Light.extend({ } } /** - * @method + * @function * @name clone - * @return {qtek.light.AmbientCubemap} - * @memberOf qtek.light.AmbientCubemap.prototype + * @return {clay.light.AmbientCubemap} + * @memberOf clay.light.AmbientCubemap.prototype */ }); /** * Spherical Harmonic Ambient Light - * @constructor qtek.light.AmbientSH - * @extends qtek.Light + * @constructor clay.light.AmbientSH + * @extends clay.Light */ var AmbientSHLight = Light.extend({ castShadow: false, - /** * Spherical Harmonic Coefficients * @type {Array.} + * @memberOf clay.light.AmbientSH# */ coefficients: [], @@ -27455,15 +27729,15 @@ var AmbientSHLight = Light.extend({ } } /** - * @method + * @function * @name clone - * @return {qtek.light.Ambient} - * @memberOf qtek.light.Ambient.prototype + * @return {clay.light.Ambient} + * @memberOf clay.light.Ambient.prototype */ }); // Spherical Harmonic Helpers -var vec3$16 = glmatrix.vec3; +var vec3$14 = glmatrix.vec3; var sh = {}; var targets$3 = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; @@ -27514,15 +27788,15 @@ var normalTransform = { // Project on cpu. function projectEnvironmentMapCPU(renderer, cubePixels, width, height) { var coeff = new vendor.Float32Array(9 * 3); - var normal = vec3$16.create(); - var texel = vec3$16.create(); - var fetchNormal = vec3$16.create(); + var normal = vec3$14.create(); + var texel = vec3$14.create(); + var fetchNormal = vec3$14.create(); for (var m = 0; m < 9; m++) { - var result = vec3$16.create(); + var result = vec3$14.create(); for (var k = 0; k < targets$3.length; k++) { var pixels = cubePixels[targets$3[k]]; - var sideResult = vec3$16.create(); + var sideResult = vec3$14.create(); var divider = 0; var i = 0; var transform = normalTransform[targets$3[k]]; @@ -27533,7 +27807,7 @@ function projectEnvironmentMapCPU(renderer, cubePixels, width, height) { // TODO Flip y? normal[1] = y / (height - 1.0) * 2.0 - 1.0; normal[2] = -1.0; - vec3$16.normalize(normal, normal); + vec3$14.normalize(normal, normal); fetchNormal[0] = normal[transform[0]] * transform[3]; fetchNormal[1] = normal[transform[1]] * transform[4]; @@ -27543,17 +27817,17 @@ function projectEnvironmentMapCPU(renderer, cubePixels, width, height) { texel[1] = pixels[i++] / 255; texel[2] = pixels[i++] / 255; // RGBM Decode - var scale = pixels[i++] / 255 * 51.5; + var scale = pixels[i++] / 255 * 8.12; texel[0] *= scale; texel[1] *= scale; texel[2] *= scale; - vec3$16.scaleAndAdd(sideResult, sideResult, texel, harmonics(fetchNormal, m) * -normal[2]); + vec3$14.scaleAndAdd(sideResult, sideResult, texel, harmonics(fetchNormal, m) * -normal[2]); // -normal.z equals cos(theta) of Lambertian divider += -normal[2]; } } - vec3$16.scaleAndAdd(result, result, sideResult, 1 / divider); + vec3$14.scaleAndAdd(result, result, sideResult, 1 / divider); } coeff[m * 3] = result[0] / 6.0; @@ -27564,8 +27838,8 @@ function projectEnvironmentMapCPU(renderer, cubePixels, width, height) { } /** - * @param {qtek.Renderer} renderer - * @param {qtek.Texture} envMap + * @param {clay.Renderer} renderer + * @param {clay.Texture} envMap * @param {Object} [textureOpts] * @param {Object} [textureOpts.lod] * @param {boolean} [textureOpts.decodeRGBM] @@ -27580,7 +27854,7 @@ sh.projectEnvironmentMap = function (renderer, envMap, opts) { var skybox; var dummyScene = new Scene(); var size = 64; - if (envMap instanceof Texture2D) { + if (envMap.textureType === 'texture2D') { skybox = new Skydome({ scene: dummyScene, environmentMap: envMap @@ -27601,9 +27875,9 @@ sh.projectEnvironmentMap = function (renderer, envMap, opts) { height: height }); var framebuffer = new FrameBuffer(); - skybox.material.shader.define('fragment', 'RGBM_ENCODE'); + skybox.material.define('fragment', 'RGBM_ENCODE'); if (opts.decodeRGBM) { - skybox.material.shader.define('fragment', 'RGBM_DECODE'); + skybox.material.define('fragment', 'RGBM_DECODE'); } skybox.material.set('lod', opts.lod); var envMapPass = new EnvironmentMapPass({ @@ -27619,7 +27893,7 @@ sh.projectEnvironmentMap = function (renderer, envMap, opts) { renderer.render(dummyScene, camera); renderer.gl.readPixels( 0, 0, width, height, - Texture.RGBA, Texture.UNSIGNED_BYTE, cubePixels[targets$3[i]] + Texture$1.RGBA, Texture$1.UNSIGNED_BYTE, cubePixels[targets$3[i]] ); framebuffer.unbind(renderer); } @@ -27631,7 +27905,7 @@ sh.projectEnvironmentMap = function (renderer, envMap, opts) { return projectEnvironmentMapCPU(renderer, cubePixels, width, height); }; -var kCSSColorTable = { +var kCSSColorTable$1 = { 'transparent': [0,0,0,0], 'aliceblue': [240,248,255,1], 'antiquewhite': [250,235,215,1], 'aqua': [0,255,255,1], 'aquamarine': [127,255,212,1], 'azure': [240,255,255,1], @@ -27708,30 +27982,30 @@ var kCSSColorTable = { 'yellow': [255,255,0,1], 'yellowgreen': [154,205,50,1] }; -function clampCssByte(i) { // Clamp to integer 0 .. 255. +function clampCssByte$1(i) { // Clamp to integer 0 .. 255. i = Math.round(i); // Seems to be what Chrome does (vs truncation). return i < 0 ? 0 : i > 255 ? 255 : i; } -function clampCssFloat(f) { // Clamp to float 0.0 .. 1.0. +function clampCssFloat$1(f) { // Clamp to float 0.0 .. 1.0. return f < 0 ? 0 : f > 1 ? 1 : f; } -function parseCssInt(str) { // int or percentage. +function parseCssInt$1(str) { // int or percentage. if (str.length && str.charAt(str.length - 1) === '%') { - return clampCssByte(parseFloat(str) / 100 * 255); + return clampCssByte$1(parseFloat(str) / 100 * 255); } - return clampCssByte(parseInt(str, 10)); + return clampCssByte$1(parseInt(str, 10)); } -function parseCssFloat(str) { // float or percentage. +function parseCssFloat$1(str) { // float or percentage. if (str.length && str.charAt(str.length - 1) === '%') { - return clampCssFloat(parseFloat(str) / 100); + return clampCssFloat$1(parseFloat(str) / 100); } - return clampCssFloat(parseFloat(str)); + return clampCssFloat$1(parseFloat(str)); } -function cssHueToRgb(m1, m2, h) { +function cssHueToRgb$1(m1, m2, h) { if (h < 0) { h += 1; } @@ -27751,24 +28025,24 @@ function cssHueToRgb(m1, m2, h) { return m1; } -function setRgba(out, r, g, b, a) { +function setRgba$1(out, r, g, b, a) { out[0] = r; out[1] = g; out[2] = b; out[3] = a; return out; } -function copyRgba(out, a) { +function copyRgba$1(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; return out; } -var colorCache = new LRU(20); -var lastRemovedArr = null; +var colorCache$1 = new LRU$1(20); +var lastRemovedArr$1 = null; -function putToCache(colorStr, rgbaArr) { +function putToCache$1(colorStr, rgbaArr) { // Reuse removed array - if (lastRemovedArr) { - copyRgba(lastRemovedArr, rgbaArr); + if (lastRemovedArr$1) { + copyRgba$1(lastRemovedArr$1, rgbaArr); } - lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice())); + lastRemovedArr$1 = colorCache$1.put(colorStr, lastRemovedArr$1 || (rgbaArr.slice())); } /** @@ -27783,9 +28057,9 @@ function parse(colorStr, rgbaArr) { } rgbaArr = rgbaArr || []; - var cached = colorCache.get(colorStr); + var cached = colorCache$1.get(colorStr); if (cached) { - return copyRgba(rgbaArr, cached); + return copyRgba$1(rgbaArr, cached); } // colorStr may be not string @@ -27794,9 +28068,9 @@ function parse(colorStr, rgbaArr) { var str = colorStr.replace(/ /g, '').toLowerCase(); // Color keywords (and transparent) lookup. - if (str in kCSSColorTable) { - copyRgba(rgbaArr, kCSSColorTable[str]); - putToCache(colorStr, rgbaArr); + if (str in kCSSColorTable$1) { + copyRgba$1(rgbaArr, kCSSColorTable$1[str]); + putToCache$1(colorStr, rgbaArr); return rgbaArr; } @@ -27805,31 +28079,31 @@ function parse(colorStr, rgbaArr) { if (str.length === 4) { var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. if (!(iv >= 0 && iv <= 0xfff)) { - setRgba(rgbaArr, 0, 0, 0, 1); + setRgba$1(rgbaArr, 0, 0, 0, 1); return; // Covers NaN. } - setRgba(rgbaArr, + setRgba$1(rgbaArr, ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8), (iv & 0xf0) | ((iv & 0xf0) >> 4), (iv & 0xf) | ((iv & 0xf) << 4), 1 ); - putToCache(colorStr, rgbaArr); + putToCache$1(colorStr, rgbaArr); return rgbaArr; } else if (str.length === 7) { var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. if (!(iv >= 0 && iv <= 0xffffff)) { - setRgba(rgbaArr, 0, 0, 0, 1); + setRgba$1(rgbaArr, 0, 0, 0, 1); return; // Covers NaN. } - setRgba(rgbaArr, + setRgba$1(rgbaArr, (iv & 0xff0000) >> 16, (iv & 0xff00) >> 8, iv & 0xff, 1 ); - putToCache(colorStr, rgbaArr); + putToCache$1(colorStr, rgbaArr); return rgbaArr; } @@ -27843,47 +28117,47 @@ function parse(colorStr, rgbaArr) { switch (fname) { case 'rgba': if (params.length !== 4) { - setRgba(rgbaArr, 0, 0, 0, 1); + setRgba$1(rgbaArr, 0, 0, 0, 1); return; } - alpha = parseCssFloat(params.pop()); // jshint ignore:line + alpha = parseCssFloat$1(params.pop()); // jshint ignore:line // Fall through. case 'rgb': if (params.length !== 3) { - setRgba(rgbaArr, 0, 0, 0, 1); + setRgba$1(rgbaArr, 0, 0, 0, 1); return; } - setRgba(rgbaArr, - parseCssInt(params[0]), - parseCssInt(params[1]), - parseCssInt(params[2]), + setRgba$1(rgbaArr, + parseCssInt$1(params[0]), + parseCssInt$1(params[1]), + parseCssInt$1(params[2]), alpha ); - putToCache(colorStr, rgbaArr); + putToCache$1(colorStr, rgbaArr); return rgbaArr; case 'hsla': if (params.length !== 4) { - setRgba(rgbaArr, 0, 0, 0, 1); + setRgba$1(rgbaArr, 0, 0, 0, 1); return; } - params[3] = parseCssFloat(params[3]); - hsla2rgba(params, rgbaArr); - putToCache(colorStr, rgbaArr); + params[3] = parseCssFloat$1(params[3]); + hsla2rgba$1(params, rgbaArr); + putToCache$1(colorStr, rgbaArr); return rgbaArr; case 'hsl': if (params.length !== 3) { - setRgba(rgbaArr, 0, 0, 0, 1); + setRgba$1(rgbaArr, 0, 0, 0, 1); return; } - hsla2rgba(params, rgbaArr); - putToCache(colorStr, rgbaArr); + hsla2rgba$1(params, rgbaArr); + putToCache$1(colorStr, rgbaArr); return rgbaArr; default: return; } } - setRgba(rgbaArr, 0, 0, 0, 1); + setRgba$1(rgbaArr, 0, 0, 0, 1); return; } @@ -27892,20 +28166,20 @@ function parse(colorStr, rgbaArr) { * @param {Array.} rgba * @return {Array.} rgba */ -function hsla2rgba(hsla, rgba) { +function hsla2rgba$1(hsla, rgba) { var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360; // 0 .. 1 // NOTE(deanm): According to the CSS spec s/l should only be // percentages, but we don't bother and let float or percentage. - var s = parseCssFloat(hsla[1]); - var l = parseCssFloat(hsla[2]); + var s = parseCssFloat$1(hsla[1]); + var l = parseCssFloat$1(hsla[2]); var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; var m1 = l * 2 - m2; rgba = rgba || []; - setRgba(rgba, - clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255), - clampCssByte(cssHueToRgb(m1, m2, h) * 255), - clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255), + setRgba$1(rgba, + clampCssByte$1(cssHueToRgb$1(m1, m2, h + 1 / 3) * 255), + clampCssByte$1(cssHueToRgb$1(m1, m2, h) * 255), + clampCssByte$1(cssHueToRgb$1(m1, m2, h - 1 / 3) * 255), 1 ); @@ -28001,6 +28275,7 @@ function isValueNone(value) { function isValueImage(value) { return value instanceof HTMLCanvasElement || value instanceof HTMLImageElement + || value instanceof HTMLVideoElement || value instanceof Image; } @@ -28019,10 +28294,10 @@ Material.prototype.setTextureImage = function (textureName, imgValue, app, textu var material = this; var texture; // disableTexture first - material.shader.disableTexture(textureName); + material.disableTexture(textureName); if (!isValueNone(imgValue)) { texture = helper.loadTexture(imgValue, app, textureOpts, function (texture) { - material.shader.enableTexture(textureName); + material.enableTexture(textureName); app.refresh(); }); // Set texture immediately for other code to verify if have this texture. @@ -28037,30 +28312,6 @@ var helper = {}; // Texture utilities var blankImage = textureUtil.createBlank('rgba(255,255,255,0)').image; - -function nearestPowerOfTwo(val) { - return Math.pow(2, Math.round(Math.log(val) / Math.LN2)); -} -function convertTextureToPowerOfTwo(texture) { - if ((texture.wrapS === Texture.REPEAT || texture.wrapT === Texture.REPEAT) - && texture.image - ) { - // var canvas = document.createElement('canvas'); - var width = nearestPowerOfTwo(texture.width); - var height = nearestPowerOfTwo(texture.height); - if (width !== texture.width || height !== texture.height) { - var canvas = document.createElement('canvas'); - canvas.width = width; - canvas.height = height; - var ctx = canvas.getContext('2d'); - ctx.drawImage(texture.image, 0, 0, width, height); - canvas.srcImage = texture.image; - texture.image = canvas; - texture.dirty(); - } - } -} - helper.firstNotNull = function () { for (var i = 0, len = arguments.length; i < len; i++) { if (arguments[i] != null) { @@ -28080,7 +28331,7 @@ helper.firstNotNull = function () { prefix += keys[i] + '_' + textureOpts[keys[i]] + '_'; } - var textureCache = app.__textureCache = app.__textureCache || new LRU(20); + var textureCache = app.__textureCache = app.__textureCache || new LRU$1(20); if (isValueImage(imgValue)) { var id = imgValue.__textureid__; @@ -28088,7 +28339,9 @@ helper.firstNotNull = function () { if (!textureObj) { textureObj = { texture: new Texture2D({ - image: imgValue + image: imgValue, + convertToPOT: true, + dynamic: imgValue instanceof HTMLVideoElement }) }; for (var i = 0; i < keys.length; i++) { @@ -28098,7 +28351,6 @@ helper.firstNotNull = function () { imgValue.__textureid__ = id; textureCache.put(prefix + id, textureObj); - convertTextureToPowerOfTwo(textureObj.texture); // TODO Next tick? cb && cb(textureObj.texture); } @@ -28136,9 +28388,16 @@ helper.firstNotNull = function () { textureCache.put(prefix + imgValue, textureObj); } else { + var fileType = imgValue.split('.').pop(); + var isVideo = fileType === 'mp4' + || fileType === 'webm' + || fileType === 'ogg'; var texture = new Texture2D({ - image: new Image() + convertToPOT: true, + image: isVideo ? document.createElement('video') : new Image(), + dynamic: isVideo }); + for (var i = 0; i < keys.length; i++) { texture[keys[i]] = textureOpts[keys[i]]; } @@ -28148,9 +28407,8 @@ helper.firstNotNull = function () { callbacks: [cb] }; var originalImage = texture.image; - originalImage.onload = function () { + var onload = function () { texture.image = originalImage; - convertTextureToPowerOfTwo(texture); texture.dirty(); textureObj.callbacks.forEach(function (cb) { @@ -28158,6 +28416,19 @@ helper.firstNotNull = function () { }); textureObj.callbacks = null; }; + if (isVideo) { + originalImage.oncanplay = function () { + originalImage.width = originalImage.videoWidth; + originalImage.height = originalImage.videoHeight; + originalImage.oncanplay = null; + originalImage.loop = true; + originalImage.play(); + onload(); + }; + } + else { + originalImage.onload = onload; + } originalImage.src = imgValue; // Use blank image as place holder. texture.image = blankImage; @@ -28201,7 +28472,7 @@ helper.createAmbientCubemap = function (opt, app, cb) { }); setTimeout(function () { - cb && cb(); + cb && cb(); }); // TODO Refresh ? }); @@ -28298,8 +28569,6 @@ helper.directionFromAlphaBeta = function (alpha, beta) { return dir; }; -helper.convertTextureToPowerOfTwo = convertTextureToPowerOfTwo; - var effectJson = { 'type' : 'compositor', 'nodes' : [ @@ -28312,7 +28581,7 @@ var effectJson = { }, { 'name': 'source_half', - 'shader': '#source(qtek.compositor.downsample)', + 'shader': '#source(clay.compositor.downsample)', 'inputs': { 'texture': 'source' }, @@ -28333,7 +28602,7 @@ var effectJson = { { 'name' : 'bright', - 'shader' : '#source(qtek.compositor.bright)', + 'shader' : '#source(clay.compositor.bright)', 'inputs' : { 'texture' : 'source_half' }, @@ -28355,7 +28624,7 @@ var effectJson = { { 'name': 'bright_downsample_4', - 'shader' : '#source(qtek.compositor.downsample)', + 'shader' : '#source(clay.compositor.downsample)', 'inputs' : { 'texture' : 'bright' }, @@ -28374,7 +28643,7 @@ var effectJson = { }, { 'name': 'bright_downsample_8', - 'shader' : '#source(qtek.compositor.downsample)', + 'shader' : '#source(clay.compositor.downsample)', 'inputs' : { 'texture' : 'bright_downsample_4' }, @@ -28393,7 +28662,7 @@ var effectJson = { }, { 'name': 'bright_downsample_16', - 'shader' : '#source(qtek.compositor.downsample)', + 'shader' : '#source(clay.compositor.downsample)', 'inputs' : { 'texture' : 'bright_downsample_8' }, @@ -28412,7 +28681,7 @@ var effectJson = { }, { 'name': 'bright_downsample_32', - 'shader' : '#source(qtek.compositor.downsample)', + 'shader' : '#source(clay.compositor.downsample)', 'inputs' : { 'texture' : 'bright_downsample_16' }, @@ -28433,7 +28702,7 @@ var effectJson = { { 'name' : 'bright_upsample_16_blur_h', - 'shader' : '#source(qtek.compositor.gaussian_blur)', + 'shader' : '#source(clay.compositor.gaussian_blur)', 'inputs' : { 'texture' : 'bright_downsample_32' }, @@ -28454,7 +28723,7 @@ var effectJson = { }, { 'name' : 'bright_upsample_16_blur_v', - 'shader' : '#source(qtek.compositor.gaussian_blur)', + 'shader' : '#source(clay.compositor.gaussian_blur)', 'inputs' : { 'texture' : 'bright_upsample_16_blur_h' }, @@ -28478,7 +28747,7 @@ var effectJson = { { 'name' : 'bright_upsample_8_blur_h', - 'shader' : '#source(qtek.compositor.gaussian_blur)', + 'shader' : '#source(clay.compositor.gaussian_blur)', 'inputs' : { 'texture' : 'bright_downsample_16' }, @@ -28499,7 +28768,7 @@ var effectJson = { }, { 'name' : 'bright_upsample_8_blur_v', - 'shader' : '#source(qtek.compositor.gaussian_blur)', + 'shader' : '#source(clay.compositor.gaussian_blur)', 'inputs' : { 'texture' : 'bright_upsample_8_blur_h' }, @@ -28520,7 +28789,7 @@ var effectJson = { }, { 'name' : 'bright_upsample_8_blend', - 'shader' : '#source(qtek.compositor.blend)', + 'shader' : '#source(clay.compositor.blend)', 'inputs' : { 'texture1' : 'bright_upsample_8_blur_v', 'texture2' : 'bright_upsample_16_blur_v' @@ -28543,7 +28812,7 @@ var effectJson = { { 'name' : 'bright_upsample_4_blur_h', - 'shader' : '#source(qtek.compositor.gaussian_blur)', + 'shader' : '#source(clay.compositor.gaussian_blur)', 'inputs' : { 'texture' : 'bright_downsample_8' }, @@ -28564,7 +28833,7 @@ var effectJson = { }, { 'name' : 'bright_upsample_4_blur_v', - 'shader' : '#source(qtek.compositor.gaussian_blur)', + 'shader' : '#source(clay.compositor.gaussian_blur)', 'inputs' : { 'texture' : 'bright_upsample_4_blur_h' }, @@ -28585,7 +28854,7 @@ var effectJson = { }, { 'name' : 'bright_upsample_4_blend', - 'shader' : '#source(qtek.compositor.blend)', + 'shader' : '#source(clay.compositor.blend)', 'inputs' : { 'texture1' : 'bright_upsample_4_blur_v', 'texture2' : 'bright_upsample_8_blend' @@ -28611,7 +28880,7 @@ var effectJson = { { 'name' : 'bright_upsample_2_blur_h', - 'shader' : '#source(qtek.compositor.gaussian_blur)', + 'shader' : '#source(clay.compositor.gaussian_blur)', 'inputs' : { 'texture' : 'bright_downsample_4' }, @@ -28632,7 +28901,7 @@ var effectJson = { }, { 'name' : 'bright_upsample_2_blur_v', - 'shader' : '#source(qtek.compositor.gaussian_blur)', + 'shader' : '#source(clay.compositor.gaussian_blur)', 'inputs' : { 'texture' : 'bright_upsample_2_blur_h' }, @@ -28653,7 +28922,7 @@ var effectJson = { }, { 'name' : 'bright_upsample_2_blend', - 'shader' : '#source(qtek.compositor.blend)', + 'shader' : '#source(clay.compositor.blend)', 'inputs' : { 'texture1' : 'bright_upsample_2_blur_v', 'texture2' : 'bright_upsample_4_blend' @@ -28677,7 +28946,7 @@ var effectJson = { { 'name' : 'bright_upsample_full_blur_h', - 'shader' : '#source(qtek.compositor.gaussian_blur)', + 'shader' : '#source(clay.compositor.gaussian_blur)', 'inputs' : { 'texture' : 'bright' }, @@ -28698,7 +28967,7 @@ var effectJson = { }, { 'name' : 'bright_upsample_full_blur_v', - 'shader' : '#source(qtek.compositor.gaussian_blur)', + 'shader' : '#source(clay.compositor.gaussian_blur)', 'inputs' : { 'texture' : 'bright_upsample_full_blur_h' }, @@ -28719,7 +28988,7 @@ var effectJson = { }, { 'name' : 'bloom_composite', - 'shader' : '#source(qtek.compositor.blend)', + 'shader' : '#source(clay.compositor.blend)', 'inputs' : { 'texture1' : 'bright_upsample_full_blur_v', 'texture2' : 'bright_upsample_2_blend' @@ -28850,7 +29119,7 @@ var effectJson = { }, { 'name' : 'composite', - 'shader' : '#source(qtek.compositor.hdr.composite)', + 'shader' : '#source(clay.compositor.hdr.composite)', 'inputs' : { 'texture': 'source', 'bloom' : 'bloom_composite' @@ -28858,12 +29127,12 @@ var effectJson = { 'defines': { // Images are all premultiplied alpha before composite because of blending. // 'PREMULTIPLY_ALPHA': null, - // 'DEBUG': 2 + // 'DEBUG': 1 } }, { 'name' : 'FXAA', - 'shader' : '#source(qtek.compositor.fxaa)', + 'shader' : '#source(clay.compositor.fxaa)', 'inputs' : { 'texture' : 'composite' } @@ -28871,31 +29140,30 @@ var effectJson = { ] }; -var dofGLSL = "@export ecgl.dof.coc\n\nuniform sampler2D depth;\n\nuniform float zNear: 0.1;\nuniform float zFar: 2000;\n\nuniform float focalDistance: 3;\nuniform float focalRange: 1;\nuniform float focalLength: 30;\nuniform float fstop: 2.8;\n\nvarying vec2 v_Texcoord;\n\n@import qtek.util.encode_float\n\nvoid main()\n{\n float z = texture2D(depth, v_Texcoord).r * 2.0 - 1.0;\n\n float dist = 2.0 * zNear * zFar / (zFar + zNear - z * (zFar - zNear));\n\n float aperture = focalLength / fstop;\n\n float coc;\n\n float uppper = focalDistance + focalRange;\n float lower = focalDistance - focalRange;\n if (dist <= uppper && dist >= lower) {\n coc = 0.5;\n }\n else {\n float focalAdjusted = dist > uppper ? uppper : lower;\n\n coc = abs(aperture * (focalLength * (dist - focalAdjusted)) / (dist * (focalAdjusted - focalLength)));\n coc = clamp(coc, 0.0, 2.0) / 2.00001;\n\n if (dist < lower) {\n coc = -coc;\n }\n coc = coc * 0.5 + 0.5;\n }\n\n gl_FragColor = encodeFloat(coc);\n}\n@end\n\n\n@export ecgl.dof.composite\n\n#define DEBUG 0\n\nuniform sampler2D original;\nuniform sampler2D blurred;\nuniform sampler2D nearfield;\nuniform sampler2D coc;\nuniform sampler2D nearcoc;\nvarying vec2 v_Texcoord;\n\n@import qtek.util.rgbm\n@import qtek.util.float\n\nvoid main()\n{\n vec4 blurredColor = decodeHDR(texture2D(blurred, v_Texcoord));\n vec4 originalColor = decodeHDR(texture2D(original, v_Texcoord));\n\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord));\n\n fCoc = abs(fCoc * 2.0 - 1.0);\n\n float weight = smoothstep(0.0, 1.0, fCoc);\n \n#ifdef NEARFIELD_ENABLED\n vec4 nearfieldColor = decodeHDR(texture2D(nearfield, v_Texcoord));\n float fNearCoc = decodeFloat(texture2D(nearcoc, v_Texcoord));\n fNearCoc = abs(fNearCoc * 2.0 - 1.0);\n\n gl_FragColor = encodeHDR(\n mix(\n nearfieldColor, mix(originalColor, blurredColor, weight),\n pow(1.0 - fNearCoc, 4.0)\n )\n );\n#else\n gl_FragColor = encodeHDR(mix(originalColor, blurredColor, weight));\n#endif\n\n}\n\n@end\n\n\n\n@export ecgl.dof.diskBlur\n\n#define POISSON_KERNEL_SIZE 16;\n\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\n\nuniform float blurRadius : 10.0;\nuniform vec2 textureSize : [512.0, 512.0];\n\nuniform vec2 poissonKernel[POISSON_KERNEL_SIZE];\n\nuniform float percent;\n\nfloat nrand(const in vec2 n) {\n return fract(sin(dot(n.xy ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\n@import qtek.util.rgbm\n@import qtek.util.float\n\n\nvoid main()\n{\n vec2 offset = blurRadius / textureSize;\n\n float rnd = 6.28318 * nrand(v_Texcoord + 0.07 * percent );\n float cosa = cos(rnd);\n float sina = sin(rnd);\n vec4 basis = vec4(cosa, -sina, sina, cosa);\n\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n\n#ifdef BLUR_COC\n float cocSum = 0.0;\n#else\n vec4 color = vec4(0.0);\n#endif\n\n\n float weightSum = 0.0;\n\n for (int i = 0; i < POISSON_KERNEL_SIZE; i++) {\n vec2 ofs = poissonKernel[i];\n\n ofs = vec2(dot(ofs, basis.xy), dot(ofs, basis.zw));\n\n vec2 uv = v_Texcoord + ofs * offset;\n vec4 texel = texture2D(texture, uv);\n\n float w = 1.0;\n#ifdef BLUR_COC\n float fCoc = decodeFloat(texel) * 2.0 - 1.0;\n cocSum += clamp(fCoc, -1.0, 0.0) * w;\n#else\n texel = decodeHDR(texel);\n #if !defined(BLUR_NEARFIELD)\n float fCoc = decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0;\n w *= abs(fCoc);\n #endif\n color += texel * w;\n#endif\n\n weightSum += w;\n }\n\n#ifdef BLUR_COC\n gl_FragColor = encodeFloat(clamp(cocSum / weightSum, -1.0, 0.0) * 0.5 + 0.5);\n#else\n color /= weightSum;\n gl_FragColor = encodeHDR(color);\n#endif\n}\n\n@end"; +var dofGLSL = "@export ecgl.dof.coc\n\nuniform sampler2D depth;\n\nuniform float zNear: 0.1;\nuniform float zFar: 2000;\n\nuniform float focalDistance: 3;\nuniform float focalRange: 1;\nuniform float focalLength: 30;\nuniform float fstop: 2.8;\n\nvarying vec2 v_Texcoord;\n\n@import clay.util.encode_float\n\nvoid main()\n{\n float z = texture2D(depth, v_Texcoord).r * 2.0 - 1.0;\n\n float dist = 2.0 * zNear * zFar / (zFar + zNear - z * (zFar - zNear));\n\n float aperture = focalLength / fstop;\n\n float coc;\n\n float uppper = focalDistance + focalRange;\n float lower = focalDistance - focalRange;\n if (dist <= uppper && dist >= lower) {\n coc = 0.5;\n }\n else {\n float focalAdjusted = dist > uppper ? uppper : lower;\n\n coc = abs(aperture * (focalLength * (dist - focalAdjusted)) / (dist * (focalAdjusted - focalLength)));\n coc = clamp(coc, 0.0, 2.0) / 2.00001;\n\n if (dist < lower) {\n coc = -coc;\n }\n coc = coc * 0.5 + 0.5;\n }\n\n gl_FragColor = encodeFloat(coc);\n}\n@end\n\n\n@export ecgl.dof.composite\n\n#define DEBUG 0\n\nuniform sampler2D original;\nuniform sampler2D blurred;\nuniform sampler2D nearfield;\nuniform sampler2D coc;\nuniform sampler2D nearcoc;\nvarying vec2 v_Texcoord;\n\n@import clay.util.rgbm\n@import clay.util.float\n\nvoid main()\n{\n vec4 blurredColor = decodeHDR(texture2D(blurred, v_Texcoord));\n vec4 originalColor = decodeHDR(texture2D(original, v_Texcoord));\n\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord));\n\n fCoc = abs(fCoc * 2.0 - 1.0);\n\n float weight = smoothstep(0.0, 1.0, fCoc);\n \n#ifdef NEARFIELD_ENABLED\n vec4 nearfieldColor = decodeHDR(texture2D(nearfield, v_Texcoord));\n float fNearCoc = decodeFloat(texture2D(nearcoc, v_Texcoord));\n fNearCoc = abs(fNearCoc * 2.0 - 1.0);\n\n gl_FragColor = encodeHDR(\n mix(\n nearfieldColor, mix(originalColor, blurredColor, weight),\n pow(1.0 - fNearCoc, 4.0)\n )\n );\n#else\n gl_FragColor = encodeHDR(mix(originalColor, blurredColor, weight));\n#endif\n\n}\n\n@end\n\n\n\n@export ecgl.dof.diskBlur\n\n#define POISSON_KERNEL_SIZE 16;\n\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\n\nuniform float blurRadius : 10.0;\nuniform vec2 textureSize : [512.0, 512.0];\n\nuniform vec2 poissonKernel[POISSON_KERNEL_SIZE];\n\nuniform float percent;\n\nfloat nrand(const in vec2 n) {\n return fract(sin(dot(n.xy ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\n@import clay.util.rgbm\n@import clay.util.float\n\n\nvoid main()\n{\n vec2 offset = blurRadius / textureSize;\n\n float rnd = 6.28318 * nrand(v_Texcoord + 0.07 * percent );\n float cosa = cos(rnd);\n float sina = sin(rnd);\n vec4 basis = vec4(cosa, -sina, sina, cosa);\n\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n\n#ifdef BLUR_COC\n float cocSum = 0.0;\n#else\n vec4 color = vec4(0.0);\n#endif\n\n\n float weightSum = 0.0;\n\n for (int i = 0; i < POISSON_KERNEL_SIZE; i++) {\n vec2 ofs = poissonKernel[i];\n\n ofs = vec2(dot(ofs, basis.xy), dot(ofs, basis.zw));\n\n vec2 uv = v_Texcoord + ofs * offset;\n vec4 texel = texture2D(texture, uv);\n\n float w = 1.0;\n#ifdef BLUR_COC\n float fCoc = decodeFloat(texel) * 2.0 - 1.0;\n cocSum += clamp(fCoc, -1.0, 0.0) * w;\n#else\n texel = decodeHDR(texel);\n #if !defined(BLUR_NEARFIELD)\n float fCoc = decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0;\n w *= abs(fCoc);\n #endif\n color += texel * w;\n#endif\n\n weightSum += w;\n }\n\n#ifdef BLUR_COC\n gl_FragColor = encodeFloat(clamp(cocSum / weightSum, -1.0, 0.0) * 0.5 + 0.5);\n#else\n color /= weightSum;\n gl_FragColor = encodeHDR(color);\n#endif\n}\n\n@end"; var edgeGLSL = "@export ecgl.edge\n\nuniform sampler2D texture;\n\nuniform sampler2D normalTexture;\nuniform sampler2D depthTexture;\n\nuniform mat4 projectionInv;\n\nuniform vec2 textureSize;\n\nuniform vec4 edgeColor: [0,0,0,0.8];\n\nvarying vec2 v_Texcoord;\n\nvec3 packColor(vec2 coord) {\n float z = texture2D(depthTexture, coord).r * 2.0 - 1.0;\n vec4 p = vec4(v_Texcoord * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * p;\n\n return vec3(\n texture2D(normalTexture, coord).rg,\n -p4.z / p4.w / 5.0\n );\n}\n\nvoid main() {\n vec2 cc = v_Texcoord;\n vec3 center = packColor(cc);\n\n float size = clamp(1.0 - (center.z - 10.0) / 100.0, 0.0, 1.0) * 0.5;\n float dx = size / textureSize.x;\n float dy = size / textureSize.y;\n\n vec2 coord;\n vec3 topLeft = packColor(cc+vec2(-dx, -dy));\n vec3 top = packColor(cc+vec2(0.0, -dy));\n vec3 topRight = packColor(cc+vec2(dx, -dy));\n vec3 left = packColor(cc+vec2(-dx, 0.0));\n vec3 right = packColor(cc+vec2(dx, 0.0));\n vec3 bottomLeft = packColor(cc+vec2(-dx, dy));\n vec3 bottom = packColor(cc+vec2(0.0, dy));\n vec3 bottomRight = packColor(cc+vec2(dx, dy));\n\n vec3 v = -topLeft-2.0*top-topRight+bottomLeft+2.0*bottom+bottomRight;\n vec3 h = -bottomLeft-2.0*left-topLeft+bottomRight+2.0*right+topRight;\n\n float edge = sqrt(dot(h, h) + dot(v, v));\n\n edge = smoothstep(0.8, 1.0, edge);\n\n gl_FragColor = mix(texture2D(texture, v_Texcoord), vec4(edgeColor.rgb, 1.0), edgeColor.a * edge);\n}\n@end"; // import EdgePass from './EdgePass'; -Shader['import'](blurGLSL); -Shader['import'](outputGLSL); -Shader['import'](brightGLSL); -Shader['import'](downsampleGLSL); -Shader['import'](upsampleGLSL); -Shader['import'](hdrGLSL); -Shader['import'](blendGLSL); -Shader['import'](fxaaGLSL); +Shader['import'](blurEssl); +Shader['import'](outputEssl); +Shader['import'](brightEssl); +Shader['import'](downsampleEssl); +Shader['import'](upsampleEssl); +Shader['import'](hdrEssl); +Shader['import'](blendEssl); +Shader['import'](fxaaEssl); Shader['import'](gbufferEssl); Shader['import'](dofGLSL); Shader['import'](edgeGLSL); - var commonOutputs = { - color : { - parameters : { - width : function (renderer) { + color: { + parameters: { + width: function (renderer) { return renderer.getWidth(); }, - height : function (renderer) { + height: function (renderer) { return renderer.getHeight(); } } @@ -28906,11 +29174,11 @@ var FINAL_NODES_CHAIN = ['composite', 'FXAA']; function EffectCompositor() { this._sourceTexture = new Texture2D({ - type: Texture.HALF_FLOAT + type: Texture$1.HALF_FLOAT }); this._depthTexture = new Texture2D({ - format: Texture.DEPTH_COMPONENT, - type: Texture.UNSIGNED_INT + format: Texture$1.DEPTH_COMPONENT, + type: Texture$1.UNSIGNED_INT }); this._framebuffer = new FrameBuffer(); @@ -28918,11 +29186,11 @@ function EffectCompositor() { this._framebuffer.attach(this._depthTexture, FrameBuffer.DEPTH_ATTACHMENT); this._gBufferPass = new GBuffer({ + renderTransparent: true, enableTargetTexture3: false }); - var loader = new FXLoader(); - this._compositor = loader.parse(effectJson); + this._compositor = createCompositor$1(effectJson); var sourceNode = this._compositor.getNodeByName('source'); sourceNode.texture = this._sourceTexture; @@ -28946,11 +29214,11 @@ function EffectCompositor() { var gBufferObj = { normalTexture: this._gBufferPass.getTargetTexture1(), - depthTexture: this._gBufferPass.getTargetTexture2() + depthTexture: this._gBufferPass.getTargetTexture2(), + albedoTexture: this._gBufferPass.getTargetTexture3() }; this._ssaoPass = new SSAOPass(gBufferObj); this._ssrPass = new SSRPass(gBufferObj); - // this._edgePass = new EdgePass(gBufferObj); } EffectCompositor.prototype.resize = function (width, height, dpr) { @@ -29027,7 +29295,7 @@ EffectCompositor.prototype._removeChainNode = function (node) { /** * Update normal */ -EffectCompositor.prototype.updateNormal = function (renderer, scene, camera, frame) { +EffectCompositor.prototype.updateGBuffer = function (renderer, scene, camera, frame) { if (this._ifRenderNormalPass()) { this._gBufferPass.update(renderer, scene, camera); } @@ -29059,30 +29327,32 @@ EffectCompositor.prototype.disableSSAO = function () { */ EffectCompositor.prototype.enableSSR = function () { this._enableSSR = true; + this._gBufferPass.enableTargetTexture3 = true; }; /** * Disable SSR effect */ EffectCompositor.prototype.disableSSR = function () { this._enableSSR = false; + this._gBufferPass.enableTargetTexture3 = false; }; /** * Render SSAO after render the scene, before compositing */ -EffectCompositor.prototype.getSSAOTexture = function (renderer, scene, camera, frame) { +EffectCompositor.prototype.getSSAOTexture = function () { return this._ssaoPass.getTargetTexture(); }; /** - * @return {qtek.FrameBuffer} + * @return {clay.FrameBuffer} */ EffectCompositor.prototype.getSourceFrameBuffer = function () { return this._framebuffer; }; /** - * @return {qtek.Texture2D} + * @return {clay.Texture2D} */ EffectCompositor.prototype.getSourceTexture = function () { return this._sourceTexture; @@ -29137,14 +29407,14 @@ EffectCompositor.prototype.disableDOF = function () { * Enable color correction */ EffectCompositor.prototype.enableColorCorrection = function () { - this._compositeNode.shaderDefine('COLOR_CORRECTION'); + this._compositeNode.define('COLOR_CORRECTION'); this._enableColorCorrection = true; }; /** * Disable color correction */ EffectCompositor.prototype.disableColorCorrection = function () { - this._compositeNode.shaderUndefine('COLOR_CORRECTION'); + this._compositeNode.undefine('COLOR_CORRECTION'); this._enableColorCorrection = false; }; @@ -29219,7 +29489,7 @@ EffectCompositor.prototype.setDOFParameter = function (name, value) { })[value] || 8; this._dofBlurKernelSize = kernelSize; for (var i = 0; i < this._dofBlurNodes.length; i++) { - this._dofBlurNodes[i].shaderDefine('POISSON_KERNEL_SIZE', kernelSize); + this._dofBlurNodes[i].define('POISSON_KERNEL_SIZE', kernelSize); } this._dofBlurKernel = new Float32Array(kernelSize * 2); break; @@ -29235,8 +29505,8 @@ EffectCompositor.prototype.setSSRParameter = function (name, value) { // PENDING var maxIteration = ({ low: 10, - medium: 20, - high: 40, + medium: 15, + high: 30, ultra: 80 })[value] || 20; var pixelStride = ({ @@ -29251,13 +29521,17 @@ EffectCompositor.prototype.setSSRParameter = function (name, value) { case 'maxRoughness': this._ssrPass.setParameter('minGlossiness', Math.max(Math.min(1.0 - value, 1.0), 0.0)); break; + case 'physical': + this.setPhysicallyCorrectSSR(value); + break; default: - if (__DEV__) { - console.warn('Unkown SSR parameter ' + name); - } + console.warn('Unkown SSR parameter ' + name); } -} -; +}; + +EffectCompositor.prototype.setPhysicallyCorrectSSR = function (physical) { + this._ssrPass.setPhysicallyCorrect(physical); +}; /** * Set color of edge */ @@ -29277,8 +29551,8 @@ EffectCompositor.prototype.setExposure = function (value) { EffectCompositor.prototype.setColorLookupTexture = function (image, api) { this._compositeNode.pass.material.setTextureImage('lut', this._enableColorCorrection ? image : 'none', api, { - minFilter: Texture.NEAREST, - magFilter: Texture.NEAREST, + minFilter: Texture$1.NEAREST, + magFilter: Texture$1.NEAREST, flipY: false }); }; @@ -29286,14 +29560,11 @@ EffectCompositor.prototype.setColorCorrection = function (type, value) { this._compositeNode.setParameter(type, value); }; -EffectCompositor.prototype.composite = function (renderer, camera, framebuffer, frame) { +EffectCompositor.prototype.composite = function (renderer, scene, camera, framebuffer, frame) { var sourceTexture = this._sourceTexture; var targetTexture = sourceTexture; - // if (this._enableEdge) { - // this._edgePass.update(renderer, camera, sourceTexture, frame); - // sourceTexture = targetTexture = this._edgePass.getTargetTexture(); - // } + if (this._enableSSR) { this._ssrPass.update(renderer, camera, sourceTexture, frame); targetTexture = this._ssrPass.getTargetTexture(); @@ -29301,6 +29572,12 @@ EffectCompositor.prototype.composite = function (renderer, camera, framebuffer, this._ssrPass.setSSAOTexture( this._enableSSAO ? this._ssaoPass.getTargetTexture() : null ); + var lights = scene.getLights(); + for (var i = 0; i < lights.length; i++) { + if (lights[i].cubemap) { + this._ssrPass.setAmbientCubemap(lights[i].cubemap, lights[i].intensity); + } + } } this._sourceNode.texture = targetTexture; @@ -29326,6 +29603,18 @@ EffectCompositor.prototype.composite = function (renderer, camera, framebuffer, this._compositor.render(renderer, framebuffer); }; +EffectCompositor.prototype.isSSRFinished = function (frame) { + return this._ssrPass ? this._ssrPass.isFinished(frame) : true; +}; + +EffectCompositor.prototype.isSSAOFinished = function (frame) { + return this._ssaoPass ? this._ssaoPass.isFinished(frame) : true; +}; + +EffectCompositor.prototype.isSSREnabled = function () { + return this._enableSSR; +}; + EffectCompositor.prototype.dispose = function (renderer) { this._sourceTexture.dispose(renderer); this._depthTexture.dispose(renderer); @@ -29359,21 +29648,21 @@ function TemporalSuperSampling () { this._outputTex = new Texture2D(); var blendPass = this._blendPass = new Pass({ - fragment: Shader.source('qtek.compositor.blend') + fragment: Shader.source('clay.compositor.blend') }); - blendPass.material.shader.disableTexturesAll(); - blendPass.material.shader.enableTexture(['texture1', 'texture2']); + blendPass.material.disableTexturesAll(); + blendPass.material.enableTexture(['texture1', 'texture2']); this._blendFb = new FrameBuffer({ depthBuffer: false }); this._outputPass = new Pass({ - fragment: Shader.source('qtek.compositor.output'), + fragment: Shader.source('clay.compositor.output'), // TODO, alpha is premultiplied? blendWithPrevious: true }); - this._outputPass.material.shader.define('fragment', 'OUTPUT_ALPHA'); + this._outputPass.material.define('fragment', 'OUTPUT_ALPHA'); this._outputPass.material.blend = function (_gl) { // FIXME. // Output is premultiplied alpha when BLEND is enabled ? @@ -29389,8 +29678,8 @@ TemporalSuperSampling.prototype = { /** * Jitter camera projectionMatrix - * @parma {qtek.Renderer} renderer - * @param {qtek.Camera} camera + * @parma {clay.Renderer} renderer + * @param {clay.Camera} camera */ jitterProjection: function (renderer, camera) { var viewport = renderer.viewport; @@ -29398,14 +29687,14 @@ TemporalSuperSampling.prototype = { var width = viewport.width * dpr; var height = viewport.height * dpr; - var offset = this._haltonSequence[this._frame]; + var offset = this._haltonSequence[this._frame % this._haltonSequence.length]; var translationMat = new Matrix4(); - translationMat._array[12] = (offset[0] * 2.0 - 1.0) / width; - translationMat._array[13] = (offset[1] * 2.0 - 1.0) / height; + translationMat.array[12] = (offset[0] * 2.0 - 1.0) / width; + translationMat.array[13] = (offset[1] * 2.0 - 1.0) / height; Matrix4.mul(camera.projectionMatrix, translationMat, camera.projectionMatrix); - + Matrix4.invert(camera.invProjectionMatrix, camera.projectionMatrix); }, @@ -29498,16 +29787,16 @@ TemporalSuperSampling.prototype = { function RenderMain(renderer, enableShadow, projection) { this.renderer = renderer; - + projection = projection || 'perspective'; /** - * @type {qtek.Scene} + * @type {clay.Scene} */ this.scene = new Scene(); /** - * @type {qtek.Node} + * @type {clay.Node} */ this.rootNode = this.scene; @@ -29623,8 +29912,8 @@ RenderMain.prototype.containPoint = function (x, y) { * Cast a ray * @param {number} x offsetX * @param {number} y offsetY - * @param {qtek.math.Ray} out - * @return {qtek.math.Ray} + * @param {clay.math.Ray} out + * @return {clay.math.Ray} */ var ndc = new Vector2(); RenderMain.prototype.castRay = function (x, y, out) { @@ -29644,10 +29933,25 @@ RenderMain.prototype.castRay = function (x, y, out) { */ RenderMain.prototype.prepareRender = function () { this.scene.update(); + this.scene.updateLights(); + this.scene.updateRenderList(this.camera); + this.camera.update(); this._frame = 0; this._temporalSS.resetFrame(); + + var lights = this.scene.getLights(); + for (var i = 0; i < lights.length; i++) { + if (lights[i].cubemap) { + if (this._compositor && this._compositor.isSSREnabled()) { + lights[i].invisible = true; + } + else { + lights[i].invisible = false; + } + } + } }; RenderMain.prototype.render = function (accumulating) { @@ -29661,7 +29965,7 @@ RenderMain.prototype.needsAccumulate = function () { RenderMain.prototype.needsTemporalSS = function () { var enableTemporalSS = this._enableTemporalSS; - if (enableTemporalSS == 'auto') { + if (enableTemporalSS === 'auto') { enableTemporalSS = this._enablePostEffect; } return enableTemporalSS; @@ -29672,8 +29976,11 @@ RenderMain.prototype.hasDOF = function () { }; RenderMain.prototype.isAccumulateFinished = function () { - return this.needsTemporalSS() ? this._temporalSS.isFinished() - : (this._frame > 30); + var frame = this._frame; + return !(this.needsTemporalSS() && !this._temporalSS.isFinished(frame)) + && !(this._compositor && !this._compositor.isSSAOFinished(frame)) + && !(this._compositor && !this._compositor.isSSRFinished(frame)) + && !(this._compositor && frame < 30); }; RenderMain.prototype._doRender = function (accumulating, accumFrame) { @@ -29700,15 +30007,17 @@ RenderMain.prototype._doRender = function (accumulating, accumFrame) { if (this.needsTemporalSS()) { this._temporalSS.jitterProjection(renderer, camera); } - this._compositor.updateNormal(renderer, scene, camera, this._temporalSS.getFrame()); + this._compositor.updateGBuffer(renderer, scene, camera, this._temporalSS.getFrame()); } // Always update SSAO to make sure have correct ssaoMap status + // TODO TRANSPARENT OBJECTS. this._updateSSAO(renderer, scene, camera, this._temporalSS.getFrame()); + var frameBuffer; if (this._enablePostEffect) { - var frameBuffer = this._compositor.getSourceFrameBuffer(); + frameBuffer = this._compositor.getSourceFrameBuffer(); frameBuffer.bind(renderer); renderer.gl.clear(renderer.gl.DEPTH_BUFFER_BIT | renderer.gl.COLOR_BUFFER_BIT); // FIXME Enable pre z will make alpha test failed @@ -29717,18 +30026,18 @@ RenderMain.prototype._doRender = function (accumulating, accumFrame) { frameBuffer.unbind(renderer); if (this.needsTemporalSS() && accumulating) { - this._compositor.composite(renderer, camera, this._temporalSS.getSourceFrameBuffer(), this._temporalSS.getFrame()); + this._compositor.composite(renderer, scene, camera, this._temporalSS.getSourceFrameBuffer(), this._temporalSS.getFrame()); renderer.setViewport(this.viewport); this._temporalSS.render(renderer); } else { renderer.setViewport(this.viewport); - this._compositor.composite(renderer, camera, null, 0); + this._compositor.composite(renderer, scene, camera, null, 0); } } else { if (this.needsTemporalSS() && accumulating) { - var frameBuffer = this._temporalSS.getSourceFrameBuffer(); + frameBuffer = this._temporalSS.getSourceFrameBuffer(); frameBuffer.bind(renderer); renderer.saveClear(); renderer.clearBit = renderer.gl.DEPTH_BUFFER_BIT | renderer.gl.COLOR_BUFFER_BIT; @@ -29765,14 +30074,14 @@ RenderMain.prototype._updateSSAO = function (renderer, scene, camera, frame) { function updateQueue(queue) { for (var i = 0; i < queue.length; i++) { var renderable = queue[i]; - renderable.material.shader[ifEnableSSAO ? 'enableTexture' : 'disableTexture']('ssaoMap'); + renderable.material[ifEnableSSAO ? 'enableTexture' : 'disableTexture']('ssaoMap'); if (ifEnableSSAO) { renderable.material.set('ssaoMap', compositor.getSSAOTexture()); } } } - updateQueue(scene.opaqueQueue); - updateQueue(scene.transparentQueue); + updateQueue(scene.getRenderList(camera).opaque); + updateQueue(scene.getRenderList(camera).transparent); }; RenderMain.prototype._updateShadowPCFKernel = function (frame) { @@ -29781,21 +30090,21 @@ RenderMain.prototype._updateShadowPCFKernel = function (frame) { for (var i = 0; i < queue.length; i++) { if (queue[i].receiveShadow) { queue[i].material.set('pcfKernel', pcfKernel); - if (queue[i].material.shader) { - queue[i].material.shader.define('fragment', 'PCF_KERNEL_SIZE', pcfKernel.length / 2); + if (queue[i].material) { + queue[i].material.define('fragment', 'PCF_KERNEL_SIZE', pcfKernel.length / 2); } } } } - updateQueue(this.scene.opaqueQueue); - updateQueue(this.scene.transparentQueue); + updateQueue(this.scene.getRenderList(this.camera).opaque); + updateQueue(this.scene.getRenderList(this.camera).transparent); }; RenderMain.prototype.dispose = function (renderer) { this._compositor.dispose(renderer); this._temporalSS.dispose(renderer); if (this._shadowMapPass) { - this._shadowMapPass.dispose(renderer); + this._shadowMapPass.dispose(renderer); } }; @@ -29830,7 +30139,7 @@ RenderMain.prototype.setPostEffect = function (opts, api) { ['radius', 'quality', 'intensity'].forEach(function (name) { compositor.setSSAOParameter(name, ssaoOpts[name]); }); - ['quality', 'maxRoughness'].forEach(function (name) { + ['quality', 'maxRoughness', 'physical'].forEach(function (name) { compositor.setSSRParameter(name, ssrOpts[name]); }); ['quality', 'focalDistance', 'focalRange', 'blurRadius', 'fstop'].forEach(function (name) { @@ -29892,8 +30201,76 @@ RenderMain.prototype.removeAll = function (node3D) { }; /** - * @constructor qtek.light.Ambient - * @extends qtek.Light + * @constructor clay.light.Directional + * @extends clay.Light + * + * @example + * var light = new clay.light.Directional({ + * intensity: 0.5, + * color: [1.0, 0.0, 0.0] + * }); + * light.position.set(10, 10, 10); + * light.lookAt(clay.Vector3.ZERO); + * scene.add(light); + */ +var DirectionalLight = Light.extend(/** @lends clay.light.Directional# */ { + /** + * @type {number} + */ + shadowBias: 0.001, + /** + * @type {number} + */ + shadowSlopeScale: 2.0, + /** + * Shadow cascade. + * Use PSSM technique when it is larger than 1 and have a unique directional light in scene. + * @type {number} + */ + shadowCascade: 1, + + /** + * Available when shadowCascade is larger than 1 and have a unique directional light in scene. + * @type {number} + */ + cascadeSplitLogFactor: 0.2 +}, { + + type: 'DIRECTIONAL_LIGHT', + + uniformTemplates: { + directionalLightDirection: { + type: '3f', + value: function (instance) { + instance.__dir = instance.__dir || new Vector3(); + // Direction is target to eye + return instance.__dir.copy(instance.worldTransform.z).normalize().negate().array; + } + }, + directionalLightColor: { + type: '3f', + value: function (instance) { + var color = instance.color; + var intensity = instance.intensity; + return [color[0] * intensity, color[1] * intensity, color[2] * intensity]; + } + } + }, + /** + * @return {clay.light.Directional} + * @memberOf clay.light.Directional.prototype + */ + clone: function () { + var light = Light.prototype.clone.call(this); + light.shadowBias = this.shadowBias; + light.shadowSlopeScale = this.shadowSlopeScale; + return light; + } +}); + +/** + * @constructor clay.light.Ambient + * @extends clay.Light */ var AmbientLight = Light.extend({ @@ -29914,10 +30291,10 @@ var AmbientLight = Light.extend({ } } /** - * @method + * @function * @name clone - * @return {qtek.light.Ambient} - * @memberOf qtek.light.Ambient.prototype + * @return {clay.light.Ambient} + * @memberOf clay.light.Ambient.prototype */ }); @@ -29940,26 +30317,26 @@ SceneHelper.prototype = { initLight: function (rootNode) { this._lightRoot = rootNode; /** - * @type {qtek.light.Directional} + * @type {clay.light.Directional} */ this.mainLight = new DirectionalLight({ shadowBias: 0.005 }); /** - * @type {qtek.light.Directional} + * @type {clay.light.Directional} */ this.secondaryLight = new DirectionalLight({ shadowBias: 0.005 }); /** - * @type {qtek.light.Directional} + * @type {clay.light.Directional} */ this.tertiaryLight = new DirectionalLight({ shadowBias: 0.005 }); /** - * @type {qtek.light.Ambient} + * @type {clay.light.Ambient} */ this.ambientLight = new AmbientLight(); }, @@ -29967,6 +30344,8 @@ SceneHelper.prototype = { dispose: function (renderer) { if (this._lightRoot) { this._lightRoot.remove(this.mainLight); + this._lightRoot.remove(this.secondaryLight); + this._lightRoot.remove(this.tertiaryLight); this._lightRoot.remove(this.ambientLight); } if (this._currentCubemapLights) { @@ -30057,7 +30436,7 @@ SceneHelper.prototype = { if (lights.specular) { this._lightRoot.add(lights.specular); } - + this._currentCubemapLights = lights; this._currentCubemapLights.textureUrl = textureUrl; } @@ -30068,7 +30447,7 @@ SceneHelper.prototype = { } } } - + if (this._currentCubemapLights) { if (opts.specularIntensity != null && this._currentCubemapLights.specular) { this._currentCubemapLights.specular.intensity = opts.specularIntensity; @@ -30077,12 +30456,12 @@ SceneHelper.prototype = { this._currentCubemapLights.diffuse.intensity = opts.diffuseIntensity; } } - }, updateSkybox: function (environmentUrl, isLinearSpace, app) { var renderer = app.getRenderer(); var self = this; + function getSkybox() { if (!(self._skybox instanceof Skybox)) { if (self._skybox) { @@ -30145,10 +30524,10 @@ SceneHelper.prototype = { && !(environmentUrl.match && environmentUrl.match(/.hdr$/)) ) { var srgbDefineMethod = isLinearSpace ? 'define' : 'undefine'; - this._skybox.material.shader[srgbDefineMethod]('fragment', 'SRGB_DECODE'); + this._skybox.material[srgbDefineMethod]('fragment', 'SRGB_DECODE'); } else { - this._skybox.material.shader.undefine('fragment', 'SRGB_DECODE'); + this._skybox.material.undefine('fragment', 'SRGB_DECODE'); } } } @@ -30169,9 +30548,11 @@ var defaultSceneConfig = { // Configuration abount ground ground: { - show: false + show: false, + + grid: false }, - + // QMV provide three directional lights and two ambient lights. // Configuration of main light @@ -30192,7 +30573,7 @@ var defaultSceneConfig = { // Configuration of secondary light secondaryLight: { // If enable shadow of secondary light. - shadow: false, + shadow: true, shadowQuality: 'medium', // Intensity of secondary light. Defaultly not enable secondary light. intensity: 0, @@ -30204,7 +30585,7 @@ var defaultSceneConfig = { // Configuration of tertiary light tertiaryLight: { // If enable shadow of tertiary light. - shadow: false, + shadow: true, shadowQuality: 'medium', // Intensity of secondary light. Defaultly not enable secondary light. intensity: 0, @@ -30260,6 +30641,8 @@ var defaultSceneConfig = { screenSpaceAmbientOcculusion: { // If enable SSAO enable: false, + // If physically corrected. + physical: false, // Sampling radius in work space. // Larger will produce more soft concat shadow. // But also needs higher quality or it will have more obvious artifacts @@ -30654,7 +31037,7 @@ function isPrimitive(obj) { return obj[primitiveKey]; } -var vec3$17 = glmatrix.vec3; +var vec3$15 = glmatrix.vec3; function getBoundingBoxOfSkinningMesh(mesh, out) { var pos = []; @@ -30672,7 +31055,7 @@ function getBoundingBoxOfSkinningMesh(mesh, out) { skinMatrices[i][k] = skinMatricesArray[i * 16 + k]; } } - + var positionAttr = geometry.attributes.position; var weightAttr = geometry.attributes.weight; var jointAttr = geometry.attributes.joint; @@ -30686,16 +31069,16 @@ function getBoundingBoxOfSkinningMesh(mesh, out) { jointAttr.get(i, joint); weight[3] = 1 - weight[0] - weight[1] - weight[2]; - vec3$17.set(skinnedPos, 0, 0, 0); + vec3$15.set(skinnedPos, 0, 0, 0); for (var k = 0; k < 4; k++) { if (joint[k] >= 0 && weight[k] > 1e-6) { - vec3$17.transformMat4(tmp, pos, skinMatrices[joint[k]]); - vec3$17.scaleAndAdd(skinnedPos, skinnedPos, tmp, weight[k]); - } + vec3$15.transformMat4(tmp, pos, skinMatrices[joint[k]]); + vec3$15.scaleAndAdd(skinnedPos, skinnedPos, tmp, weight[k]); + } } - vec3$17.min(min, min, skinnedPos); - vec3$17.max(max, max, skinnedPos); + vec3$15.min(min, min, skinnedPos); + vec3$15.max(max, max, skinnedPos); } out.min.setArray(min); out.max.setArray(max); @@ -30722,15 +31105,8 @@ function getBoundingBoxWithSkinning(node, out) { return out; } -/** - * Only implements needed gestures for mobile. - */ var GestureMgr = function () { - /** - * @private - * @type {Array.} - */ this._track = []; }; @@ -30840,25 +31216,26 @@ function convertToArray(val) { } /** - * @alias module:echarts-x/util/OrbitControl + * @constructor + * @alias clay.plugin.OrbitControl */ var OrbitControl = Base.extend(function () { - return { + return /** @lends clay.plugin.OrbitControl# */ { - animation: null, + timeline: null, /** - * @type {HTMLDomElement} + * @type {HTMLElement} */ domElement: null, /** - * @type {qtek.Node} + * @type {clay.Node} */ target: null, /** - * @type {qtek.math.Vector3} + * @type {clay.Vector3} */ _center: new Vector3(), @@ -30973,7 +31350,7 @@ var OrbitControl = Base.extend(function () { this.update = this.update.bind(this); this.init(); -}, { +}, /** @lends clay.plugin.OrbitControl# */ { /** * Initialize. * Mouse event binding @@ -30986,8 +31363,8 @@ var OrbitControl = Base.extend(function () { dom.addEventListener('mousedown', this._mouseDownHandler); dom.addEventListener('mousewheel', this._mouseWheelHandler); - if (this.animation) { - this.animation.on('frame', this.update); + if (this.timeline) { + this.timeline.on('frame', this.update); } }, @@ -31006,9 +31383,10 @@ var OrbitControl = Base.extend(function () { dom.removeEventListener('mousemove', this._mouseMoveHandler); dom.removeEventListener('mouseup', this._mouseUpHandler); dom.removeEventListener('mousewheel', this._mouseWheelHandler); + dom.removeEventListener('mouseout', this._mouseUpHandler); - if (this.animation) { - this.animation.off('frame', this.update); + if (this.timeline) { + this.timeline.off('frame', this.update); } this.stopAllAnimation(); }, @@ -31124,6 +31502,7 @@ var OrbitControl = Base.extend(function () { * @param {number} opts.distance * @param {number} opts.alpha * @param {number} opts.beta + * @param {Array.} opts.center * @param {number} [opts.duration=1000] * @param {number} [opts.easing='linear'] * @param {number} [opts.done] @@ -31133,8 +31512,8 @@ var OrbitControl = Base.extend(function () { var obj = {}; var target = {}; - var animation = this.animation; - if (!animation) { + var timeline = this.timeline; + if (!timeline) { return; } if (opts.distance != null) { @@ -31155,7 +31534,7 @@ var OrbitControl = Base.extend(function () { } return this._addAnimator( - animation.animate(obj) + timeline.animate(obj) .when(opts.duration || 1000, target) .during(function () { if (obj.alpha != null) { @@ -31177,7 +31556,7 @@ var OrbitControl = Base.extend(function () { }, /** - * Stop all animation + * Stop all animations */ stopAllAnimation: function () { for (var i = 0; i < this._animators.length; i++) { @@ -31239,6 +31618,8 @@ var OrbitControl = Base.extend(function () { this.setBeta(this.getBeta()); this._vectorDamping(velocity, this.damping); + + velocity.x = velocity.y = 0; }, _updateDistance: function (deltaTime) { @@ -31264,6 +31645,8 @@ var OrbitControl = Base.extend(function () { .scaleAndAdd(yAxis, -velocity.y * len / 200); this._vectorDamping(velocity, 0); + + velocity.x = velocity.y = 0; }, _updateTransform: function () { @@ -31306,11 +31689,6 @@ var OrbitControl = Base.extend(function () { v.normalize().scale(speed); }, - // TODO Following code will cause decompose problem. - // camera.position.y = 2; - // camera.position.z = -4; - // camera.lookAt(scene.position); - // decomposeTransform: function () { if (!this.target) { return; @@ -31318,13 +31696,21 @@ var OrbitControl = Base.extend(function () { // FIXME euler order...... // FIXME alpha is not certain when beta is 90 or -90 - var euler = new Vector3(); - euler.eulerFromQuat( - this.target.rotation.normalize(), 'ZYX' - ); - - this._theta = -euler.x; - this._phi = -euler.y; + // var euler = new Vector3(); + // euler.eulerFromMat3( + // new Matrix3().fromQuat(this.target.rotation), 'ZYX' + // ); + // euler.eulerFromQuat( + // this.target.rotation.normalize(), 'ZYX' + // ); + this.target.updateWorldTransform(); + + var forward = this.target.worldTransform.z; + var alpha = Math.asin(forward.y); + var beta = Math.atan2(forward.x, forward.z); + + this._theta = alpha; + this._phi = -beta; this.setBeta(this.getBeta()); this.setAlpha(this.getAlpha()); @@ -31355,6 +31741,7 @@ var OrbitControl = Base.extend(function () { dom.addEventListener('mousemove', this._mouseMoveHandler); dom.addEventListener('mouseup', this._mouseUpHandler); + dom.addEventListener('mouseout', this._mouseUpHandler); if (e.button === 0) { this._mode = 'rotate'; @@ -31362,6 +31749,9 @@ var OrbitControl = Base.extend(function () { else if (e.button === 1) { this._mode = 'pan'; } + else { + this._mode = null; + } // Reset rotate velocity this._rotateVelocity.set(0, 0); @@ -31396,12 +31786,12 @@ var OrbitControl = Base.extend(function () { if (!haveGesture) { if (this._mode === 'rotate') { - this._rotateVelocity.y = (x - this._mouseX) / this.domElement.clientHeight * 2 * rotateSensitivity[0]; - this._rotateVelocity.x = (y - this._mouseY) / this.domElement.clientWidth * 2 * rotateSensitivity[1]; + this._rotateVelocity.y += (x - this._mouseX) / this.domElement.clientWidth * 2 * rotateSensitivity[0]; + this._rotateVelocity.x += (y - this._mouseY) / this.domElement.clientHeight * 2 * rotateSensitivity[1]; } else if (this._mode === 'pan') { - this._panVelocity.x = (x - this._mouseX) / this.domElement.clientWidth * panSensitivity[0] * 400; - this._panVelocity.y = (-y + this._mouseY) / this.domElement.clientHeight * panSensitivity[1] * 400; + this._panVelocity.x += (x - this._mouseX) / this.domElement.clientWidth * panSensitivity[0] * 400; + this._panVelocity.y += (-y + this._mouseY) / this.domElement.clientHeight * panSensitivity[1] * 400; } } @@ -31453,6 +31843,7 @@ var OrbitControl = Base.extend(function () { dom.removeEventListener('touchend', this._mouseUpHandler); dom.removeEventListener('mousemove', this._mouseMoveHandler); dom.removeEventListener('mouseup', this._mouseUpHandler); + dom.removeEventListener('mouseout', this._mouseUpHandler); this._processGesture(event, 'end'); }, @@ -31527,7 +31918,7 @@ var vec4$2 = glmatrix.vec4; /** * @constructor - * @alias qtek.math.Vector4 + * @alias clay.Vector4 * @param {number} x * @param {number} y * @param {number} z @@ -31541,18 +31932,20 @@ var Vector4 = function(x, y, z, w) { w = w || 0; /** - * Storage of Vector4, read and write of x, y, z, w will change the values in _array - * All methods also operate on the _array instead of x, y, z, w components - * @name _array + * Storage of Vector4, read and write of x, y, z, w will change the values in array + * All methods also operate on the array instead of x, y, z, w components + * @name array * @type {Float32Array} + * @memberOf clay.Vector4# */ - this._array = vec4$2.fromValues(x, y, z, w); + this.array = vec4$2.fromValues(x, y, z, w); /** * Dirty flag is used by the Node to determine * if the matrix is updated to latest * @name _dirty * @type {boolean} + * @memberOf clay.Vector4# */ this._dirty = true; }; @@ -31563,11 +31956,11 @@ Vector4.prototype = { /** * Add b to self - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} b + * @return {clay.Vector4} */ add: function(b) { - vec4$2.add(this._array, this._array, b._array); + vec4$2.add(this.array, this.array, b.array); this._dirty = true; return this; }, @@ -31578,13 +31971,13 @@ Vector4.prototype = { * @param {number} y * @param {number} z * @param {number} w - * @return {qtek.math.Vector4} + * @return {clay.Vector4} */ set: function(x, y, z, w) { - this._array[0] = x; - this._array[1] = y; - this._array[2] = z; - this._array[3] = w; + this.array[0] = x; + this.array[1] = y; + this.array[2] = z; + this.array[3] = w; this._dirty = true; return this; }, @@ -31592,13 +31985,13 @@ Vector4.prototype = { /** * Set x, y, z and w components from array * @param {Float32Array|number[]} arr - * @return {qtek.math.Vector4} + * @return {clay.Vector4} */ setArray: function(arr) { - this._array[0] = arr[0]; - this._array[1] = arr[1]; - this._array[2] = arr[2]; - this._array[3] = arr[3]; + this.array[0] = arr[0]; + this.array[1] = arr[1]; + this.array[2] = arr[2]; + this.array[3] = arr[3]; this._dirty = true; return this; @@ -31606,7 +31999,7 @@ Vector4.prototype = { /** * Clone a new Vector4 - * @return {qtek.math.Vector4} + * @return {clay.Vector4} */ clone: function() { return new Vector4(this.x, this.y, this.z, this.w); @@ -31614,62 +32007,62 @@ Vector4.prototype = { /** * Copy from b - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} b + * @return {clay.Vector4} */ copy: function(b) { - vec4$2.copy(this._array, b._array); + vec4$2.copy(this.array, b.array); this._dirty = true; return this; }, /** * Alias for distance - * @param {qtek.math.Vector4} b + * @param {clay.Vector4} b * @return {number} */ dist: function(b) { - return vec4$2.dist(this._array, b._array); + return vec4$2.dist(this.array, b.array); }, /** * Distance between self and b - * @param {qtek.math.Vector4} b + * @param {clay.Vector4} b * @return {number} */ distance: function(b) { - return vec4$2.distance(this._array, b._array); + return vec4$2.distance(this.array, b.array); }, /** * Alias for divide - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} b + * @return {clay.Vector4} */ div: function(b) { - vec4$2.div(this._array, this._array, b._array); + vec4$2.div(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Divide self by b - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} b + * @return {clay.Vector4} */ divide: function(b) { - vec4$2.divide(this._array, this._array, b._array); + vec4$2.divide(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Dot product of self and b - * @param {qtek.math.Vector4} b + * @param {clay.Vector4} b * @return {number} */ dot: function(b) { - return vec4$2.dot(this._array, b._array); + return vec4$2.dot(this.array, b.array); }, /** @@ -31677,7 +32070,7 @@ Vector4.prototype = { * @return {number} */ len: function() { - return vec4$2.len(this._array); + return vec4$2.len(this.array); }, /** @@ -31685,81 +32078,81 @@ Vector4.prototype = { * @return {number} */ length: function() { - return vec4$2.length(this._array); + return vec4$2.length(this.array); }, /** * Linear interpolation between a and b - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b + * @param {clay.Vector4} a + * @param {clay.Vector4} b * @param {number} t - * @return {qtek.math.Vector4} + * @return {clay.Vector4} */ lerp: function(a, b, t) { - vec4$2.lerp(this._array, a._array, b._array, t); + vec4$2.lerp(this.array, a.array, b.array, t); this._dirty = true; return this; }, /** * Minimum of self and b - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} b + * @return {clay.Vector4} */ min: function(b) { - vec4$2.min(this._array, this._array, b._array); + vec4$2.min(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Maximum of self and b - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} b + * @return {clay.Vector4} */ max: function(b) { - vec4$2.max(this._array, this._array, b._array); + vec4$2.max(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Alias for multiply - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} b + * @return {clay.Vector4} */ mul: function(b) { - vec4$2.mul(this._array, this._array, b._array); + vec4$2.mul(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Mutiply self and b - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} b + * @return {clay.Vector4} */ multiply: function(b) { - vec4$2.multiply(this._array, this._array, b._array); + vec4$2.multiply(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Negate self - * @return {qtek.math.Vector4} + * @return {clay.Vector4} */ negate: function() { - vec4$2.negate(this._array, this._array); + vec4$2.negate(this.array, this.array); this._dirty = true; return this; }, /** * Normalize self - * @return {qtek.math.Vector4} + * @return {clay.Vector4} */ normalize: function() { - vec4$2.normalize(this._array, this._array); + vec4$2.normalize(this.array, this.array); this._dirty = true; return this; }, @@ -31767,10 +32160,10 @@ Vector4.prototype = { /** * Generate random x, y, z, w components with a given scale * @param {number} scale - * @return {qtek.math.Vector4} + * @return {clay.Vector4} */ random: function(scale) { - vec4$2.random(this._array, scale); + vec4$2.random(this.array, scale); this._dirty = true; return this; }, @@ -31778,41 +32171,41 @@ Vector4.prototype = { /** * Scale self * @param {number} scale - * @return {qtek.math.Vector4} + * @return {clay.Vector4} */ scale: function(s) { - vec4$2.scale(this._array, this._array, s); + vec4$2.scale(this.array, this.array, s); this._dirty = true; return this; }, /** * Scale b and add to self - * @param {qtek.math.Vector4} b + * @param {clay.Vector4} b * @param {number} scale - * @return {qtek.math.Vector4} + * @return {clay.Vector4} */ scaleAndAdd: function(b, s) { - vec4$2.scaleAndAdd(this._array, this._array, b._array, s); + vec4$2.scaleAndAdd(this.array, this.array, b.array, s); this._dirty = true; return this; }, /** * Alias for squaredDistance - * @param {qtek.math.Vector4} b + * @param {clay.Vector4} b * @return {number} */ sqrDist: function(b) { - return vec4$2.sqrDist(this._array, b._array); + return vec4$2.sqrDist(this.array, b.array); }, /** * Squared distance between self and b - * @param {qtek.math.Vector4} b + * @param {clay.Vector4} b * @return {number} */ squaredDistance: function(b) { - return vec4$2.squaredDistance(this._array, b._array); + return vec4$2.squaredDistance(this.array, b.array); }, /** @@ -31820,7 +32213,7 @@ Vector4.prototype = { * @return {number} */ sqrLen: function() { - return vec4$2.sqrLen(this._array); + return vec4$2.sqrLen(this.array); }, /** @@ -31828,59 +32221,59 @@ Vector4.prototype = { * @return {number} */ squaredLength: function() { - return vec4$2.squaredLength(this._array); + return vec4$2.squaredLength(this.array); }, /** * Alias for subtract - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} b + * @return {clay.Vector4} */ sub: function(b) { - vec4$2.sub(this._array, this._array, b._array); + vec4$2.sub(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Subtract b from self - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} b + * @return {clay.Vector4} */ subtract: function(b) { - vec4$2.subtract(this._array, this._array, b._array); + vec4$2.subtract(this.array, this.array, b.array); this._dirty = true; return this; }, /** * Transform self with a Matrix4 m - * @param {qtek.math.Matrix4} m - * @return {qtek.math.Vector4} + * @param {clay.Matrix4} m + * @return {clay.Vector4} */ transformMat4: function(m) { - vec4$2.transformMat4(this._array, this._array, m._array); + vec4$2.transformMat4(this.array, this.array, m.array); this._dirty = true; return this; }, /** * Transform self with a Quaternion q - * @param {qtek.math.Quaternion} q - * @return {qtek.math.Vector4} + * @param {clay.Quaternion} q + * @return {clay.Vector4} */ transformQuat: function(q) { - vec4$2.transformQuat(this._array, this._array, q._array); + vec4$2.transformQuat(this.array, this.array, q.array); this._dirty = true; return this; }, toString: function() { - return '[' + Array.prototype.join.call(this._array, ',') + ']'; + return '[' + Array.prototype.join.call(this.array, ',') + ']'; }, toArray: function () { - return Array.prototype.slice.call(this._array); + return Array.prototype.slice.call(this.array); } }; @@ -31892,15 +32285,15 @@ if (defineProperty$3) { /** * @name x * @type {number} - * @memberOf qtek.math.Vector4 + * @memberOf clay.Vector4 * @instance */ defineProperty$3(proto$4, 'x', { get: function () { - return this._array[0]; + return this.array[0]; }, set: function (value) { - this._array[0] = value; + this.array[0] = value; this._dirty = true; } }); @@ -31908,15 +32301,15 @@ if (defineProperty$3) { /** * @name y * @type {number} - * @memberOf qtek.math.Vector4 + * @memberOf clay.Vector4 * @instance */ defineProperty$3(proto$4, 'y', { get: function () { - return this._array[1]; + return this.array[1]; }, set: function (value) { - this._array[1] = value; + this.array[1] = value; this._dirty = true; } }); @@ -31924,15 +32317,15 @@ if (defineProperty$3) { /** * @name z * @type {number} - * @memberOf qtek.math.Vector4 + * @memberOf clay.Vector4 * @instance */ defineProperty$3(proto$4, 'z', { get: function () { - return this._array[2]; + return this.array[2]; }, set: function (value) { - this._array[2] = value; + this.array[2] = value; this._dirty = true; } }); @@ -31940,15 +32333,15 @@ if (defineProperty$3) { /** * @name w * @type {number} - * @memberOf qtek.math.Vector4 + * @memberOf clay.Vector4 * @instance */ defineProperty$3(proto$4, 'w', { get: function () { - return this._array[3]; + return this.array[3]; }, set: function (value) { - this._array[3] = value; + this.array[3] = value; this._dirty = true; } }); @@ -31957,284 +32350,284 @@ if (defineProperty$3) { // Supply methods that are not in place /** - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @param {clay.Vector4} b + * @return {clay.Vector4} */ Vector4.add = function(out, a, b) { - vec4$2.add(out._array, a._array, b._array); + vec4$2.add(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector4} out + * @param {clay.Vector4} out * @param {number} x * @param {number} y * @param {number} z - * @return {qtek.math.Vector4} + * @return {clay.Vector4} */ Vector4.set = function(out, x, y, z, w) { - vec4$2.set(out._array, x, y, z, w); + vec4$2.set(out.array, x, y, z, w); out._dirty = true; }; /** - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} out + * @param {clay.Vector4} b + * @return {clay.Vector4} */ Vector4.copy = function(out, b) { - vec4$2.copy(out._array, b._array); + vec4$2.copy(out.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b + * @param {clay.Vector4} a + * @param {clay.Vector4} b * @return {number} */ Vector4.dist = function(a, b) { - return vec4$2.distance(a._array, b._array); + return vec4$2.distance(a.array, b.array); }; /** - * @method - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b + * @function + * @param {clay.Vector4} a + * @param {clay.Vector4} b * @return {number} */ Vector4.distance = Vector4.dist; /** - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @param {clay.Vector4} b + * @return {clay.Vector4} */ Vector4.div = function(out, a, b) { - vec4$2.divide(out._array, a._array, b._array); + vec4$2.divide(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @method - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @function + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @param {clay.Vector4} b + * @return {clay.Vector4} */ Vector4.divide = Vector4.div; /** - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b + * @param {clay.Vector4} a + * @param {clay.Vector4} b * @return {number} */ Vector4.dot = function(a, b) { - return vec4$2.dot(a._array, b._array); + return vec4$2.dot(a.array, b.array); }; /** - * @param {qtek.math.Vector4} a + * @param {clay.Vector4} a * @return {number} */ Vector4.len = function(b) { - return vec4$2.length(b._array); + return vec4$2.length(b.array); }; // Vector4.length = Vector4.len; /** - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @param {clay.Vector4} b * @param {number} t - * @return {qtek.math.Vector4} + * @return {clay.Vector4} */ Vector4.lerp = function(out, a, b, t) { - vec4$2.lerp(out._array, a._array, b._array, t); + vec4$2.lerp(out.array, a.array, b.array, t); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @param {clay.Vector4} b + * @return {clay.Vector4} */ Vector4.min = function(out, a, b) { - vec4$2.min(out._array, a._array, b._array); + vec4$2.min(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @param {clay.Vector4} b + * @return {clay.Vector4} */ Vector4.max = function(out, a, b) { - vec4$2.max(out._array, a._array, b._array); + vec4$2.max(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @param {clay.Vector4} b + * @return {clay.Vector4} */ Vector4.mul = function(out, a, b) { - vec4$2.multiply(out._array, a._array, b._array); + vec4$2.multiply(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @method - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @function + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @param {clay.Vector4} b + * @return {clay.Vector4} */ Vector4.multiply = Vector4.mul; /** - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @return {qtek.math.Vector4} + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @return {clay.Vector4} */ Vector4.negate = function(out, a) { - vec4$2.negate(out._array, a._array); + vec4$2.negate(out.array, a.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @return {qtek.math.Vector4} + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @return {clay.Vector4} */ Vector4.normalize = function(out, a) { - vec4$2.normalize(out._array, a._array); + vec4$2.normalize(out.array, a.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector4} out + * @param {clay.Vector4} out * @param {number} scale - * @return {qtek.math.Vector4} + * @return {clay.Vector4} */ Vector4.random = function(out, scale) { - vec4$2.random(out._array, scale); + vec4$2.random(out.array, scale); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a + * @param {clay.Vector4} out + * @param {clay.Vector4} a * @param {number} scale - * @return {qtek.math.Vector4} + * @return {clay.Vector4} */ Vector4.scale = function(out, a, scale) { - vec4$2.scale(out._array, a._array, scale); + vec4$2.scale(out.array, a.array, scale); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @param {clay.Vector4} b * @param {number} scale - * @return {qtek.math.Vector4} + * @return {clay.Vector4} */ Vector4.scaleAndAdd = function(out, a, b, scale) { - vec4$2.scaleAndAdd(out._array, a._array, b._array, scale); + vec4$2.scaleAndAdd(out.array, a.array, b.array, scale); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b + * @param {clay.Vector4} a + * @param {clay.Vector4} b * @return {number} */ Vector4.sqrDist = function(a, b) { - return vec4$2.sqrDist(a._array, b._array); + return vec4$2.sqrDist(a.array, b.array); }; /** - * @method - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b + * @function + * @param {clay.Vector4} a + * @param {clay.Vector4} b * @return {number} */ Vector4.squaredDistance = Vector4.sqrDist; /** - * @param {qtek.math.Vector4} a + * @param {clay.Vector4} a * @return {number} */ Vector4.sqrLen = function(a) { - return vec4$2.sqrLen(a._array); + return vec4$2.sqrLen(a.array); }; /** - * @method - * @param {qtek.math.Vector4} a + * @function + * @param {clay.Vector4} a * @return {number} */ Vector4.squaredLength = Vector4.sqrLen; /** - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @param {clay.Vector4} b + * @return {clay.Vector4} */ Vector4.sub = function(out, a, b) { - vec4$2.subtract(out._array, a._array, b._array); + vec4$2.subtract(out.array, a.array, b.array); out._dirty = true; return out; }; /** - * @method - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @param {qtek.math.Vector4} b - * @return {qtek.math.Vector4} + * @function + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @param {clay.Vector4} b + * @return {clay.Vector4} */ Vector4.subtract = Vector4.sub; /** - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @param {qtek.math.Matrix4} m - * @return {qtek.math.Vector4} + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @param {clay.Matrix4} m + * @return {clay.Vector4} */ Vector4.transformMat4 = function(out, a, m) { - vec4$2.transformMat4(out._array, a._array, m._array); + vec4$2.transformMat4(out.array, a.array, m.array); out._dirty = true; return out; }; /** - * @param {qtek.math.Vector4} out - * @param {qtek.math.Vector4} a - * @param {qtek.math.Quaternion} q - * @return {qtek.math.Vector4} + * @param {clay.Vector4} out + * @param {clay.Vector4} a + * @param {clay.Quaternion} q + * @return {clay.Vector4} */ Vector4.transformQuat = function(out, a, q) { - vec4$2.transformQuat(out._array, a._array, q._array); + vec4$2.transformQuat(out.array, a.array, q.array); out._dirty = true; return out; }; @@ -32252,12 +32645,12 @@ var HotspotManger = Base.extend(function () { dom: null, /** - * @type {qtek.Renderer} + * @type {clay.Renderer} */ renderer: null, /** - * @type {qtek.camera.Perspective} + * @type {clay.camera.Perspective} */ camera: null, @@ -32355,7 +32748,7 @@ var HotspotManger = Base.extend(function () { } }); -var groundGLSLCode = "@export qmv.ground.vertex\n@import qtek.lambert.vertex\n@end\n\n\n@export qmv.ground.fragment\n\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\nuniform float gridSize: 5;\nuniform float gridSize2: 1;\nuniform vec4 gridColor: [0, 0, 0, 1];\nuniform vec4 gridColor2: [0.3, 0.3, 0.3, 1];\n\nuniform float glossiness: 0.7;\n\n#ifdef SSAOMAP_ENABLED\nuniform sampler2D ssaoMap;\nuniform vec4 viewport : VIEWPORT;\n#endif\n\n#ifdef AMBIENT_LIGHT_COUNT\n@import qtek.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import qtek.header.ambient_sh_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import qtek.header.directional_light\n#endif\n\n@import qtek.plugin.compute_shadow_map\n\nvoid main()\n{\n gl_FragColor = color;\n\n float wx = v_WorldPosition.x;\n float wz = v_WorldPosition.z;\n float x0 = abs(fract(wx / gridSize - 0.5) - 0.5) / fwidth(wx) * gridSize / 2.0;\n float z0 = abs(fract(wz / gridSize - 0.5) - 0.5) / fwidth(wz) * gridSize / 2.0;\n\n float x1 = abs(fract(wx / gridSize2 - 0.5) - 0.5) / fwidth(wx) * gridSize2;\n float z1 = abs(fract(wz / gridSize2 - 0.5) - 0.5) / fwidth(wz) * gridSize2;\n\n float v0 = 1.0 - clamp(min(x0, z0), 0.0, 1.0);\n float v1 = 1.0 - clamp(min(x1, z1), 0.0, 1.0);\n if (v0 > 0.1) {\n gl_FragColor = mix(gl_FragColor, gridColor, v0);\n }\n else {\n gl_FragColor = mix(gl_FragColor, gridColor2, v1);\n }\n\n vec3 diffuseColor = vec3(0.0, 0.0, 0.0);\n\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {\n diffuseColor += ambientLightColor[_idx_];\n }\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseColor += calcAmbientSHLight(_idx_, v_Normal) * ambientSHLightColor[_idx_];\n }}\n#endif\n\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++)\n {\n vec3 lightDirection = -directionalLightDirection[i];\n vec3 lightColor = directionalLightColor[i];\n\n float ndl = dot(v_Normal, normalize(lightDirection));\n\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsDir[i];\n }\n#endif\n\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * shadowContrib;\n }\n#endif\n\n#ifdef SSAOMAP_ENABLED\n diffuseColor *= texture2D(ssaoMap, (gl_FragCoord.xy - viewport.xy) / viewport.zw).r;\n#endif\n\n gl_FragColor.rgb *= diffuseColor;\n\n gl_FragColor.a *= 1.0 - clamp(length(v_WorldPosition.xz) / 30.0, 0.0, 1.0);\n\n}\n\n@end"; +var groundGLSLCode = "@export qmv.ground.vertex\n@import clay.lambert.vertex\n@end\n\n\n@export qmv.ground.fragment\n\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\nuniform float gridSize: 5;\nuniform float gridSize2: 1;\nuniform vec4 gridColor: [0, 0, 0, 1];\nuniform vec4 gridColor2: [0.3, 0.3, 0.3, 1];\n\nuniform bool showGrid: true;\n\nuniform float glossiness: 0.7;\n\n#ifdef SSAOMAP_ENABLED\nuniform sampler2D ssaoMap;\nuniform vec4 viewport : VIEWPORT;\n#endif\n\n#ifdef AMBIENT_LIGHT_COUNT\n@import clay.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import clay.header.ambient_sh_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n\n@import clay.plugin.compute_shadow_map\n\nvoid main()\n{\n gl_FragColor = color;\n\n if (showGrid) {\n float wx = v_WorldPosition.x;\n float wz = v_WorldPosition.z;\n float x0 = abs(fract(wx / gridSize - 0.5) - 0.5) / fwidth(wx) * gridSize / 2.0;\n float z0 = abs(fract(wz / gridSize - 0.5) - 0.5) / fwidth(wz) * gridSize / 2.0;\n\n float x1 = abs(fract(wx / gridSize2 - 0.5) - 0.5) / fwidth(wx) * gridSize2;\n float z1 = abs(fract(wz / gridSize2 - 0.5) - 0.5) / fwidth(wz) * gridSize2;\n\n float v0 = 1.0 - clamp(min(x0, z0), 0.0, 1.0);\n float v1 = 1.0 - clamp(min(x1, z1), 0.0, 1.0);\n if (v0 > 0.1) {\n gl_FragColor = mix(gl_FragColor, gridColor, v0);\n }\n else {\n gl_FragColor = mix(gl_FragColor, gridColor2, v1);\n }\n }\n\n vec3 diffuseColor = vec3(0.0, 0.0, 0.0);\n\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {\n diffuseColor += ambientLightColor[_idx_];\n }\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseColor += calcAmbientSHLight(_idx_, v_Normal) * ambientSHLightColor[_idx_];\n }}\n#endif\n\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++)\n {\n vec3 lightDirection = -directionalLightDirection[i];\n vec3 lightColor = directionalLightColor[i];\n\n float ndl = dot(v_Normal, normalize(lightDirection));\n\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsDir[i];\n }\n#endif\n\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * shadowContrib;\n }\n#endif\n\n#ifdef SSAOMAP_ENABLED\n diffuseColor *= texture2D(ssaoMap, (gl_FragCoord.xy - viewport.xy) / viewport.zw).r;\n#endif\n\n gl_FragColor.rgb *= diffuseColor;\n\n gl_FragColor.a *= 1.0 - clamp(length(v_WorldPosition.xz) / 30.0, 0.0, 1.0);\n\n}\n\n@end"; Shader.import(groundGLSLCode); @@ -32373,7 +32766,7 @@ var TEXTURES = ['diffuseMap', 'normalMap', 'emissiveMap', 'metalnessMap', 'rough * @param {Object} [sceneConfig.ambientLight] * @param {Object} [sceneConfig.ambientCubemapLight] */ -function Viewer(dom, sceneConfig) { +function Viewer$1(dom, sceneConfig) { sceneConfig = clone(sceneConfig); merge(sceneConfig, defaultSceneConfig); @@ -32381,9 +32774,9 @@ function Viewer(dom, sceneConfig) { this.init(dom, sceneConfig); } -Viewer.prototype.init = function (dom, opts) { +Viewer$1.prototype.init = function (dom, opts) { opts = opts || {}; - + /** * @type {HTMLDivElement} */ @@ -32392,7 +32785,7 @@ Viewer.prototype.init = function (dom, opts) { /** * @private */ - this._animation = new Animation(); + this._timeline = new Timeline$1(); var renderer = new Renderer({ devicePixelRatio: opts.devicePixelRatio || window.devicePixelRatio @@ -32416,7 +32809,7 @@ Viewer.prototype.init = function (dom, opts) { var cameraControl = this._cameraControl = new OrbitControl({ renderer: renderer, - animation: this._animation, + timeline: this._timeline, domElement: dom }); cameraControl.target = this._renderMain.camera; @@ -32501,10 +32894,9 @@ Viewer.prototype.init = function (dom, opts) { this.refresh(); }, this); - this.shaderLibrary = library.createLibrary(); }; -Viewer.prototype._createGround = function () { +Viewer$1.prototype._createGround = function () { var groundMesh = new Mesh({ isGround: true, material: new Material({ @@ -32515,7 +32907,8 @@ Viewer.prototype._createGround = function () { transparent: true }), castShadow: false, - geometry: new Plane$2() + geometry: new Plane$2(), + renderOrder: -10 }); groundMesh.material.set('color', [1, 1, 1, 1]); groundMesh.scale.set(40, 40, 1); @@ -32525,7 +32918,7 @@ Viewer.prototype._createGround = function () { this._renderMain.scene.add(groundMesh); }; -Viewer.prototype._addModel = function (modelNode, nodes, skeletons, clips) { +Viewer$1.prototype._addModel = function (modelNode, nodes, skeletons, clips) { // Remove previous loaded this.removeModel(); @@ -32553,19 +32946,19 @@ Viewer.prototype._addModel = function (modelNode, nodes, skeletons, clips) { this._materialsMap = materialsMap; this._updateMaterialsSRGB(); - + this._stopAccumulating(); }; -Viewer.prototype._removeAnimationClips = function () { +Viewer$1.prototype._removeAnimationClips = function () { this._clips.forEach(function (clip) { - this._animation.removeClip(clip); + this._timeline.removeClip(clip); }, this); this._clips = []; this._takes = []; }; -Viewer.prototype._setAnimationClips = function (clips) { +Viewer$1.prototype._setAnimationClips = function (clips) { var self = this; function refresh() { self.refresh(); @@ -32578,7 +32971,7 @@ Viewer.prototype._setAnimationClips = function (clips) { }, this); clip.onframe = refresh; - this._animation.addClip(clip); + this._timeline.addClip(clip); this._takes.push({ name: clip.name, @@ -32590,7 +32983,7 @@ Viewer.prototype._setAnimationClips = function (clips) { this._clips = clips.slice(); }; -Viewer.prototype._initHandlers = function () { +Viewer$1.prototype._initHandlers = function () { this._picking = new RayPicking({ renderer: this._renderer, @@ -32605,18 +32998,18 @@ Viewer.prototype._initHandlers = function () { this.root.addEventListener('click', this._clickHandler); }; -Viewer.prototype._mouseDownHandler = function (e) { +Viewer$1.prototype._mouseDownHandler = function (e) { this._startX = e.clientX; this._startY = e.clientY; }; -Viewer.prototype._clickHandler = function (e) { +Viewer$1.prototype._clickHandler = function (e) { if (!this._enablePicking && !this._renderMain.isDOFEnabled()) { return; } var dx = e.clientX - this._startX; var dy = e.clientY - this._startY; - if (Math.sqrt(dx * dx + dy * dy) >= 40) { + if (Math.sqrt(dx * dx + dy * dy) >= 5) { return; } @@ -32642,19 +33035,19 @@ Viewer.prototype._clickHandler = function (e) { /** * Enable picking */ -Viewer.prototype.enablePicking = function () { +Viewer$1.prototype.enablePicking = function () { this._enablePicking = true; }; /** * Disable picking */ -Viewer.prototype.disablePicking = function () { +Viewer$1.prototype.disablePicking = function () { this._enablePicking = false; }; /** * Model coordinate system is y up. */ -Viewer.prototype.setModelUpAxis = function (upAxis) { +Viewer$1.prototype.setModelUpAxis = function (upAxis) { var modelNode = this._modelNode; if (!modelNode) { return; @@ -32668,7 +33061,7 @@ Viewer.prototype.setModelUpAxis = function (upAxis) { this.autoFitModel(); }; -Viewer.prototype.setTextureFlipY = function (flipY) { +Viewer$1.prototype.setTextureFlipY = function (flipY) { if (!this._modelNode) { return; } @@ -32689,7 +33082,7 @@ Viewer.prototype.setTextureFlipY = function (flipY) { /** * Resize the viewport */ -Viewer.prototype.resize = function () { +Viewer$1.prototype.resize = function () { var renderer = this._renderer; renderer.resize(this.root.clientWidth, this.root.clientHeight); this._renderMain.setViewport(0, 0, renderer.getWidth(), renderer.getHeight(), renderer.getDevicePixelRatio()); @@ -32700,11 +33093,15 @@ Viewer.prototype.resize = function () { /** * Scale model to auto fit the camera. */ -Viewer.prototype.autoFitModel = function (fitSize) { +Viewer$1.prototype.autoFitModel = function (fitSize) { fitSize = fitSize || 10; if (this._modelNode) { this.setPose(10); this._modelNode.update(); + // Update skeleton after model node transform updated. + this._skeletons.forEach(function (skeleton) { + skeleton.update(); + }); var bbox = getBoundingBoxWithSkinning(this._modelNode); var size = new Vector3(); @@ -32720,7 +33117,7 @@ Viewer.prototype.autoFitModel = function (fitSize) { this._modelNode.position.copy(center).scale(-scale); this._modelNode.update(); - this._hotspotManager.setBoundingBox(bbox.min._array, bbox.max._array); + this._hotspotManager.setBoundingBox(bbox.min.array, bbox.max.array); // FIXME, Do it in the renderer? this._modelNode.traverse(function (mesh) { @@ -32746,8 +33143,9 @@ Viewer.prototype.autoFitModel = function (fitSize) { * @param {Array.} [opts.buffers] * @param {boolean} [opts.upAxis='y'] Change model to y up if upAxis is 'z' * @param {boolean} [opts.textureFlipY=false] + * @param {boolean} [opts.regenerateNormal=false] If regenerate per vertex normal. */ -Viewer.prototype.loadModel = function (gltfFile, opts) { +Viewer$1.prototype.loadModel = function (gltfFile, opts) { opts = opts || {}; if (!gltfFile) { throw new Error('URL of model is not provided'); @@ -32772,13 +33170,13 @@ Viewer.prototype.loadModel = function (gltfFile, opts) { } var loaderOpts = { rootNode: new Node(), - shaderName: 'qtek.' + shaderName, + shader: 'clay.' + shaderName, textureRootPath: opts.textureRootPath, bufferRootPath: opts.bufferRootPath, crossOrigin: 'Anonymous', includeTexture: opts.includeTexture == null ? true : opts.includeTexture, textureFlipY: opts.textureFlipY, - shaderLibrary: this.shaderLibrary + textureConvertToPOT: true }; if (pathResolver) { loaderOpts.resolveTexturePath = @@ -32830,7 +33228,7 @@ Viewer.prototype.loadModel = function (gltfFile, opts) { }; task.trigger('loadmodel', stat); - + var loadingTextures = []; util.each(res.textures, function (texture) { if (!texture.isRenderable()) { @@ -32839,7 +33237,7 @@ Viewer.prototype.loadModel = function (gltfFile, opts) { }); var taskGroup = new TaskGroup(); taskGroup.allSettled(loadingTextures).success(function () { - this._convertToPOT(); + this._convertBumpToNormal(); task.trigger('ready'); this.refresh(); @@ -32857,7 +33255,7 @@ Viewer.prototype.loadModel = function (gltfFile, opts) { return task; }; -Viewer.prototype._convertBumpToNormal = function () { +Viewer$1.prototype._convertBumpToNormal = function () { for (var key in this._materialsMap) { for (var i = 0; i < this._materialsMap[key].length; i++) { var mat = this._materialsMap[key][i]; @@ -32869,47 +33267,13 @@ Viewer.prototype._convertBumpToNormal = function () { normalTexture.dirty(); } } - } -}; - -Viewer.prototype._convertToPOT = function () { - this._modelNode.traverse(function (mesh) { - if (mesh.material) { - var hasNPOT = false; - var needsConvert = false; - for (var i = 0; i < TEXTURES.length; i++) { - var tex = mesh.material.get(TEXTURES[i]); - if (tex && !tex.isPowerOfTwo()) { - hasNPOT = true; - break; - } - } - if (hasNPOT) { - var texcoordVal = mesh.geometry.attributes.texcoord0.value || []; - for (var i = 0; i < texcoordVal.length; i++) { - var st = texcoordVal[i]; - if (st > 1 || st < 0) { - needsConvert = true; - break; - } - } - } - if (needsConvert) { - for (var i = 0; i < TEXTURES.length; i++) { - var tex = mesh.material.get(TEXTURES[i]); - if (tex) { - helper.convertTextureToPowerOfTwo(tex); - } - } - } - } - }); + } }; /** * Remove current loaded model */ -Viewer.prototype.removeModel = function () { +Viewer$1.prototype.removeModel = function () { var prevModelNode = this._modelNode; if (prevModelNode) { this._renderer.disposeNode(prevModelNode); @@ -32925,25 +33289,23 @@ Viewer.prototype.removeModel = function () { /** * Return scene. - * @return {qtek.Scene} + * @return {clay.Scene} */ -Viewer.prototype.getScene = function () { +Viewer$1.prototype.getScene = function () { return this._renderMain.scene; }; /** - * @return {qtek.Node} + * @return {clay.Node} */ -Viewer.prototype.getModelRoot = function () { +Viewer$1.prototype.getModelRoot = function () { return this._modelNode; }; -Viewer.prototype._preprocessModel = function (rootNode, opts) { +Viewer$1.prototype._preprocessModel = function (rootNode, opts) { var alphaCutoff = opts.alphaCutoff; var doubleSided = opts.doubleSided; - var shaderName = opts.shader || 'standard'; - var shaderLibrary = this.shaderLibrary; var meshNeedsSplit = []; rootNode.traverse(function (mesh) { @@ -32952,7 +33314,7 @@ Viewer.prototype._preprocessModel = function (rootNode, opts) { } }); meshNeedsSplit.forEach(function (mesh) { - var newNode = meshUtil.splitByJoints(mesh, 15, true, shaderLibrary, 'qtek.' + shaderName); + var newNode = meshUtil.splitByJoints(mesh, 15, true); if (newNode !== mesh) { newNode.eachChild(function (mesh) { mesh.originalMeshName = newNode.name; @@ -32961,18 +33323,22 @@ Viewer.prototype._preprocessModel = function (rootNode, opts) { }, this); rootNode.traverse(function (mesh) { if (mesh.geometry) { + // TODO Shared geometry? face normal? + if (opts.regenerateNormal) { + mesh.geometry.generateVertexNormals(); + } mesh.geometry.updateBoundingBox(); if (doubleSided != null) { mesh.culling = !doubleSided; } } if (mesh.material) { - mesh.material.shader.define('fragment', 'DIFFUSEMAP_ALPHA_ALPHA'); - mesh.material.shader.define('fragment', 'ALPHA_TEST'); + mesh.material.define('fragment', 'DIFFUSEMAP_ALPHA_ALPHA'); + mesh.material.define('fragment', 'ALPHA_TEST'); if (doubleSided != null) { - mesh.material.shader[doubleSided ? 'define' : 'undefine']('fragment', 'DOUBLE_SIDED'); + mesh.material[doubleSided ? 'define' : 'undefine']('fragment', 'DOUBLE_SIDED'); } - mesh.material.shader.precision = 'mediump'; + mesh.material.precision = 'mediump'; if (alphaCutoff != null) { mesh.material.set('alphaCutoff', alphaCutoff); @@ -32991,7 +33357,7 @@ Viewer.prototype._preprocessModel = function (rootNode, opts) { * Load animation glTF * @param {string} url */ -Viewer.prototype.loadAnimation = function (url) { +Viewer$1.prototype.loadAnimation = function (url) { var loader = new GLTFLoader({ rootNode: new Node(), crossOrigin: 'Anonymous' @@ -33008,22 +33374,22 @@ Viewer.prototype.loadAnimation = function (url) { /** * Pause animation */ -Viewer.prototype.pauseAnimation = function () { +Viewer$1.prototype.pauseAnimation = function () { this._clips.forEach(function (clip) { clip.pause(); }); }; -Viewer.prototype.stopAnimation = function () { +Viewer$1.prototype.stopAnimation = function () { this._clips.forEach(function (clip) { - this._animation.removeClip(clip); + this._timeline.removeClip(clip); }, this); }; /** * Resume animation */ -Viewer.prototype.resumeAnimation = function () { +Viewer$1.prototype.resumeAnimation = function () { this._clips.forEach(function (clip) { clip.resume(); }); @@ -33044,7 +33410,7 @@ Viewer.prototype.resumeAnimation = function () { * @param {number} [opts.panSensitivity] * @param {number} [opts.zoomSensitivity] */ -Viewer.prototype.setCameraControl = function (opts) { +Viewer$1.prototype.setCameraControl = function (opts) { this._cameraControl.setOption(opts); this.refresh(); }; @@ -33058,7 +33424,7 @@ Viewer.prototype.setCameraControl = function (opts) { * @param {number} [opts.shadow] * @param {number} [opts.shadowQuality] */ -Viewer.prototype.setMainLight = function (opts) { +Viewer$1.prototype.setMainLight = function (opts) { this._sceneHelper.updateMainLight(opts, this); this.refresh(); }; @@ -33072,7 +33438,7 @@ Viewer.prototype.setMainLight = function (opts) { * @param {number} [opts.shadow] * @param {number} [opts.shadowQuality] */ -Viewer.prototype.setSecondaryLight = function (opts) { +Viewer$1.prototype.setSecondaryLight = function (opts) { this._sceneHelper.updateSecondaryLight(opts, this); this.refresh(); }; @@ -33086,7 +33452,7 @@ Viewer.prototype.setSecondaryLight = function (opts) { * @param {number} [opts.shadow] * @param {number} [opts.shadowQuality] */ -Viewer.prototype.setTertiaryLight = function (opts) { +Viewer$1.prototype.setTertiaryLight = function (opts) { this._sceneHelper.updateTertiaryLight(opts, this); this.refresh(); }; @@ -33096,7 +33462,7 @@ Viewer.prototype.setTertiaryLight = function (opts) { * @param {number} [opts.intensity] * @param {string} [opts.color] */ -Viewer.prototype.setAmbientLight = function (opts) { +Viewer$1.prototype.setAmbientLight = function (opts) { this._sceneHelper.updateAmbientLight(opts, this); this.refresh(); }; @@ -33107,7 +33473,7 @@ Viewer.prototype.setAmbientLight = function (opts) { * @param {number} [opts.diffuseIntensity] * @param {number} [opts.specularIntensity] */ -Viewer.prototype.setAmbientCubemapLight = function (opts) { +Viewer$1.prototype.setAmbientCubemapLight = function (opts) { this._sceneHelper.updateAmbientCubemapLight(opts, this); this.refresh(); }; @@ -33115,70 +33481,85 @@ Viewer.prototype.setAmbientCubemapLight = function (opts) { /** * @param {string} envUrl */ -Viewer.prototype.setEnvironment = function (envUrl) { +Viewer$1.prototype.setEnvironment = function (envUrl) { this._sceneHelper.updateSkybox(envUrl, this._renderMain.isLinearSpace(), this); }; /** - * @param {string} matName + * @param {string|Array.} matName * @param {Object} materialCfg * @param {boolean} [materialCfg.transparent] * @param {boolean} [materialCfg.alphaCutoff] * @param {boolean} [materialCfg.metalness] * @param {boolean} [materialCfg.roughness] */ -Viewer.prototype.setMaterial = function (matName, materialCfg) { +Viewer$1.prototype.setMaterial = function (matName, materialCfg) { + var renderer = this._renderer; materialCfg = materialCfg || {}; - var materials = this._materialsMap[matName]; + if (! (matName instanceof Array)) { + matName = [matName]; + } + var materials = []; + matName.forEach(function (singleMatName) { + if (this._materialsMap[singleMatName]) { + materials = materials.concat(this._materialsMap[singleMatName]); + } + }, this); var app = this; var textureFlipY = this._textureFlipY; if (!materials || !materials.length) { - console.warn('Material %s not exits', matName); + console.warn('Material %s not exits', matName.join(', ')); return; } - var enabledTextures = materials[0].shader.getEnabledTextures(); - function haveTexture(val) { return val && val !== 'none'; } - + var needTangents = false; function addTexture(propName) { // Not change if texture name is not in the config. if (propName in materialCfg) { - var idx = enabledTextures.indexOf(propName); if (haveTexture(materialCfg[propName])) { - var texture = helper.loadTexture(materialCfg[propName], app, { - flipY: textureFlipY, - anisotropic: 8 + var isEnvironmentMap = propName === 'environmentMap'; + needTangents = propName === 'normalMap' || propName === 'parallaxOcclusionMap'; + + helper.loadTexture(materialCfg[propName], app, { + flipY: isEnvironmentMap ? false : textureFlipY, + anisotropic: isEnvironmentMap ? 1 : 8 }, function (texture) { if (propName === 'normalMap' && textureUtil.isHeightImage(texture.image)) { var normalImage = textureUtil.heightToNormal(texture.image); normalImage.srcImage = texture.image; texture.image = normalImage; } + else if (propName === 'environmentMap') { + var size = Math.round(texture.width / 4); + var cubemap = new TextureCube({ + width: size, + height: size + }); + // TODO No need to use environment map if there is ambient cubemap + textureUtil.panoramaToCubeMap(renderer, texture, cubemap); + // Use the cubemap. + texture = cubemap; + } + materials.forEach(function (mat) { + mat.set(propName, texture); + }); app.refresh(); }); - // Enable texture. - if (idx < 0) { - enabledTextures.push(propName); - } - textures[propName] = texture; } else { - // Disable texture. - if (idx >= 0) { - enabledTextures.splice(idx, 1); - } - textures[propName] = null; + materials.forEach(function (mat) { + mat.set(propName, null); + }); } } } - var textures = {}; - ['diffuseMap', 'normalMap', 'parallaxOcclusionMap', 'emissiveMap'].forEach(function (propName) { + ['diffuseMap', 'normalMap', 'parallaxOcclusionMap', 'emissiveMap', 'environmentMap'].forEach(function (propName) { addTexture(propName); }, this); - if (materials[0].shader.isDefined('fragment', 'USE_METALNESS')) { + if (materials[0].isDefined('fragment', 'USE_METALNESS')) { ['metalnessMap', 'roughnessMap'].forEach(function (propName) { addTexture(propName); }, this); @@ -33189,7 +33570,7 @@ Viewer.prototype.setMaterial = function (matName, materialCfg) { }, this); } - if (textures.normalMap || textures.parallaxOcclusionMap) { + if (needTangents) { this._modelNode.traverse(function (mesh) { if (mesh.material && mesh.material.name === matName) { if (!mesh.geometry.attributes.tangent.value) { @@ -33213,15 +33594,6 @@ Viewer.prototype.setMaterial = function (matName, materialCfg) { mat.set(propName, materialCfg[propName]); } }); - for (var texName in textures) { - mat.set(texName, textures[texName]); - } - mat.attachShader(this.shaderLibrary.get('qtek.' + (this._shaderName || 'standard'), { - fragmentDefines: mat.shader.fragmentDefines, - textures: enabledTextures, - vertexDefines: mat.shader.vertexDefines, - precision: mat.shader.precision - }), true); }, this); this.refresh(); }; @@ -33229,7 +33601,7 @@ Viewer.prototype.setMaterial = function (matName, materialCfg) { /** * @param {string} name */ -Viewer.prototype.getMaterial = function (name) { +Viewer$1.prototype.getMaterial = function (name) { var materials = this._materialsMap[name]; if (!materials) { console.warn('Material %s not exits', name); @@ -33237,7 +33609,8 @@ Viewer.prototype.getMaterial = function (name) { } var mat = materials[0]; var materialCfg = { - name: name + name: name, + transparent: mat.transparent }; ['color', 'emission'].forEach(function (propName) { materialCfg[propName] = helper.stringifyColor(mat.get(propName), 'hex'); @@ -33259,7 +33632,7 @@ Viewer.prototype.getMaterial = function (name) { ['diffuseMap', 'normalMap', 'parallaxOcclusionMap', 'emissiveMap'].forEach(function (propName) { materialCfg[propName] = getTextureUri(propName); }); - if (mat.shader.isDefined('fragment', 'USE_METALNESS')) { + if (mat.isDefined('fragment', 'USE_METALNESS')) { ['metalness', 'roughness'].forEach(function (propName) { materialCfg[propName] = mat.get(propName); }); @@ -33283,23 +33656,29 @@ Viewer.prototype.getMaterial = function (name) { /** * @param {Object} opts * @param {boolean} [opts.show] + * @param {boolean} [opts.grid] */ -Viewer.prototype.setGround = function (opts) { - this._groundMesh.invisible = !opts.show; +Viewer$1.prototype.setGround = function (opts) { + if ('show' in opts) { + this._groundMesh.invisible = !opts.show; + } + if ('grid' in opts) { + this._groundMesh.material.set('showGrid', opts.grid); + } this.refresh(); }; /** * @return {Array.} */ -Viewer.prototype.getMaterialsNames = function () { +Viewer$1.prototype.getMaterialsNames = function () { return Object.keys(this._materialsMap); }; /** * @param {Object} opts */ -Viewer.prototype.setPostEffect = function (opts) { +Viewer$1.prototype.setPostEffect = function (opts) { this._renderMain.setPostEffect(opts); this._updateMaterialsSRGB(); @@ -33309,46 +33688,42 @@ Viewer.prototype.setPostEffect = function (opts) { /** * Start loop. */ -Viewer.prototype.start = function () { +Viewer$1.prototype.start = function () { if (this._disposed) { console.warn('Viewer already disposed'); return; } - this._animation.start(); - this._animation.on('frame', this._loop, this); + this._timeline.start(); + this._timeline.on('frame', this._loop, this); }; /** * Stop loop. */ -Viewer.prototype.stop = function () { - this._animation.stop(); - this._animation.off('frame', this._loop); +Viewer$1.prototype.stop = function () { + this._timeline.stop(); + this._timeline.off('frame', this._loop); }; /** * Add html tip */ -Viewer.prototype.addHotspot = function (position, tipHTML) { +Viewer$1.prototype.addHotspot = function (position, tipHTML) { return this._hotspotManager.add(position, tipHTML); }; -Viewer.prototype.setPose = function (time) { +Viewer$1.prototype.setPose = function (time) { this._clips.forEach(function (clip) { clip.setTime(time); }); - this._skeletons.forEach(function (skeleton) { - skeleton.update(); - }); - this.refresh(); }; /** * Get duration of clip */ -Viewer.prototype.getAnimationDuration = function () { +Viewer$1.prototype.getAnimationDuration = function () { var maxLife = 0; this._clips.forEach(function (clip) { maxLife = Math.max(clip.life, maxLife); @@ -33357,25 +33732,25 @@ Viewer.prototype.getAnimationDuration = function () { }; -Viewer.prototype.refresh = function () { +Viewer$1.prototype.refresh = function () { this._needsRefresh = true; }; -Viewer.prototype.getRenderer = function () { +Viewer$1.prototype.getRenderer = function () { return this._renderer; }; -Viewer.prototype._updateMaterialsSRGB = function () { +Viewer$1.prototype._updateMaterialsSRGB = function () { var isLinearSpace = this._renderMain.isLinearSpace(); for (var name in this._materialsMap) { var materials = this._materialsMap[name]; for (var i = 0; i < materials.length; i++) { - materials[i].shader[isLinearSpace ? 'define' : 'undefine']('fragment', 'SRGB_DECODE'); + materials[i][isLinearSpace ? 'define' : 'undefine']('fragment', 'SRGB_DECODE'); } } }; -Viewer.prototype._loop = function (deltaTime) { +Viewer$1.prototype._loop = function (deltaTime) { if (this._disposed) { return; } @@ -33395,12 +33770,12 @@ Viewer.prototype._loop = function (deltaTime) { }; var accumulatingId = 1; -Viewer.prototype._stopAccumulating = function () { +Viewer$1.prototype._stopAccumulating = function () { this._accumulatingId = 0; clearTimeout(this._accumulatingTimeout); }; -Viewer.prototype._startAccumulating = function (immediate) { +Viewer$1.prototype._startAccumulating = function (immediate) { var self = this; this._stopAccumulating(); @@ -33445,9 +33820,9 @@ Viewer.prototype._startAccumulating = function (immediate) { /** * Dispose viewer. */ -Viewer.prototype.dispose = function () { +Viewer$1.prototype.dispose = function () { this._disposed = true; - + this._renderer.disposeScene(this._renderMain.scene); this._renderMain.dispose(this._renderer); this._sceneHelper.dispose(this._renderer); @@ -33467,16 +33842,10 @@ Viewer.prototype.dispose = function () { this.stop(); }; -util.extend(Viewer.prototype, notifier); - -var index = { - Viewer: Viewer, - version: '0.1.1' -}; +util.extend(Viewer$1.prototype, notifier); -exports.Viewer = Viewer; -exports['default'] = index; +Viewer$1.version = '0.2.0'; -Object.defineProperty(exports, '__esModule', { value: true }); +return Viewer$1; }))); diff --git a/dist/clay-viewer.min.js b/dist/clay-viewer.min.js new file mode 100644 index 0000000..e1e4d1b --- /dev/null +++ b/dist/clay-viewer.min.js @@ -0,0 +1,15 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.ClayViewer=t()}(this,function(){"use strict";function e(e,n,i){"object"==typeof n&&(i=n,n=null);var a,o=this;if(!(e instanceof Function)){a=[];for(var s in e)e.hasOwnProperty(s)&&a.push(s)}var u=function(n){if(o.apply(this,arguments),e instanceof Function?t(this,e.call(this,n)):r(this,e,a),this.constructor===u)for(var i=u.__initializers__,s=0;sr?r:e}function o(e){return e=Math.round(e),e<0?0:e>255?255:e}function s(e){return e=Math.round(e),e<0?0:e>360?360:e}function u(e){return e<0?0:e>1?1:e}function l(e){return o(e.length&&"%"===e.charAt(e.length-1)?parseFloat(e)/100*255:parseInt(e,10))}function c(e){return u(e.length&&"%"===e.charAt(e.length-1)?parseFloat(e)/100:parseFloat(e))}function h(e,t,r){return r<0?r+=1:r>1&&(r-=1),6*r<1?e+(t-e)*r*6:2*r<1?t:3*r<2?e+(t-e)*(2/3-r)*6:e}function f(e,t,r){return e+(t-e)*r}function d(e,t,r,n,i){return e[0]=t,e[1]=r,e[2]=n,e[3]=i,e}function p(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e}function m(e,t){ir&&p(ir,t),ir=nr.put(e,ir||t.slice())}function _(e,t){var r=(parseFloat(e[0])%360+360)%360/360,n=c(e[1]),i=c(e[2]),a=i<=.5?i*(n+1):i+n-i*n,s=2*i-a;return t=t||[],d(t,o(255*h(s,a,r+1/3)),o(255*h(s,a,r)),o(255*h(s,a,r-1/3)),1),4===e.length&&(t[3]=e[3]),t}function v(e){if(e){var t,r,n=e[0]/255,i=e[1]/255,a=e[2]/255,o=Math.min(n,i,a),s=Math.max(n,i,a),u=s-o,l=(s+o)/2;if(0===u)t=0,r=0;else{r=l<.5?u/(s+o):u/(2-s-o);var c=((s-n)/6+u/2)/u,h=((s-i)/6+u/2)/u,f=((s-a)/6+u/2)/u;n===s?t=f-h:i===s?t=1/3+c-f:a===s&&(t=2/3+h-c),t<0&&(t+=1),t>1&&(t-=1)}var d=[360*t,r,l];return null!=e[3]&&d.push(e[3]),d}}function g(e){var t=Object.keys(e);t.sort();for(var r=[],n=0;n0&&n.push("#define "+i.toUpperCase()+"_COUNT "+a)}if(r)for(var o=0;o=0){if(1!==u&&4!==u){N();break}u=2,c=[]}else if(1!==u)if(4!==u)r(h),u=0;else{var f=h;br.indexOf(f)>=0||Ar.indexOf(f)>=0||Sr.indexOf(f)>=0?l[s].semantic=f:"ignore"===f||"unconfigurable"===f?l[s].ignore=!0:l[s].value="bool"===e?"true"===f:parseFloat(f)}else l[s].value="bool"===e?"true"===h:parseFloat(h),c=null;else{if(2!==u){N();break}if(!(c instanceof Array)){N();break}c.push(+i[++o])}else l[s].value=new Mt.Float32Array(c),c=null,u=5;else if(2===u){if(!(c instanceof Array)){N();break}c.push(+i[++o])}else u=5;else u=4;else{if(0!==u&&3!==u){N();break}u=1}}return l}function L(e,t){"object"==typeof e&&(t=e.fragment,e=e.vertex),e=R(e),t=R(t),this._shaderID=C(e,t),this._vertexCode=L.parseImport(e),this._fragmentCode=L.parseImport(t),this.attributeSemantics={},this.matrixSemantics={},this.uniformSemantics={},this.matrixSemanticKeys=[],this.uniformTemplates={},this.attributes={},this.textures={},this.vertexDefines={},this.fragmentDefines={},this._parseAttributes(),this._parseUniforms(),this._parseDefines()}function P(e){return e.material}function D(){}function O(e,t,r){this.availableAttributes=e,this.availableAttributeSymbols=t,this.indicesBuffer=r,this.vao=null}function I(e){var t=new XMLHttpRequest;t.open("get",e.url),t.responseType=e.responseType||"text",e.onprogress&&(t.onprogress=function(t){if(t.lengthComputable){var r=t.loaded/t.total;e.onprogress(r,t.loaded,t.total)}else e.onprogress(null)}),t.onload=function(r){t.status>=400?e.onerror&&e.onerror():e.onload&&e.onload(t.response)},e.onerror&&(t.onerror=e.onerror),t.send(null)}function F(e){var t=[],r=Object.keys(e);r.sort();for(var n=0;n1e-6?(o=Math.acos(s),u=Math.sin(o),l=Math.sin((1-n)*o)/u,c=Math.sin(n*o)/u):(l=1-n,c=n),e[0]=l*h+c*m,e[1]=l*f+c*_,e[2]=l*d+c*v,e[3]=l*p+c*g,e}function X(e){return{byte:Mt.Int8Array,ubyte:Mt.Uint8Array,short:Mt.Int16Array,ushort:Mt.Uint16Array}[e]||Mt.Float32Array}function q(e){return"attr_"+e}function K(e,t,r,n){switch(this.name=e,this.type=t,this.size=r,this.semantic=n||"",this.value=null,r){case 1:this.get=function(e){return this.value[e]},this.set=function(e,t){this.value[e]=t},this.copy=function(e,t){this.value[e]=this.value[e]};break;case 2:this.get=function(e,t){var r=this.value;return t[0]=r[2*e],t[1]=r[2*e+1],t},this.set=function(e,t){var r=this.value;r[2*e]=t[0],r[2*e+1]=t[1]},this.copy=function(e,t){var r=this.value;t*=2,e*=2,r[e]=r[t],r[e+1]=r[t+1]};break;case 3:this.get=function(e,t){var r=3*e,n=this.value;return t[0]=n[r],t[1]=n[r+1],t[2]=n[r+2],t},this.set=function(e,t){var r=3*e,n=this.value;n[r]=t[0],n[r+1]=t[1],n[r+2]=t[2]},this.copy=function(e,t){var r=this.value;t*=3,e*=3,r[e]=r[t],r[e+1]=r[t+1],r[e+2]=r[t+2]};break;case 4:this.get=function(e,t){var r=this.value,n=4*e;return t[0]=r[n],t[1]=r[n+1],t[2]=r[n+2],t[3]=r[n+3],t},this.set=function(e,t){var r=this.value,n=4*e;r[n]=t[0],r[n+1]=t[1],r[n+2]=t[2],r[n+3]=t[3]},this.copy=function(e,t){var r=this.value;t*=4,e*=4,r[e]=r[t],r[e+1]=r[t+1],r[e+2]=r[t+2],r[e+3]=r[t+3]}}}function Y(e,t,r,n,i){this.name=e,this.type=t,this.buffer=r,this.size=n,this.semantic=i,this.symbol="",this.needsRemove=!1}function Z(e){this.buffer=e,this.count=0}function J(e,t,r,n){var i=e.accessors[r],a=t.bufferViews[i.bufferView],o=i.byteOffset||0,s=ni[i.componentType]||Mt.Float32Array,u=ii[i.type];null==u&&n&&(u=1);var l=new s(a,o,u*i.count),c=i.extensions&&i.extensions.WEB3D_quantized_attributes;if(c){for(var h,f,d=new Mt.Float32Array(u*i.count),p=c.decodeMatrix,h=new Array(u),f=new Array(u),m=0;mi)e.length=i;else for(var a=n;a=0&&!(p[y]<=t);y--);y=Math.min(y,c-2)}else{for(y=R;yt);y++);y=Math.min(y-1,c-2)}R=y,N=t;var r=p[y+1]-p[y];0!==r&&(b=(t-p[y])/r,b=Math.max(Math.min(1,b),0),b=_[y+1](b),l?(S=m[y],A=m[0===y?y:y-1],w=m[y>c-2?c-1:y+1],C=m[y>c-3?c-1:y+2],a?u(e,i,a(s(e,i),A,S,w,C,b)):f?ie(A,S,w,C,b,b*b,b*b*b,s(e,i),d):u(e,i,ae(A,S,w,C,b,b*b,b*b*b))):a?u(e,i,a(s(e,i),m[y],m[y+1],b)):f?te(m[y],m[y+1],b,s(e,i),d):u(e,i,ee(m[y],m[y+1],b)))},L=new Gn({target:e._target,life:o,loop:e._loop,delay:e._delay,onframe:M,onfinish:r});return t&&"spline"!==t&&L.setEasing(t),L}}}function le(e,t,r,n,i){this._tracks={},this._target=e,this._loop=t||!1,this._getter=r||Q,this._setter=n||$,this._interpolater=i||null,this._delay=0,this._doneList=[],this._onframeList=[],this._clipList=[],this._maxTime=0,this._lastKFTime=0}function ce(e){return e}function he(e,t){var r=new di;return zr.get({url:e,responseType:t,onload:function(e){r.resolve(e)},onerror:function(e){r.reject(e)}}),r}function fe(e){return"CANVAS"===e.nodeName||"VIDEO"===e.nodeName||e.complete}function de(e){return e.charCodeAt(0)+(e.charCodeAt(1)<<8)+(e.charCodeAt(2)<<16)+(e.charCodeAt(3)<<24)}function pe(e,t,r,n){if(e[3]>0){var i=Math.pow(2,e[3]-128-8+n);t[r+0]=e[0]*i,t[r+1]=e[1]*i,t[r+2]=e[2]*i}else t[r+0]=0,t[r+1]=0,t[r+2]=0;return t[r+3]=1,t}function me(e,t,r){for(var n="",i=t;i0;)if(e[a][0]=t[r++],e[a][1]=t[r++],e[a][2]=t[r++],e[a][3]=t[r++],1===e[a][0]&&1===e[a][1]&&1===e[a][2]){for(var s=e[a][3]<>>0;s>0;s--)_e(e[a-1],e[a]),a++,o--;i+=8}else a++,o--,i=0;return r}function ge(e,t,r,n){if(nBi)return ve(e,t,r,n);var i=t[r++];if(2!=i)return ve(e,t,r-1,n);if(e[0][1]=t[r++],e[0][2]=t[r++],i=t[r++],(e[0][2]<<8>>>0|i)>>>0!==n)return null;for(var i=0;i<4;i++)for(var a=0;a128){o=(127&o)>>>0;for(var s=t[r++];o--;)e[a++][i]=s}else for(;o--;)e[a++][i]=t[r++]}return r}function ye(e){bt.defaultsWithPropList(e,ji,Xi),xe(e);for(var t="",r=0;r0;)r+=n*(i%t),i=Math.floor(i/t),n/=t;return r}function Me(e){for(var t=new Uint8Array(e*e*4),r=0,n=new Ot,i=0;i255?255:e}function Ve(e){return e<0?0:e>1?1:e}function We(e){return Ge(e.length&&"%"===e.charAt(e.length-1)?parseFloat(e)/100*255:parseInt(e,10))}function je(e){return Ve(e.length&&"%"===e.charAt(e.length-1)?parseFloat(e)/100:parseFloat(e))}function Xe(e,t,r){return r<0?r+=1:r>1&&(r-=1),6*r<1?e+(t-e)*r*6:2*r<1?t:3*r<2?e+(t-e)*(2/3-r)*6:e}function qe(e,t,r,n,i){return e[0]=t,e[1]=r,e[2]=n,e[3]=i,e}function Ke(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e}function Ye(e,t){Pa&&Ke(Pa,t),Pa=La.put(e,Pa||t.slice())}function Ze(e,t){if(e){t=t||[];var r=La.get(e);if(r)return Ke(t,r);e+="";var n=e.replace(/ /g,"").toLowerCase();if(n in Ma)return Ke(t,Ma[n]),Ye(e,t),t;if("#"!==n.charAt(0)){var i=n.indexOf("("),a=n.indexOf(")");if(-1!==i&&a+1===n.length){var o=n.substr(0,i),s=n.substr(i+1,a-(i+1)).split(","),u=1;switch(o){case"rgba":if(4!==s.length)return void qe(t,0,0,0,1);u=je(s.pop());case"rgb":return 3!==s.length?void qe(t,0,0,0,1):(qe(t,We(s[0]),We(s[1]),We(s[2]),u),Ye(e,t),t);case"hsla":return 4!==s.length?void qe(t,0,0,0,1):(s[3]=je(s[3]),Je(s,t),Ye(e,t),t);case"hsl":return 3!==s.length?void qe(t,0,0,0,1):(Je(s,t),Ye(e,t),t);default:return}}qe(t,0,0,0,1)}else{if(4===n.length){var l=parseInt(n.substr(1),16);return l>=0&&l<=4095?(qe(t,(3840&l)>>4|(3840&l)>>8,240&l|(240&l)>>4,15&l|(15&l)<<4,1),Ye(e,t),t):void qe(t,0,0,0,1)}if(7===n.length){var l=parseInt(n.substr(1),16);return l>=0&&l<=16777215?(qe(t,(16711680&l)>>16,(65280&l)>>8,255&l,1),Ye(e,t),t):void qe(t,0,0,0,1)}}}}function Je(e,t){var r=(parseFloat(e[0])%360+360)%360/360,n=je(e[1]),i=je(e[2]),a=i<=.5?i*(n+1):i+n-i*n,o=2*i-a;return t=t||[],qe(t,Ge(255*Xe(o,a,r+1/3)),Ge(255*Xe(o,a,r)),Ge(255*Xe(o,a,r-1/3)),1),4===e.length&&(t[3]=e[3]),t}function Qe(e,t){if(e&&e.length){var r=e[0]+","+e[1]+","+e[2];return"rgba"!==t&&"hsva"!==t&&"hsla"!==t||(r+=","+e[3]),t+"("+r+")"}}function $e(e){return!e||"none"===e}function et(e){return e instanceof HTMLCanvasElement||e instanceof HTMLImageElement||e instanceof HTMLVideoElement||e instanceof Image}function tt(){this._sourceTexture=new Nn({type:Qt.HALF_FLOAT}),this._depthTexture=new Nn({format:Qt.DEPTH_COMPONENT,type:Qt.UNSIGNED_INT}),this._framebuffer=new wi,this._framebuffer.attach(this._sourceTexture),this._framebuffer.attach(this._depthTexture,wi.DEPTH_ATTACHMENT),this._gBufferPass=new ga({renderTransparent:!0,enableTargetTexture3:!1}),this._compositor=Ee(Ia);var e=this._compositor.getNodeByName("source");e.texture=this._sourceTexture;var t=this._compositor.getNodeByName("coc");this._sourceNode=e,this._cocNode=t,this._compositeNode=this._compositor.getNodeByName("composite"),this._fxaaNode=this._compositor.getNodeByName("FXAA"),this._dofBlurNodes=["dof_far_blur","dof_near_blur","dof_coc_blur"].map(function(e){return this._compositor.getNodeByName(e)},this),this._dofBlurKernel=null,this._dofBlurKernelSize=new Float32Array(0),this._finalNodesChain=Ba.map(function(e){return this._compositor.getNodeByName(e)},this);var r={normalTexture:this._gBufferPass.getTargetTexture1(),depthTexture:this._gBufferPass.getTargetTexture2(),albedoTexture:this._gBufferPass.getTargetTexture3()};this._ssaoPass=new De(r),this._ssrPass=new Ie(r)}function rt(){for(var e=[],t=0;t<30;t++)e.push([Ne(t,2),Ne(t,3)]);this._haltonSequence=e,this._frame=0,this._sourceTex=new Nn,this._sourceFb=new wi,this._sourceFb.attach(this._sourceTex),this._prevFrameTex=new Nn,this._outputTex=new Nn;var r=this._blendPass=new Vi({fragment:L.source("clay.compositor.blend")});r.material.disableTexturesAll(),r.material.enableTexture(["texture1","texture2"]),this._blendFb=new wi({depthBuffer:!1}),this._outputPass=new Vi({fragment:L.source("clay.compositor.output"),blendWithPrevious:!0}),this._outputPass.material.define("fragment","OUTPUT_ALPHA"),this._outputPass.material.blend=function(e){e.blendEquationSeparate(e.FUNC_ADD,e.FUNC_ADD),e.blendFuncSeparate(e.ONE,e.ONE_MINUS_SRC_ALPHA,e.ONE,e.ONE_MINUS_SRC_ALPHA)}}function nt(e,t,r){this.renderer=e,r=r||"perspective",this.scene=new vn,this.rootNode=this.scene,this.viewport={x:0,y:0,width:0,height:0},this.preZ=!1,this.setProjection(r),this._compositor=new tt,this._temporalSS=new rt,t&&(this._shadowMapPass=new Yi({lightFrustumBias:20}));for(var n=[],i=0,a=0;a<30;a++){for(var o=[],s=0;s<6;s++)o.push(4*Ne(i,2)-2),o.push(4*Ne(i,3)-2),i++;n.push(o)}this._pcfKernels=n,this._enableTemporalSS="auto",this.scene.on("beforerender",function(e,t,r){this.needsTemporalSS()&&this._temporalSS.jitterProjection(e,r)},this)}function it(e){this.setScene(e)}function at(e){if(null==e||"object"!=typeof e)return e;var t=e,r=Wa.call(e);if("[object Array]"===r){t=[];for(var n=0,i=e.length;n=0&&i[h]>1e-6&&(Xa.transformMat4(s,r,a[n[h]]),Xa.scaleAndAdd(o,o,s,i[h]));Xa.min(m,m,o),Xa.max(_,_,o)}t.min.setArray(m),t.max.setArray(_)}function dt(e,t){t=t||new Vt;var r=new Vt;return e.traverse(function(e){e.geometry&&(e.isSkinnedMesh()?(ft(e,r),e.geometry.boundingBox.copy(r)):(r.copy(e.geometry.boundingBox),r.applyTransform(e.worldTransform)),t.union(r))}),t}function pt(e){var t=e[1][0]-e[0][0],r=e[1][1]-e[0][1];return Math.sqrt(t*t+r*r)}function mt(e){return[(e[0][0]+e[1][0])/2,(e[0][1]+e[1][1])/2]}function _t(e){return Array.isArray(e)||(e=[e,e]),e}function vt(e,t){t=at(t),ot(t,za),this.init(e,t)}var gt={extend:e,derive:e},yt={trigger:function(e){if(this.hasOwnProperty("__handlers__")&&this.__handlers__.hasOwnProperty(e)){var t=this.__handlers__[e],r=t.length,n=-1,i=arguments;switch(i.length){case 1:for(;++n0&&(i=1/Math.sqrt(i),e[0]=t[0]*i,e[1]=t[1]*i),e},s.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]},s.cross=function(e,t,r){var n=t[0]*r[1]-t[1]*r[0];return e[0]=e[1]=0,e[2]=n,e},s.lerp=function(e,t,r,n){var i=t[0],a=t[1];return e[0]=i+n*(r[0]-i),e[1]=a+n*(r[1]-a),e},s.random=function(e,t){t=t||1;var r=2*i()*Math.PI;return e[0]=Math.cos(r)*t,e[1]=Math.sin(r)*t,e},s.transformMat2=function(e,t,r){var n=t[0],i=t[1];return e[0]=r[0]*n+r[2]*i,e[1]=r[1]*n+r[3]*i,e},s.transformMat2d=function(e,t,r){var n=t[0],i=t[1];return e[0]=r[0]*n+r[2]*i+r[4],e[1]=r[1]*n+r[3]*i+r[5],e},s.transformMat3=function(e,t,r){var n=t[0],i=t[1];return e[0]=r[0]*n+r[3]*i+r[6],e[1]=r[1]*n+r[4]*i+r[7],e},s.transformMat4=function(e,t,r){var n=t[0],i=t[1];return e[0]=r[0]*n+r[4]*i+r[12],e[1]=r[1]*n+r[5]*i+r[13],e},s.forEach=function(){var e=s.create();return function(t,r,n,i,a,o){var s,u;for(r||(r=2),n||(n=0),u=i?Math.min(i*r+n,t.length):t.length,s=n;s0&&(a=1/Math.sqrt(a),e[0]=t[0]*a,e[1]=t[1]*a,e[2]=t[2]*a),e},u.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]},u.cross=function(e,t,r){var n=t[0],i=t[1],a=t[2],o=r[0],s=r[1],u=r[2];return e[0]=i*u-a*s,e[1]=a*o-n*u,e[2]=n*s-i*o,e},u.lerp=function(e,t,r,n){var i=t[0],a=t[1],o=t[2];return e[0]=i+n*(r[0]-i),e[1]=a+n*(r[1]-a),e[2]=o+n*(r[2]-o),e},u.random=function(e,t){t=t||1;var r=2*i()*Math.PI,n=2*i()-1,a=Math.sqrt(1-n*n)*t;return e[0]=Math.cos(r)*a,e[1]=Math.sin(r)*a,e[2]=n*t,e},u.transformMat4=function(e,t,r){var n=t[0],i=t[1],a=t[2],o=r[3]*n+r[7]*i+r[11]*a+r[15];return o=o||1,e[0]=(r[0]*n+r[4]*i+r[8]*a+r[12])/o,e[1]=(r[1]*n+r[5]*i+r[9]*a+r[13])/o,e[2]=(r[2]*n+r[6]*i+r[10]*a+r[14])/o,e},u.transformMat3=function(e,t,r){var n=t[0],i=t[1],a=t[2];return e[0]=n*r[0]+i*r[3]+a*r[6],e[1]=n*r[1]+i*r[4]+a*r[7],e[2]=n*r[2]+i*r[5]+a*r[8],e},u.transformQuat=function(e,t,r){var n=t[0],i=t[1],a=t[2],o=r[0],s=r[1],u=r[2],l=r[3],c=l*n+s*a-u*i,h=l*i+u*n-o*a,f=l*a+o*i-s*n,d=-o*n-s*i-u*a;return e[0]=c*l+d*-o+h*-u-f*-s,e[1]=h*l+d*-s+f*-o-c*-u,e[2]=f*l+d*-u+c*-s-h*-o,e},u.rotateX=function(e,t,r,n){var i=[],a=[];return i[0]=t[0]-r[0],i[1]=t[1]-r[1],i[2]=t[2]-r[2],a[0]=i[0],a[1]=i[1]*Math.cos(n)-i[2]*Math.sin(n),a[2]=i[1]*Math.sin(n)+i[2]*Math.cos(n),e[0]=a[0]+r[0],e[1]=a[1]+r[1],e[2]=a[2]+r[2],e},u.rotateY=function(e,t,r,n){var i=[],a=[];return i[0]=t[0]-r[0],i[1]=t[1]-r[1],i[2]=t[2]-r[2],a[0]=i[2]*Math.sin(n)+i[0]*Math.cos(n),a[1]=i[1],a[2]=i[2]*Math.cos(n)-i[0]*Math.sin(n),e[0]=a[0]+r[0],e[1]=a[1]+r[1],e[2]=a[2]+r[2],e},u.rotateZ=function(e,t,r,n){var i=[],a=[];return i[0]=t[0]-r[0],i[1]=t[1]-r[1],i[2]=t[2]-r[2],a[0]=i[0]*Math.cos(n)-i[1]*Math.sin(n),a[1]=i[0]*Math.sin(n)+i[1]*Math.cos(n),a[2]=i[2],e[0]=a[0]+r[0],e[1]=a[1]+r[1],e[2]=a[2]+r[2],e},u.forEach=function(){var e=u.create();return function(t,r,n,i,a,o){var s,u;for(r||(r=3),n||(n=0),u=i?Math.min(i*r+n,t.length):t.length,s=n;s1?0:Math.acos(i)},u.str=function(e){return"vec3("+e[0]+", "+e[1]+", "+e[2]+")"},void 0!==e&&(e.vec3=u);var l={};l.create=function(){var e=new n(4);return e[0]=0,e[1]=0,e[2]=0,e[3]=0,e},l.clone=function(e){var t=new n(4);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},l.fromValues=function(e,t,r,i){var a=new n(4);return a[0]=e,a[1]=t,a[2]=r,a[3]=i,a},l.copy=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e},l.set=function(e,t,r,n,i){return e[0]=t,e[1]=r,e[2]=n,e[3]=i,e},l.add=function(e,t,r){return e[0]=t[0]+r[0],e[1]=t[1]+r[1],e[2]=t[2]+r[2],e[3]=t[3]+r[3],e},l.subtract=function(e,t,r){return e[0]=t[0]-r[0],e[1]=t[1]-r[1],e[2]=t[2]-r[2],e[3]=t[3]-r[3],e},l.sub=l.subtract,l.multiply=function(e,t,r){return e[0]=t[0]*r[0],e[1]=t[1]*r[1],e[2]=t[2]*r[2],e[3]=t[3]*r[3],e},l.mul=l.multiply,l.divide=function(e,t,r){return e[0]=t[0]/r[0],e[1]=t[1]/r[1],e[2]=t[2]/r[2],e[3]=t[3]/r[3],e},l.div=l.divide,l.min=function(e,t,r){return e[0]=Math.min(t[0],r[0]),e[1]=Math.min(t[1],r[1]),e[2]=Math.min(t[2],r[2]),e[3]=Math.min(t[3],r[3]),e},l.max=function(e,t,r){return e[0]=Math.max(t[0],r[0]),e[1]=Math.max(t[1],r[1]),e[2]=Math.max(t[2],r[2]),e[3]=Math.max(t[3],r[3]),e},l.scale=function(e,t,r){return e[0]=t[0]*r,e[1]=t[1]*r,e[2]=t[2]*r,e[3]=t[3]*r,e},l.scaleAndAdd=function(e,t,r,n){return e[0]=t[0]+r[0]*n,e[1]=t[1]+r[1]*n,e[2]=t[2]+r[2]*n,e[3]=t[3]+r[3]*n,e},l.distance=function(e,t){var r=t[0]-e[0],n=t[1]-e[1],i=t[2]-e[2],a=t[3]-e[3];return Math.sqrt(r*r+n*n+i*i+a*a)},l.dist=l.distance,l.squaredDistance=function(e,t){var r=t[0]-e[0],n=t[1]-e[1],i=t[2]-e[2],a=t[3]-e[3];return r*r+n*n+i*i+a*a},l.sqrDist=l.squaredDistance,l.length=function(e){var t=e[0],r=e[1],n=e[2],i=e[3];return Math.sqrt(t*t+r*r+n*n+i*i)},l.len=l.length,l.squaredLength=function(e){var t=e[0],r=e[1],n=e[2],i=e[3];return t*t+r*r+n*n+i*i},l.sqrLen=l.squaredLength,l.negate=function(e,t){return e[0]=-t[0],e[1]=-t[1],e[2]=-t[2],e[3]=-t[3],e},l.inverse=function(e,t){return e[0]=1/t[0],e[1]=1/t[1],e[2]=1/t[2],e[3]=1/t[3],e},l.normalize=function(e,t){var r=t[0],n=t[1],i=t[2],a=t[3],o=r*r+n*n+i*i+a*a;return o>0&&(o=1/Math.sqrt(o),e[0]=t[0]*o,e[1]=t[1]*o,e[2]=t[2]*o,e[3]=t[3]*o),e},l.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]+e[3]*t[3]},l.lerp=function(e,t,r,n){var i=t[0],a=t[1],o=t[2],s=t[3];return e[0]=i+n*(r[0]-i),e[1]=a+n*(r[1]-a),e[2]=o+n*(r[2]-o),e[3]=s+n*(r[3]-s),e},l.random=function(e,t){return t=t||1,e[0]=i(),e[1]=i(),e[2]=i(),e[3]=i(),l.normalize(e,e),l.scale(e,e,t),e},l.transformMat4=function(e,t,r){var n=t[0],i=t[1],a=t[2],o=t[3];return e[0]=r[0]*n+r[4]*i+r[8]*a+r[12]*o,e[1]=r[1]*n+r[5]*i+r[9]*a+r[13]*o,e[2]=r[2]*n+r[6]*i+r[10]*a+r[14]*o,e[3]=r[3]*n+r[7]*i+r[11]*a+r[15]*o,e},l.transformQuat=function(e,t,r){var n=t[0],i=t[1],a=t[2],o=r[0],s=r[1],u=r[2],l=r[3],c=l*n+s*a-u*i,h=l*i+u*n-o*a,f=l*a+o*i-s*n,d=-o*n-s*i-u*a;return e[0]=c*l+d*-o+h*-u-f*-s,e[1]=h*l+d*-s+f*-o-c*-u,e[2]=f*l+d*-u+c*-s-h*-o,e},l.forEach=function(){var e=l.create();return function(t,r,n,i,a,o){var s,u;for(r||(r=4),n||(n=0),u=i?Math.min(i*r+n,t.length):t.length,s=n;s.999999?(n[0]=0,n[1]=0,n[2]=0,n[3]=1,n):(u.cross(e,i,a),n[0]=e[0],n[1]=e[1],n[2]=e[2],n[3]=1+o,p.normalize(n,n))}}(),p.setAxes=function(){var e=f.create();return function(t,r,n,i){return e[0]=n[0],e[3]=n[1],e[6]=n[2],e[1]=i[0],e[4]=i[1],e[7]=i[2],e[2]=-r[0],e[5]=-r[1],e[8]=-r[2],p.normalize(t,p.fromMat3(t,e))}}(),p.clone=l.clone,p.fromValues=l.fromValues,p.copy=l.copy,p.set=l.set,p.identity=function(e){return e[0]=0,e[1]=0,e[2]=0,e[3]=1,e},p.setAxisAngle=function(e,t,r){r*=.5;var n=Math.sin(r);return e[0]=n*t[0],e[1]=n*t[1],e[2]=n*t[2],e[3]=Math.cos(r),e},p.add=l.add,p.multiply=function(e,t,r){var n=t[0],i=t[1],a=t[2],o=t[3],s=r[0],u=r[1],l=r[2],c=r[3];return e[0]=n*c+o*s+i*l-a*u,e[1]=i*c+o*u+a*s-n*l,e[2]=a*c+o*l+n*u-i*s,e[3]=o*c-n*s-i*u-a*l,e},p.mul=p.multiply,p.scale=l.scale,p.rotateX=function(e,t,r){r*=.5;var n=t[0],i=t[1],a=t[2],o=t[3],s=Math.sin(r),u=Math.cos(r);return e[0]=n*u+o*s,e[1]=i*u+a*s,e[2]=a*u-i*s,e[3]=o*u-n*s,e},p.rotateY=function(e,t,r){r*=.5;var n=t[0],i=t[1],a=t[2],o=t[3],s=Math.sin(r),u=Math.cos(r);return e[0]=n*u-a*s,e[1]=i*u+o*s,e[2]=a*u+n*s,e[3]=o*u-i*s,e},p.rotateZ=function(e,t,r){r*=.5;var n=t[0],i=t[1],a=t[2],o=t[3],s=Math.sin(r),u=Math.cos(r);return e[0]=n*u+i*s,e[1]=i*u-n*s,e[2]=a*u+o*s,e[3]=o*u-a*s,e},p.calculateW=function(e,t){var r=t[0],n=t[1],i=t[2];return e[0]=r,e[1]=n,e[2]=i,e[3]=Math.sqrt(Math.abs(1-r*r-n*n-i*i)),e},p.dot=l.dot,p.lerp=l.lerp,p.slerp=function(e,t,r,n){var i,a,o,s,u,l=t[0],c=t[1],h=t[2],f=t[3],d=r[0],p=r[1],m=r[2],_=r[3];return a=l*d+c*p+h*m+f*_,a<0&&(a=-a,d=-d,p=-p,m=-m,_=-_),1-a>1e-6?(i=Math.acos(a),o=Math.sin(i),s=Math.sin((1-n)*i)/o,u=Math.sin(n*i)/o):(s=1-n,u=n),e[0]=s*l+u*d,e[1]=s*c+u*p,e[2]=s*h+u*m,e[3]=s*f+u*_,e},p.invert=function(e,t){var r=t[0],n=t[1],i=t[2],a=t[3],o=r*r+n*n+i*i+a*a,s=o?1/o:0;return e[0]=-r*s,e[1]=-n*s,e[2]=-i*s,e[3]=a*s,e},p.conjugate=function(e,t){return e[0]=-t[0],e[1]=-t[1],e[2]=-t[2],e[3]=t[3],e},p.length=l.length,p.len=p.length,p.squaredLength=l.squaredLength,p.sqrLen=p.squaredLength,p.normalize=l.normalize,p.fromMat3=function(e,t){var r,n=t[0]+t[4]+t[8];if(n>0)r=Math.sqrt(n+1),e[3]=.5*r,r=.5/r,e[0]=(t[5]-t[7])*r,e[1]=(t[6]-t[2])*r,e[2]=(t[1]-t[3])*r;else{var i=0;t[4]>t[0]&&(i=1),t[8]>t[3*i+i]&&(i=2);var a=(i+1)%3,o=(i+2)%3;r=Math.sqrt(t[3*i+i]-t[3*a+a]-t[3*o+o]+1),e[i]=.5*r,r=.5/r,e[3]=(t[3*a+o]-t[3*o+a])*r,e[a]=(t[3*a+i]+t[3*i+a])*r,e[o]=(t[3*o+i]+t[3*i+o])*r}return e},p.str=function(e){return"quat("+e[0]+", "+e[1]+", "+e[2]+", "+e[3]+")"},void 0!==e&&(e.quat=p)}(r.exports)}()}),Dt=Pt.vec3,Ot=function(e,t,r){e=e||0,t=t||0,r=r||0,this.array=Dt.fromValues(e,t,r),this._dirty=!0};Ot.prototype={constructor:Ot,add:function(e){return Dt.add(this.array,this.array,e.array),this._dirty=!0,this},set:function(e,t,r){return this.array[0]=e,this.array[1]=t,this.array[2]=r,this._dirty=!0,this},setArray:function(e){return this.array[0]=e[0],this.array[1]=e[1],this.array[2]=e[2],this._dirty=!0,this},clone:function(){return new Ot(this.x,this.y,this.z)},copy:function(e){return Dt.copy(this.array,e.array),this._dirty=!0,this},cross:function(e,t){return Dt.cross(this.array,e.array,t.array),this._dirty=!0,this},dist:function(e){return Dt.dist(this.array,e.array)},distance:function(e){return Dt.distance(this.array,e.array)},div:function(e){return Dt.div(this.array,this.array,e.array),this._dirty=!0,this},divide:function(e){return Dt.divide(this.array,this.array,e.array),this._dirty=!0,this},dot:function(e){return Dt.dot(this.array,e.array)},len:function(){return Dt.len(this.array)},length:function(){return Dt.length(this.array)},lerp:function(e,t,r){return Dt.lerp(this.array,e.array,t.array,r),this._dirty=!0,this},min:function(e){return Dt.min(this.array,this.array,e.array),this._dirty=!0,this},max:function(e){return Dt.max(this.array,this.array,e.array),this._dirty=!0,this},mul:function(e){return Dt.mul(this.array,this.array,e.array),this._dirty=!0,this},multiply:function(e){return Dt.multiply(this.array,this.array,e.array),this._dirty=!0,this},negate:function(){return Dt.negate(this.array,this.array),this._dirty=!0,this},normalize:function(){return Dt.normalize(this.array,this.array),this._dirty=!0,this},random:function(e){return Dt.random(this.array,e),this._dirty=!0,this},scale:function(e){return Dt.scale(this.array,this.array,e),this._dirty=!0,this},scaleAndAdd:function(e,t){return Dt.scaleAndAdd(this.array,this.array,e.array,t),this._dirty=!0,this},sqrDist:function(e){return Dt.sqrDist(this.array,e.array)},squaredDistance:function(e){return Dt.squaredDistance(this.array,e.array)},sqrLen:function(){return Dt.sqrLen(this.array)},squaredLength:function(){return Dt.squaredLength(this.array)},sub:function(e){return Dt.sub(this.array,this.array,e.array),this._dirty=!0,this},subtract:function(e){return Dt.subtract(this.array,this.array,e.array),this._dirty=!0,this},transformMat3:function(e){return Dt.transformMat3(this.array,this.array,e.array),this._dirty=!0,this},transformMat4:function(e){return Dt.transformMat4(this.array,this.array,e.array),this._dirty=!0,this},transformQuat:function(e){return Dt.transformQuat(this.array,this.array,e.array),this._dirty=!0,this},applyProjection:function(e){var t=this.array;if(e=e.array,0===e[15]){var r=-1/t[2];t[0]=e[0]*t[0]*r,t[1]=e[5]*t[1]*r,t[2]=(e[10]*t[2]+e[14])*r}else t[0]=e[0]*t[0]+e[12],t[1]=e[5]*t[1]+e[13],t[2]=e[10]*t[2]+e[14];return this._dirty=!0,this},eulerFromQuat:function(e,t){Ot.eulerFromQuat(this,e,t)},eulerFromMat3:function(e,t){Ot.eulerFromMat3(this,e,t)},toString:function(){return"["+Array.prototype.join.call(this.array,",")+"]"},toArray:function(){return Array.prototype.slice.call(this.array)}};var It=Object.defineProperty;if(It){var Ft=Ot.prototype;It(Ft,"x",{get:function(){return this.array[0]},set:function(e){this.array[0]=e,this._dirty=!0}}),It(Ft,"y",{get:function(){return this.array[1]},set:function(e){this.array[1]=e,this._dirty=!0}}),It(Ft,"z",{get:function(){return this.array[2]},set:function(e){this.array[2]=e,this._dirty=!0}})}Ot.add=function(e,t,r){return Dt.add(e.array,t.array,r.array),e._dirty=!0,e},Ot.set=function(e,t,r,n){Dt.set(e.array,t,r,n),e._dirty=!0},Ot.copy=function(e,t){return Dt.copy(e.array,t.array),e._dirty=!0,e},Ot.cross=function(e,t,r){return Dt.cross(e.array,t.array,r.array),e._dirty=!0,e},Ot.dist=function(e,t){return Dt.distance(e.array,t.array)},Ot.distance=Ot.dist,Ot.div=function(e,t,r){return Dt.divide(e.array,t.array,r.array),e._dirty=!0,e},Ot.divide=Ot.div,Ot.dot=function(e,t){return Dt.dot(e.array,t.array)},Ot.len=function(e){return Dt.length(e.array)},Ot.lerp=function(e,t,r,n){return Dt.lerp(e.array,t.array,r.array,n),e._dirty=!0,e},Ot.min=function(e,t,r){return Dt.min(e.array,t.array,r.array),e._dirty=!0,e},Ot.max=function(e,t,r){return Dt.max(e.array,t.array,r.array),e._dirty=!0,e},Ot.mul=function(e,t,r){return Dt.multiply(e.array,t.array,r.array),e._dirty=!0,e},Ot.multiply=Ot.mul,Ot.negate=function(e,t){return Dt.negate(e.array,t.array),e._dirty=!0,e},Ot.normalize=function(e,t){return Dt.normalize(e.array,t.array),e._dirty=!0,e},Ot.random=function(e,t){return Dt.random(e.array,t),e._dirty=!0,e},Ot.scale=function(e,t,r){return Dt.scale(e.array,t.array,r),e._dirty=!0,e},Ot.scaleAndAdd=function(e,t,r,n){return Dt.scaleAndAdd(e.array,t.array,r.array,n),e._dirty=!0,e},Ot.sqrDist=function(e,t){return Dt.sqrDist(e.array,t.array)},Ot.squaredDistance=Ot.sqrDist,Ot.sqrLen=function(e){return Dt.sqrLen(e.array)},Ot.squaredLength=Ot.sqrLen,Ot.sub=function(e,t,r){return Dt.subtract(e.array,t.array,r.array),e._dirty=!0,e},Ot.subtract=Ot.sub,Ot.transformMat3=function(e,t,r){return Dt.transformMat3(e.array,t.array,r.array),e._dirty=!0,e},Ot.transformMat4=function(e,t,r){return Dt.transformMat4(e.array,t.array,r.array),e._dirty=!0,e},Ot.transformQuat=function(e,t,r){return Dt.transformQuat(e.array,t.array,r.array),e._dirty=!0,e};var Bt=Math.atan2,Ut=Math.asin,kt=Math.abs;Ot.eulerFromQuat=function(e,t,r){e._dirty=!0,t=t.array;var n=e.array,i=t[0],o=t[1],s=t[2],u=t[3],l=i*i,c=o*o,h=s*s,f=u*u,r=(r||"XYZ").toUpperCase();switch(r){case"XYZ":n[0]=Bt(2*(i*u-o*s),f-l-c+h),n[1]=Ut(a(2*(i*s+o*u),-1,1)),n[2]=Bt(2*(s*u-i*o),f+l-c-h);break;case"YXZ":n[0]=Ut(a(2*(i*u-o*s),-1,1)),n[1]=Bt(2*(i*s+o*u),f-l-c+h),n[2]=Bt(2*(i*o+s*u),f-l+c-h);break;case"ZXY":n[0]=Ut(a(2*(i*u+o*s),-1,1)),n[1]=Bt(2*(o*u-s*i),f-l-c+h),n[2]=Bt(2*(s*u-i*o),f-l+c-h);break;case"ZYX":n[0]=Bt(2*(i*u+s*o),f-l-c+h),n[1]=Ut(a(2*(o*u-i*s),-1,1)),n[2]=Bt(2*(i*o+s*u),f+l-c-h);break;case"YZX":n[0]=Bt(2*(i*u-s*o),f-l+c-h),n[1]=Bt(2*(o*u-i*s),f+l-c-h),n[2]=Ut(a(2*(i*o+s*u),-1,1));break;case"XZY":n[0]=Bt(2*(i*u+o*s),f-l+c-h),n[1]=Bt(2*(i*s+o*u),f+l-c-h),n[2]=Ut(a(2*(s*u-i*o),-1,1));break;default:console.warn("Unkown order: "+r)}return e},Ot.eulerFromMat3=function(e,t,r){var n=t.array,i=n[0],o=n[3],s=n[6],u=n[1],l=n[4],c=n[7],h=n[2],f=n[5],d=n[8],p=e.array,r=(r||"XYZ").toUpperCase();switch(r){case"XYZ":p[1]=Ut(a(s,-1,1)),kt(s)<.99999?(p[0]=Bt(-c,d),p[2]=Bt(-o,i)):(p[0]=Bt(f,l),p[2]=0);break;case"YXZ":p[0]=Ut(-a(c,-1,1)),kt(c)<.99999?(p[1]=Bt(s,d),p[2]=Bt(u,l)):(p[1]=Bt(-h,i),p[2]=0);break;case"ZXY":p[0]=Ut(a(f,-1,1)),kt(f)<.99999?(p[1]=Bt(-h,d),p[2]=Bt(-o,l)):(p[1]=0,p[2]=Bt(u,i));break;case"ZYX":p[1]=Ut(-a(h,-1,1)),kt(h)<.99999?(p[0]=Bt(f,d),p[2]=Bt(u,i)):(p[0]=0,p[2]=Bt(-o,l));break;case"YZX":p[2]=Ut(a(u,-1,1)),kt(u)<.99999?(p[0]=Bt(-c,l),p[1]=Bt(-h,i)):(p[0]=0,p[1]=Bt(s,d));break;case"XZY":p[2]=Ut(-a(o,-1,1)),kt(o)<.99999?(p[0]=Bt(f,l),p[1]=Bt(s,i)):(p[0]=Bt(-c,d),p[1]=0);break;default:console.warn("Unkown order: "+r)}return e._dirty=!0,e},Ot.POSITIVE_X=new Ot(1,0,0),Ot.NEGATIVE_X=new Ot(-1,0,0),Ot.POSITIVE_Y=new Ot(0,1,0),Ot.NEGATIVE_Y=new Ot(0,-1,0),Ot.POSITIVE_Z=new Ot(0,0,1),Ot.NEGATIVE_Z=new Ot(0,0,-1),Ot.UP=new Ot(0,1,0),Ot.ZERO=new Ot(0,0,0);var Ht=Pt.vec3,zt=Ht.copy,Gt=Ht.set,Vt=function(e,t){this.min=e||new Ot(1/0,1/0,1/0),this.max=t||new Ot(-1/0,-1/0,-1/0),this.vertices=null};Vt.prototype={constructor:Vt,updateFromVertices:function(e){if(e.length>0){var t=this.min,r=this.max,n=t.array,i=r.array;zt(n,e[0]),zt(i,e[0]);for(var a=1;ai[0]&&(i[0]=o[0]),o[1]>i[1]&&(i[1]=o[1]),o[2]>i[2]&&(i[2]=o[2])}t._dirty=!0,r._dirty=!0}},union:function(e){var t=this.min,r=this.max;return Ht.min(t.array,t.array,e.min.array),Ht.max(r.array,r.array,e.max.array),t._dirty=!0,r._dirty=!0,this},intersection:function(e){var t=this.min,r=this.max;return Ht.max(t.array,t.array,e.min.array),Ht.min(r.array,r.array,e.max.array),t._dirty=!0,r._dirty=!0,this},intersectBoundingBox:function(e){var t=this.min.array,r=this.max.array,n=e.min.array,i=e.max.array;return!(t[0]>i[0]||t[1]>i[1]||t[2]>i[2]||r[0]=i[0]&&r[1]>=i[1]&&r[2]>=i[2]},containPoint:function(e){var t=this.min.array,r=this.max.array,n=e.array;return t[0]<=n[0]&&t[1]<=n[1]&&t[2]<=n[2]&&r[0]>=n[0]&&r[1]>=n[1]&&r[2]>=n[2]},isFinite:function(){var e=this.min.array,t=this.max.array;return isFinite(e[0])&&isFinite(e[1])&&isFinite(e[2])&&isFinite(t[0])&&isFinite(t[1])&&isFinite(t[2])},applyTransform:function(e){this.transformFrom(this,e)},transformFrom:function(){var e=Ht.create(),t=Ht.create(),r=Ht.create(),n=Ht.create(),i=Ht.create(),a=Ht.create();return function(o,s){var u=o.min.array,l=o.max.array,c=s.array;return e[0]=c[0]*u[0],e[1]=c[1]*u[0],e[2]=c[2]*u[0],t[0]=c[0]*l[0],t[1]=c[1]*l[0],t[2]=c[2]*l[0],r[0]=c[4]*u[1],r[1]=c[5]*u[1],r[2]=c[6]*u[1],n[0]=c[4]*l[1],n[1]=c[5]*l[1],n[2]=c[6]*l[1],i[0]=c[8]*u[2],i[1]=c[9]*u[2],i[2]=c[10]*u[2],a[0]=c[8]*l[2],a[1]=c[9]*l[2],a[2]=c[10]*l[2],u=this.min.array,l=this.max.array,u[0]=Math.min(e[0],t[0])+Math.min(r[0],n[0])+Math.min(i[0],a[0])+c[12],u[1]=Math.min(e[1],t[1])+Math.min(r[1],n[1])+Math.min(i[1],a[1])+c[13],u[2]=Math.min(e[2],t[2])+Math.min(r[2],n[2])+Math.min(i[2],a[2])+c[14],l[0]=Math.max(e[0],t[0])+Math.max(r[0],n[0])+Math.max(i[0],a[0])+c[12],l[1]=Math.max(e[1],t[1])+Math.max(r[1],n[1])+Math.max(i[1],a[1])+c[13],l[2]=Math.max(e[2],t[2])+Math.max(r[2],n[2])+Math.max(i[2],a[2])+c[14],this.min._dirty=!0,this.max._dirty=!0,this}}(),applyProjection:function(e){var t=this.min.array,r=this.max.array,n=e.array,i=t[0],a=t[1],o=t[2],s=r[0],u=r[1],l=t[2],c=r[0],h=r[1],f=r[2];if(1===n[15])t[0]=n[0]*i+n[12],t[1]=n[5]*a+n[13],r[2]=n[10]*o+n[14],r[0]=n[0]*c+n[12],r[1]=n[5]*h+n[13],t[2]=n[10]*f+n[14];else{var d=-1/o;t[0]=n[0]*i*d,t[1]=n[5]*a*d,r[2]=(n[10]*o+n[14])*d,d=-1/l,r[0]=n[0]*s*d,r[1]=n[5]*u*d,d=-1/f,t[2]=(n[10]*f+n[14])*d}return this.min._dirty=!0,this.max._dirty=!0,this},updateVertices:function(){var e=this.vertices;if(!e){e=[];for(var t=0;t<8;t++)e[t]=Ht.fromValues(0,0,0);this.vertices=e}var r=this.min.array,n=this.max.array;return Gt(e[0],r[0],r[1],r[2]),Gt(e[1],r[0],n[1],r[2]),Gt(e[2],n[0],r[1],r[2]),Gt(e[3],n[0],n[1],r[2]),Gt(e[4],r[0],r[1],n[2]),Gt(e[5],r[0],n[1],n[2]),Gt(e[6],n[0],r[1],n[2]),Gt(e[7],n[0],n[1],n[2]),this},copy:function(e){var t=this.min,r=this.max;return zt(t.array,e.min.array),zt(r.array,e.max.array),t._dirty=!0,r._dirty=!0,this},clone:function(){var e=new Vt;return e.copy(this),e}};var Wt=Pt.mat4,jt=Pt.vec3,Xt=Pt.mat3,qt=Pt.quat,Kt=function(){this._axisX=new Ot,this._axisY=new Ot,this._axisZ=new Ot,this.array=Wt.create(),this._dirty=!0};Kt.prototype={constructor:Kt,setArray:function(e){for(var t=0;t>t;return e+1},dispose:function(e){var t=this._cache;t.use(e.__uid__);var r=t.get("webgl_texture");r&&e.gl.deleteTexture(r),t.deleteContext(e.__uid__)},isRenderable:function(){},isPowerOfTwo:function(){}});Object.defineProperty(Qt.prototype,"width",{get:function(){return this._width},set:function(e){this._width=e}}),Object.defineProperty(Qt.prototype,"height",{get:function(){return this._height},set:function(e){this._height=e}}),Qt.BYTE=Ct.BYTE,Qt.UNSIGNED_BYTE=Ct.UNSIGNED_BYTE,Qt.SHORT=Ct.SHORT,Qt.UNSIGNED_SHORT=Ct.UNSIGNED_SHORT,Qt.INT=Ct.INT,Qt.UNSIGNED_INT=Ct.UNSIGNED_INT,Qt.FLOAT=Ct.FLOAT,Qt.HALF_FLOAT=36193,Qt.UNSIGNED_INT_24_8_WEBGL=34042,Qt.DEPTH_COMPONENT=Ct.DEPTH_COMPONENT,Qt.DEPTH_STENCIL=Ct.DEPTH_STENCIL,Qt.ALPHA=Ct.ALPHA,Qt.RGB=Ct.RGB,Qt.RGBA=Ct.RGBA,Qt.LUMINANCE=Ct.LUMINANCE,Qt.LUMINANCE_ALPHA=Ct.LUMINANCE_ALPHA,Qt.SRGB=35904,Qt.SRGB_ALPHA=35906,Qt.COMPRESSED_RGB_S3TC_DXT1_EXT=33776,Qt.COMPRESSED_RGBA_S3TC_DXT1_EXT=33777,Qt.COMPRESSED_RGBA_S3TC_DXT3_EXT=33778,Qt.COMPRESSED_RGBA_S3TC_DXT5_EXT=33779,Qt.NEAREST=Ct.NEAREST,Qt.LINEAR=Ct.LINEAR,Qt.NEAREST_MIPMAP_NEAREST=Ct.NEAREST_MIPMAP_NEAREST,Qt.LINEAR_MIPMAP_NEAREST=Ct.LINEAR_MIPMAP_NEAREST,Qt.NEAREST_MIPMAP_LINEAR=Ct.NEAREST_MIPMAP_LINEAR,Qt.LINEAR_MIPMAP_LINEAR=Ct.LINEAR_MIPMAP_LINEAR,Qt.REPEAT=Ct.REPEAT,Qt.CLAMP_TO_EDGE=Ct.CLAMP_TO_EDGE,Qt.MIRRORED_REPEAT=Ct.MIRRORED_REPEAT;var $t=function(){this.head=null,this.tail=null,this._length=0};$t.prototype.insert=function(e){var t=new $t.Entry(e);return this.insertEntry(t),t},$t.prototype.insertAt=function(e,t){if(!(e<0)){for(var r=this.head,n=0;r&&n!=e;)r=r.next,n++;if(r){var i=new $t.Entry(t),a=r.prev;a?(a.next=i,i.prev=a):this.head=i,i.next=r,r.prev=i}else this.insert(t)}},$t.prototype.insertBeforeEntry=function(e,t){var r=new $t.Entry(e),n=t.prev;n?(n.next=r,r.prev=n):this.head=r,r.next=t,t.prev=r,this._length++},$t.prototype.insertEntry=function(e){this.head?(this.tail.next=e,e.prev=this.tail,this.tail=e):this.head=this.tail=e,this._length++},$t.prototype.remove=function(e){var t=e.prev,r=e.next;t?t.next=r:this.head=r,r?r.prev=t:this.tail=t,e.next=e.prev=null,this._length--},$t.prototype.removeAt=function(e){if(!(e<0)){for(var t=this.head,r=0;t&&r!=e;)t=t.next,r++;return t?(this.remove(t),t.value):void 0}},$t.prototype.getHead=function(){if(this.head)return this.head.value},$t.prototype.getTail=function(){if(this.tail)return this.tail.value},$t.prototype.getAt=function(e){if(!(e<0)){for(var t=this.head,r=0;t&&r!=e;)t=t.next,r++;return t.value}},$t.prototype.indexOf=function(e){for(var t=this.head,r=0;t;){if(t.value===e)return r;t=t.next,r++}},$t.prototype.length=function(){return this._length},$t.prototype.isEmpty=function(){return 0===this._length},$t.prototype.forEach=function(e,t){for(var r=this.head,n=0,i=void 0!==t;r;)i?e.call(t,r.value,n):e(r.value,n),r=r.next,n++},$t.prototype.clear=function(){this.tail=this.head=null,this._length=0},$t.Entry=function(e){this.value=e,this.next=null,this.prev=null};var er=function(e){this._list=new $t,this._map={},this._maxSize=e||10};er.prototype.setMaxSize=function(e){this._maxSize=e},er.prototype.put=function(e,t){if(void 0===this._map[e]){var r=this._list.length();if(r>=this._maxSize&&r>0){var n=this._list.head;this._list.remove(n),delete this._map[n.key]}var i=this._list.insert(t);i.key=e,this._map[e]=i}},er.prototype.get=function(e){var t=this._map[e];if(void 0!==t)return t!==this._list.tail&&(this._list.remove(t),this._list.insertEntry(t)),t.value},er.prototype.remove=function(e){var t=this._map[e];void 0!==t&&(delete this._map[e],this._list.remove(t))},er.prototype.clear=function(){this._list.clear(),this._map={}};var tr={},rr={transparent:[0,0,0,0],aliceblue:[240,248,255,1],antiquewhite:[250,235,215,1],aqua:[0,255,255,1],aquamarine:[127,255,212,1],azure:[240,255,255,1],beige:[245,245,220,1],bisque:[255,228,196,1],black:[0,0,0,1],blanchedalmond:[255,235,205,1],blue:[0,0,255,1],blueviolet:[138,43,226,1],brown:[165,42,42,1],burlywood:[222,184,135,1],cadetblue:[95,158,160,1],chartreuse:[127,255,0,1],chocolate:[210,105,30,1],coral:[255,127,80,1],cornflowerblue:[100,149,237,1],cornsilk:[255,248,220,1],crimson:[220,20,60,1],cyan:[0,255,255,1],darkblue:[0,0,139,1],darkcyan:[0,139,139,1],darkgoldenrod:[184,134,11,1],darkgray:[169,169,169,1],darkgreen:[0,100,0,1],darkgrey:[169,169,169,1],darkkhaki:[189,183,107,1],darkmagenta:[139,0,139,1],darkolivegreen:[85,107,47,1],darkorange:[255,140,0,1],darkorchid:[153,50,204,1],darkred:[139,0,0,1],darksalmon:[233,150,122,1],darkseagreen:[143,188,143,1],darkslateblue:[72,61,139,1],darkslategray:[47,79,79,1],darkslategrey:[47,79,79,1],darkturquoise:[0,206,209,1],darkviolet:[148,0,211,1],deeppink:[255,20,147,1],deepskyblue:[0,191,255,1],dimgray:[105,105,105,1],dimgrey:[105,105,105,1],dodgerblue:[30,144,255,1],firebrick:[178,34,34,1],floralwhite:[255,250,240,1],forestgreen:[34,139,34,1],fuchsia:[255,0,255,1],gainsboro:[220,220,220,1],ghostwhite:[248,248,255,1],gold:[255,215,0,1],goldenrod:[218,165,32,1],gray:[128,128,128,1],green:[0,128,0,1],greenyellow:[173,255,47,1],grey:[128,128,128,1],honeydew:[240,255,240,1],hotpink:[255,105,180,1],indianred:[205,92,92,1],indigo:[75,0,130,1],ivory:[255,255,240,1],khaki:[240,230,140,1],lavender:[230,230,250,1],lavenderblush:[255,240,245,1],lawngreen:[124,252,0,1],lemonchiffon:[255,250,205,1],lightblue:[173,216,230,1],lightcoral:[240,128,128,1],lightcyan:[224,255,255,1],lightgoldenrodyellow:[250,250,210,1],lightgray:[211,211,211,1],lightgreen:[144,238,144,1],lightgrey:[211,211,211,1],lightpink:[255,182,193,1],lightsalmon:[255,160,122,1],lightseagreen:[32,178,170,1],lightskyblue:[135,206,250,1],lightslategray:[119,136,153,1],lightslategrey:[119,136,153,1],lightsteelblue:[176,196,222,1],lightyellow:[255,255,224,1],lime:[0,255,0,1],limegreen:[50,205,50,1],linen:[250,240,230,1],magenta:[255,0,255,1],maroon:[128,0,0,1],mediumaquamarine:[102,205,170,1],mediumblue:[0,0,205,1],mediumorchid:[186,85,211,1],mediumpurple:[147,112,219,1],mediumseagreen:[60,179,113,1],mediumslateblue:[123,104,238,1],mediumspringgreen:[0,250,154,1],mediumturquoise:[72,209,204,1],mediumvioletred:[199,21,133,1],midnightblue:[25,25,112,1],mintcream:[245,255,250,1],mistyrose:[255,228,225,1],moccasin:[255,228,181,1],navajowhite:[255,222,173,1],navy:[0,0,128,1],oldlace:[253,245,230,1],olive:[128,128,0,1],olivedrab:[107,142,35,1],orange:[255,165,0,1],orangered:[255,69,0,1],orchid:[218,112,214,1],palegoldenrod:[238,232,170,1],palegreen:[152,251,152,1],paleturquoise:[175,238,238,1],palevioletred:[219,112,147,1],papayawhip:[255,239,213,1],peachpuff:[255,218,185,1],peru:[205,133,63,1],pink:[255,192,203,1],plum:[221,160,221,1],powderblue:[176,224,230,1],purple:[128,0,128,1],red:[255,0,0,1],rosybrown:[188,143,143,1],royalblue:[65,105,225,1],saddlebrown:[139,69,19,1],salmon:[250,128,114,1],sandybrown:[244,164,96,1],seagreen:[46,139,87,1],seashell:[255,245,238,1],sienna:[160,82,45,1],silver:[192,192,192,1],skyblue:[135,206,235,1],slateblue:[106,90,205,1],slategray:[112,128,144,1],slategrey:[112,128,144,1],snow:[255,250,250,1],springgreen:[0,255,127,1],steelblue:[70,130,180,1],tan:[210,180,140,1],teal:[0,128,128,1],thistle:[216,191,216,1],tomato:[255,99,71,1],turquoise:[64,224,208,1],violet:[238,130,238,1],wheat:[245,222,179,1],white:[255,255,255,1],whitesmoke:[245,245,245,1],yellow:[255,255,0,1],yellowgreen:[154,205,50,1]},nr=new er(20),ir=null;tr.parse=function(e,t){if(e){t=t||[];var r=nr.get(e);if(r)return p(t,r);e+="";var n=e.replace(/ /g,"").toLowerCase();if(n in rr)return p(t,rr[n]),m(e,t),t;if("#"!==n.charAt(0)){var i=n.indexOf("("),a=n.indexOf(")");if(-1!==i&&a+1===n.length){var o=n.substr(0,i),s=n.substr(i+1,a-(i+1)).split(","),u=1;switch(o){case"rgba":if(4!==s.length)return void d(t,0,0,0,1);u=c(s.pop());case"rgb":return 3!==s.length?void d(t,0,0,0,1):(d(t,l(s[0]),l(s[1]),l(s[2]),u),m(e,t),t);case"hsla":return 4!==s.length?void d(t,0,0,0,1):(s[3]=c(s[3]),_(s,t),m(e,t),t);case"hsl":return 3!==s.length?void d(t,0,0,0,1):(_(s,t),m(e,t),t);default:return}}d(t,0,0,0,1)}else{if(4===n.length){var h=parseInt(n.substr(1),16);return h>=0&&h<=4095?(d(t,(3840&h)>>4|(3840&h)>>8,240&h|(240&h)>>4,15&h|(15&h)<<4,1),m(e,t),t):void d(t,0,0,0,1)}if(7===n.length){var h=parseInt(n.substr(1),16);return h>=0&&h<=16777215?(d(t,(16711680&h)>>16,(65280&h)>>8,255&h,1),m(e,t),t):void d(t,0,0,0,1)}}}},tr.parseToFloat=function(e,t){if(t=tr.parse(e,t))return t[0]/=255,t[1]/=255,t[2]/=255,t},tr.lift=function(e,t){var r=tr.parse(e);if(r){for(var n=0;n<3;n++)r[n]=t<0?r[n]*(1-t)|0:(255-r[n])*t+r[n]|0;return tr.stringify(r,4===r.length?"rgba":"rgb")}},tr.toHex=function(e){var t=tr.parse(e);if(t)return((1<<24)+(t[0]<<16)+(t[1]<<8)+ +t[2]).toString(16).slice(1)},tr.fastLerp=function(e,t,r){if(t&&t.length&&e>=0&&e<=1){r=r||[];var n=e*(t.length-1),i=Math.floor(n),a=Math.ceil(n),s=t[i],l=t[a],c=n-i;return r[0]=o(f(s[0],l[0],c)),r[1]=o(f(s[1],l[1],c)),r[2]=o(f(s[2],l[2],c)),r[3]=u(f(s[3],l[3],c)),r}},tr.fastMapToColor=tr.fastLerp,tr.lerp=function(e,t,r){if(t&&t.length&&e>=0&&e<=1){var n=e*(t.length-1),i=Math.floor(n),a=Math.ceil(n),s=tr.parse(t[i]),l=tr.parse(t[a]),c=n-i,h=tr.stringify([o(f(s[0],l[0],c)),o(f(s[1],l[1],c)),o(f(s[2],l[2],c)),u(f(s[3],l[3],c))],"rgba");return r?{color:h,leftIndex:i,rightIndex:a,value:n}:h}},tr.mapToColor=tr.lerp,tr.modifyHSL=function(e,t,r,n){if(e=tr.parse(e))return e=v(e),null!=t&&(e[0]=s(t)),null!=r&&(e[1]=c(r)),null!=n&&(e[2]=c(n)),tr.stringify(_(e),"rgba")},tr.modifyAlpha=function(e,t){if((e=tr.parse(e))&&null!=t)return e[3]=u(t),tr.stringify(e,"rgba")},tr.stringify=function(e,t){if(e&&e.length){var r=e[0]+","+e[1]+","+e[2];return"rgba"!==t&&"hsva"!==t&&"hsla"!==t||(r+=","+e[3]),t+"("+r+")"}};var ar=tr.parseToFloat,or={},sr=At.extend(function(){return{name:"",depthTest:!0,depthMask:!0,transparent:!1,blend:null,autoUpdateTextureStatus:!0,uniforms:{},vertexDefines:{},fragmentDefines:{},_textureStatus:{},_enabledUniforms:null}},function(){ +this.name||(this.name="MATERIAL_"+this.__uid__),this.shader&&this.attachShader(this.shader,!0)},{precision:"highp",setUniform:function(e,t){void 0===t&&console.warn('Uniform value "'+e+'" is undefined');var r=this.uniforms[e];r&&("string"==typeof t&&(t=ar(t)||t),r.value=t,this.autoUpdateTextureStatus&&"t"===r.type&&(t?this.enableTexture(e):this.disableTexture(e)))},setUniforms:function(e){for(var t in e){var r=e[t];this.setUniform(t,r)}},isUniformEnabled:function(e){return this._enabledUniforms.indexOf(e)>=0},getEnabledUniforms:function(){return this._enabledUniforms},getTextureUniforms:function(){return this._textureUniforms},set:function(e,t){if("object"==typeof e)for(var r in e){var n=e[r];this.setUniform(r,n)}else this.setUniform(e,t)},get:function(e){var t=this.uniforms[e];if(t)return t.value},attachShader:function(e,t){var r=this.uniforms;this.uniforms=e.createUniforms(),this.shader=e;var n=this.uniforms;this._enabledUniforms=Object.keys(n),this._enabledUniforms.sort(),this._textureUniforms=this._enabledUniforms.filter(function(e){var t=this.uniforms[e].type;return"t"===t||"tv"===t},this);var i=this.vertexDefines,a=this.fragmentDefines;if(this.vertexDefines=bt.clone(e.vertexDefines),this.fragmentDefines=bt.clone(e.fragmentDefines),t){for(var o in r)n[o]&&(n[o].value=r[o].value);bt.defaults(this.vertexDefines,i),bt.defaults(this.fragmentDefines,a)}var s={};for(var u in e.textures)s[u]={shaderType:e.textures[u].shaderType,type:e.textures[u].type,enabled:!(!t||!this._textureStatus[u])&&this._textureStatus[u].enabled};this._textureStatus=s,this._programKey=""},clone:function(){var e=new this.constructor({name:this.name,shader:this.shader});for(var t in this.uniforms)e.uniforms[t].value=this.uniforms[t].value;return e.depthTest=this.depthTest,e.depthMask=this.depthMask,e.transparent=this.transparent,e.blend=this.blend,e.vertexDefines=bt.clone(this.vertexDefines),e.fragmentDefines=bt.clone(this.fragmentDefines),e.enableTexture(this.getEnabledTextures()),e.precision=this.precision,e},define:function(e,t,r){var n=this.vertexDefines,i=this.fragmentDefines;"vertex"!==e&&"fragment"!==e&&"both"!==e&&arguments.length<3&&(r=t,t=e,e="both"),r=null!=r?r:null,"vertex"!==e&&"both"!==e||n[t]!==r&&(n[t]=r,this._programKey=""),"fragment"!==e&&"both"!==e||i[t]!==r&&(i[t]=r,"both"!==e&&(this._programKey=""))},undefine:function(e,t){"vertex"!==e&&"fragment"!==e&&"both"!==e&&arguments.length<2&&(t=e,e="both"),"vertex"!==e&&"both"!==e||this.isDefined("vertex",t)&&(delete this.vertexDefines[t],this._programKey=""),"fragment"!==e&&"both"!==e||this.isDefined("fragment",t)&&(delete this.fragmentDefines[t],"both"!==e&&(this._programKey=""))},isDefined:function(e,t){switch(e){case"vertex":return void 0!==this.vertexDefines[t];case"fragment":return void 0!==this.fragmentDefines[t]}},getDefine:function(e,t){switch(e){case"vertex":return this.vertexDefines[t];case"fragment":return this.fragmentDefines[t]}},enableTexture:function(e){if(Array.isArray(e))for(var t=0;t=0)this.attributeSemantics[r]={symbol:e,type:t};else if(Sr.indexOf(r)>=0){var n=!1,i=r;r.match(/TRANSPOSE$/)&&(n=!0,i=r.slice(0,-9)),this.matrixSemantics[r]={symbol:e,type:t,isTranspose:n,semanticNoTranspose:i}}else Ar.indexOf(r)>=0&&(this.uniformSemantics[r]={symbol:e,type:t})},_addMaterialUniform:function(e,t,r,n,i,a){a[e]={type:r,value:i?Er.array:n||Er[t],semantic:null}},_parseUniforms:function(){function e(e){return null!=e?function(){return e}:null}function t(t,a,o){var s=M(a,o),u=[];for(var l in s){var c=s[l],h=c.semantic,f=l,d=Tr[a],p=e(s[l].value);s[l].isArray&&(f+="["+s[l].arraySize+"]",d+="v"),u.push(f),n._uniformList.push(l),c.ignore||("sampler2D"!==a&&"samplerCube"!==a||(n.textures[l]={shaderType:i,type:a}),h?n._addSemanticUniform(l,d,h):n._addMaterialUniform(l,a,d,p,s[l].isArray,r))}return u.length>0?"uniform "+a+" "+u.join(",")+";\n":""}var r={},n=this,i="vertex";this._uniformList=[],this._vertexCode=this._vertexCode.replace(gr,t),i="fragment",this._fragmentCode=this._fragmentCode.replace(gr,t),n.matrixSemanticKeys=Object.keys(this.matrixSemantics),this.uniformTemplates=r},_parseAttributes:function(){function e(e,n,i){var a=M(n,i),o=wr[n]||1,s=[];for(var u in a){var l=a[u].semantic;if(t[u]={type:"float",size:o,semantic:l||null},l){if(br.indexOf(l)<0)throw new Error('Unkown semantic "'+l+'"');r.attributeSemantics[l]={symbol:u,type:n}}s.push(u)}return"attribute "+n+" "+s.join(",")+";\n"}var t={},r=this;this._vertexCode=this._vertexCode.replace(yr,e),this.attributes=t},_parseDefines:function(){function e(e,n,i){var a="vertex"===r?t.vertexDefines:t.fragmentDefines;return a[n]||(a[n]="false"!==i&&("true"===i||(i?isNaN(parseFloat(i))?i.trim():parseFloat(i):null))),""}var t=this,r="vertex";this._vertexCode=this._vertexCode.replace(xr,e),r="fragment",this._fragmentCode=this._fragmentCode.replace(xr,e)},clone:function(){var e=Rr[this._shaderID];return new L(e.vertex,e.fragment)}},Object.defineProperty&&(Object.defineProperty(L.prototype,"shaderID",{get:function(){return this._shaderID}}),Object.defineProperty(L.prototype,"vertex",{get:function(){return this._vertexCode}}),Object.defineProperty(L.prototype,"fragment",{get:function(){return this._fragmentCode}}),Object.defineProperty(L.prototype,"uniforms",{get:function(){return this._uniformList}}));var Nr=/(@import)\s*([0-9a-zA-Z_\-\.]*)/g;L.parseImport=function(e){return e=e.replace(Nr,function(e,t,r){var e=L.source(r);return e?L.parseImport(e):(console.error('Shader chunk "'+r+'" not existed in library'),"")})};var Mr=/(@export)\s*([0-9a-zA-Z_\-\.]*)\s*\n([\s\S]*?)@end/g;L.import=function(e){e.replace(Mr,function(e,t,r,n){var n=n.replace(/(^[\s\t\xa0\u3000]+)|([\u3000\xa0\s\t]+\x24)/g,"");if(n){for(var i,a=r.split("."),o=L.codes,s=0;s0&&this.setViewport(this._viewportStack.pop())},saveClear:function(){this._clearStack.push({clearBit:this.clearBit,clearColor:this.clearColor})},restoreClear:function(){if(this._clearStack.length>0){var e=this._clearStack.pop();this.clearColor=e.clearColor,this.clearBit=e.clearBit}},bindSceneRendering:function(e){this._sceneRendering=e},render:function(e,t,r,n){var i=this.gl,a=this.clearColor;if(this.clearBit){i.colorMask(!0,!0,!0,!0),i.depthMask(!0);var o=this.viewport,s=!1,u=o.devicePixelRatio;(o.width!==this._width||o.height!==this._height||u&&u!==this.devicePixelRatio||o.x||o.y)&&(s=!0,i.enable(i.SCISSOR_TEST),i.scissor(o.x*u,o.y*u,o.width*u,o.height*u)),i.clearColor(a[0],a[1],a[2],a[3]),i.clear(this.clearBit),s&&i.disable(i.SCISSOR_TEST)}if(r||e.update(!1),e.updateLights(),!(t=t||e.getMainCamera()))return void console.error("Can't find camera in the scene.");t.update();var l=e.updateRenderList(t);this._sceneRendering=e;var c=l.opaque,h=l.transparent,f=e.material;e.trigger("beforerender",this,e,t,l),n?(this.renderPreZ(c,e,t),i.depthFunc(i.LEQUAL)):i.depthFunc(i.LESS);for(var d=Fr(),p=Ir.create(),m=0;m0){var s=e[i-1],u=s.joints?s.joints.length:0;if((a.joints?a.joints.length:0)===u&&a.material===s.material&&a.lightGroup===s.lightGroup){a.__program=s.__program;continue}}var l=this._programMgr.getProgram(a,o,t);this.validateProgram(l),a.__program=l}},renderPass:function(e,t,r){this.trigger("beforerenderpass",this,e,t,r),r=r||{},r.getMaterial=r.getMaterial||P,r.beforeRender=r.beforeRender||D,r.afterRender=r.afterRender||D,this.updatePrograms(e,this._sceneRendering,r),r.sortCompare&&e.sort(r.sortCompare);var n=this.viewport,i=n.devicePixelRatio,a=[n.x*i,n.y*i,n.width*i,n.height*i],o=this.devicePixelRatio,s=this.__currentFrameBuffer?[this.__currentFrameBuffer.getTextureWidth(),this.__currentFrameBuffer.getTextureHeight()]:[this._width*o,this._height*o],u=[a[2],a[3]],l=Date.now();Or.copy(Hr.VIEW,t.viewMatrix.array),Or.copy(Hr.PROJECTION,t.projectionMatrix.array),Or.multiply(Hr.VIEWPROJECTION,t.projectionMatrix.array,Hr.VIEW),Or.copy(Hr.VIEWINVERSE,t.worldTransform.array),Or.invert(Hr.PROJECTIONINVERSE,Hr.PROJECTION),Or.invert(Hr.VIEWPROJECTIONINVERSE,Hr.VIEWPROJECTION);for(var c,h,f,d,p,m,_,v,g,y,x=this.gl,T=this._sceneRendering,E=this.getGLExtension("OES_vertex_array_object"),b=0;bthis.distance,i=1;i<8;i++)if(Zr.dot(t[i].array,r)>this.distance!=n)return!0},intersectLine:function(){var e=Zr.create();return function(t,r,n){var i=this.distanceToPoint(t),a=this.distanceToPoint(r);if(i>0&&a>0||i<0&&a<0)return null;var o=this.normal.array,s=this.distance,u=t.array;Zr.sub(e,r.array,t.array),Zr.normalize(e,e);var l=Zr.dot(o,e);if(0===l)return null;n||(n=new Ot);var c=(Zr.dot(o,u)-s)/l;return Zr.scaleAndAdd(n.array,u,e,-c),n._dirty=!0,n}}(),applyTransform:function(){var e=Jr.create(),t=Qr.create(),r=Qr.create();return r[3]=1,function(n){n=n.array,Zr.scale(r,this.normal.array,this.distance),Qr.transformMat4(r,r,n),this.distance=Zr.dot(r,this.normal.array),Jr.invert(e,n),Jr.transpose(e,e),t[3]=0,Zr.copy(t,this.normal.array),Qr.transformMat4(t,t,e),Zr.copy(this.normal.array,t)}}(),copy:function(e){Zr.copy(this.normal.array,e.normal.array),this.normal._dirty=!0,this.distance=e.distance},clone:function(){var e=new $r;return e.copy(this),e}};var en=Pt.vec3,tn=en.set,rn=en.copy,nn=en.transformMat4,an=Math.min,on=Math.max,sn=function(){this.planes=[];for(var e=0;e<6;e++)this.planes.push(new $r);this.boundingBox=new Vt,this.vertices=[];for(var e=0;e<8;e++)this.vertices[e]=en.fromValues(0,0,0)};sn.prototype={setFromProjection:function(e){var t=this.planes,r=e.array,n=r[0],i=r[1],a=r[2],o=r[3],s=r[4],u=r[5],l=r[6],c=r[7],h=r[8],f=r[9],d=r[10],p=r[11],m=r[12],_=r[13],v=r[14],g=r[15];tn(t[0].normal.array,o-n,c-s,p-h),t[0].distance=-(g-m),t[0].normalize(),tn(t[1].normal.array,o+n,c+s,p+h),t[1].distance=-(g+m),t[1].normalize(),tn(t[2].normal.array,o+i,c+u,p+f),t[2].distance=-(g+_),t[2].normalize(),tn(t[3].normal.array,o-i,c-u,p-f),t[3].distance=-(g-_),t[3].normalize(),tn(t[4].normal.array,o-a,c-l,p-d),t[4].distance=-(g-v),t[4].normalize(),tn(t[5].normal.array,o+a,c+l,p+d),t[5].distance=-(g+v),t[5].normalize();var y=this.boundingBox,x=this.vertices;if(0===g){var T=u/n,E=-v/(d-1),b=-v/(d+1),A=-b/u,S=-E/u;y.min.set(-A*T,-A,b),y.max.set(A*T,A,E),tn(x[0],-A*T,-A,b),tn(x[1],-A*T,A,b),tn(x[2],A*T,-A,b),tn(x[3],A*T,A,b),tn(x[4],-S*T,-S,E),tn(x[5],-S*T,S,E),tn(x[6],S*T,-S,E),tn(x[7],S*T,S,E)}else{var w=(-1-m)/n,C=(1-m)/n,R=(1-_)/u,N=(-1-_)/u,M=(-1-v)/d,L=(1-v)/d;y.min.set(Math.min(w,C),Math.min(N,R),Math.min(L,M)),y.max.set(Math.max(C,w),Math.max(R,N),Math.max(M,L));var P=y.min.array,D=y.max.array;tn(x[0],P[0],P[1],P[2]),tn(x[1],P[0],D[1],P[2]),tn(x[2],D[0],P[1],P[2]),tn(x[3],D[0],D[1],P[2]),tn(x[4],P[0],P[1],D[2]),tn(x[5],P[0],D[1],D[2]),tn(x[6],D[0],P[1],D[2]),tn(x[7],D[0],D[1],D[2])}},getTransformedBoundingBox:function(){var e=en.create();return function(t,r){var n=this.vertices,i=r.array,a=t.min,o=t.max,s=a.array,u=o.array,l=n[0];nn(e,l,i),rn(s,e),rn(u,e);for(var c=1;c<8;c++)l=n[c],nn(e,l,i),s[0]=an(e[0],s[0]),s[1]=an(e[1],s[1]),s[2]=an(e[2],s[2]),u[0]=on(e[0],u[0]),u[1]=on(e[1],u[1]),u[2]=on(e[2],u[2]);return a._dirty=!0,o._dirty=!0,t}}()};var un=Pt.vec3,ln=function(e,t){this.origin=e||new Ot,this.direction=t||new Ot};ln.prototype={constructor:ln,intersectPlane:function(e,t){var r=e.normal.array,n=e.distance,i=this.origin.array,a=this.direction.array,o=un.dot(r,a);if(0===o)return null;t||(t=new Ot);var s=(un.dot(r,i)-n)/o;return un.scaleAndAdd(t.array,i,a,-s),t._dirty=!0,t},mirrorAgainstPlane:function(e){var t=un.dot(e.normal.array,this.direction.array);un.scaleAndAdd(this.direction.array,this.direction.array,e.normal.array,2*-t),this.direction._dirty=!0},distanceToPoint:function(){var e=un.create();return function(t){un.sub(e,t,this.origin.array);var r=un.dot(e,this.direction.array);if(r<0)return un.distance(this.origin.array,t);var n=un.lenSquared(e);return Math.sqrt(n-r*r)}}(),intersectSphere:function(){var e=un.create();return function(t,r,n){var i=this.origin.array,a=this.direction.array;t=t.array,un.sub(e,t,i);var o=un.dot(e,a),s=un.squaredLength(e),u=s-o*o,l=r*r;if(!(u>l)){var c=Math.sqrt(l-u),h=o-c,f=o+c;return n||(n=new Ot),h<0?f<0?null:(un.scaleAndAdd(n.array,i,a,f),n):(un.scaleAndAdd(n.array,i,a,h),n)}}}(),intersectBoundingBox:function(e,t){var r,n,i,a,o,s,u=this.direction.array,l=this.origin.array,c=e.min.array,h=e.max.array,f=1/u[0],d=1/u[1],p=1/u[2];if(f>=0?(r=(c[0]-l[0])*f,n=(h[0]-l[0])*f):(n=(c[0]-l[0])*f,r=(h[0]-l[0])*f),d>=0?(i=(c[1]-l[1])*d,a=(h[1]-l[1])*d):(a=(c[1]-l[1])*d,i=(h[1]-l[1])*d),r>a||i>n)return null;if((i>r||r!==r)&&(r=i),(a=0?(o=(c[2]-l[2])*p,s=(h[2]-l[2])*p):(s=(c[2]-l[2])*p,o=(h[2]-l[2])*p),r>s||o>n)return null;if((o>r||r!==r)&&(r=o),(s=0?r:n;return t||(t=new Ot),un.scaleAndAdd(t.array,l,u,m),t},intersectTriangle:function(){var e=un.create(),t=un.create(),r=un.create(),n=un.create();return function(i,a,o,s,u,l){var c=this.direction.array,h=this.origin.array;i=i.array,a=a.array,o=o.array,un.sub(e,a,i),un.sub(t,o,i),un.cross(n,t,c);var f=un.dot(e,n);if(s){if(f>-1e-5)return null}else if(f>-1e-5&&f<1e-5)return null;un.sub(r,h,i);var d=un.dot(n,r)/f;if(d<0||d>1)return null;un.cross(n,e,r);var p=un.dot(c,n)/f;if(p<0||p>1||d+p>1)return null;un.cross(n,e,t);var m=-un.dot(r,n)/f;return m<0?null:(u||(u=new Ot),l&&Ot.set(l,1-d-p,d,p),un.scaleAndAdd(u.array,h,c,m),u)}}(),applyTransform:function(e){Ot.add(this.direction,this.direction,this.origin),Ot.transformMat4(this.origin,this.origin,e),Ot.transformMat4(this.direction,this.direction,e),Ot.sub(this.direction,this.direction,this.origin),Ot.normalize(this.direction,this.direction)},copy:function(e){Ot.copy(this.origin,e.origin),Ot.copy(this.direction,e.direction)},clone:function(){var e=new ln;return e.copy(this),e}};var cn=Pt.vec3,hn=Pt.vec4,fn=Kr.extend(function(){return{projectionMatrix:new Kt,invProjectionMatrix:new Kt,viewMatrix:new Kt,frustum:new sn}},function(){this.update(!0)},{update:function(e){Kr.prototype.update.call(this,e),Kt.invert(this.viewMatrix,this.worldTransform),this.updateProjectionMatrix(),Kt.invert(this.invProjectionMatrix,this.projectionMatrix),this.frustum.setFromProjection(this.projectionMatrix)},setViewMatrix:function(e){Kt.copy(this.viewMatrix,e),Kt.invert(this.worldTransform,e),this.decomposeWorldTransform()},decomposeProjectionMatrix:function(){},setProjectionMatrix:function(e){Kt.copy(this.projectionMatrix,e),Kt.invert(this.invProjectionMatrix,e),this.decomposeProjectionMatrix()},updateProjectionMatrix:function(){},castRay:function(){var e=hn.create();return function(t,r){var n=void 0!==r?r:new ln,i=t.array[0],a=t.array[1];return hn.set(e,i,a,-1,1),hn.transformMat4(e,e,this.invProjectionMatrix.array),hn.transformMat4(e,e,this.worldTransform.array),cn.scale(n.origin.array,e,1/e[3]),hn.set(e,i,a,1,1),hn.transformMat4(e,e,this.invProjectionMatrix.array),hn.transformMat4(e,e,this.worldTransform.array),cn.scale(e,e,1/e[3]),cn.sub(n.direction.array,e,n.origin.array),cn.normalize(n.direction.array,n.direction.array),n.direction._dirty=!0,n.origin._dirty=!0,n}}()}),dn=Pt.mat4,pn=dn.create(),mn=dn.create(),_n={};B.prototype.startCount=function(){this._opaqueCount=0,this._transparentCount=0},B.prototype.add=function(e,t){t?this.transparent[this._transparentCount++]=e:this.opaque[this._opaqueCount++]=e},B.prototype.endCount=function(){this.transparent.length=this._transparentCount,this.opaque.length=this._opaqueCount};var vn=Kr.extend(function(){return{material:null,lights:[],viewBoundingBoxLastFrame:new Vt,shadowUniforms:{},_cameraList:[],_lightUniforms:{},_previousLightNumber:{},_lightNumber:{},_lightProgramKeys:{},_nodeRepository:{},_renderLists:new er(20)}},function(){this._scene=this},{addToScene:function(e){e instanceof fn?(this._cameraList.length>0&&console.warn("Found multiple camera in one scene. Use the fist one."),this._cameraList.push(e)):e instanceof Yr&&this.lights.push(e),e.name&&(this._nodeRepository[e.name]=e)},removeFromScene:function(e){var t;e instanceof fn?(t=this._cameraList.indexOf(e))>=0&&this._cameraList.splice(t,1):e instanceof Yr&&(t=this.lights.indexOf(e))>=0&&this.lights.splice(t,1),e.name&&delete this._nodeRepository[e.name]},getNode:function(e){return this._nodeRepository[e]},setMainCamera:function(e){var t=this._cameraList.indexOf(e);t>=0&&this._cameraList.splice(t,1),this._cameraList.unshift(e)},getMainCamera:function(){return this._cameraList[0]},getLights:function(){return this.lights},updateLights:function(){var e=this.lights;this._previousLightNumber=this._lightNumber;for(var t={},r=0;r0&&this._doUpdateRenderList(a,t,r,n)}},isFrustumCulled:function(){var e=new Vt,t=new Kt;return function(r,n,i){var a=r.boundingBox||r.geometry.boundingBox;if(t.array=i,e.transformFrom(a,t),r.castShadow&&this.viewBoundingBoxLastFrame.union(e),r.frustumCulling&&!r.isSkinnedMesh()){if(!e.intersectBoundingBox(n.frustum.boundingBox))return!0;t.array=n.projectionMatrix.array,e.max.array[2]>0&&e.min.array[2]<0&&(e.max.array[2]=-1e-20),e.applyProjection(t);var o=e.min.array,s=e.max.array;if(s[0]<-1||o[0]>1||s[1]<-1||o[1]>1||s[2]<-1||o[2]>1)return!0}return!1}}(),_updateLightUniforms:function(){var e=this.lights;e.sort(U);var t=this._lightUniforms;for(var r in t)for(var n in t[r])t[r][n].value.length=0;for(var i=0;i0},beforeRender:function(e){},afterRender:function(e,t){},getBoundingBox:function(e,t){return t=Kr.prototype.getBoundingBox.call(this,e,t),this.geometry&&this.geometry.boundingBox&&t.union(this.geometry.boundingBox),t},clone:function(){var e=["castShadow","receiveShadow","mode","culling","cullFace","frontFace","frustumCulling","renderOrder","lineWidth","ignorePicking","ignorePreZ","ignoreGBuffer"];return function(){var t=Kr.prototype.clone.call(this);t.geometry=this.geometry,t.material=this.material;for(var r=0;r>1,e|=e>>2,e|=e>>4,e|=e>>8,e|=e>>16,++e},Cn.nearestPowerOfTwo=function(e){return Math.pow(2,Math.round(Math.log(e)/Math.LN2))};var Rn=Cn.isPowerOfTwo,Nn=Qt.extend(function(){return{image:null,pixels:null,mipmaps:[],convertToPOT:!1}},{textureType:"texture2D",update:function(e){var t=e.gl;t.bindTexture(t.TEXTURE_2D,this._cache.get("webgl_texture")),this.updateCommon(e);var r=this.format,n=this.type,i=!(!this.convertToPOT||this.mipmaps.length||!this.image||this.wrapS!==Qt.REPEAT&&this.wrapT!==Qt.REPEAT||!this.NPOT);t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,i?this.wrapS:this.getAvailableWrapS()),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,i?this.wrapT:this.getAvailableWrapT()),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,i?this.magFilter:this.getAvailableMagFilter()),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,i?this.minFilter:this.getAvailableMinFilter());var a=e.getGLExtension("EXT_texture_filter_anisotropic");if(a&&this.anisotropic>1&&t.texParameterf(t.TEXTURE_2D,a.TEXTURE_MAX_ANISOTROPY_EXT,this.anisotropic),36193===n){e.getGLExtension("OES_texture_half_float")||(n=Ct.FLOAT)}if(this.mipmaps.length)for(var o=this.width,s=this.height,u=0;u=Qt.COMPRESSED_RGB_S3TC_DXT1_EXT?e.compressedTexImage2D(e.TEXTURE_2D,r,a,n,i,0,t.pixels):e.texImage2D(e.TEXTURE_2D,r,a,n,i,0,a,o,t.pixels)},generateMipmap:function(e){var t=e.gl;this.useMipmap&&!this.NPOT&&(t.bindTexture(t.TEXTURE_2D,this._cache.get("webgl_texture")),t.generateMipmap(t.TEXTURE_2D))},isPowerOfTwo:function(){return Rn(this.width)&&Rn(this.height)},isRenderable:function(){return this.image?"CANVAS"===this.image.nodeName||"VIDEO"===this.image.nodeName||this.image.complete:!(!this.width||!this.height)},bind:function(e){e.gl.bindTexture(e.gl.TEXTURE_2D,this.getWebGLTexture(e))},unbind:function(e){e.gl.bindTexture(e.gl.TEXTURE_2D,null)},load:function(e,t){var r=new Image;t&&(r.crossOrigin=t);var n=this;return r.onload=function(){n.dirty(),n.trigger("success",n),r.onload=null},r.onerror=function(){n.trigger("error",n),r.onerror=null},r.src=e,this.image=r,this}});Object.defineProperty(Nn.prototype,"width",{get:function(){return this.image?this.image.width:this._width},set:function(e){this.image?console.warn("Texture from image can't set width"):(this._width!==e&&this.dirty(),this._width=e)}}),Object.defineProperty(Nn.prototype,"height",{get:function(){return this.image?this.image.height:this._height},set:function(e){this.image?console.warn("Texture from image can't set height"):(this._height!==e&&this.dirty(),this._height=e)}});var Mn=wn.extend({skeleton:null,joints:null,useSkinMatricesTexture:!1},function(){this.joints||(this.joints=[])},{isSkinnedMesh:function(){return!!(this.skeleton&&this.joints&&this.joints.length>0)},getSkinMatricesTexture:function(){return this._skinMatricesTexture=this._skinMatricesTexture||new Nn({type:Ct.FLOAT,minFilter:Ct.NEAREST,magFilter:Ct.NEAREST,useMipmap:!1,flipY:!1}),this._skinMatricesTexture},clone:function(){var e=wn.prototype.clone.call(this);return e.skeleton=this.skeleton,this.joints&&(e.joints=this.joints.slice()),e}});Mn.POINTS=Ct.POINTS,Mn.LINES=Ct.LINES,Mn.LINE_LOOP=Ct.LINE_LOOP,Mn.LINE_STRIP=Ct.LINE_STRIP,Mn.TRIANGLES=Ct.TRIANGLES,Mn.TRIANGLE_STRIP=Ct.TRIANGLE_STRIP,Mn.TRIANGLE_FAN=Ct.TRIANGLE_FAN,Mn.BACK=Ct.BACK,Mn.FRONT=Ct.FRONT,Mn.FRONT_AND_BACK=Ct.FRONT_AND_BACK,Mn.CW=Ct.CW,Mn.CCW=Ct.CCW;var Ln={};z.prototype.get=function(e){var t=e;if(this._pool[t])return this._pool[t];var r=Ln[e];if(!r)return void console.error('Shader "'+e+'" is not in the library');var n=new L(r.vertex,r.fragment);return this._pool[t]=n,n},z.prototype.clear=function(){this._pool={}};var Pn=new z,Dn={createLibrary:function(){return new z},get:function(){return Pn.get.apply(Pn,arguments)},template:G,clear:function(){return Pn.clear()}},On=At.extend({name:"",index:-1,node:null}),In=Pt.quat,Fn=Pt.vec3,Bn=Pt.mat4,Un=At.extend(function(){return{relativeRootNode:null,name:"",joints:[],_clips:[],_invBindPoseMatricesArray:null,_jointMatricesSubArrays:[],_skinMatricesArray:null,_skinMatricesSubArrays:[],_subSkinMatricesArray:{}}},{addClip:function(e,t){for(var r=0;r0&&this._clips.splice(t,1)},removeClipsAll:function(){this._clips=[]},getClip:function(e){if(this._clips[e])return this._clips[e].clip},getClipNumber:function(){return this._clips.length},updateJointMatrices:function(){var e=Bn.create();return function(){this._invBindPoseMatricesArray=new Float32Array(16*this.joints.length),this._skinMatricesArray=new Float32Array(16*this.joints.length);for(var t=0;t0?(this._restartInLoop(e),this._loopRemained--,"restart"):(this._needsRemove=!0,"finish"):null}}},setTime:function(e){return this.step(e+this._startTime)},restart:function(e){var t=0;e&&(this._elapse(e),t=this._elapsedTime%this.life),e=e||Date.now(),this._startTime=e-t+this.delay,this._elapsedTime=0,this._needsRemove=!1,this._paused=!1},getElapsedTime:function(){return this._elapsedTime},_restartInLoop:function(e){this._startTime=e+this.gap,this._elapsedTime=0},_elapse:function(e,t){this._elapsedTime+=t*this.playbackRate},fire:function(e,t){var r="on"+e;this[r]&&this[r](this.target,t)},clone:function(){var e=new this.constructor;return e.name=this.name,e._loop=this._loop,e._loopRemained=this._loopRemained,e.life=this.life,e.gap=this.gap,e.delay=this.delay,e},pause:function(){this._paused=!0},resume:function(){this._paused=!1}},Gn.prototype.constructor=Gn;var Vn=Pt.quat,Wn=Pt.vec3,jn=function(e){e=e||{},Gn.call(this,e),this.tracks=e.tracks||[],this.calcLifeFromTracks()};jn.prototype=Object.create(Gn.prototype),jn.prototype.constructor=jn,jn.prototype.step=function(e,t,r){var n=Gn.prototype.step.call(this,e,t,!0);if("finish"!==n){var e=this.getElapsedTime();this._range&&(e=this._range[0]+e),this.setTime(e)}return r||"paused"===n||this.fire("frame"),n},jn.prototype.setRange=function(e){this.calcLifeFromTracks(),this._range=e,e&&(e[1]=Math.min(e[1],this.life),e[0]=Math.min(e[0],this.life),this.life=e[1]-e[0])},jn.prototype.setTime=function(e){for(var t=0;t=0&&this.tracks.splice(t,1)},jn.prototype.getSubClip=function(e,t,r){for(var n=new jn({name:this.name}),i=0;i=t.time[r-1])e=t.time[r-1],n=r-2;else if(e=0;a--)if(t.time[a-1]<=e&&t.time[a]>e){n=a-1;break}}else for(var a=this._cacheKey;ae){n=a;break}if(n>-1){this._cacheKey=n,this._cacheTime=e;var o=n,s=n+1,u=t.time[o],l=t.time[s],c=l-u,h=0===c?0:(e-u)/c;t.rotation&&j(this.rotation,t.rotation,t.rotation,h,4*o,4*s),t.position&&W(this.position,t.position,t.position,h,3*o,3*s),t.scale&&W(this.scale,t.scale,t.scale,h,3*o,3*s)}n===r-2&&(this._cacheKey=0,this._cacheTime=0),this.updateTarget()}},Kn.prototype.updateTarget=function(){var e=this.channels;this.target&&(e.position&&this.target.position.setArray(this.position),e.rotation&&this.target.rotation.setArray(this.rotation),e.scale&&this.target.scale.setArray(this.scale))},Kn.prototype.getMaxTime=function(){return this.channels.time[this.channels.time.length-1]},Kn.prototype.getSubTrack=function(e,t){var r=new Kn({name:this.name}),n=this.channels.time[0];e=Math.min(Math.max(e,n),this.life),t=Math.min(Math.max(t,n),this.life);var i=this._findRange(e),a=this._findRange(t),o=a[0]-i[0]+1;0===i[1]&&0===a[1]&&(o-=1),this.channels.rotation&&(r.channels.rotation=new Float32Array(4*o)),this.channels.position&&(r.channels.position=new Float32Array(3*o)),this.channels.scale&&(r.channels.scale=new Float32Array(3*o)),this.channels.time&&(r.channels.time=new Float32Array(o)),this.setTime(e);for(var s=0;s<3;s++)r.channels.rotation[s]=this.rotation[s],r.channels.position[s]=this.position[s],r.channels.scale[s]=this.scale[s];r.channels.time[0]=0,r.channels.rotation[3]=this.rotation[3];for(var s=1;se&&(n=i);var a=0;if(n>=0)var o=t.time[n],s=t.time[n+1],a=(e-o)/(s-o);return[n,a]},Kn.prototype.blend1D=function(e,t,r){qn.lerp(this.position,e.position,t.position,r),qn.lerp(this.scale,e.scale,t.scale,r),Xn.slerp(this.rotation,e.rotation,t.rotation,r)},Kn.prototype.blend2D=function(){var e=Xn.create(),t=Xn.create();return function(r,n,i,a,o){var s=1-a-o;this.position[0]=r.position[0]*s+n.position[0]*a+i.position[0]*o,this.position[1]=r.position[1]*s+n.position[1]*a+i.position[1]*o,this.position[2]=r.position[2]*s+n.position[2]*a+i.position[2]*o,this.scale[0]=r.scale[0]*s+n.scale[0]*a+i.scale[0]*o,this.scale[1]=r.scale[1]*s+n.scale[1]*a+i.scale[1]*o,this.scale[2]=r.scale[2]*s+n.scale[2]*a+i.scale[2]*o;var u=a+o;0===u?Xn.copy(this.rotation,r.rotation):(Xn.slerp(e,r.rotation,n.rotation,u),Xn.slerp(t,r.rotation,i.rotation,u),Xn.slerp(this.rotation,e,t,o/u))}}(),Kn.prototype.additiveBlend=function(e,t){qn.add(this.position,e.position,t.position),qn.add(this.scale,e.scale,t.scale),Xn.multiply(this.rotation,t.rotation,e.rotation)},Kn.prototype.subtractiveBlend=function(e,t){qn.sub(this.position,e.position,t.position),qn.sub(this.scale,e.scale,t.scale),Xn.invert(this.rotation,t.rotation),Xn.multiply(this.rotation,this.rotation,e.rotation)},Kn.prototype.clone=function(){var e=Kn.prototype.clone.call(this);return e.channels={time:this.channels.time||null,position:this.channels.position||null,rotation:this.channels.rotation||null,scale:this.channels.scale||null},qn.copy(e.position,this.position),Xn.copy(e.rotation,this.rotation),qn.copy(e.scale,this.scale),e.target=this.target,e.updateTarget(),e};var Yn=Pt.vec3,Zn=Pt.mat4,Jn=Yn.create,Qn=Yn.add,$n=Yn.set;K.prototype.init=function(e){if(!this.value||this.value.length!=e*this.size){var t=X(this.type);this.value=new t(e*this.size)}},K.prototype.fromArray=function(e){var t,r=X(this.type);if(e[0]&&e[0].length){var n=0,i=this.size;t=new r(e.length*i);for(var a=0;aa[0]&&(a[0]=s),u>a[1]&&(a[1]=u),l>a[2]&&(a[2]=l)}r._dirty=!0,n._dirty=!0}},dirty:function(){for(var e=this.getEnabledAttributes(),t=0;t=0){t||(t=Jn());var r=this.indices;return t[0]=r[3*e],t[1]=r[3*e+1],t[2]=r[3*e+2],t}},setTriangleIndices:function(e,t){var r=this.indices;r[3*e]=t[0],r[3*e+1]=t[1],r[3*e+2]=t[2]},isUseIndices:function(){return!!this.indices},initIndicesFromArray:function(e){var t,r=this.vertexCount>65535?Mt.Uint32Array:Mt.Uint16Array;if(e[0]&&e[0].length){var n=0;t=new r(3*e.length);for(var i=0;i=0&&(t.splice(r,1),delete this.attributes[e],!0)},getAttribute:function(e){return this.attributes[e]},getEnabledAttributes:function(){var e=this._enabledAttributes,t=this._attributeList;if(e)return e;for(var r=[],n=this.vertexCount,i=0;i65535&&(this.indices=new Mt.Uint32Array(this.indices));for(var e=this.attributes,t=this.indices,r=this.getEnabledAttributes(),n={},i=0;i 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.y) * weight.y;\n}\nif (weight.z > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.z) * weight.z;\n}\nfloat weightW = 1.0-weight.x-weight.y-weight.z;\nif (weightW > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.w) * weightW;\n}\n@end\n@export clay.util.parallax_correct\nvec3 parallaxCorrect(in vec3 dir, in vec3 pos, in vec3 boxMin, in vec3 boxMax) {\n vec3 first = (boxMax - pos) / dir;\n vec3 second = (boxMin - pos) / dir;\n vec3 further = max(first, second);\n float dist = min(further.x, min(further.y, further.z));\n vec3 fixedPos = pos + dir * dist;\n vec3 boxCenter = (boxMax + boxMin) * 0.5;\n return normalize(fixedPos - boxCenter);\n}\n@end\n@export clay.util.clamp_sample\nvec4 clampSample(const in sampler2D texture, const in vec2 coord)\n{\n#ifdef STEREO\n float eye = step(0.5, coord.x) * 0.5;\n vec2 coordClamped = clamp(coord, vec2(eye, 0.0), vec2(0.5 + eye, 1.0));\n#else\n vec2 coordClamped = clamp(coord, vec2(0.0), vec2(1.0));\n#endif\n return texture2D(texture, coordClamped);\n}\n@end\n@export clay.util.ACES\nvec3 ACESToneMapping(vec3 color)\n{\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\n@end"),L.import("@export clay.basic.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec2 texcoord : TEXCOORD_0;\nattribute vec3 position : POSITION;\nattribute vec3 barycentric;\n@import clay.chunk.skinning_header\nvarying vec2 v_Texcoord;\nvarying vec3 v_Barycentric;\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n#endif\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_Barycentric = barycentric;\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n}\n@end\n@export clay.basic.fragment\nvarying vec2 v_Texcoord;\nuniform sampler2D diffuseMap;\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\nvarying vec3 v_Barycentric;\n@import clay.util.edge_factor\n@import clay.util.rgbm\n@import clay.util.srgb\n@import clay.util.ACES\nvoid main()\n{\n#ifdef RENDER_TEXCOORD\n gl_FragColor = vec4(v_Texcoord, 1.0, 1.0);\n return;\n#endif\n gl_FragColor = vec4(color, alpha);\n#ifdef VERTEX_COLOR\n gl_FragColor *= v_Color;\n#endif\n#ifdef DIFFUSEMAP_ENABLED\n vec4 texel = decodeHDR(texture2D(diffuseMap, v_Texcoord));\n#ifdef SRGB_DECODE\n texel = sRGBToLinear(texel);\n#endif\n#if defined(DIFFUSEMAP_ALPHA_ALPHA)\n gl_FragColor.a = texel.a;\n#endif\n gl_FragColor.rgb *= texel.rgb;\n#endif\n gl_FragColor.rgb += emission;\n if( lineWidth > 0.)\n {\n gl_FragColor.rgb = mix(gl_FragColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (gl_FragColor.a < alphaCutoff) {\n discard;\n }\n#endif\n#ifdef TONEMAPPING\n gl_FragColor.rgb = ACESToneMapping(gl_FragColor.rgb);\n#endif\n#ifdef SRGB_ENCODE\n gl_FragColor = linearTosRGB(gl_FragColor);\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n}\n@end"),L.import("\n@export clay.lambert.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\nattribute vec3 normal : NORMAL;\nattribute vec3 barycentric;\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n#endif\n@import clay.chunk.skinning_header\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nvarying vec3 v_Barycentric;\nvoid main()\n{\n vec3 skinnedPosition = position;\n vec3 skinnedNormal = normal;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4( skinnedPosition, 1.0 );\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_Normal = normalize( ( worldInverseTranspose * vec4(skinnedNormal, 0.0) ).xyz );\n v_WorldPosition = ( world * vec4( skinnedPosition, 1.0) ).xyz;\n v_Barycentric = barycentric;\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n}\n@end\n@export clay.lambert.fragment\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nuniform sampler2D diffuseMap;\nuniform sampler2D alphaMap;\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\nvarying vec3 v_Barycentric;\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\n#ifdef AMBIENT_LIGHT_COUNT\n@import clay.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import clay.header.ambient_sh_light\n#endif\n#ifdef POINT_LIGHT_COUNT\n@import clay.header.point_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n#ifdef SPOT_LIGHT_COUNT\n@import clay.header.spot_light\n#endif\n@import clay.util.calculate_attenuation\n@import clay.util.edge_factor\n@import clay.util.rgbm\n@import clay.plugin.compute_shadow_map\n@import clay.util.ACES\nvoid main()\n{\n#ifdef RENDER_NORMAL\n gl_FragColor = vec4(v_Normal * 0.5 + 0.5, 1.0);\n return;\n#endif\n#ifdef RENDER_TEXCOORD\n gl_FragColor = vec4(v_Texcoord, 1.0, 1.0);\n return;\n#endif\n gl_FragColor = vec4(color, alpha);\n#ifdef VERTEX_COLOR\n gl_FragColor *= v_Color;\n#endif\n#ifdef DIFFUSEMAP_ENABLED\n vec4 tex = texture2D( diffuseMap, v_Texcoord );\n#ifdef SRGB_DECODE\n tex.rgb = pow(tex.rgb, vec3(2.2));\n#endif\n gl_FragColor.rgb *= tex.rgb;\n#ifdef DIFFUSEMAP_ALPHA_ALPHA\n gl_FragColor.a *= tex.a;\n#endif\n#endif\n vec3 diffuseColor = vec3(0.0, 0.0, 0.0);\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {\n diffuseColor += ambientLightColor[_idx_];\n }\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseColor += calcAmbientSHLight(_idx_, v_Normal) * ambientSHLightColor[_idx_];\n }}\n#endif\n#ifdef POINT_LIGHT_COUNT\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsPoint[POINT_LIGHT_COUNT];\n if( shadowEnabled )\n {\n computeShadowOfPointLights(v_WorldPosition, shadowContribsPoint);\n }\n#endif\n for(int i = 0; i < POINT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = pointLightPosition[i];\n vec3 lightColor = pointLightColor[i];\n float range = pointLightRange[i];\n vec3 lightDirection = lightPosition - v_WorldPosition;\n float dist = length(lightDirection);\n float attenuation = lightAttenuation(dist, range);\n lightDirection /= dist;\n float ndl = dot( v_Normal, lightDirection );\n float shadowContrib = 1.0;\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsPoint[i];\n }\n#endif\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * attenuation * shadowContrib;\n }\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++)\n {\n vec3 lightDirection = -directionalLightDirection[i];\n vec3 lightColor = directionalLightColor[i];\n float ndl = dot(v_Normal, normalize(lightDirection));\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsDir[i];\n }\n#endif\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * shadowContrib;\n }\n#endif\n#ifdef SPOT_LIGHT_COUNT\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsSpot[SPOT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfSpotLights(v_WorldPosition, shadowContribsSpot);\n }\n#endif\n for(int i = 0; i < SPOT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = -spotLightPosition[i];\n vec3 spotLightDirection = -normalize( spotLightDirection[i] );\n vec3 lightColor = spotLightColor[i];\n float range = spotLightRange[i];\n float a = spotLightUmbraAngleCosine[i];\n float b = spotLightPenumbraAngleCosine[i];\n float falloffFactor = spotLightFalloffFactor[i];\n vec3 lightDirection = lightPosition - v_WorldPosition;\n float dist = length(lightDirection);\n float attenuation = lightAttenuation(dist, range);\n lightDirection /= dist;\n float c = dot(spotLightDirection, lightDirection);\n float falloff;\n falloff = clamp((c - a) /( b - a), 0.0, 1.0);\n falloff = pow(falloff, falloffFactor);\n float ndl = dot(v_Normal, lightDirection);\n ndl = clamp(ndl, 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsSpot[i];\n }\n#endif\n diffuseColor += lightColor * ndl * attenuation * (1.0-falloff) * shadowContrib;\n }\n#endif\n gl_FragColor.rgb *= diffuseColor;\n gl_FragColor.rgb += emission;\n if(lineWidth > 0.)\n {\n gl_FragColor.rgb = mix(gl_FragColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (gl_FragColor.a < alphaCutoff) {\n discard;\n }\n#endif\n#ifdef TONEMAPPING\n gl_FragColor.rgb = ACESToneMapping(gl_FragColor.rgb);\n#endif\n#ifdef SRGB_ENCODE\n gl_FragColor = linearTosRGB(gl_FragColor);\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n}\n@end"),L.import(gn),L.import("@export clay.wireframe.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 world : WORLD;\nattribute vec3 position : POSITION;\nattribute vec3 barycentric;\n@import clay.chunk.skinning_header\nvarying vec3 v_Barycentric;\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0 );\n v_Barycentric = barycentric;\n}\n@end\n@export clay.wireframe.fragment\nuniform vec3 color : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\nuniform float lineWidth : 1.0;\nvarying vec3 v_Barycentric;\n@import clay.util.edge_factor\nvoid main()\n{\n gl_FragColor.rgb = color;\n gl_FragColor.a = (1.0-edgeFactor(lineWidth)) * alpha;\n}\n@end"),L.import(ti),L.import(Dr),Dn.template("clay.basic",L.source("clay.basic.vertex"),L.source("clay.basic.fragment")),Dn.template("clay.lambert",L.source("clay.lambert.vertex"),L.source("clay.lambert.fragment")),Dn.template("clay.wireframe",L.source("clay.wireframe.vertex"),L.source("clay.wireframe.fragment")),Dn.template("clay.skybox",L.source("clay.skybox.vertex"),L.source("clay.skybox.fragment")),Dn.template("clay.prez",L.source("clay.prez.vertex"),L.source("clay.prez.fragment")),Dn.template("clay.standard",L.source("clay.standard.vertex"),L.source("clay.standard.fragment")),Dn.template("clay.standardMR",L.source("clay.standardMR.vertex"),L.source("clay.standardMR.fragment"));var ri={NORMAL:"normal",POSITION:"position",TEXCOORD_0:"texcoord0",TEXCOORD_1:"texcoord1",WEIGHTS_0:"weight",JOINTS_0:"joint",COLOR_0:"color"},ni={5120:Mt.Int8Array,5121:Mt.Uint8Array,5122:Mt.Int16Array,5123:Mt.Uint16Array,5125:Mt.Uint32Array,5126:Mt.Float32Array},ii={SCALAR:1,VEC2:2,VEC3:3,VEC4:4,MAT2:4,MAT3:9,MAT4:16},ai=At.extend({rootNode:null,rootPath:null,textureRootPath:null,bufferRootPath:null,shader:"clay.standard",useStandardMaterial:!1,includeCamera:!0,includeAnimation:!0,includeMesh:!0,includeTexture:!0,crossOrigin:"",textureFlipY:!1,textureConvertToPOT:!1,shaderLibrary:null},function(){this.shaderLibrary||(this.shaderLibrary=Dn.createLibrary())},{load:function(e){var t=this,r=e.endsWith(".glb");null==this.rootPath&&(this.rootPath=e.slice(0,e.lastIndexOf("/"))),zr.get({url:e,onprogress:function(e,r,n){t.trigger("progress",e,r,n)},onerror:function(e){t.trigger("error",e)},responseType:r?"arraybuffer":"text",onload:function(e){r?t.parseBinary(e):t.parse(JSON.parse(e))}})},parseBinary:function(e){var t=new Uint32Array(e,0,4);if(1179937895!==t[0])return void this.trigger("error","Invalid glTF binary format: Invalid header");if(t[0]<2)return void this.trigger("error","Only glTF2.0 is supported.");for(var r,n=new DataView(e,12),i=[],a=0;a=0&&this._clips.splice(t,1)},removeAnimator:function(e){for(var t=e.getClips(),r=0;r=65535?new Uint32Array(3*f):new Uint16Array(3*f);for(var _=0,v=0,g=n.isUseIndices(),y=0;y0;){for(var _=[],v=[],g=[],y=0,f=0;f=0&&-1===v[S]&&(y65535?new Uint32Array(3*M.triangles.length):new Uint16Array(3*M.triangles.length);var H=0;O=0;for(var f=0;f=0?L[S]:-1}O++}P.indices[H++]=R[b]}P.updateBoundingBox(),w.add(D)}for(var j=e.children(),f=0;f=0&&x[g]>1e-4&&(vi.transformMat4(b,y,_[T[g]]),vi.scaleAndAdd(E,E,b,x[g]));A.set(v,E)}}for(var v=0;v1&&t.texParameterf(t.TEXTURE_CUBE_MAP,i.TEXTURE_MAX_ANISOTROPY_EXT,this.anisotropic),36193===n){e.getGLExtension("OES_texture_half_float")||(n=Ct.FLOAT)}if(this.mipmaps.length)for(var a=this.width,o=this.height,s=0;s65535?Uint32Array:Uint16Array,p=this.indices=new d(t*e*6),m=this.radius,_=this.phiStart,v=this.phiLength,g=this.thetaStart,y=this.thetaLength,m=this.radius,x=[],T=[],E=0,b=1/m;for(f=0;f<=e;f++)for(h=0;h<=t;h++)l=h/t,c=f/e,o=-m*Math.cos(_+l*v)*Math.sin(g+c*y),s=m*Math.cos(g+c*y),u=m*Math.sin(_+l*v)*Math.sin(g+c*y),x[0]=o,x[1]=s,x[2]=u,T[0]=l,T[1]=c,r.set(E,x),n.set(E,T),x[0]*=b,x[1]*=b,x[2]*=b,i.set(E,x),E++;var A,S,w,C,R=t+1,N=0;for(f=0;f=i)){a+=2;for(var o="";a20)return console.warn("Given image is not a height map"),e}var f,d,p,m;u%(4*n)==0?(f=o.data[u],p=o.data[u+4]):u%(4*n)==4*(n-1)?(f=o.data[u-4],p=o.data[u]):(f=o.data[u-4],p=o.data[u+4]),u<4*n?(d=o.data[u],m=o.data[u+4*n]):u>n*(i-1)*4?(d=o.data[u-4*n],m=o.data[u]):(d=o.data[u-4*n],m=o.data[u+4*n]),s.data[u]=f-p+127,s.data[u+1]=d-m+127,s.data[u+2]=255,s.data[u+3]=255}return a.putImageData(s,0,0),r},isHeightImage:function(e,t,r){if(!e||!e.width||!e.height)return!1;var n=document.createElement("canvas"),i=n.getContext("2d"),a=t||32;r=r||20,n.width=n.height=a,i.drawImage(e,0,0,a,a);for(var o=i.getImageData(0,0,a,a),s=0;sr)return!1}return!0},_fetchTexture:function(e,t,r){zr.get({url:e,responseType:"arraybuffer",onload:t,onerror:r})},createChessboard:function(e,t,r,n){e=e||512,t=t||64,r=r||"black",n=n||"white";var i=Math.ceil(e/t),a=document.createElement("canvas");a.width=e,a.height=e;var o=a.getContext("2d");o.fillStyle=n,o.fillRect(0,0,e,e),o.fillStyle=r;for(var s=0;s=r.COLOR_ATTACHMENT0&&a<=r.COLOR_ATTACHMENT0+8&&i.push(a);n.drawBuffersEXT(i)}}this.trigger("beforerender",this,e);var o=this.clearDepth?r.DEPTH_BUFFER_BIT:0;if(r.depthMask(!0),this.clearColor){o|=r.COLOR_BUFFER_BIT,r.colorMask(!0,!0,!0,!0);var s=this.clearColor;Array.isArray(s)&&r.clearColor(s[0],s[1],s[2],s[3])}r.clear(o),this.blendWithPrevious?(r.enable(r.BLEND),this.material.transparent=!0):(r.disable(r.BLEND),this.material.transparent=!1),this.renderQuad(e),this.trigger("afterrender",this,e),t&&this.unbind(e,t)},renderQuad:function(e){zi.material=this.material,e.renderPass([zi],Gi)},dispose:function(e){}}),Wi=function(){this._pool={},this._allocatedTextures=[]};Wi.prototype={constructor:Wi,get:function(e){var t=ye(e);this._pool.hasOwnProperty(t)||(this._pool[t]=[]);var r=this._pool[t];if(!r.length){var n=new Nn(e);return this._allocatedTextures.push(n),n}return r.pop()},put:function(e){var t=ye(e);this._pool.hasOwnProperty(t)||(this._pool[t]=[]),this._pool[t].push(e)},clear:function(e){for(var t=0;t= shadowCascadeClipsNear[_idx_] &&\n depth <= shadowCascadeClipsFar[_idx_]\n ) {\n shadowContrib = computeShadowContrib(\n directionalLightShadowMaps[0], directionalLightMatrices[_idx_], position,\n directionalLightShadowMapSizes[0],\n vec2(1.0 / float(SHADOW_CASCADE), 1.0),\n vec2(float(_idx_) / float(SHADOW_CASCADE), 0.0)\n );\n shadowContribs[0] = shadowContrib;\n }\n }}\n for(int _idx_ = DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#else\nvoid computeShadowOfDirectionalLights(vec3 position, inout float shadowContribs[DIRECTIONAL_LIGHT_COUNT]){\n float shadowContrib;\n for(int _idx_ = 0; _idx_ < DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n shadowContrib = computeShadowContrib(\n directionalLightShadowMaps[_idx_], directionalLightMatrices[_idx_], position,\n directionalLightShadowMapSizes[_idx_]\n );\n shadowContribs[_idx_] = shadowContrib;\n }}\n for(int _idx_ = DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#endif\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\nvoid computeShadowOfPointLights(vec3 position, inout float shadowContribs[POINT_LIGHT_COUNT] ){\n vec3 lightPosition;\n vec3 direction;\n for(int _idx_ = 0; _idx_ < POINT_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n lightPosition = pointLightPosition[_idx_];\n direction = position - lightPosition;\n shadowContribs[_idx_] = computeShadowContribOmni(pointLightShadowMaps[_idx_], direction, pointLightRange[_idx_]);\n }}\n for(int _idx_ = POINT_LIGHT_SHADOWMAP_COUNT; _idx_ < POINT_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#endif\n@end");var Yi=At.extend(function(){return{softShadow:Yi.PCF,shadowBlur:1,lightFrustumBias:"auto",kernelPCF:new Float32Array([1,0,1,1,-1,1,0,1,-1,0,-1,-1,1,-1,0,-1]),precision:"highp",_lastRenderNotCastShadow:!1,_frameBuffer:new wi,_textures:{},_shadowMapNumber:{POINT_LIGHT:0,DIRECTIONAL_LIGHT:0,SPOT_LIGHT:0},_depthMaterials:{},_distanceMaterials:{},_receivers:[],_lightsCastShadow:[],_lightCameras:{},_lightMaterials:{},_texturePool:new Wi}},function(){this._gaussianPassH=new Vi({fragment:L.source("clay.compositor.gaussian_blur")}),this._gaussianPassV=new Vi({fragment:L.source("clay.compositor.gaussian_blur")}),this._gaussianPassH.setUniform("blurSize",this.shadowBlur),this._gaussianPassH.setUniform("blurDir",0),this._gaussianPassV.setUniform("blurSize",this.shadowBlur),this._gaussianPassV.setUniform("blurDir",1),this._outputDepthPass=new Vi({fragment:L.source("clay.sm.debug_depth")})},{render:function(e,t,r,n){r||(r=t.getMainCamera()),this.trigger("beforerender",this,e,t,r),this._renderShadowPass(e,t,r,n),this.trigger("afterrender",this,e,t,r)},renderDebug:function(e,t){e.saveClear();var r=e.viewport,n=0,i=t||r.width/4,a=i;this.softShadow===Yi.VSM?this._outputDepthPass.material.define("fragment","USE_VSM"):this._outputDepthPass.material.undefine("fragment","USE_VSM");for(var o in this._textures){var s=this._textures[o];e.setViewport(n,0,i*s.width/s.height,a),this._outputDepthPass.setUniform("depthMap",s),this._outputDepthPass.render(e),n+=i*s.width/s.height}e.setViewport(r),e.restoreClear()},_updateReceivers:function(e,t){if(t.receiveShadow?(this._receivers.push(t),t.material.set("shadowEnabled",1),t.material.set("pcfKernel",this.kernelPCF)):t.material.set("shadowEnabled",0),this.softShadow===Yi.VSM)t.material.define("fragment","USE_VSM"),t.material.undefine("fragment","PCF_KERNEL_SIZE");else{t.material.undefine("fragment","USE_VSM");var r=this.kernelPCF;r&&r.length?t.material.define("fragment","PCF_KERNEL_SIZE",r.length/2):t.material.undefine("fragment","PCF_KERNEL_SIZE")}},_update:function(e,t){var r=this;t.traverse(function(t){t.isRenderable()&&r._updateReceivers(e,t)});for(var n=0;n4){console.warn("Support at most 4 cascade");continue}m.shadowCascade>1&&(s=m),this.renderDirectionalLightShadow(e,t,r,m,f,h,c)}else"SPOT_LIGHT"===m.type?this.renderSpotLightShadow(e,t,m,l,u):"POINT_LIGHT"===m.type&&this.renderPointLightShadow(e,t,m,d);this._shadowMapNumber[m.type]++}for(var _ in this._shadowMapNumber)for(var v=this._shadowMapNumber[_],g=_+"_SHADOWMAP_COUNT",p=0;p0?x.define("fragment",g,v):x.isDefined("fragment",g)&&x.undefine("fragment",g))}for(var p=0;p0){var E=c.map(i);if(T.directionalLightShadowMaps={value:c,type:"tv"},T.directionalLightMatrices={value:h,type:"m4v"},T.directionalLightShadowMapSizes={value:E,type:"1fv"},s){var b=f.slice(),A=f.slice();b.pop(),A.shift(),b.reverse(),A.reverse(),h.reverse(),T.shadowCascadeClipsNear={value:b,type:"1fv"},T.shadowCascadeClipsFar={value:A,type:"1fv"}}}if(u.length>0){var S=u.map(i),T=t.shadowUniforms;T.spotLightShadowMaps={value:u,type:"tv"},T.spotLightMatrices={value:l,type:"m4v"},T.spotLightShadowMapSizes={value:S,type:"1fv"}}d.length>0&&(T.pointLightShadowMaps={value:d,type:"tv"})}},renderDirectionalLightShadow:function(){var e=new sn,t=new Kt,r=new Vt,n=new Kt,i=new Kt,a=new Kt,o=new Kt;return function(s,u,l,c,h,f,d){var p=this._getDepthMaterial(c),m={getMaterial:function(e){return e.shadowDepthMaterial||p},ifRender:function(e){return e.castShadow},sortCompare:kr.opaqueSortCompare};if(!u.viewBoundingBoxLastFrame.isFinite()){var _=u.getBoundingBox();u.viewBoundingBoxLastFrame.copy(_).applyTransform(l.viewMatrix)}var v=Math.min(-u.viewBoundingBoxLastFrame.min.z,l.far),g=Math.max(-u.viewBoundingBoxLastFrame.max.z,l.near),y=this._getDirectionalLightCamera(c,u,l),x=a.array;o.copy(y.projectionMatrix),qi.invert(i.array,y.worldTransform.array),qi.multiply(i.array,i.array,l.worldTransform.array),qi.multiply(x,o.array,i.array);for(var T=[],E=l instanceof kn,b=(l.near+l.far)/(l.near-l.far),A=2*l.near*l.far/(l.near-l.far),S=0;S<=c.shadowCascade;S++){var w=g*Math.pow(v/g,S/c.shadowCascade),C=g+(v-g)*S/c.shadowCascade,R=w*c.cascadeSplitLogFactor+C*(1-c.cascadeSplitLogFactor);T.push(R),h.push(-(-R*b+A)/-R)}var N=this._getTexture(c,c.shadowCascade);d.push(N);var M=s.viewport,L=s.gl;this._frameBuffer.attach(N),this._frameBuffer.bind(s),L.clear(L.COLOR_BUFFER_BIT|L.DEPTH_BUFFER_BIT);for(var S=0;Sf?s>d?p[i>0?"px":"nx"]=!0:p[o>0?"pz":"nz"]=!0:f>d?p[a>0?"py":"ny"]=!0:p[o>0?"pz":"nz"]=!0}for(var r=0;r0){var t=this.outputs[e];t.keepLastFrame?(this._prevOutputTextures[e]&&this._compositor.releaseTexture(this._prevOutputTextures[e]),this._prevOutputTextures[e]=this._outputTextures[e]):this._compositor.releaseTexture(this._outputTextures[e])}}}),Ji=At.extend(function(){return{nodes:[]}},{dirty:function(){this._dirty=!0},addNode:function(e){this.nodes.indexOf(e)>=0||(this.nodes.push(e),this._dirty=!0)},removeNode:function(e){"string"==typeof e&&(e=this.getNodeByName(e));var t=this.nodes.indexOf(e);t>=0&&(this.nodes.splice(t,1),this._dirty=!0)},getNodeByName:function(e){for(var t=0;t=t.COLOR_ATTACHMENT0&&u<=t.COLOR_ATTACHMENT0+8&&c.push(u);l.drawBuffersEXT(c)}e.saveClear(),e.clearBit=Ct.DEPTH_BUFFER_BIT|Ct.COLOR_BUFFER_BIT,r=e.render(this.scene,this.camera,!this.autoUpdateScene,this.preZ),e.restoreClear(),n.unbind(e)}else r=e.render(this.scene,this.camera,!this.autoUpdateScene,this.preZ);this.trigger("afterrender",r),this._rendering=!1,this._rendered=!0}}),ea=Zi.extend(function(){return{texture:null,outputs:{color:{}}}},function(){},{getOutput:function(e,t){return this.texture},beforeFrame:function(){},afterFrame:function(){}}),ta=Zi.extend(function(){return{name:"",inputs:{},outputs:null,shader:"",inputLinks:{},outputLinks:{},pass:null,_prevOutputTextures:{},_outputTextures:{},_outputReferences:{},_rendering:!1,_rendered:!1,_compositor:null}},function(){var e=new Vi({fragment:this.shader});this.pass=e},{render:function(e,t){this.trigger("beforerender",e),this._rendering=!0;var r=e.gl;for(var n in this.inputLinks){var i=this.inputLinks[n],a=i.node.getOutput(e,i.pin);this.pass.setUniform(n,a)}if(this.outputs){this.pass.outputs={};var o={};for(var s in this.outputs){var u=this.updateParameter(s,e);isNaN(u.width)&&this.updateParameter(s,e);var l=this.outputs[s],c=this._compositor.allocateTexture(u);this._outputTextures[s]=c;var h=l.attachment||r.COLOR_ATTACHMENT0;"string"==typeof h&&(h=r[h]),o[h]=c}this._compositor.getFrameBuffer().bind(e);for(var h in o)this._compositor.getFrameBuffer().attach(o[h],h);this.pass.render(e),this._compositor.getFrameBuffer().updateMipmap(e.gl)}else this.pass.outputs=null,this._compositor.getFrameBuffer().unbind(e),this.pass.render(e,t);for(var n in this.inputLinks){var i=this.inputLinks[n];i.node.removeReference(i.pin)}this._rendering=!1,this._rendered=!0,this.trigger("afterrender",e)},updateParameter:function(e,t){var r=this.outputs[e],n=r.parameters,i=r._parametersCopy;if(i||(i=r._parametersCopy={}),n)for(var a in n)"width"!==a&&"height"!==a&&(i[a]=n[a]);var o,s;return o=n.width instanceof Function?n.width.call(this,t):n.width,s=n.height instanceof Function?n.height.call(this,t):n.height,i.width===o&&i.height===s||this._outputTextures[e]&&this._outputTextures[e].dispose(t),i.width=o,i.height=s,i},setParameter:function(e,t){this.pass.setUniform(e,t)},getParameter:function(e){return this.pass.getUniform(e)},setParameters:function(e){for(var t in e)this.setParameter(t,e[t])},define:function(e,t){this.pass.material.define("fragment",e,t)},undefine:function(e){this.pass.material.undefine("fragment",e)},removeReference:function(e){if(0===--this._outputReferences[e]){this.outputs[e].keepLastFrame?(this._prevOutputTextures[e]&&this._compositor.releaseTexture(this._prevOutputTextures[e]),this._prevOutputTextures[e]=this._outputTextures[e]):this._compositor.releaseTexture(this._outputTextures[e])}},clear:function(){Zi.prototype.clear.call(this),this.pass.material.disableTexturesAll()}}),ra="@export clay.compositor.kernel.gaussian_9\nfloat gaussianKernel[9];\ngaussianKernel[0] = 0.07;\ngaussianKernel[1] = 0.09;\ngaussianKernel[2] = 0.12;\ngaussianKernel[3] = 0.14;\ngaussianKernel[4] = 0.16;\ngaussianKernel[5] = 0.14;\ngaussianKernel[6] = 0.12;\ngaussianKernel[7] = 0.09;\ngaussianKernel[8] = 0.07;\n@end\n@export clay.compositor.kernel.gaussian_13\nfloat gaussianKernel[13];\ngaussianKernel[0] = 0.02;\ngaussianKernel[1] = 0.03;\ngaussianKernel[2] = 0.06;\ngaussianKernel[3] = 0.08;\ngaussianKernel[4] = 0.11;\ngaussianKernel[5] = 0.13;\ngaussianKernel[6] = 0.14;\ngaussianKernel[7] = 0.13;\ngaussianKernel[8] = 0.11;\ngaussianKernel[9] = 0.08;\ngaussianKernel[10] = 0.06;\ngaussianKernel[11] = 0.03;\ngaussianKernel[12] = 0.02;\n@end\n@export clay.compositor.gaussian_blur\n#define SHADER_NAME gaussian_blur\nuniform sampler2D texture;varying vec2 v_Texcoord;\nuniform float blurSize : 2.0;\nuniform vec2 textureSize : [512.0, 512.0];\nuniform float blurDir : 0.0;\n@import clay.util.rgbm\n@import clay.util.clamp_sample\nvoid main (void)\n{\n @import clay.compositor.kernel.gaussian_9\n vec2 off = blurSize / textureSize;\n off *= vec2(1.0 - blurDir, blurDir);\n vec4 sum = vec4(0.0);\n float weightAll = 0.0;\n for (int i = 0; i < 9; i++) {\n float w = gaussianKernel[i];\n vec4 texel = decodeHDR(clampSample(texture, v_Texcoord + float(i - 4) * off));\n sum += texel * w;\n weightAll += w;\n }\n gl_FragColor = encodeHDR(sum / max(weightAll, 0.01));\n}\n@end\n",na="@export clay.compositor.output\n#define OUTPUT_ALPHA\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\n@import clay.util.rgbm\nvoid main()\n{\n vec4 tex = decodeHDR(texture2D(texture, v_Texcoord));\n gl_FragColor.rgb = tex.rgb;\n#ifdef OUTPUT_ALPHA\n gl_FragColor.a = tex.a;\n#else\n gl_FragColor.a = 1.0;\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n#ifdef PREMULTIPLY_ALPHA\n gl_FragColor.rgb *= gl_FragColor.a;\n#endif\n}\n@end",ia="@export clay.compositor.bright\nuniform sampler2D texture;\nuniform float threshold : 1;\nuniform float scale : 1.0;\nuniform vec2 textureSize: [512, 512];\nvarying vec2 v_Texcoord;\nconst vec3 lumWeight = vec3(0.2125, 0.7154, 0.0721);\n@import clay.util.rgbm\nvec4 median(vec4 a, vec4 b, vec4 c)\n{\n return a + b + c - min(min(a, b), c) - max(max(a, b), c);\n}\nvoid main()\n{\n vec4 texel = decodeHDR(texture2D(texture, v_Texcoord));\n#ifdef ANTI_FLICKER\n vec3 d = 1.0 / textureSize.xyx * vec3(1.0, 1.0, 0.0);\n vec4 s1 = decodeHDR(texture2D(texture, v_Texcoord - d.xz));\n vec4 s2 = decodeHDR(texture2D(texture, v_Texcoord + d.xz));\n vec4 s3 = decodeHDR(texture2D(texture, v_Texcoord - d.zy));\n vec4 s4 = decodeHDR(texture2D(texture, v_Texcoord + d.zy));\n texel = median(median(texel, s1, s2), s3, s4);\n#endif\n float lum = dot(texel.rgb , lumWeight);\n vec4 color;\n if (lum > threshold && texel.a > 0.0)\n {\n color = vec4(texel.rgb * scale, texel.a * scale);\n }\n else\n {\n color = vec4(0.0);\n }\n gl_FragColor = encodeHDR(color);\n}\n@end\n",aa="@export clay.compositor.downsample\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\nfloat brightness(vec3 c)\n{\n return max(max(c.r, c.g), c.b);\n}\n@import clay.util.clamp_sample\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n#ifdef ANTI_FLICKER\n vec3 s1 = decodeHDR(clampSample(texture, v_Texcoord + d.xy)).rgb;\n vec3 s2 = decodeHDR(clampSample(texture, v_Texcoord + d.zy)).rgb;\n vec3 s3 = decodeHDR(clampSample(texture, v_Texcoord + d.xw)).rgb;\n vec3 s4 = decodeHDR(clampSample(texture, v_Texcoord + d.zw)).rgb;\n float s1w = 1.0 / (brightness(s1) + 1.0);\n float s2w = 1.0 / (brightness(s2) + 1.0);\n float s3w = 1.0 / (brightness(s3) + 1.0);\n float s4w = 1.0 / (brightness(s4) + 1.0);\n float oneDivideSum = 1.0 / (s1w + s2w + s3w + s4w);\n vec4 color = vec4(\n (s1 * s1w + s2 * s2w + s3 * s3w + s4 * s4w) * oneDivideSum,\n 1.0\n );\n#else\n vec4 color = decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.xw));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.zw));\n color *= 0.25;\n#endif\n gl_FragColor = encodeHDR(color);\n}\n@end",oa="\n@export clay.compositor.upsample\n#define HIGH_QUALITY\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.clamp_sample\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n vec4 s;\n s = decodeHDR(clampSample(texture, v_Texcoord - d.xy));\n s += decodeHDR(clampSample(texture, v_Texcoord - d.wy)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord - d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zw)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord )) * 4.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xw)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.wy)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n gl_FragColor = encodeHDR(s / 16.0);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n vec4 s;\n s = decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xw));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zw));\n gl_FragColor = encodeHDR(s / 4.0);\n#endif\n}\n@end",sa="@export clay.compositor.hdr.composite\nuniform sampler2D texture;\n#ifdef BLOOM_ENABLED\nuniform sampler2D bloom;\n#endif\n#ifdef LENSFLARE_ENABLED\nuniform sampler2D lensflare;\nuniform sampler2D lensdirt;\n#endif\n#ifdef LUM_ENABLED\nuniform sampler2D lum;\n#endif\n#ifdef LUT_ENABLED\nuniform sampler2D lut;\n#endif\n#ifdef COLOR_CORRECTION\nuniform float brightness : 0.0;\nuniform float contrast : 1.0;\nuniform float saturation : 1.0;\n#endif\n#ifdef VIGNETTE\nuniform float vignetteDarkness: 1.0;\nuniform float vignetteOffset: 1.0;\n#endif\nuniform float exposure : 1.0;\nuniform float bloomIntensity : 0.25;\nuniform float lensflareIntensity : 1;\nvarying vec2 v_Texcoord;\n@import clay.util.srgb\nvec3 ACESToneMapping(vec3 color)\n{\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nfloat eyeAdaption(float fLum)\n{\n return mix(0.2, fLum, 0.5);\n}\n#ifdef LUT_ENABLED\nvec3 lutTransform(vec3 color) {\n float blueColor = color.b * 63.0;\n vec2 quad1;\n quad1.y = floor(floor(blueColor) / 8.0);\n quad1.x = floor(blueColor) - (quad1.y * 8.0);\n vec2 quad2;\n quad2.y = floor(ceil(blueColor) / 8.0);\n quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n vec2 texPos1;\n texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.r);\n texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.g);\n vec2 texPos2;\n texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.r);\n texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.g);\n vec4 newColor1 = texture2D(lut, texPos1);\n vec4 newColor2 = texture2D(lut, texPos2);\n vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n return newColor.rgb;\n}\n#endif\n@import clay.util.rgbm\nvoid main()\n{\n vec4 texel = vec4(0.0);\n vec4 originalTexel = vec4(0.0);\n#ifdef TEXTURE_ENABLED\n texel = decodeHDR(texture2D(texture, v_Texcoord));\n originalTexel = texel;\n#endif\n#ifdef BLOOM_ENABLED\n vec4 bloomTexel = decodeHDR(texture2D(bloom, v_Texcoord));\n texel.rgb += bloomTexel.rgb * bloomIntensity;\n texel.a += bloomTexel.a * bloomIntensity;\n#endif\n#ifdef LENSFLARE_ENABLED\n texel += decodeHDR(texture2D(lensflare, v_Texcoord)) * texture2D(lensdirt, v_Texcoord) * lensflareIntensity;\n#endif\n texel.a = min(texel.a, 1.0);\n#ifdef LUM_ENABLED\n float fLum = texture2D(lum, vec2(0.5, 0.5)).r;\n float adaptedLumDest = 3.0 / (max(0.1, 1.0 + 10.0*eyeAdaption(fLum)));\n float exposureBias = adaptedLumDest * exposure;\n#else\n float exposureBias = exposure;\n#endif\n texel.rgb *= exposureBias;\n texel.rgb = ACESToneMapping(texel.rgb);\n texel = linearTosRGB(texel);\n#ifdef LUT_ENABLED\n texel.rgb = lutTransform(clamp(texel.rgb,vec3(0.0),vec3(1.0)));\n#endif\n#ifdef COLOR_CORRECTION\n texel.rgb = clamp(texel.rgb + vec3(brightness), 0.0, 1.0);\n texel.rgb = clamp((texel.rgb - vec3(0.5))*contrast+vec3(0.5), 0.0, 1.0);\n float lum = dot(texel.rgb, vec3(0.2125, 0.7154, 0.0721));\n texel.rgb = mix(vec3(lum), texel.rgb, saturation);\n#endif\n#ifdef VIGNETTE\n vec2 uv = (v_Texcoord - vec2(0.5)) * vec2(vignetteOffset);\n texel.rgb = mix(texel.rgb, vec3(1.0 - vignetteDarkness), dot(uv, uv));\n#endif\n gl_FragColor = encodeHDR(texel);\n#ifdef DEBUG\n #if DEBUG == 1\n gl_FragColor = encodeHDR(decodeHDR(texture2D(texture, v_Texcoord)));\n #elif DEBUG == 2\n gl_FragColor = encodeHDR(decodeHDR(texture2D(bloom, v_Texcoord)) * bloomIntensity);\n #elif DEBUG == 3\n gl_FragColor = encodeHDR(decodeHDR(texture2D(lensflare, v_Texcoord) * lensflareIntensity));\n #endif\n#endif\n if (originalTexel.a <= 0.01 && gl_FragColor.a > 1e-5) {\n gl_FragColor.a = dot(gl_FragColor.rgb, vec3(0.2125, 0.7154, 0.0721));\n }\n#ifdef PREMULTIPLY_ALPHA\n gl_FragColor.rgb *= gl_FragColor.a;\n#endif\n}\n@end",ua="@export clay.compositor.blend\n#define SHADER_NAME blend\n#ifdef TEXTURE1_ENABLED\nuniform sampler2D texture1;\nuniform float weight1 : 1.0;\n#endif\n#ifdef TEXTURE2_ENABLED\nuniform sampler2D texture2;\nuniform float weight2 : 1.0;\n#endif\n#ifdef TEXTURE3_ENABLED\nuniform sampler2D texture3;\nuniform float weight3 : 1.0;\n#endif\n#ifdef TEXTURE4_ENABLED\nuniform sampler2D texture4;\nuniform float weight4 : 1.0;\n#endif\n#ifdef TEXTURE5_ENABLED\nuniform sampler2D texture5;\nuniform float weight5 : 1.0;\n#endif\n#ifdef TEXTURE6_ENABLED\nuniform sampler2D texture6;\nuniform float weight6 : 1.0;\n#endif\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\nvoid main()\n{\n vec4 tex = vec4(0.0);\n#ifdef TEXTURE1_ENABLED\n tex += decodeHDR(texture2D(texture1, v_Texcoord)) * weight1;\n#endif\n#ifdef TEXTURE2_ENABLED\n tex += decodeHDR(texture2D(texture2, v_Texcoord)) * weight2;\n#endif\n#ifdef TEXTURE3_ENABLED\n tex += decodeHDR(texture2D(texture3, v_Texcoord)) * weight3;\n#endif\n#ifdef TEXTURE4_ENABLED\n tex += decodeHDR(texture2D(texture4, v_Texcoord)) * weight4;\n#endif\n#ifdef TEXTURE5_ENABLED\n tex += decodeHDR(texture2D(texture5, v_Texcoord)) * weight5;\n#endif\n#ifdef TEXTURE6_ENABLED\n tex += decodeHDR(texture2D(texture6, v_Texcoord)) * weight6;\n#endif\n gl_FragColor = encodeHDR(tex);\n}\n@end",la="@export clay.compositor.fxaa\nuniform sampler2D texture;\nuniform vec4 viewport : VIEWPORT;\nvarying vec2 v_Texcoord;\n#define FXAA_REDUCE_MIN (1.0/128.0)\n#define FXAA_REDUCE_MUL (1.0/8.0)\n#define FXAA_SPAN_MAX 8.0\n@import clay.util.rgbm\nvoid main()\n{\n vec2 resolution = 1.0 / viewport.zw;\n vec3 rgbNW = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( -1.0, -1.0 ) ) * resolution ) ).xyz;\n vec3 rgbNE = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( 1.0, -1.0 ) ) * resolution ) ).xyz;\n vec3 rgbSW = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( -1.0, 1.0 ) ) * resolution ) ).xyz;\n vec3 rgbSE = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( 1.0, 1.0 ) ) * resolution ) ).xyz;\n vec4 rgbaM = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution ) );\n vec3 rgbM = rgbaM.xyz;\n float opacity = rgbaM.w;\n vec3 luma = vec3( 0.299, 0.587, 0.114 );\n float lumaNW = dot( rgbNW, luma );\n float lumaNE = dot( rgbNE, luma );\n float lumaSW = dot( rgbSW, luma );\n float lumaSE = dot( rgbSE, luma );\n float lumaM = dot( rgbM, luma );\n float lumaMin = min( lumaM, min( min( lumaNW, lumaNE ), min( lumaSW, lumaSE ) ) );\n float lumaMax = max( lumaM, max( max( lumaNW, lumaNE) , max( lumaSW, lumaSE ) ) );\n vec2 dir;\n dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\n dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));\n float dirReduce = max( ( lumaNW + lumaNE + lumaSW + lumaSE ) * ( 0.25 * FXAA_REDUCE_MUL ), FXAA_REDUCE_MIN );\n float rcpDirMin = 1.0 / ( min( abs( dir.x ), abs( dir.y ) ) + dirReduce );\n dir = min( vec2( FXAA_SPAN_MAX, FXAA_SPAN_MAX),\n max( vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),\n dir * rcpDirMin)) * resolution;\n vec3 rgbA = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * ( 1.0 / 3.0 - 0.5 ) ) ).xyz;\n rgbA += decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * ( 2.0 / 3.0 - 0.5 ) ) ).xyz;\n rgbA *= 0.5;\n vec3 rgbB = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * -0.5 ) ).xyz;\n rgbB += decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * 0.5 ) ).xyz;\n rgbB *= 0.25;\n rgbB += rgbA * 0.5;\n float lumaB = dot( rgbB, luma );\n if ( ( lumaB < lumaMin ) || ( lumaB > lumaMax ) )\n {\n gl_FragColor = vec4( rgbA, opacity );\n }\n else {\n gl_FragColor = vec4( rgbB, opacity );\n }\n}\n@end";L.import("@export clay.compositor.coloradjust\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float brightness : 0.0;\nuniform float contrast : 1.0;\nuniform float exposure : 0.0;\nuniform float gamma : 1.0;\nuniform float saturation : 1.0;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = clamp(tex.rgb + vec3(brightness), 0.0, 1.0);\n color = clamp( (color-vec3(0.5))*contrast+vec3(0.5), 0.0, 1.0);\n color = clamp( color * pow(2.0, exposure), 0.0, 1.0);\n color = clamp( pow(color, vec3(gamma)), 0.0, 1.0);\n float luminance = dot( color, w );\n color = mix(vec3(luminance), color, saturation);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.brightness\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float brightness : 0.0;\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = tex.rgb + vec3(brightness);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.contrast\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float contrast : 1.0;\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = (tex.rgb-vec3(0.5))*contrast+vec3(0.5);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.exposure\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float exposure : 0.0;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = tex.rgb * pow(2.0, exposure);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.gamma\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float gamma : 1.0;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = pow(tex.rgb, vec3(gamma));\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.saturation\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float saturation : 1.0;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = tex.rgb;\n float luminance = dot(color, w);\n color = mix(vec3(luminance), color, saturation);\n gl_FragColor = vec4(color, tex.a);\n}\n@end"),L.import(ra),L.import("@export clay.compositor.hdr.log_lum\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\n@import clay.util.rgbm\nvoid main()\n{\n vec4 tex = decodeHDR(texture2D(texture, v_Texcoord));\n float luminance = dot(tex.rgb, w);\n luminance = log(luminance + 0.001);\n gl_FragColor = encodeHDR(vec4(vec3(luminance), 1.0));\n}\n@end\n@export clay.compositor.hdr.lum_adaption\nvarying vec2 v_Texcoord;\nuniform sampler2D adaptedLum;\nuniform sampler2D currentLum;\nuniform float frameTime : 0.02;\n@import clay.util.rgbm\nvoid main()\n{\n float fAdaptedLum = decodeHDR(texture2D(adaptedLum, vec2(0.5, 0.5))).r;\n float fCurrentLum = exp(encodeHDR(texture2D(currentLum, vec2(0.5, 0.5))).r);\n fAdaptedLum += (fCurrentLum - fAdaptedLum) * (1.0 - pow(0.98, 30.0 * frameTime));\n gl_FragColor = encodeHDR(vec4(vec3(fAdaptedLum), 1.0));\n}\n@end\n@export clay.compositor.lum\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord );\n float luminance = dot(tex.rgb, w);\n gl_FragColor = vec4(vec3(luminance), 1.0);\n}\n@end"),L.import("\n@export clay.compositor.lut\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform sampler2D lookup;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n float blueColor = tex.b * 63.0;\n vec2 quad1;\n quad1.y = floor(floor(blueColor) / 8.0);\n quad1.x = floor(blueColor) - (quad1.y * 8.0);\n vec2 quad2;\n quad2.y = floor(ceil(blueColor) / 8.0);\n quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n vec2 texPos1;\n texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.r);\n texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.g);\n vec2 texPos2;\n texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.r);\n texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.g);\n vec4 newColor1 = texture2D(lookup, texPos1);\n vec4 newColor2 = texture2D(lookup, texPos2);\n vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n gl_FragColor = vec4(newColor.rgb, tex.w);\n}\n@end"),L.import("@export clay.compositor.vignette\n#define OUTPUT_ALPHA\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float darkness: 1;\nuniform float offset: 1;\n@import clay.util.rgbm\nvoid main()\n{\n vec4 texel = decodeHDR(texture2D(texture, v_Texcoord));\n gl_FragColor.rgb = texel.rgb;\n vec2 uv = (v_Texcoord - vec2(0.5)) * vec2(offset);\n gl_FragColor = encodeHDR(vec4(mix(texel.rgb, vec3(1.0 - darkness), dot(uv, uv)), texel.a));\n}\n@end"),L.import(na),L.import(ia),L.import(aa),L.import(oa),L.import(sa), +L.import("@export clay.compositor.dof.coc\nuniform sampler2D depth;\nuniform float zNear: 0.1;\nuniform float zFar: 2000;\nuniform float focalDist: 3;\nuniform float focalRange: 1;\nuniform float focalLength: 30;\nuniform float fstop: 2.8;\nvarying vec2 v_Texcoord;\n@import clay.util.encode_float\nvoid main()\n{\n float z = texture2D(depth, v_Texcoord).r * 2.0 - 1.0;\n float dist = 2.0 * zNear * zFar / (zFar + zNear - z * (zFar - zNear));\n float aperture = focalLength / fstop;\n float coc;\n float uppper = focalDist + focalRange;\n float lower = focalDist - focalRange;\n if (dist <= uppper && dist >= lower) {\n coc = 0.5;\n }\n else {\n float focalAdjusted = dist > uppper ? uppper : lower;\n coc = abs(aperture * (focalLength * (dist - focalAdjusted)) / (dist * (focalAdjusted - focalLength)));\n coc = clamp(coc, 0.0, 0.4) / 0.4000001;\n if (dist < lower) {\n coc = -coc;\n }\n coc = coc * 0.5 + 0.5;\n }\n gl_FragColor = encodeFloat(coc);\n}\n@end\n@export clay.compositor.dof.premultiply\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.decode_float\nvoid main() {\n float fCoc = max(abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0), 0.1);\n gl_FragColor = encodeHDR(\n vec4(decodeHDR(texture2D(texture, v_Texcoord)).rgb * fCoc, 1.0)\n );\n}\n@end\n@export clay.compositor.dof.min_coc\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.float\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zy)));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.xw)));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zw)));\n gl_FragColor = encodeFloat(fCoc);\n}\n@end\n@export clay.compositor.dof.max_coc\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.float\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zy)));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.xw)));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zw)));\n gl_FragColor = encodeFloat(fCoc);\n}\n@end\n@export clay.compositor.dof.coc_upsample\n#define HIGH_QUALITY\nuniform sampler2D coc;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import clay.util.float\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n float s;\n s = decodeFloat(texture2D(coc, v_Texcoord - d.xy));\n s += decodeFloat(texture2D(coc, v_Texcoord - d.wy)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord - d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zw)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord )) * 4.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xw)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.wy)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n gl_FragColor = encodeFloat(s / 16.0);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n float s;\n s = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xw));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zw));\n gl_FragColor = encodeFloat(s / 4.0);\n#endif\n}\n@end\n@export clay.compositor.dof.upsample\n#define HIGH_QUALITY\nuniform sampler2D coc;\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.decode_float\nfloat tap(vec2 uv, inout vec4 color, float baseWeight) {\n float weight = abs(decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0) * baseWeight;\n color += decodeHDR(texture2D(texture, uv)) * weight;\n return weight;\n}\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n vec4 color = vec4(0.0);\n float baseWeight = 1.0 / 16.0;\n float w = tap(v_Texcoord - d.xy, color, baseWeight);\n w += tap(v_Texcoord - d.wy, color, baseWeight * 2.0);\n w += tap(v_Texcoord - d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.zw, color, baseWeight * 2.0);\n w += tap(v_Texcoord , color, baseWeight * 4.0);\n w += tap(v_Texcoord + d.xw, color, baseWeight * 2.0);\n w += tap(v_Texcoord + d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.wy, color, baseWeight * 2.0);\n w += tap(v_Texcoord + d.xy, color, baseWeight);\n gl_FragColor = encodeHDR(color / w);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n vec4 color = vec4(0.0);\n float baseWeight = 1.0 / 4.0;\n float w = tap(v_Texcoord + d.xy, color, baseWeight);\n w += tap(v_Texcoord + d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.xw, color, baseWeight);\n w += tap(v_Texcoord + d.zw, color, baseWeight);\n gl_FragColor = encodeHDR(color / w);\n#endif\n}\n@end\n@export clay.compositor.dof.downsample\nuniform sampler2D texture;\nuniform sampler2D coc;\nuniform vec2 textureSize : [512, 512];\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.decode_float\nfloat tap(vec2 uv, inout vec4 color) {\n float weight = abs(decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0) * 0.25;\n color += decodeHDR(texture2D(texture, uv)) * weight;\n return weight;\n}\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n vec4 color = vec4(0.0);\n float weight = tap(v_Texcoord + d.xy, color);\n weight += tap(v_Texcoord + d.zy, color);\n weight += tap(v_Texcoord + d.xw, color);\n weight += tap(v_Texcoord + d.zw, color);\n color /= weight;\n gl_FragColor = encodeHDR(color);\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_frag\n@import clay.util.float\nvec4 doBlur(sampler2D targetTexture, vec2 offset) {\n#ifdef BLUR_COC\n float cocSum = 0.0;\n#else\n vec4 color = vec4(0.0);\n#endif\n float weightSum = 0.0;\n float kernelWeight = 1.0 / float(KERNEL_SIZE);\n for (int i = 0; i < KERNEL_SIZE; i++) {\n vec2 coord = v_Texcoord + offset * float(i);\n float w = kernelWeight;\n#ifdef BLUR_COC\n float fCoc = decodeFloat(texture2D(targetTexture, coord)) * 2.0 - 1.0;\n cocSum += clamp(fCoc, -1.0, 0.0) * w;\n#else\n float fCoc = decodeFloat(texture2D(coc, coord)) * 2.0 - 1.0;\n vec4 texel = texture2D(targetTexture, coord);\n #if !defined(BLUR_NEARFIELD)\n w *= abs(fCoc);\n #endif\n color += decodeHDR(texel) * w;\n#endif\n weightSum += w;\n }\n#ifdef BLUR_COC\n return encodeFloat(clamp(cocSum / weightSum, -1.0, 0.0) * 0.5 + 0.5);\n#else\n return color / weightSum;\n#endif\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_1\n#define KERNEL_SIZE 5\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.rgbm\n@import clay.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n gl_FragColor = doBlur(texture, vec2(0.0, offset.y));\n#if !defined(BLUR_COC)\n gl_FragColor = encodeHDR(gl_FragColor);\n#endif\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_2\n#define KERNEL_SIZE 5\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.rgbm\n@import clay.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n offset.y /= 2.0;\n gl_FragColor = doBlur(texture, -offset);\n#if !defined(BLUR_COC)\n gl_FragColor = encodeHDR(gl_FragColor);\n#endif\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_3\n#define KERNEL_SIZE 5\nuniform sampler2D texture1;\nuniform sampler2D texture2;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.rgbm\n@import clay.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n offset.y /= 2.0;\n vec2 vDownRight = vec2(offset.x, -offset.y);\n vec4 texel1 = doBlur(texture1, -offset);\n vec4 texel2 = doBlur(texture1, vDownRight);\n vec4 texel3 = doBlur(texture2, vDownRight);\n#ifdef BLUR_COC\n float coc1 = decodeFloat(texel1) * 2.0 - 1.0;\n float coc2 = decodeFloat(texel2) * 2.0 - 1.0;\n float coc3 = decodeFloat(texel3) * 2.0 - 1.0;\n gl_FragColor = encodeFloat(\n ((coc1 + coc2 + coc3) / 3.0) * 0.5 + 0.5\n );\n#else\n vec4 color = (texel1 + texel2 + texel3) / 3.0;\n gl_FragColor = encodeHDR(color);\n#endif\n}\n@end\n@export clay.compositor.dof.composite\n#define DEBUG 0\nuniform sampler2D original;\nuniform sampler2D blurred;\nuniform sampler2D nearfield;\nuniform sampler2D coc;\nuniform sampler2D nearcoc;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.float\nvoid main()\n{\n vec4 blurredColor = decodeHDR(texture2D(blurred, v_Texcoord));\n vec4 originalColor = decodeHDR(texture2D(original, v_Texcoord));\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord));\n fCoc = abs(fCoc * 2.0 - 1.0);\n float weight = smoothstep(0.0, 1.0, fCoc);\n#ifdef NEARFIELD_ENABLED\n vec4 nearfieldColor = decodeHDR(texture2D(nearfield, v_Texcoord));\n float fNearCoc = decodeFloat(texture2D(nearcoc, v_Texcoord));\n fNearCoc = abs(fNearCoc * 2.0 - 1.0);\n gl_FragColor = encodeHDR(\n mix(\n nearfieldColor, mix(originalColor, blurredColor, weight),\n pow(1.0 - fNearCoc, 4.0)\n )\n );\n#else\n gl_FragColor = encodeHDR(mix(originalColor, blurredColor, weight));\n#endif\n#if DEBUG == 1\n gl_FragColor = vec4(vec3(fCoc), 1.0);\n#elif DEBUG == 2\n gl_FragColor = vec4(vec3(fNearCoc), 1.0);\n#elif DEBUG == 3\n gl_FragColor = encodeHDR(blurredColor);\n#elif DEBUG == 4\n gl_FragColor = encodeHDR(nearfieldColor);\n#endif\n}\n@end"),L.import("@export clay.compositor.lensflare\n#define SAMPLE_NUMBER 8\nuniform sampler2D texture;\nuniform sampler2D lenscolor;\nuniform vec2 textureSize : [512, 512];\nuniform float dispersal : 0.3;\nuniform float haloWidth : 0.4;\nuniform float distortion : 1.0;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\nvec4 textureDistorted(\n in vec2 texcoord,\n in vec2 direction,\n in vec3 distortion\n) {\n return vec4(\n decodeHDR(texture2D(texture, texcoord + direction * distortion.r)).r,\n decodeHDR(texture2D(texture, texcoord + direction * distortion.g)).g,\n decodeHDR(texture2D(texture, texcoord + direction * distortion.b)).b,\n 1.0\n );\n}\nvoid main()\n{\n vec2 texcoord = -v_Texcoord + vec2(1.0); vec2 textureOffset = 1.0 / textureSize;\n vec2 ghostVec = (vec2(0.5) - texcoord) * dispersal;\n vec2 haloVec = normalize(ghostVec) * haloWidth;\n vec3 distortion = vec3(-textureOffset.x * distortion, 0.0, textureOffset.x * distortion);\n vec4 result = vec4(0.0);\n for (int i = 0; i < SAMPLE_NUMBER; i++)\n {\n vec2 offset = fract(texcoord + ghostVec * float(i));\n float weight = length(vec2(0.5) - offset) / length(vec2(0.5));\n weight = pow(1.0 - weight, 10.0);\n result += textureDistorted(offset, normalize(ghostVec), distortion) * weight;\n }\n result *= texture2D(lenscolor, vec2(length(vec2(0.5) - texcoord)) / length(vec2(0.5)));\n float weight = length(vec2(0.5) - fract(texcoord + haloVec)) / length(vec2(0.5));\n weight = pow(1.0 - weight, 10.0);\n vec2 offset = fract(texcoord + haloVec);\n result += textureDistorted(offset, normalize(ghostVec), distortion) * weight;\n gl_FragColor = result;\n}\n@end"),L.import(ua),L.import(la);var ca=/^#source\((.*?)\)/;L.import("@export ecgl.ssao.estimate\n\n#define SHADER_NAME SSAO\n\nuniform sampler2D depthTex;\n\nuniform sampler2D normalTex;\n\nuniform sampler2D noiseTex;\n\nuniform vec2 depthTexSize;\n\nuniform vec2 noiseTexSize;\n\nuniform mat4 projection;\n\nuniform mat4 projectionInv;\n\nuniform mat4 viewInverseTranspose;\n\nuniform vec3 kernel[KERNEL_SIZE];\n\nuniform float radius : 1;\n\nuniform float power : 1;\n\nuniform float bias: 0.01;\n\nuniform float intensity: 1.0;\n\nvarying vec2 v_Texcoord;\n\nfloat ssaoEstimator(in vec3 originPos, in vec3 N, in mat3 kernelBasis) {\n float occlusion = 0.0;\n\n for (int i = 0; i < KERNEL_SIZE; i++) {\n vec3 samplePos = kernel[i];\n#ifdef NORMALTEX_ENABLED\n samplePos = kernelBasis * samplePos;\n#endif\n samplePos = samplePos * radius + originPos;\n\n vec4 texCoord = projection * vec4(samplePos, 1.0);\n texCoord.xy /= texCoord.w;\n texCoord.xy = texCoord.xy * 0.5 + 0.5;\n\n vec4 depthTexel = texture2D(depthTex, texCoord.xy);\n float z = depthTexel.r * 2.0 - 1.0;\n#ifdef ALCHEMY\n vec4 projectedPos = vec4(texCoord.xy * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * projectedPos;\n p4.xyz /= p4.w;\n vec3 cDir = p4.xyz - originPos;\n\n float vv = dot(cDir, cDir);\n float vn = dot(cDir, N);\n\n float radius2 = radius * radius;\n\n vn = max(vn + p4.z * bias, 0.0);\n float f = max(radius2 - vv, 0.0) / radius2;\n occlusion += f * f * f * max(vn / (0.01 + vv), 0.0);\n#else\n if (projection[3][3] == 0.0) {\n z = projection[3][2] / (z * projection[2][3] - projection[2][2]);\n }\n else {\n z = (z - projection[3][2]) / projection[2][2];\n }\n float factor = step(samplePos.z, z - bias);\n float rangeCheck = smoothstep(0.0, 1.0, radius / abs(originPos.z - z));\n occlusion += rangeCheck * factor;\n#endif\n }\n#ifdef NORMALTEX_ENABLED\n occlusion = 1.0 - occlusion / float(KERNEL_SIZE);\n#else\n occlusion = 1.0 - clamp((occlusion / float(KERNEL_SIZE) - 0.6) * 2.5, 0.0, 1.0);\n#endif\n return pow(occlusion, power);\n}\n\nvoid main()\n{\n\n vec4 depthTexel = texture2D(depthTex, v_Texcoord);\n\n#ifdef NORMALTEX_ENABLED\n vec4 tex = texture2D(normalTex, v_Texcoord);\n if (dot(tex.rgb, tex.rgb) == 0.0) {\n gl_FragColor = vec4(1.0);\n return;\n }\n vec3 N = tex.rgb * 2.0 - 1.0;\n N = (viewInverseTranspose * vec4(N, 0.0)).xyz;\n\n vec2 noiseTexCoord = depthTexSize / vec2(noiseTexSize) * v_Texcoord;\n vec3 rvec = texture2D(noiseTex, noiseTexCoord).rgb * 2.0 - 1.0;\n vec3 T = normalize(rvec - N * dot(rvec, N));\n vec3 BT = normalize(cross(N, T));\n mat3 kernelBasis = mat3(T, BT, N);\n#else\n if (depthTexel.r > 0.99999) {\n gl_FragColor = vec4(1.0);\n return;\n }\n mat3 kernelBasis;\n#endif\n\n float z = depthTexel.r * 2.0 - 1.0;\n\n vec4 projectedPos = vec4(v_Texcoord * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * projectedPos;\n\n vec3 position = p4.xyz / p4.w;\n\n float ao = ssaoEstimator(position, N, kernelBasis);\n ao = clamp(1.0 - (1.0 - ao) * intensity, 0.0, 1.0);\n gl_FragColor = vec4(vec3(ao), 1.0);\n}\n\n@end\n\n\n@export ecgl.ssao.blur\n#define SHADER_NAME SSAO_BLUR\n\nuniform sampler2D ssaoTexture;\n\n#ifdef NORMALTEX_ENABLED\nuniform sampler2D normalTex;\n#endif\n\nvarying vec2 v_Texcoord;\n\nuniform vec2 textureSize;\nuniform float blurSize : 1.0;\n\nuniform int direction: 0.0;\n\n#ifdef DEPTHTEX_ENABLED\nuniform sampler2D depthTex;\nuniform mat4 projection;\nuniform float depthRange : 0.05;\n\nfloat getLinearDepth(vec2 coord)\n{\n float depth = texture2D(depthTex, coord).r * 2.0 - 1.0;\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n}\n#endif\n\nvoid main()\n{\n float kernel[5];\n kernel[0] = 0.122581;\n kernel[1] = 0.233062;\n kernel[2] = 0.288713;\n kernel[3] = 0.233062;\n kernel[4] = 0.122581;\n\n vec2 off = vec2(0.0);\n if (direction == 0) {\n off[0] = blurSize / textureSize.x;\n }\n else {\n off[1] = blurSize / textureSize.y;\n }\n\n vec2 coord = v_Texcoord;\n\n float sum = 0.0;\n float weightAll = 0.0;\n\n#ifdef NORMALTEX_ENABLED\n vec3 centerNormal = texture2D(normalTex, v_Texcoord).rgb * 2.0 - 1.0;\n#endif\n#if defined(DEPTHTEX_ENABLED)\n float centerDepth = getLinearDepth(v_Texcoord);\n#endif\n\n for (int i = 0; i < 5; i++) {\n vec2 coord = clamp(v_Texcoord + vec2(float(i) - 2.0) * off, vec2(0.0), vec2(1.0));\n\n float w = kernel[i];\n#ifdef NORMALTEX_ENABLED\n vec3 normal = texture2D(normalTex, coord).rgb * 2.0 - 1.0;\n w *= clamp(dot(normal, centerNormal), 0.0, 1.0);\n#endif\n#ifdef DEPTHTEX_ENABLED\n float d = getLinearDepth(coord);\n w *= (1.0 - smoothstep(abs(centerDepth - d) / depthRange, 0.0, 1.0));\n#endif\n\n weightAll += w;\n sum += texture2D(ssaoTexture, coord).r * w;\n }\n\n gl_FragColor = vec4(vec3(sum / weightAll), 1.0);\n}\n@end\n"),De.prototype.setDepthTexture=function(e){this._depthTex=e},De.prototype.setNormalTexture=function(e){this._normalTex=e,this._ssaoPass.material[e?"enableTexture":"disableTexture"]("normalTex"),this.setKernelSize(this._kernelSize)},De.prototype.update=function(e,t,r){var n=e.getWidth(),i=e.getHeight(),a=this._ssaoPass,o=this._blurPass;a.setUniform("kernel",this._kernels[r%this._kernels.length]),a.setUniform("depthTex",this._depthTex),null!=this._normalTex&&a.setUniform("normalTex",this._normalTex),a.setUniform("depthTexSize",[this._depthTex.width,this._depthTex.height]);var s=new Kt;Kt.transpose(s,t.worldTransform),a.setUniform("projection",t.projectionMatrix.array),a.setUniform("projectionInv",t.invProjectionMatrix.array),a.setUniform("viewInverseTranspose",s.array);var u=this._ssaoTexture,l=this._blurTexture;u.width=n,u.height=i,l.width=n,l.height=i,this._framebuffer.attach(u),this._framebuffer.bind(e),e.gl.clearColor(1,1,1,1),e.gl.clear(e.gl.COLOR_BUFFER_BIT),a.render(e),o.setUniform("textureSize",[n,i]),o.setUniform("projection",t.projectionMatrix.array),this._framebuffer.attach(l),o.setUniform("direction",0),o.setUniform("ssaoTexture",u),o.render(e),this._framebuffer.attach(u),o.setUniform("direction",1),o.setUniform("ssaoTexture",l),o.render(e),this._framebuffer.unbind(e);var c=e.clearColor;e.gl.clearColor(c[0],c[1],c[2],c[3])},De.prototype.getTargetTexture=function(){return this._ssaoTexture},De.prototype.setParameter=function(e,t){"noiseTexSize"===e?this.setNoiseSize(t):"kernelSize"===e?this.setKernelSize(t):"intensity"===e?this._ssaoPass.material.set("intensity",t):this._ssaoPass.setUniform(e,t)},De.prototype.setKernelSize=function(e){this._kernelSize=e,this._ssaoPass.material.define("fragment","KERNEL_SIZE",e),this._kernels=this._kernels||[];for(var t=0;t<30;t++)this._kernels[t]=Pe(e,t*e,!!this._normalTex)},De.prototype.setNoiseSize=function(e){var t=this._ssaoPass.getUniform("noiseTex");t?(t.data=Me(e),t.width=t.height=e,t.dirty()):(t=Le(e),this._ssaoPass.setUniform("noiseTex",Le(e))),this._ssaoPass.setUniform("noiseTexSize",[e,e])},De.prototype.dispose=function(e){this._blurTexture.dispose(e),this._ssaoTexture.dispose(e)},De.prototype.isFinished=function(e){return e>30};var ha=new Kt,fa=ei.extend({dynamic:!1,widthSegments:1,heightSegments:1,depthSegments:1,inside:!1},function(){this.build()},{build:function(){var e={px:Oe("px",this.depthSegments,this.heightSegments),nx:Oe("nx",this.depthSegments,this.heightSegments),py:Oe("py",this.widthSegments,this.depthSegments),ny:Oe("ny",this.widthSegments,this.depthSegments),pz:Oe("pz",this.widthSegments,this.heightSegments),nz:Oe("nz",this.widthSegments,this.heightSegments)},t=["position","texcoord0","normal"],r=0,n=0;for(var i in e)r+=e[i].vertexCount,n+=e[i].indices.length;for(var a=0;a0?this.material.define("fragment","LOD"):this.material.undefine("fragment","LOD"),e.renderPass([this],t)}}),pa={},ma=["px","nx","py","ny","pz","nz"];pa.prefilterEnvironmentMap=function(e,t,r,n,i){i&&n||(n=pa.generateNormalDistribution(),i=pa.integrateBRDF(e,n)),r=r||{};var a=r.width||64,o=r.height||64,s=r.type||t.type,u=new Ti({width:a,height:o,type:s,flipY:!1,mipmaps:[]});u.isPowerOfTwo()||console.warn("Width and height must be power of two to enable mipmap.");var l=Math.min(a,o),c=Math.log(l)/Math.log(2)+1,h=new sr({shader:new L({vertex:L.source("clay.skybox.vertex"),fragment:"#define SHADER_NAME prefilter\n#define SAMPLE_NUMBER 1024\n#define PI 3.14159265358979\nuniform mat4 viewInverse : VIEWINVERSE;\nuniform samplerCube environmentMap;\nuniform sampler2D normalDistribution;\nuniform float roughness : 0.5;\nuniform int maxSampleNumber: 1024\nvarying vec2 v_Texcoord;\nvarying vec3 v_WorldPosition;\n@import clay.util.rgbm\nvec3 importanceSampleNormal(float i, float roughness, vec3 N) {\n vec3 H = texture2D(normalDistribution, vec2(roughness, i)).rgb;\n vec3 upVector = abs(N.y) > 0.999 ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);\n vec3 tangentX = normalize(cross(N, upVector));\n vec3 tangentZ = cross(N, tangentX);\n return normalize(tangentX * H.x + N * H.y + tangentZ * H.z);\n}\nvoid main() {\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = normalize(v_WorldPosition - eyePos);\n vec3 N = V;\n vec3 prefilteredColor = vec3(0.0);\n float totalWeight = 0.0;\n float fMaxSampleNumber = float(maxSampleNumber);\n for (int i = 0; i < SAMPLE_NUMBER; i++) {\n if (i > maxSampleNumber) {\n break;\n }\n vec3 H = importanceSampleNormal(float(i) / fMaxSampleNumber, roughness, N);\n vec3 L = reflect(-V, H);\n float NoL = clamp(dot(N, L), 0.0, 1.0);\n if (NoL > 0.0) {\n prefilteredColor += decodeHDR(textureCube(environmentMap, L)).rgb * NoL;\n totalWeight += NoL;\n }\n }\n gl_FragColor = encodeHDR(vec4(prefilteredColor / totalWeight, 1.0));\n}\n"})});h.set("normalDistribution",n),r.encodeRGBM&&h.define("fragment","RGBM_ENCODE"),r.decodeRGBM&&h.define("fragment","RGBM_DECODE");var f,d=new vn;if("texture2D"===t.textureType){var p=new Ti({width:a,height:o,type:s===Qt.FLOAT?Qt.HALF_FLOAT:s});ki.panoramaToCubeMap(e,t,p,{encodeRGBM:r.decodeRGBM}),t=p}f=new da({scene:d,material:h}),f.material.set("environmentMap",t);var m=new Ri({texture:u});r.encodeRGBM&&(s=u.type=Qt.UNSIGNED_BYTE);for(var _=new Nn({width:a,height:o,type:s}),v=new wi({depthBuffer:!1}),g=Mt[s===Qt.UNSIGNED_BYTE?"Uint8Array":"Float32Array"],y=0;y=32&&(x/=4),f.material.set("maxSampleNumber",Math.min(x,1024));for(var T=_.width,E=2*Math.atan(T/(T-.5))/Math.PI*180,b=0;b 0.999 ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);\n vec3 tangentX = normalize(cross(N, upVector));\n vec3 tangentZ = cross(N, tangentX);\n return normalize(tangentX * H.x + N * H.y + tangentZ * H.z);\n}\nfloat G_Smith(float roughness, float NoV, float NoL) {\n float k = roughness * roughness / 2.0;\n float G1V = NoV / (NoV * (1.0 - k) + k);\n float G1L = NoL / (NoL * (1.0 - k) + k);\n return G1L * G1V;\n}\nvoid main() {\n vec2 uv = gl_FragCoord.xy / viewportSize;\n float NoV = uv.x;\n float roughness = uv.y;\n vec3 V;\n V.x = sqrt(1.0 - NoV * NoV);\n V.y = 0.0;\n V.z = NoV;\n float A = 0.0;\n float B = 0.0;\n for (int i = 0; i < SAMPLE_NUMBER; i++) {\n vec3 H = importanceSampleNormal(float(i) / fSampleNumber, roughness, N);\n vec3 L = reflect(-V, H);\n float NoL = clamp(L.z, 0.0, 1.0);\n float NoH = clamp(H.z, 0.0, 1.0);\n float VoH = clamp(dot(V, H), 0.0, 1.0);\n if (NoL > 0.0) {\n float G = G_Smith(roughness, NoV, NoL);\n float G_Vis = G * VoH / (NoH * NoV);\n float Fc = pow(1.0 - VoH, 5.0);\n A += (1.0 - Fc) * G_Vis;\n B += Fc * G_Vis;\n }\n }\n gl_FragColor = vec4(vec2(A, B) / fSampleNumber, 0.0, 1.0);\n}\n"}),i=new Nn({width:512,height:256,type:Qt.HALF_FLOAT,wrapS:Qt.CLAMP_TO_EDGE,wrapT:Qt.CLAMP_TO_EDGE,minFilter:Qt.NEAREST,magFilter:Qt.NEAREST,useMipmap:!1});return n.setUniform("normalDistribution",t),n.setUniform("viewportSize",[512,256]),n.attachOutput(i),n.render(e,r),r.dispose(e),i},pa.generateNormalDistribution=function(e,t){for(var e=e||256,t=t||1024,r=new Nn({width:e,height:t,type:Qt.FLOAT,minFilter:Qt.NEAREST,magFilter:Qt.NEAREST,wrapS:Qt.CLAMP_TO_EDGE,wrapT:Qt.CLAMP_TO_EDGE,useMipmap:!1}),n=new Float32Array(t*e*4),i=[],a=0;a>>16)>>>0;l=((1431655765&l)<<1|(2863311530&l)>>>1)>>>0,l=((858993459&l)<<2|(3435973836&l)>>>2)>>>0,l=((252645135&l)<<4|(4042322160&l)>>>4)>>>0,l=(((16711935&l)<<8|(4278255360&l)>>>8)>>>0)/4294967296;var c=Math.sqrt((1-l)/(1+(s*s-1)*l));i[u]=c}for(var u=0;u 0.999 ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);\n vec3 tangentX = normalize(cross(N, upVector));\n vec3 tangentZ = cross(N, tangentX);\n return normalize(tangentX * H.x + N * H.y + tangentZ * H.z);\n}\nvec3 importanceSampleNormalGGX(float i, float roughness, vec3 N) {\n float p = fract((i + sampleOffset) / float(TOTAL_SAMPLES));\n vec3 H = texture2D(normalDistribution,vec2(roughness, p)).rgb;\n return transformNormal(H, N);\n}\nfloat G_Smith(float g, float ndv, float ndl) {\n float roughness = 1.0 - g;\n float k = roughness * roughness / 2.0;\n float G1V = ndv / (ndv * (1.0 - k) + k);\n float G1L = ndl / (ndl * (1.0 - k) + k);\n return G1L * G1V;\n}\nvec3 F_Schlick(float ndv, vec3 spec) {\n return spec + (1.0 - spec) * pow(1.0 - ndv, 5.0);\n}\n#endif\n\nfloat fetchDepth(sampler2D depthTexture, vec2 uv)\n{\n vec4 depthTexel = texture2D(depthTexture, uv);\n return depthTexel.r * 2.0 - 1.0;\n}\n\nfloat linearDepth(float depth)\n{\n if (projection[3][3] == 0.0) {\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n }\n else {\n return (depth - projection[3][2]) / projection[2][2];\n }\n}\n\nbool rayIntersectDepth(float rayZNear, float rayZFar, vec2 hitPixel)\n{\n if (rayZFar > rayZNear)\n {\n float t = rayZFar; rayZFar = rayZNear; rayZNear = t;\n }\n float cameraZ = linearDepth(fetchDepth(gBufferTexture2, hitPixel));\n return rayZFar <= cameraZ && rayZNear >= cameraZ - zThicknessThreshold;\n}\n\n\nbool traceScreenSpaceRay(\n vec3 rayOrigin, vec3 rayDir, float jitter,\n out vec2 hitPixel, out vec3 hitPoint, out float iterationCount\n)\n{\n float rayLength = ((rayOrigin.z + rayDir.z * maxRayDistance) > -nearZ)\n ? (-nearZ - rayOrigin.z) / rayDir.z : maxRayDistance;\n\n vec3 rayEnd = rayOrigin + rayDir * rayLength;\n\n vec4 H0 = projection * vec4(rayOrigin, 1.0);\n vec4 H1 = projection * vec4(rayEnd, 1.0);\n\n float k0 = 1.0 / H0.w, k1 = 1.0 / H1.w;\n\n vec3 Q0 = rayOrigin * k0, Q1 = rayEnd * k1;\n\n vec2 P0 = (H0.xy * k0 * 0.5 + 0.5) * viewportSize;\n vec2 P1 = (H1.xy * k1 * 0.5 + 0.5) * viewportSize;\n\n P1 += dot(P1 - P0, P1 - P0) < 0.0001 ? 0.01 : 0.0;\n vec2 delta = P1 - P0;\n\n bool permute = false;\n if (abs(delta.x) < abs(delta.y)) {\n permute = true;\n delta = delta.yx;\n P0 = P0.yx;\n P1 = P1.yx;\n }\n float stepDir = sign(delta.x);\n float invdx = stepDir / delta.x;\n\n vec3 dQ = (Q1 - Q0) * invdx;\n float dk = (k1 - k0) * invdx;\n\n vec2 dP = vec2(stepDir, delta.y * invdx);\n\n float strideScaler = 1.0 - min(1.0, -rayOrigin.z / pixelStrideZCutoff);\n float pixStride = 1.0 + strideScaler * pixelStride;\n\n dP *= pixStride; dQ *= pixStride; dk *= pixStride;\n\n vec4 pqk = vec4(P0, Q0.z, k0);\n vec4 dPQK = vec4(dP, dQ.z, dk);\n\n pqk += dPQK * jitter;\n float rayZFar = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);\n float rayZNear;\n\n bool intersect = false;\n\n vec2 texelSize = 1.0 / viewportSize;\n\n iterationCount = 0.0;\n\n for (int i = 0; i < MAX_ITERATION; i++)\n {\n pqk += dPQK;\n\n rayZNear = rayZFar;\n rayZFar = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);\n\n hitPixel = permute ? pqk.yx : pqk.xy;\n hitPixel *= texelSize;\n\n intersect = rayIntersectDepth(rayZNear, rayZFar, hitPixel);\n\n iterationCount += 1.0;\n\n dPQK *= 1.2;\n\n if (intersect) {\n break;\n }\n }\n\n Q0.xy += dQ.xy * iterationCount;\n Q0.z = pqk.z;\n hitPoint = Q0 / pqk.w;\n\n return intersect;\n}\n\nfloat calculateAlpha(\n float iterationCount, float reflectivity,\n vec2 hitPixel, vec3 hitPoint, float dist, vec3 rayDir\n)\n{\n float alpha = clamp(reflectivity, 0.0, 1.0);\n alpha *= 1.0 - (iterationCount / float(MAX_ITERATION));\n vec2 hitPixelNDC = hitPixel * 2.0 - 1.0;\n float maxDimension = min(1.0, max(abs(hitPixelNDC.x), abs(hitPixelNDC.y)));\n alpha *= 1.0 - max(0.0, maxDimension - screenEdgeFadeStart) / (1.0 - screenEdgeFadeStart);\n\n float _eyeFadeStart = eyeFadeStart;\n float _eyeFadeEnd = eyeFadeEnd;\n if (_eyeFadeStart > _eyeFadeEnd) {\n float tmp = _eyeFadeEnd;\n _eyeFadeEnd = _eyeFadeStart;\n _eyeFadeStart = tmp;\n }\n\n float eyeDir = clamp(rayDir.z, _eyeFadeStart, _eyeFadeEnd);\n alpha *= 1.0 - (eyeDir - _eyeFadeStart) / (_eyeFadeEnd - _eyeFadeStart);\n\n alpha *= 1.0 - clamp(dist / maxRayDistance, 0.0, 1.0);\n\n return alpha;\n}\n\n@import clay.util.rand\n\n@import clay.util.rgbm\n\nvoid main()\n{\n vec4 normalAndGloss = texture2D(gBufferTexture1, v_Texcoord);\n\n if (dot(normalAndGloss.rgb, vec3(1.0)) == 0.0) {\n discard;\n }\n\n float g = normalAndGloss.a;\n#if !defined(PHYSICALLY_CORRECT)\n if (g <= minGlossiness) {\n discard;\n }\n#endif\n\n float reflectivity = (g - minGlossiness) / (1.0 - minGlossiness);\n\n vec3 N = normalize(normalAndGloss.rgb * 2.0 - 1.0);\n N = normalize((toViewSpace * vec4(N, 0.0)).xyz);\n\n vec4 projectedPos = vec4(v_Texcoord * 2.0 - 1.0, fetchDepth(gBufferTexture2, v_Texcoord), 1.0);\n vec4 pos = projectionInv * projectedPos;\n vec3 rayOrigin = pos.xyz / pos.w;\n vec3 V = -normalize(rayOrigin);\n\n float ndv = clamp(dot(N, V), 0.0, 1.0);\n float iterationCount;\n float jitter = rand(fract(v_Texcoord + jitterOffset));\n\n#ifdef PHYSICALLY_CORRECT\n vec4 color = vec4(vec3(0.0), 1.0);\n vec4 albedoMetalness = texture2D(gBufferTexture3, v_Texcoord);\n vec3 albedo = albedoMetalness.rgb;\n float m = albedoMetalness.a;\n vec3 diffuseColor = albedo * (1.0 - m);\n vec3 spec = mix(vec3(0.04), albedo, m);\n\n float jitter2 = rand(fract(v_Texcoord)) * float(TOTAL_SAMPLES);\n\n for (int i = 0; i < SAMPLE_PER_FRAME; i++) {\n vec3 H = importanceSampleNormalGGX(float(i) + jitter2, 1.0 - g, N);\n vec3 rayDir = normalize(reflect(-V, H));\n#else\n vec3 rayDir = normalize(reflect(-V, N));\n#endif\n vec2 hitPixel;\n vec3 hitPoint;\n\n bool intersect = traceScreenSpaceRay(rayOrigin, rayDir, jitter, hitPixel, hitPoint, iterationCount);\n\n float dist = distance(rayOrigin, hitPoint);\n\n vec3 hitNormal = texture2D(gBufferTexture1, hitPixel).rgb * 2.0 - 1.0;\n hitNormal = normalize((toViewSpace * vec4(hitNormal, 0.0)).xyz);\n#ifdef PHYSICALLY_CORRECT\n float ndl = clamp(dot(N, rayDir), 0.0, 1.0);\n float vdh = clamp(dot(V, H), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n vec3 litTexel = vec3(0.0);\n if (dot(hitNormal, rayDir) < 0.0 && intersect) {\n litTexel = texture2D(sourceTexture, hitPixel).rgb;\n litTexel *= pow(clamp(1.0 - dist / 200.0, 0.0, 1.0), 3.0);\n\n }\n else {\n #ifdef SPECULARCUBEMAP_ENABLED\n vec3 rayDirW = normalize(toWorldSpace * vec4(rayDir, 0.0)).rgb;\n litTexel = RGBMDecode(textureCubeLodEXT(specularCubemap, rayDirW, 0.0), 8.12).rgb * specularIntensity;\n#endif\n }\n color.rgb += ndl * litTexel * (\n F_Schlick(ndl, spec) * G_Smith(g, ndv, ndl) * vdh / (ndh * ndv + 0.001)\n );\n }\n color.rgb /= float(SAMPLE_PER_FRAME);\n#else\n #if !defined(SPECULARCUBEMAP_ENABLED)\n if (dot(hitNormal, rayDir) >= 0.0) {\n discard;\n }\n if (!intersect) {\n discard;\n }\n#endif\n float alpha = clamp(calculateAlpha(iterationCount, reflectivity, hitPixel, hitPoint, dist, rayDir), 0.0, 1.0);\n vec4 color = texture2D(sourceTexture, hitPixel);\n color.rgb *= alpha;\n\n#ifdef SPECULARCUBEMAP_ENABLED\n vec3 rayDirW = normalize(toWorldSpace * vec4(rayDir, 0.0)).rgb;\n alpha = alpha * (intersect ? 1.0 : 0.0);\n float bias = (1.0 -g) * 5.0;\n color.rgb += (1.0 - alpha) * RGBMDecode(textureCubeLodEXT(specularCubemap, rayDirW, bias), 8.12).rgb * specularIntensity;\n#endif\n\n#endif\n\n gl_FragColor = encodeHDR(color);\n}\n@end\n\n@export ecgl.ssr.blur\n\nuniform sampler2D texture;\nuniform sampler2D gBufferTexture1;\nuniform sampler2D gBufferTexture2;\nuniform mat4 projection;\nuniform float depthRange : 0.05;\n\nvarying vec2 v_Texcoord;\n\nuniform vec2 textureSize;\nuniform float blurSize : 1.0;\n\n#ifdef BLEND\n #ifdef SSAOTEX_ENABLED\nuniform sampler2D ssaoTex;\n #endif\nuniform sampler2D sourceTexture;\n#endif\n\nfloat getLinearDepth(vec2 coord)\n{\n float depth = texture2D(gBufferTexture2, coord).r * 2.0 - 1.0;\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n}\n\n@import clay.util.rgbm\n\n\nvoid main()\n{\n @import clay.compositor.kernel.gaussian_9\n\n vec4 centerNTexel = texture2D(gBufferTexture1, v_Texcoord);\n float g = centerNTexel.a;\n float maxBlurSize = clamp(1.0 - g, 0.0, 1.0) * blurSize;\n#ifdef VERTICAL\n vec2 off = vec2(0.0, maxBlurSize / textureSize.y);\n#else\n vec2 off = vec2(maxBlurSize / textureSize.x, 0.0);\n#endif\n\n vec2 coord = v_Texcoord;\n\n vec4 sum = vec4(0.0);\n float weightAll = 0.0;\n\n vec3 cN = centerNTexel.rgb * 2.0 - 1.0;\n float cD = getLinearDepth(v_Texcoord);\n for (int i = 0; i < 9; i++) {\n vec2 coord = clamp((float(i) - 4.0) * off + v_Texcoord, vec2(0.0), vec2(1.0));\n float w = gaussianKernel[i]\n * clamp(dot(cN, texture2D(gBufferTexture1, coord).rgb * 2.0 - 1.0), 0.0, 1.0);\n float d = getLinearDepth(coord);\n w *= (1.0 - smoothstep(abs(cD - d) / depthRange, 0.0, 1.0));\n\n weightAll += w;\n sum += decodeHDR(texture2D(texture, coord)) * w;\n }\n\n#ifdef BLEND\n float aoFactor = 1.0;\n #ifdef SSAOTEX_ENABLED\n aoFactor = texture2D(ssaoTex, v_Texcoord).r;\n #endif\n gl_FragColor = encodeHDR(\n sum / weightAll * aoFactor + decodeHDR(texture2D(sourceTexture, v_Texcoord))\n );\n#else\n gl_FragColor = encodeHDR(sum / weightAll);\n#endif\n}\n\n@end"),Ie.prototype.setAmbientCubemap=function(e,t){this._ssrPass.material.set("specularCubemap",e),this._ssrPass.material.set("specularIntensity",t);var r=e&&t;this._ssrPass.material[r?"enableTexture":"disableTexture"]("specularCubemap")},Ie.prototype.update=function(e,t,r,n){var i=e.getWidth(),a=e.getHeight(),o=this._ssrTexture,s=this._texture2,u=this._texture3;o.width=this._prevTexture.width=this._currentTexture.width=i/this._downScale,o.height=this._prevTexture.height=this._currentTexture.height=a/this._downScale,s.width=u.width=i,s.height=u.height=a;var l=this._frameBuffer,c=this._ssrPass,h=this._blurPass1,f=this._blurPass2,d=this._blendPass,p=new Kt,m=new Kt;Kt.transpose(p,t.worldTransform),Kt.transpose(m,t.viewMatrix),c.setUniform("sourceTexture",r),c.setUniform("projection",t.projectionMatrix.array),c.setUniform("projectionInv",t.invProjectionMatrix.array),c.setUniform("toViewSpace",p.array),c.setUniform("toWorldSpace",m.array),c.setUniform("nearZ",t.near);var _=n/this._totalSamples*this._samplePerFrame;if(c.setUniform("jitterOffset",_),c.setUniform("sampleOffset",n*this._samplePerFrame),h.setUniform("textureSize",[o.width,o.height]),f.setUniform("textureSize",[i,a]),f.setUniform("sourceTexture",r),h.setUniform("projection",t.projectionMatrix.array),f.setUniform("projection",t.projectionMatrix.array),l.attach(o),l.bind(e),c.render(e),this._physicallyCorrect&&(l.attach(this._currentTexture),d.setUniform("texture1",this._prevTexture),d.setUniform("texture2",o),d.material.set({weight1:n>=1?.95:0,weight2:n>=1?.05:1}),d.render(e)),l.attach(s),h.setUniform("texture",this._physicallyCorrect?this._currentTexture:o),h.render(e),l.attach(u),f.setUniform("texture",s),f.render(e),l.unbind(e),this._physicallyCorrect){var v=this._prevTexture;this._prevTexture=this._currentTexture,this._currentTexture=v}},Ie.prototype.getTargetTexture=function(){return this._texture3},Ie.prototype.setParameter=function(e,t){"maxIteration"===e?this._ssrPass.material.define("fragment","MAX_ITERATION",t):this._ssrPass.setUniform(e,t)},Ie.prototype.setPhysicallyCorrect=function(e){e?(this._normalDistribution||(this._normalDistribution=pa.generateNormalDistribution(64,this._totalSamples)),this._ssrPass.material.define("fragment","PHYSICALLY_CORRECT"),this._ssrPass.material.set("normalDistribution",this._normalDistribution),this._ssrPass.material.set("normalDistributionSize",[64,this._totalSamples])):this._ssrPass.material.undefine("fragment","PHYSICALLY_CORRECT"),this._physicallyCorrect=e},Ie.prototype.setSSAOTexture=function(e){var t=this._blurPass2;e?(t.material.enableTexture("ssaoTex"),t.material.set("ssaoTex",e)):t.material.disableTexture("ssaoTex")},Ie.prototype.isFinished=function(e){return!this._physicallyCorrect||e>this._totalSamples/this._samplePerFrame},Ie.prototype.dispose=function(e){this._ssrTexture.dispose(e),this._texture2.dispose(e),this._texture3.dispose(e),this._prevTexture.dispose(e),this._currentTexture.dispose(e),this._frameBuffer.dispose(e)};var _a=[0,0,-.321585265978,-.154972575841,.458126042375,.188473391593,.842080129861,.527766490688,.147304551086,-.659453822776,-.331943915203,-.940619700594,.0479226680259,.54812163202,.701581552186,-.709825561388,-.295436780218,.940589268233,-.901489676764,.237713156085,.973570876096,-.109899459384,-.866792314779,-.451805525005,.330975007087,.800048655954,-.344275183665,.381779221166,-.386139432542,-.437418421534,-.576478634965,-.0148463392551,.385798197415,-.262426961053,-.666302061145,.682427250835,-.628010632582,-.732836215494,.10163141741,-.987658134403,.711995289051,-.320024291314,.0296005138058,.950296523438,.0130612307608,-.351024443122,-.879596633704,-.10478487883,.435712737232,.504254490347,.779203817497,.206477676721,.388264289969,-.896736162545,-.153106280781,-.629203242522,-.245517550697,.657969239148,.126830499058,.26862328493,-.634888119007,-.302301223431,.617074219636,.779817204925],va="@export clay.deferred.gbuffer.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat;\nuniform vec2 uvOffset;\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\n#ifdef FIRST_PASS\nattribute vec3 normal : NORMAL;\n#endif\n@import clay.chunk.skinning_header\n#ifdef FIRST_PASS\nvarying vec3 v_Normal;\nattribute vec4 tangent : TANGENT;\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\nvarying vec3 v_WorldPosition;\n#endif\nvarying vec2 v_Texcoord;\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef FIRST_PASS\n vec3 skinnedNormal = normal;\n vec3 skinnedTangent = tangent.xyz;\n bool hasTangent = dot(tangent, tangent) > 0.0;\n#endif\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n #ifdef FIRST_PASS\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n if (hasTangent) {\n skinnedTangent = (skinMatrixWS * vec4(tangent.xyz, 0.0)).xyz;\n }\n #endif\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n#ifdef FIRST_PASS\n v_Normal = normalize((worldInverseTranspose * vec4(skinnedNormal, 0.0)).xyz);\n if (hasTangent) {\n v_Tangent = normalize((worldInverseTranspose * vec4(skinnedTangent, 0.0)).xyz);\n v_Bitangent = normalize(cross(v_Normal, v_Tangent) * tangent.w);\n }\n v_WorldPosition = (world * vec4(skinnedPosition, 1.0)).xyz;\n#endif\n}\n@end\n@export clay.deferred.gbuffer1.fragment\nuniform mat4 viewInverse : VIEWINVERSE;\nuniform float glossiness;\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nuniform sampler2D normalMap;\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\nuniform sampler2D roughGlossMap;\nuniform bool useRoughGlossMap;\nuniform bool useRoughness;\nuniform bool doubleSided;\nuniform int roughGlossChannel: 0;\nfloat indexingTexel(in vec4 texel, in int idx) {\n if (idx == 3) return texel.a;\n else if (idx == 1) return texel.g;\n else if (idx == 2) return texel.b;\n else return texel.r;\n}\nvoid main()\n{\n vec3 N = v_Normal;\n if (doubleSided) {\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = eyePos - v_WorldPosition;\n if (dot(N, V) < 0.0) {\n N = -N;\n }\n }\n if (dot(v_Tangent, v_Tangent) > 0.0) {\n vec3 normalTexel = texture2D(normalMap, v_Texcoord).xyz;\n if (dot(normalTexel, normalTexel) > 0.0) { N = normalTexel * 2.0 - 1.0;\n mat3 tbn = mat3(v_Tangent, v_Bitangent, v_Normal);\n N = normalize(tbn * N);\n }\n }\n gl_FragColor.rgb = (N + 1.0) * 0.5;\n float g = glossiness;\n if (useRoughGlossMap) {\n float g2 = indexingTexel(texture2D(roughGlossMap, v_Texcoord), roughGlossChannel);\n if (useRoughness) {\n g2 = 1.0 - g2;\n }\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n }\n gl_FragColor.a = g + 0.005;\n}\n@end\n@export clay.deferred.gbuffer2.fragment\nuniform sampler2D diffuseMap;\nuniform sampler2D metalnessMap;\nuniform vec3 color;\nuniform float metalness;\nuniform bool useMetalnessMap;\nuniform bool linear;\nvarying vec2 v_Texcoord;\n@import clay.util.srgb\nvoid main ()\n{\n float m = metalness;\n if (useMetalnessMap) {\n vec4 metalnessTexel = texture2D(metalnessMap, v_Texcoord);\n m = clamp(metalnessTexel.r + (m * 2.0 - 1.0), 0.0, 1.0);\n }\n vec4 texel = texture2D(diffuseMap, v_Texcoord);\n if (linear) {\n texel = sRGBToLinear(texel);\n }\n gl_FragColor.rgb = texel.rgb * color;\n gl_FragColor.a = m + 0.005;\n}\n@end\n@export clay.deferred.gbuffer.debug\n@import clay.deferred.chunk.light_head\nuniform int debug: 0;\nvoid main ()\n{\n @import clay.deferred.chunk.gbuffer_read\n if (debug == 0) {\n gl_FragColor = vec4(N, 1.0);\n }\n else if (debug == 1) {\n gl_FragColor = vec4(vec3(z), 1.0);\n }\n else if (debug == 2) {\n gl_FragColor = vec4(position, 1.0);\n }\n else if (debug == 3) {\n gl_FragColor = vec4(vec3(glossiness), 1.0);\n }\n else if (debug == 4) {\n gl_FragColor = vec4(vec3(metalness), 1.0);\n }\n else {\n gl_FragColor = vec4(albedo, 1.0);\n }\n}\n@end";L.import(va),L.import("@export clay.deferred.chunk.light_head\nuniform sampler2D gBufferTexture1;\nuniform sampler2D gBufferTexture2;\nuniform sampler2D gBufferTexture3;\nuniform vec2 windowSize: WINDOW_SIZE;\nuniform vec4 viewport: VIEWPORT;\nuniform mat4 viewProjectionInv;\n#ifdef DEPTH_ENCODED\n@import clay.util.decode_float\n#endif\n@end\n@export clay.deferred.chunk.gbuffer_read\n vec2 uv = gl_FragCoord.xy / windowSize;\n vec2 uv2 = (gl_FragCoord.xy - viewport.xy) / viewport.zw;\n vec4 texel1 = texture2D(gBufferTexture1, uv);\n vec4 texel3 = texture2D(gBufferTexture3, uv);\n if (dot(texel1.rgb, vec3(1.0)) == 0.0) {\n discard;\n }\n float glossiness = texel1.a;\n float metalness = texel3.a;\n vec3 N = texel1.rgb * 2.0 - 1.0;\n float z = texture2D(gBufferTexture2, uv).r * 2.0 - 1.0;\n vec2 xy = uv2 * 2.0 - 1.0;\n vec4 projectedPos = vec4(xy, z, 1.0);\n vec4 p4 = viewProjectionInv * projectedPos;\n vec3 position = p4.xyz / p4.w;\n vec3 albedo = texel3.rgb;\n vec3 diffuseColor = albedo * (1.0 - metalness);\n vec3 specularColor = mix(vec3(0.04), albedo, metalness);\n@end\n@export clay.deferred.chunk.light_equation\nfloat D_Phong(in float g, in float ndh) {\n float a = pow(8192.0, g);\n return (a + 2.0) / 8.0 * pow(ndh, a);\n}\nfloat D_GGX(in float g, in float ndh) {\n float r = 1.0 - g;\n float a = r * r;\n float tmp = ndh * ndh * (a - 1.0) + 1.0;\n return a / (3.1415926 * tmp * tmp);\n}\nvec3 F_Schlick(in float ndv, vec3 spec) {\n return spec + (1.0 - spec) * pow(1.0 - ndv, 5.0);\n}\nvec3 lightEquation(\n in vec3 lightColor, in vec3 diffuseColor, in vec3 specularColor,\n in float ndl, in float ndh, in float ndv, in float g\n)\n{\n return ndl * lightColor\n * (diffuseColor + D_Phong(g, ndh) * F_Schlick(ndv, specularColor));\n}\n@end");var ga=At.extend(function(){return{enableTargetTexture1:!0,enableTargetTexture2:!0,enableTargetTexture3:!0,renderTransparent:!1,_gBufferRenderList:[],_gBufferTex1:new Nn({minFilter:Qt.NEAREST,magFilter:Qt.NEAREST,type:Qt.HALF_FLOAT}),_gBufferTex2:new Nn({minFilter:Qt.NEAREST,magFilter:Qt.NEAREST,format:Qt.DEPTH_STENCIL,type:Qt.UNSIGNED_INT_24_8_WEBGL}),_gBufferTex3:new Nn({minFilter:Qt.NEAREST,magFilter:Qt.NEAREST}),_defaultNormalMap:new Nn({image:Fe("#000")}),_defaultRoughnessMap:new Nn({image:Fe("#fff")}),_defaultMetalnessMap:new Nn({image:Fe("#fff")}),_defaultDiffuseMap:new Nn({image:Fe("#fff")}),_frameBuffer:new wi,_gBufferMaterial1:new sr({shader:new L(L.source("clay.deferred.gbuffer.vertex"),L.source("clay.deferred.gbuffer1.fragment")),vertexDefines:{FIRST_PASS:null},fragmentDefines:{FIRST_PASS:null}}),_gBufferMaterial2:new sr({shader:new L(L.source("clay.deferred.gbuffer.vertex"),L.source("clay.deferred.gbuffer2.fragment"))}),_debugPass:new Vi({fragment:L.source("clay.deferred.gbuffer.debug")})}},{resize:function(e,t){this._gBufferTex1.width===e&&this._gBufferTex1.height===t||(this._gBufferTex1.width=e,this._gBufferTex1.height=t,this._gBufferTex2.width=e,this._gBufferTex2.height=t,this._gBufferTex3.width=e,this._gBufferTex3.height=t)},setViewport:function(e,t,r,n,i){var a;a="object"==typeof e?e:{x:e,y:t,width:r,height:n,devicePixelRatio:i||1},this._frameBuffer.viewport=a},getViewport:function(){return this._frameBuffer.viewport?this._frameBuffer.viewport:{x:0,y:0,width:this._gBufferTex1.width,height:this._gBufferTex1.height,devicePixelRatio:1}},update:function(e,t,r){for(var n=e.gl,i=this._frameBuffer,a=i.viewport,o=t.updateRenderList(r),s=o.opaque,u=o.transparent,l=0,c=this._gBufferRenderList,h=0;h=this._maxSize&&a>0){var s=r.head;r.remove(s),delete n[s.key],i=s.value,this._lastRemovedEntry=s}o?o.value=t:o=new Ta(t),o.key=e,r.insertEntry(o),n[e]=o}return i},ba.get=function(e){var t=this._map[e],r=this._list;if(null!=t)return t!==r.tail&&(r.remove(t),r.insertEntry(t)),t.value},ba.clear=function(){this._list.clear(),this._map={}};var Aa=Yr.extend({cubemap:null,castShadow:!1,_normalDistribution:null,_brdfLookup:null},{type:"AMBIENT_CUBEMAP_LIGHT",prefilter:function(e,t){this._brdfLookup||(this._normalDistribution=pa.generateNormalDistribution(),this._brdfLookup=pa.integrateBRDF(e,this._normalDistribution));var r=this.cubemap;if(!r.__prefiltered){var n=pa.prefilterEnvironmentMap(e,r,{encodeRGBM:!0,width:t,height:t},this._normalDistribution,this._brdfLookup);this.cubemap=n.environmentMap,this.cubemap.__prefiltered=!0,r.dispose(e)}},uniformTemplates:{ambientCubemapLightColor:{type:"3f",value:function(e){var t=e.color,r=e.intensity;return[t[0]*r,t[1]*r,t[2]*r]}},ambientCubemapLightCubemap:{type:"t",value:function(e){return e.cubemap}},ambientCubemapLightBRDFLookup:{type:"t",value:function(e){return e._brdfLookup}}}}),Sa=Yr.extend({castShadow:!1,coefficients:[]},function(){this._coefficientsTmpArr=new Mt.Float32Array(27)},{type:"AMBIENT_SH_LIGHT",uniformTemplates:{ambientSHLightColor:{type:"3f",value:function(e){var t=e.color,r=e.intensity;return[t[0]*r,t[1]*r,t[2]*r]}},ambientSHLightCoefficients:{type:"3f",value:function(e){for(var t=e._coefficientsTmpArr,r=0;r3?t[3]=e[3]:t[3]=1,t):(t=Ze(e||"#000",t)||[0,0,0,0],t[0]/=255,t[1]/=255,t[2]/=255,t)},Da.stringifyColor=function(e,t){return e=e.slice(),e[0]=Math.round(255*e[0]),e[1]=Math.round(255*e[1]),e[2]=Math.round(255*e[2]),"hex"===t?"#"+((1<<24)+(e[0]<<16)+(e[1]<<8)+e[2]).toString(16).slice(1):Qe(e,t)},Da.directionFromAlphaBeta=function(e,t){var r=e/180*Math.PI+Math.PI/2,n=-t/180*Math.PI+Math.PI/2,i=[],a=Math.sin(r);return i[0]=a*Math.cos(n),i[1]=-Math.cos(r),i[2]=a*Math.sin(n),i};var Ia={type:"compositor",nodes:[{name:"source",type:"texture",outputs:{color:{}}},{name:"source_half",shader:"#source(clay.compositor.downsample)",inputs:{texture:"source"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0, height * 1.0] )"}},{name:"bright",shader:"#source(clay.compositor.bright)",inputs:{texture:"source_half"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{threshold:2,scale:4,textureSize:"expr([width * 1.0 / 2, height / 2])"}},{name:"bright_downsample_4",shader:"#source(clay.compositor.downsample)",inputs:{texture:"bright"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 4)",height:"expr(height * 1.0 / 4)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0 / 2, height / 2] )"}},{name:"bright_downsample_8",shader:"#source(clay.compositor.downsample)",inputs:{texture:"bright_downsample_4"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 8)",height:"expr(height * 1.0 / 8)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0 / 4, height / 4] )"}},{name:"bright_downsample_16",shader:"#source(clay.compositor.downsample)",inputs:{texture:"bright_downsample_8"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 16)",height:"expr(height * 1.0 / 16)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0 / 8, height / 8] )"}},{name:"bright_downsample_32",shader:"#source(clay.compositor.downsample)",inputs:{texture:"bright_downsample_16"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 32)",height:"expr(height * 1.0 / 32)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0 / 16, height / 16] )"}},{name:"bright_upsample_16_blur_h",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_downsample_32"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 16)",height:"expr(height * 1.0 / 16)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 32, height / 32] )"}},{name:"bright_upsample_16_blur_v",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_16_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 16)",height:"expr(height * 1.0 / 16)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 32, height * 1.0 / 32] )"}},{name:"bright_upsample_8_blur_h",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_downsample_16"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 8)",height:"expr(height * 1.0 / 8)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 16, height * 1.0 / 16] )"}},{name:"bright_upsample_8_blur_v",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_8_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 8)",height:"expr(height * 1.0 / 8)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 16, height * 1.0 / 16] )"}},{name:"bright_upsample_8_blend",shader:"#source(clay.compositor.blend)",inputs:{texture1:"bright_upsample_8_blur_v",texture2:"bright_upsample_16_blur_v"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 8)",height:"expr(height * 1.0 / 8)",type:"HALF_FLOAT"}}},parameters:{weight1:.3,weight2:.7}},{name:"bright_upsample_4_blur_h",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_downsample_8"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 4)",height:"expr(height * 1.0 / 4)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 8, height * 1.0 / 8] )"}},{name:"bright_upsample_4_blur_v",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_4_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 4)",height:"expr(height * 1.0 / 4)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 8, height * 1.0 / 8] )"}},{name:"bright_upsample_4_blend",shader:"#source(clay.compositor.blend)",inputs:{texture1:"bright_upsample_4_blur_v",texture2:"bright_upsample_8_blend"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 4)",height:"expr(height * 1.0 / 4)",type:"HALF_FLOAT"}}},parameters:{weight1:.3,weight2:.7}},{name:"bright_upsample_2_blur_h",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_downsample_4"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 4, height * 1.0 / 4] )"}},{name:"bright_upsample_2_blur_v",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_2_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 4, height * 1.0 / 4] )"}},{name:"bright_upsample_2_blend",shader:"#source(clay.compositor.blend)",inputs:{texture1:"bright_upsample_2_blur_v",texture2:"bright_upsample_4_blend"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{weight1:.3,weight2:.7}},{name:"bright_upsample_full_blur_h",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 2, height * 1.0 / 2] )"}},{name:"bright_upsample_full_blur_v",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_full_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 2, height * 1.0 / 2] )"}},{name:"bloom_composite",shader:"#source(clay.compositor.blend)",inputs:{texture1:"bright_upsample_full_blur_v",texture2:"bright_upsample_2_blend"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{weight1:.3,weight2:.7}},{name:"coc",shader:"#source(ecgl.dof.coc)",outputs:{color:{parameters:{minFilter:"NEAREST",magFilter:"NEAREST",width:"expr(width * 1.0)",height:"expr(height * 1.0)"}}},parameters:{focalDist:50,focalRange:30}},{name:"dof_far_blur",shader:"#source(ecgl.dof.diskBlur)",inputs:{texture:"source",coc:"coc"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0, height * 1.0] )"}},{name:"dof_near_blur",shader:"#source(ecgl.dof.diskBlur)",inputs:{texture:"source",coc:"coc"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0, height * 1.0] )"},defines:{BLUR_NEARFIELD:null}},{name:"dof_coc_blur",shader:"#source(ecgl.dof.diskBlur)",inputs:{texture:"coc"},outputs:{color:{parameters:{minFilter:"NEAREST",magFilter:"NEAREST",width:"expr(width * 1.0)",height:"expr(height * 1.0)"}}},parameters:{textureSize:"expr( [width * 1.0, height * 1.0] )"},defines:{BLUR_COC:null}},{name:"dof_composite",shader:"#source(ecgl.dof.composite)",inputs:{original:"source",blurred:"dof_far_blur",nearfield:"dof_near_blur",coc:"coc",nearcoc:"dof_coc_blur"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}}},{name:"composite",shader:"#source(clay.compositor.hdr.composite)",inputs:{texture:"source",bloom:"bloom_composite"},defines:{}},{name:"FXAA",shader:"#source(clay.compositor.fxaa)",inputs:{texture:"composite"}}]};L.import(ra),L.import(na),L.import(ia),L.import(aa),L.import(oa),L.import(sa),L.import(ua),L.import(la),L.import(va),L.import("@export ecgl.dof.coc\n\nuniform sampler2D depth;\n\nuniform float zNear: 0.1;\nuniform float zFar: 2000;\n\nuniform float focalDistance: 3;\nuniform float focalRange: 1;\nuniform float focalLength: 30;\nuniform float fstop: 2.8;\n\nvarying vec2 v_Texcoord;\n\n@import clay.util.encode_float\n\nvoid main()\n{\n float z = texture2D(depth, v_Texcoord).r * 2.0 - 1.0;\n\n float dist = 2.0 * zNear * zFar / (zFar + zNear - z * (zFar - zNear));\n\n float aperture = focalLength / fstop;\n\n float coc;\n\n float uppper = focalDistance + focalRange;\n float lower = focalDistance - focalRange;\n if (dist <= uppper && dist >= lower) {\n coc = 0.5;\n }\n else {\n float focalAdjusted = dist > uppper ? uppper : lower;\n\n coc = abs(aperture * (focalLength * (dist - focalAdjusted)) / (dist * (focalAdjusted - focalLength)));\n coc = clamp(coc, 0.0, 2.0) / 2.00001;\n\n if (dist < lower) {\n coc = -coc;\n }\n coc = coc * 0.5 + 0.5;\n }\n\n gl_FragColor = encodeFloat(coc);\n}\n@end\n\n\n@export ecgl.dof.composite\n\n#define DEBUG 0\n\nuniform sampler2D original;\nuniform sampler2D blurred;\nuniform sampler2D nearfield;\nuniform sampler2D coc;\nuniform sampler2D nearcoc;\nvarying vec2 v_Texcoord;\n\n@import clay.util.rgbm\n@import clay.util.float\n\nvoid main()\n{\n vec4 blurredColor = decodeHDR(texture2D(blurred, v_Texcoord));\n vec4 originalColor = decodeHDR(texture2D(original, v_Texcoord));\n\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord));\n\n fCoc = abs(fCoc * 2.0 - 1.0);\n\n float weight = smoothstep(0.0, 1.0, fCoc);\n \n#ifdef NEARFIELD_ENABLED\n vec4 nearfieldColor = decodeHDR(texture2D(nearfield, v_Texcoord));\n float fNearCoc = decodeFloat(texture2D(nearcoc, v_Texcoord));\n fNearCoc = abs(fNearCoc * 2.0 - 1.0);\n\n gl_FragColor = encodeHDR(\n mix(\n nearfieldColor, mix(originalColor, blurredColor, weight),\n pow(1.0 - fNearCoc, 4.0)\n )\n );\n#else\n gl_FragColor = encodeHDR(mix(originalColor, blurredColor, weight));\n#endif\n\n}\n\n@end\n\n\n\n@export ecgl.dof.diskBlur\n\n#define POISSON_KERNEL_SIZE 16;\n\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\n\nuniform float blurRadius : 10.0;\nuniform vec2 textureSize : [512.0, 512.0];\n\nuniform vec2 poissonKernel[POISSON_KERNEL_SIZE];\n\nuniform float percent;\n\nfloat nrand(const in vec2 n) {\n return fract(sin(dot(n.xy ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\n@import clay.util.rgbm\n@import clay.util.float\n\n\nvoid main()\n{\n vec2 offset = blurRadius / textureSize;\n\n float rnd = 6.28318 * nrand(v_Texcoord + 0.07 * percent );\n float cosa = cos(rnd);\n float sina = sin(rnd);\n vec4 basis = vec4(cosa, -sina, sina, cosa);\n\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n\n#ifdef BLUR_COC\n float cocSum = 0.0;\n#else\n vec4 color = vec4(0.0);\n#endif\n\n\n float weightSum = 0.0;\n\n for (int i = 0; i < POISSON_KERNEL_SIZE; i++) {\n vec2 ofs = poissonKernel[i];\n\n ofs = vec2(dot(ofs, basis.xy), dot(ofs, basis.zw));\n\n vec2 uv = v_Texcoord + ofs * offset;\n vec4 texel = texture2D(texture, uv);\n\n float w = 1.0;\n#ifdef BLUR_COC\n float fCoc = decodeFloat(texel) * 2.0 - 1.0;\n cocSum += clamp(fCoc, -1.0, 0.0) * w;\n#else\n texel = decodeHDR(texel);\n #if !defined(BLUR_NEARFIELD)\n float fCoc = decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0;\n w *= abs(fCoc);\n #endif\n color += texel * w;\n#endif\n\n weightSum += w;\n }\n\n#ifdef BLUR_COC\n gl_FragColor = encodeFloat(clamp(cocSum / weightSum, -1.0, 0.0) * 0.5 + 0.5);\n#else\n color /= weightSum;\n gl_FragColor = encodeHDR(color);\n#endif\n}\n\n@end"),L.import("@export ecgl.edge\n\nuniform sampler2D texture;\n\nuniform sampler2D normalTexture;\nuniform sampler2D depthTexture;\n\nuniform mat4 projectionInv;\n\nuniform vec2 textureSize;\n\nuniform vec4 edgeColor: [0,0,0,0.8];\n\nvarying vec2 v_Texcoord;\n\nvec3 packColor(vec2 coord) {\n float z = texture2D(depthTexture, coord).r * 2.0 - 1.0;\n vec4 p = vec4(v_Texcoord * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * p;\n\n return vec3(\n texture2D(normalTexture, coord).rg,\n -p4.z / p4.w / 5.0\n );\n}\n\nvoid main() {\n vec2 cc = v_Texcoord;\n vec3 center = packColor(cc);\n\n float size = clamp(1.0 - (center.z - 10.0) / 100.0, 0.0, 1.0) * 0.5;\n float dx = size / textureSize.x;\n float dy = size / textureSize.y;\n\n vec2 coord;\n vec3 topLeft = packColor(cc+vec2(-dx, -dy));\n vec3 top = packColor(cc+vec2(0.0, -dy));\n vec3 topRight = packColor(cc+vec2(dx, -dy));\n vec3 left = packColor(cc+vec2(-dx, 0.0));\n vec3 right = packColor(cc+vec2(dx, 0.0));\n vec3 bottomLeft = packColor(cc+vec2(-dx, dy));\n vec3 bottom = packColor(cc+vec2(0.0, dy));\n vec3 bottomRight = packColor(cc+vec2(dx, dy));\n\n vec3 v = -topLeft-2.0*top-topRight+bottomLeft+2.0*bottom+bottomRight;\n vec3 h = -bottomLeft-2.0*left-topLeft+bottomRight+2.0*right+topRight;\n\n float edge = sqrt(dot(h, h) + dot(v, v));\n\n edge = smoothstep(0.8, 1.0, edge);\n\n gl_FragColor = mix(texture2D(texture, v_Texcoord), vec4(edgeColor.rgb, 1.0), edgeColor.a * edge);\n}\n@end");var Fa={color:{parameters:{width:function(e){return e.getWidth()},height:function(e){return e.getHeight()}}}},Ba=["composite","FXAA"];tt.prototype.resize=function(e,t,r){r=r||1,e*=r,t*=r;var n=this._sourceTexture,i=this._depthTexture;n.width=e,n.height=t,i.width=e,i.height=t,this._gBufferPass.resize(e,t)},tt.prototype._ifRenderNormalPass=function(){return this._enableSSAO||this._enableEdge||this._enableSSR},tt.prototype._getPrevNode=function(e){for(var t=Ba.indexOf(e.name)-1,r=this._finalNodesChain[t];r&&!this._compositor.getNodeByName(r.name);)t-=1,r=this._finalNodesChain[t];return r},tt.prototype._getNextNode=function(e){for(var t=Ba.indexOf(e.name)+1,r=this._finalNodesChain[t];r&&!this._compositor.getNodeByName(r.name);)t+=1,r=this._finalNodesChain[t];return r},tt.prototype._addChainNode=function(e){var t=this._getPrevNode(e),r=this._getNextNode(e);t&&(t.outputs=Fa,e.inputs.texture=t.name,r?(e.outputs=Fa,r.inputs.texture=e.name):e.outputs=null,this._compositor.addNode(e))},tt.prototype._removeChainNode=function(e){var t=this._getPrevNode(e),r=this._getNextNode(e);t&&(r?(t.outputs=Fa,r.inputs.texture=t.name):t.outputs=null,this._compositor.removeNode(e))},tt.prototype.updateGBuffer=function(e,t,r,n){this._ifRenderNormalPass()&&this._gBufferPass.update(e,t,r)},tt.prototype.updateSSAO=function(e,t,r,n){this._ssaoPass.update(e,r,n)},tt.prototype.enableSSAO=function(){this._enableSSAO=!0},tt.prototype.disableSSAO=function(){this._enableSSAO=!1},tt.prototype.enableSSR=function(){this._enableSSR=!0,this._gBufferPass.enableTargetTexture3=!0},tt.prototype.disableSSR=function(){this._enableSSR=!1,this._gBufferPass.enableTargetTexture3=!1},tt.prototype.getSSAOTexture=function(){return this._ssaoPass.getTargetTexture()},tt.prototype.getSourceFrameBuffer=function(){return this._framebuffer},tt.prototype.getSourceTexture=function(){return this._sourceTexture},tt.prototype.disableFXAA=function(){this._removeChainNode(this._fxaaNode)},tt.prototype.enableFXAA=function(){this._addChainNode(this._fxaaNode)},tt.prototype.enableBloom=function(){this._compositeNode.inputs.bloom="bloom_composite",this._compositor.dirty()},tt.prototype.disableBloom=function(){this._compositeNode.inputs.bloom=null,this._compositor.dirty()},tt.prototype.enableDOF=function(){this._compositeNode.inputs.texture="dof_composite",this._compositor.dirty()},tt.prototype.disableDOF=function(){this._compositeNode.inputs.texture="source",this._compositor.dirty()},tt.prototype.enableColorCorrection=function(){this._compositeNode.define("COLOR_CORRECTION"),this._enableColorCorrection=!0},tt.prototype.disableColorCorrection=function(){this._compositeNode.undefine("COLOR_CORRECTION"),this._enableColorCorrection=!1},tt.prototype.enableEdge=function(){this._enableEdge=!0},tt.prototype.disableEdge=function(){this._enableEdge=!1},tt.prototype.setBloomIntensity=function(e){null!=e&&this._compositeNode.setParameter("bloomIntensity",e)},tt.prototype.setSSAOParameter=function(e,t){if(null!=t)switch(e){case"quality":var r={low:6,medium:12,high:32,ultra:62}[t]||12;this._ssaoPass.setParameter("kernelSize",r);break;case"radius":this._ssaoPass.setParameter(e,t),this._ssaoPass.setParameter("bias",t/50);break;case"intensity":this._ssaoPass.setParameter(e,t)}},tt.prototype.setDOFParameter=function(e,t){if(null!=t)switch(e){case"focalDistance":case"focalRange":case"fstop":this._cocNode.setParameter(e,t);break;case"blurRadius":for(var r=0;r=this._haltonSequence.length},render:function(e){var t=this._blendPass;0===this._frame?(t.setUniform("weight1",0),t.setUniform("weight2",1)):(t.setUniform("weight1",.9),t.setUniform("weight2",.1)),t.setUniform("texture1",this._prevFrameTex),t.setUniform("texture2",this._sourceTex),this._blendFb.attach(this._outputTex),this._blendFb.bind(e),t.render(e),this._blendFb.unbind(e),this._outputPass.setUniform("texture",this._outputTex),this._outputPass.render(e);var r=this._prevFrameTex;this._prevFrameTex=this._outputTex,this._outputTex=r,this._frame++},dispose:function(e){this._sourceFb.dispose(e),this._blendFb.dispose(e),this._prevFrameTex.dispose(e),this._outputTex.dispose(e),this._sourceTex.dispose(e),this._outputPass.dispose(e),this._blendPass.dispose(e)}},nt.prototype.setProjection=function(e){var t=this.camera;t&&t.update(),"perspective"===e?this.camera instanceof kn||(this.camera=new kn,t&&this.camera.setLocalTransform(t.localTransform)):this.camera instanceof Hn||(this.camera=new Hn,t&&this.camera.setLocalTransform(t.localTransform)),this.camera.near=.1,this.camera.far=2e3},nt.prototype.setViewport=function(e,t,r,n,i){this.camera instanceof kn&&(this.camera.aspect=r/n),i=i||1,this.viewport.x=e,this.viewport.y=t,this.viewport.width=r,this.viewport.height=n,this.viewport.devicePixelRatio=i,this._compositor.resize(r*i,n*i),this._temporalSS.resize(r*i,n*i)},nt.prototype.containPoint=function(e,t){var r=this.viewport;return t=this.layer.renderer.getHeight()-t,e>=r.x&&t>=r.y&&e<=r.x+r.width&&t<=r.y+r.height};var Ua=new lr;nt.prototype.castRay=function(e,t,r){var n=this.layer.renderer,i=n.viewport;return n.viewport=this.viewport,n.screenToNDC(e,t,Ua),this.camera.castRay(Ua,r),n.viewport=i,r},nt.prototype.prepareRender=function(){this.scene.update(),this.scene.updateLights(),this.scene.updateRenderList(this.camera),this.camera.update(),this._frame=0,this._temporalSS.resetFrame();for(var e=this.scene.getLights(),t=0;tthis.camera.far||e1&&n&&n.length>1){var a=pt(n)/pt(i);!isFinite(a)&&(a=1),t.pinchScale=a;var o=mt(n);return t.pinchX=o[0],t.pinchY=o[1],{type:"pinch",target:e[0].target,event:t}}}}},Ya=At.extend(function(){return{timeline:null,domElement:null,target:null,_center:new Ot,minDistance:.1,maxDistance:1e3,minAlpha:-90,maxAlpha:90,minBeta:-1/0,maxBeta:1/0,autoRotateAfterStill:0,autoRotateDirection:"cw",autoRotateSpeed:60,_mode:"rotate",damping:.8,rotateSensitivity:1,zoomSensitivity:1,panSensitivity:1,_needsUpdate:!1,_rotating:!1,_phi:0,_theta:0,_mouseX:0,_mouseY:0,_rotateVelocity:new lr,_panVelocity:new lr,_distance:20,_zoomSpeed:0,_stillTimeout:0,_animators:[],_gestureMgr:new qa}},function(){this._mouseDownHandler=this._mouseDownHandler.bind(this),this._mouseWheelHandler=this._mouseWheelHandler.bind(this),this._mouseMoveHandler=this._mouseMoveHandler.bind(this),this._mouseUpHandler=this._mouseUpHandler.bind(this),this._pinchHandler=this._pinchHandler.bind(this),this.update=this.update.bind(this),this.init()},{init:function(){var e=this.domElement;e.addEventListener("touchstart",this._mouseDownHandler),e.addEventListener("mousedown",this._mouseDownHandler),e.addEventListener("mousewheel",this._mouseWheelHandler),this.timeline&&this.timeline.on("frame",this.update)},dispose:function(){var e=this.domElement;e.removeEventListener("touchstart",this._mouseDownHandler),e.removeEventListener("touchmove",this._mouseMoveHandler),e.removeEventListener("touchend",this._mouseUpHandler),e.removeEventListener("mousedown",this._mouseDownHandler),e.removeEventListener("mousemove",this._mouseMoveHandler),e.removeEventListener("mouseup",this._mouseUpHandler),e.removeEventListener("mousewheel",this._mouseWheelHandler),e.removeEventListener("mouseout",this._mouseUpHandler),this.timeline&&this.timeline.off("frame",this.update),this.stopAllAnimation()},getDistance:function(){return this._distance},setDistance:function(e){this._distance=e,this._needsUpdate=!0},getAlpha:function(){return this._theta/Math.PI*180},getBeta:function(){return-this._phi/Math.PI*180},getCenter:function(){return this._center.toArray()},setAlpha:function(e){e=Math.max(Math.min(this.maxAlpha,e),this.minAlpha),this._theta=e/180*Math.PI,this._needsUpdate=!0},setBeta:function(e){e=Math.max(Math.min(this.maxBeta,e),this.minBeta),this._phi=-e/180*Math.PI,this._needsUpdate=!0},setCenter:function(e){this._center.setArray(e)},setOption:function(e){e=e||{},["autoRotate","autoRotateAfterStill","autoRotateDirection","autoRotateSpeed","damping","minDistance","maxDistance","minAlpha","maxAlpha","minBeta","maxBeta","rotateSensitivity","zoomSensitivity","panSensitivity"].forEach(function(t){null!=e[t]&&(this[t]=e[t])},this),null!=e.distance&&this.setDistance(e.distance),null!=e.alpha&&this.setAlpha(e.alpha),null!=e.beta&&this.setBeta(e.beta),e.center&&this.setCenter(e.center)},animateTo:function(e){var t=this,r={},n={},i=this.timeline;if(i)return null!=e.distance&&(r.distance=this.getDistance(),n.distance=e.distance),null!=e.alpha&&(r.alpha=this.getAlpha(),n.alpha=e.alpha),null!=e.beta&&(r.beta=this.getBeta(),n.beta=e.beta),null!=e.center&&(r.center=this.getCenter(),n.center=e.center),this._addAnimator(i.animate(r).when(e.duration||1e3,n).during(function(){null!=r.alpha&&t.setAlpha(r.alpha),null!=r.beta&&t.setBeta(r.beta),null!=r.distance&&t.setDistance(r.distance),null!=r.center&&t.setCenter(r.center),t._needsUpdate=!0}).done(e.done)).start(e.easing||"linear")},stopAllAnimation:function(){for(var e=0;e0},update:function(e){if(e=e||16,this._rotating){var t=("cw"===this.autoRotateDirection?1:-1)*this.autoRotateSpeed/180*Math.PI;this._phi-=t*e/1e3,this._needsUpdate=!0}else this._rotateVelocity.len()>0&&(this._needsUpdate=!0);(Math.abs(this._zoomSpeed)>.01||this._panVelocity.len()>0)&&(this._needsUpdate=!0),this._needsUpdate&&(this._updateDistance(Math.min(e,50)),this._updatePan(Math.min(e,50)),this._updateRotate(Math.min(e,50)),this._updateTransform(),this.target.update(),this.trigger("update"),this._needsUpdate=!1)},_updateRotate:function(e){var t=this._rotateVelocity;this._phi=t.y*e/20+this._phi,this._theta=t.x*e/20+this._theta,this.setAlpha(this.getAlpha()),this.setBeta(this.getBeta()),this._vectorDamping(t,this.damping),t.x=t.y=0},_updateDistance:function(e){this._setDistance(this._distance+this._zoomSpeed*e/20),this._zoomSpeed*=this.damping},_setDistance:function(e){this._distance=Math.max(Math.min(e,this.maxDistance),this.minDistance)},_updatePan:function(e){var t=this._panVelocity,r=this._distance,n=this.target,i=n.worldTransform.y,a=n.worldTransform.x;this._center.scaleAndAdd(a,-t.x*r/200).scaleAndAdd(i,-t.y*r/200),this._vectorDamping(t,0),t.x=t.y=0},_updateTransform:function(){var e=this.target,t=new Ot,r=this._theta+Math.PI/2,n=this._phi+Math.PI/2,i=Math.sin(r);t.x=i*Math.cos(n),t.y=-Math.cos(r),t.z=i*Math.sin(n),e.position.copy(this._center).scaleAndAdd(t,this._distance),e.rotation.identity().rotateY(-this._phi).rotateX(-this._theta)},_startCountingStill:function(){clearTimeout(this._stillTimeout);var e=this.autoRotateAfterStill,t=this;!isNaN(e)&&e>0&&(this._stillTimeout=setTimeout(function(){t._rotating=!0},1e3*e))},_vectorDamping:function(e,t){var r=e.len();r*=t,r<1e-4&&(r=0),e.normalize().scale(r)},decomposeTransform:function(){if(this.target){this.target.updateWorldTransform();var e=this.target.worldTransform.z,t=Math.asin(e.y),r=Math.atan2(e.x,e.z);this._theta=t,this._phi=-r,this.setBeta(this.getBeta()),this.setAlpha(this.getAlpha()),this._setDistance(this.target.position.dist(this._center))}},_mouseDownHandler:function(e){if(!this._isAnimating()){var t=e.clientX,r=e.clientY;if(e.targetTouches){var n=e.targetTouches[0];t=n.clientX,r=n.clientY,this._mode="rotate",this._processGesture(e,"start")}var i=this.domElement;i.addEventListener("touchmove",this._mouseMoveHandler),i.addEventListener("touchend",this._mouseUpHandler),i.addEventListener("mousemove",this._mouseMoveHandler),i.addEventListener("mouseup",this._mouseUpHandler),i.addEventListener("mouseout",this._mouseUpHandler),0===e.button?this._mode="rotate":1===e.button?this._mode="pan":this._mode=null,this._rotateVelocity.set(0,0),this._rotating=!1,this.autoRotate&&this._startCountingStill(),this._mouseX=t,this._mouseY=r}},_mouseMoveHandler:function(e){if(!this._isAnimating()){var t,r=e.clientX,n=e.clientY;if(e.targetTouches){var i=e.targetTouches[0];r=i.clientX,n=i.clientY,t=this._processGesture(e,"change")}var a=_t(this.panSensitivity),o=_t(this.rotateSensitivity);t||("rotate"===this._mode?(this._rotateVelocity.y+=(r-this._mouseX)/this.domElement.clientWidth*2*o[0],this._rotateVelocity.x+=(n-this._mouseY)/this.domElement.clientHeight*2*o[1]):"pan"===this._mode&&(this._panVelocity.x+=(r-this._mouseX)/this.domElement.clientWidth*a[0]*400,this._panVelocity.y+=(-n+this._mouseY)/this.domElement.clientHeight*a[1]*400)),this._mouseX=r,this._mouseY=n,e.preventDefault()}},_mouseWheelHandler:function(e){if(!this._isAnimating()){var t=e.wheelDelta||-e.detail;0!==t&&this._zoomHandler(e,t>0?-1:1)}},_pinchHandler:function(e){this._isAnimating()||this._zoomHandler(e,e.pinchScale>1?-.4:.4)},_zoomHandler:function(e,t){var r=Math.max(Math.min(this._distance-this.minDistance,this.maxDistance-this._distance));this._zoomSpeed=t*Math.max(r/40*this.zoomSensitivity,.2),this._rotating=!1,this.autoRotate&&"rotate"===this._mode&&this._startCountingStill(),e.preventDefault()},_mouseUpHandler:function(e){var t=this.domElement;t.removeEventListener("touchmove",this._mouseMoveHandler),t.removeEventListener("touchend",this._mouseUpHandler),t.removeEventListener("mousemove",this._mouseMoveHandler),t.removeEventListener("mouseup",this._mouseUpHandler),t.removeEventListener("mouseout",this._mouseUpHandler),this._processGesture(e,"end")},_addAnimator:function(e){var t=this._animators;return t.push(e),e.done(function(){var r=t.indexOf(e);r>=0&&t.splice(r,1)}),e},_processGesture:function(e,t){var r=this._gestureMgr;"start"===t&&r.clear();var n=r.recognize(e,null,this.domElement);if("end"===t&&r.clear(),n){var i=n.type;e.gestureEvent=i,this._pinchHandler(n.event)}return n}});Object.defineProperty(Ya.prototype,"autoRotate",{get:function(){return this._autoRotate},set:function(e){this._autoRotate=e,this._rotating=e}}),Object.defineProperty(Ya.prototype,"target",{get:function(){return this._target},set:function(e){e&&e.target&&this.setCenter(e.target.toArray()),this._target=e,this.decomposeTransform()}});var Za=Pt.vec4,Ja=function(e,t,r,n){e=e||0,t=t||0,r=r||0,n=n||0,this.array=Za.fromValues(e,t,r,n),this._dirty=!0};Ja.prototype={constructor:Ja,add:function(e){return Za.add(this.array,this.array,e.array),this._dirty=!0,this},set:function(e,t,r,n){return this.array[0]=e,this.array[1]=t,this.array[2]=r,this.array[3]=n,this._dirty=!0,this},setArray:function(e){return this.array[0]=e[0],this.array[1]=e[1],this.array[2]=e[2],this.array[3]=e[3],this._dirty=!0,this},clone:function(){return new Ja(this.x,this.y,this.z,this.w)},copy:function(e){return Za.copy(this.array,e.array),this._dirty=!0,this},dist:function(e){return Za.dist(this.array,e.array)},distance:function(e){return Za.distance(this.array,e.array)},div:function(e){return Za.div(this.array,this.array,e.array),this._dirty=!0,this},divide:function(e){return Za.divide(this.array,this.array,e.array),this._dirty=!0,this},dot:function(e){return Za.dot(this.array,e.array)},len:function(){return Za.len(this.array)},length:function(){return Za.length(this.array)},lerp:function(e,t,r){return Za.lerp(this.array,e.array,t.array,r),this._dirty=!0,this},min:function(e){return Za.min(this.array,this.array,e.array),this._dirty=!0,this},max:function(e){return Za.max(this.array,this.array,e.array),this._dirty=!0,this},mul:function(e){return Za.mul(this.array,this.array,e.array),this._dirty=!0,this},multiply:function(e){return Za.multiply(this.array,this.array,e.array),this._dirty=!0,this},negate:function(){return Za.negate(this.array,this.array),this._dirty=!0,this},normalize:function(){return Za.normalize(this.array,this.array),this._dirty=!0,this},random:function(e){return Za.random(this.array,e),this._dirty=!0,this},scale:function(e){return Za.scale(this.array,this.array,e),this._dirty=!0,this},scaleAndAdd:function(e,t){return Za.scaleAndAdd(this.array,this.array,e.array,t),this._dirty=!0,this},sqrDist:function(e){return Za.sqrDist(this.array,e.array)},squaredDistance:function(e){return Za.squaredDistance(this.array,e.array)},sqrLen:function(){return Za.sqrLen(this.array)},squaredLength:function(){return Za.squaredLength(this.array)},sub:function(e){return Za.sub(this.array,this.array,e.array),this._dirty=!0,this},subtract:function(e){return Za.subtract(this.array,this.array,e.array),this._dirty=!0,this},transformMat4:function(e){return Za.transformMat4(this.array,this.array,e.array),this._dirty=!0,this},transformQuat:function(e){return Za.transformQuat(this.array,this.array,e.array),this._dirty=!0,this},toString:function(){return"["+Array.prototype.join.call(this.array,",")+"]"},toArray:function(){return Array.prototype.slice.call(this.array)}};var Qa=Object.defineProperty;if(Qa){var $a=Ja.prototype;Qa($a,"x",{get:function(){return this.array[0]},set:function(e){this.array[0]=e,this._dirty=!0}}),Qa($a,"y",{get:function(){return this.array[1]},set:function(e){this.array[1]=e,this._dirty=!0}}),Qa($a,"z",{get:function(){return this.array[2]},set:function(e){this.array[2]=e,this._dirty=!0}}),Qa($a,"w",{get:function(){return this.array[3]},set:function(e){this.array[3]=e,this._dirty=!0}})}Ja.add=function(e,t,r){return Za.add(e.array,t.array,r.array),e._dirty=!0,e},Ja.set=function(e,t,r,n,i){Za.set(e.array,t,r,n,i),e._dirty=!0},Ja.copy=function(e,t){return Za.copy(e.array,t.array),e._dirty=!0,e},Ja.dist=function(e,t){return Za.distance(e.array,t.array)},Ja.distance=Ja.dist,Ja.div=function(e,t,r){return Za.divide(e.array,t.array,r.array),e._dirty=!0,e},Ja.divide=Ja.div,Ja.dot=function(e,t){return Za.dot(e.array,t.array)},Ja.len=function(e){return Za.length(e.array)},Ja.lerp=function(e,t,r,n){return Za.lerp(e.array,t.array,r.array,n),e._dirty=!0,e},Ja.min=function(e,t,r){return Za.min(e.array,t.array,r.array),e._dirty=!0,e},Ja.max=function(e,t,r){return Za.max(e.array,t.array,r.array),e._dirty=!0,e},Ja.mul=function(e,t,r){return Za.multiply(e.array,t.array,r.array),e._dirty=!0,e},Ja.multiply=Ja.mul,Ja.negate=function(e,t){return Za.negate(e.array,t.array),e._dirty=!0,e},Ja.normalize=function(e,t){return Za.normalize(e.array,t.array),e._dirty=!0,e},Ja.random=function(e,t){return Za.random(e.array,t),e._dirty=!0,e},Ja.scale=function(e,t,r){return Za.scale(e.array,t.array,r),e._dirty=!0,e},Ja.scaleAndAdd=function(e,t,r,n){return Za.scaleAndAdd(e.array,t.array,r.array,n),e._dirty=!0,e},Ja.sqrDist=function(e,t){return Za.sqrDist(e.array,t.array)},Ja.squaredDistance=Ja.sqrDist,Ja.sqrLen=function(e){return Za.sqrLen(e.array)},Ja.squaredLength=Ja.sqrLen,Ja.sub=function(e,t,r){return Za.subtract(e.array,t.array,r.array),e._dirty=!0,e},Ja.subtract=Ja.sub,Ja.transformMat4=function(e,t,r){return Za.transformMat4(e.array,t.array,r.array),e._dirty=!0,e},Ja.transformQuat=function(e,t,r){return Za.transformQuat(e.array,t.array,r.array),e._dirty=!0,e};var eo=At.extend(function(){return{dom:null,renderer:null,camera:null,_boundingBox:new Vt,_hotspotRoot:null,_hotspots:[]}},function(){if(!this.dom||!this.renderer||!this.camera)throw new Error("Tip manager needs `root`, `camera`, `renderer`");var e=this._hotspotRoot=document.createElement("div");e.style.cssText="position:absolute;top:0;left:0;right:0;bottom:0;overflow:hidden;",this.dom.appendChild(e)},{setBoundingBox:function(e,t){this._boundingBox.min.setArray(e),this._boundingBox.max.setArray(t)},add:function(e,t){if("string"==typeof t){var r=document.createElement("div");r.innerHTML=t,t=r}return t.classList.add("qmv-annotation"),t.style.position="absolute",this._hotspotRoot.appendChild(t),this._hotspots.push({position:e,dom:t}),t},remove:function(e){for(var t=-1,r=0;r=0&&(this._hotspots.splice(t,1),this._hotspotRoot.removeChild(e))},update:function(){var e=new Ja,t=new Vt;this._hotspots.forEach(function(r){var n=r.position;e.set(n[0],n[1],n[2],1),e.transformMat4(this.camera.viewMatrix);var i=e.z;e.transformMat4(this.camera.projectionMatrix),e.scale(1/e.w);var a=.5*(e.x+1)*this.renderer.getWidth(),o=.5*(e.y+1)*this.renderer.getHeight();r.dom.style.left=a+"px",r.dom.style.top=this.renderer.getHeight()-o+"px";null==r.farAlpha||r.farAlpha,null==r.nearAlpha||r.nearAlpha;t.copy(this._boundingBox),t.applyTransform(this.camera.viewMatrix);t.max.z,t.min.z,t.max.z;r.dom.style.opacity=1,r.onupdate&&r.onupdate(a,o)},this)}});L.import("@export qmv.ground.vertex\n@import clay.lambert.vertex\n@end\n\n\n@export qmv.ground.fragment\n\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\nuniform float gridSize: 5;\nuniform float gridSize2: 1;\nuniform vec4 gridColor: [0, 0, 0, 1];\nuniform vec4 gridColor2: [0.3, 0.3, 0.3, 1];\n\nuniform bool showGrid: true;\n\nuniform float glossiness: 0.7;\n\n#ifdef SSAOMAP_ENABLED\nuniform sampler2D ssaoMap;\nuniform vec4 viewport : VIEWPORT;\n#endif\n\n#ifdef AMBIENT_LIGHT_COUNT\n@import clay.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import clay.header.ambient_sh_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n\n@import clay.plugin.compute_shadow_map\n\nvoid main()\n{\n gl_FragColor = color;\n\n if (showGrid) {\n float wx = v_WorldPosition.x;\n float wz = v_WorldPosition.z;\n float x0 = abs(fract(wx / gridSize - 0.5) - 0.5) / fwidth(wx) * gridSize / 2.0;\n float z0 = abs(fract(wz / gridSize - 0.5) - 0.5) / fwidth(wz) * gridSize / 2.0;\n\n float x1 = abs(fract(wx / gridSize2 - 0.5) - 0.5) / fwidth(wx) * gridSize2;\n float z1 = abs(fract(wz / gridSize2 - 0.5) - 0.5) / fwidth(wz) * gridSize2;\n\n float v0 = 1.0 - clamp(min(x0, z0), 0.0, 1.0);\n float v1 = 1.0 - clamp(min(x1, z1), 0.0, 1.0);\n if (v0 > 0.1) {\n gl_FragColor = mix(gl_FragColor, gridColor, v0);\n }\n else {\n gl_FragColor = mix(gl_FragColor, gridColor2, v1);\n }\n }\n\n vec3 diffuseColor = vec3(0.0, 0.0, 0.0);\n\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {\n diffuseColor += ambientLightColor[_idx_];\n }\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseColor += calcAmbientSHLight(_idx_, v_Normal) * ambientSHLightColor[_idx_];\n }}\n#endif\n\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++)\n {\n vec3 lightDirection = -directionalLightDirection[i];\n vec3 lightColor = directionalLightColor[i];\n\n float ndl = dot(v_Normal, normalize(lightDirection));\n\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsDir[i];\n }\n#endif\n\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * shadowContrib;\n }\n#endif\n\n#ifdef SSAOMAP_ENABLED\n diffuseColor *= texture2D(ssaoMap, (gl_FragCoord.xy - viewport.xy) / viewport.zw).r;\n#endif\n\n gl_FragColor.rgb *= diffuseColor;\n\n gl_FragColor.a *= 1.0 - clamp(length(v_WorldPosition.xz) / 30.0, 0.0, 1.0);\n\n}\n\n@end");var to=["diffuseMap","normalMap","emissiveMap","metalnessMap","roughnessMap","specularMap","glossinessMap"];vt.prototype.init=function(e,t){t=t||{},this.root=e,this._timeline=new li;var r=new kr({devicePixelRatio:t.devicePixelRatio||window.devicePixelRatio});e.appendChild(r.canvas),r.canvas.style.cssText="position:absolute;left:0;top:0",this._renderer=r,this._renderMain=new nt(r,t.shadow,"perspective"),this._renderMain.afterRenderScene=function(e,t,r){this.trigger("renderscene",e,t,r)}.bind(this),this._renderMain.afterRenderAll=function(e,t,r){this.trigger("afterrender",e,t,r)}.bind(this),this._renderMain.preZ=t.preZ||!1;var n=this._cameraControl=new Ya({renderer:r,timeline:this._timeline,domElement:e});n.target=this._renderMain.camera,n.init(),this._hotspotManager=new eo({dom:e,renderer:r,camera:this._renderMain.camera}),this._skeletons=[],this._clips=[],this._takes=[],this._materialsMap={},this._sceneHelper=new it(this._renderMain.scene),this._sceneHelper.initLight(this._renderMain.scene),this.resize(),t.postEffect&&this.setPostEffect(t.postEffect),t.mainLight&&this.setMainLight(t.mainLight),t.secondaryLight&&this.setSecondaryLight(t.secondaryLight),t.tertiaryLight&&this.setTertiaryLight(t.tertiaryLight),t.ambientCubemapLight&&this.setAmbientCubemapLight(t.ambientCubemapLight),t.ambientLight&&this.setAmbientLight(t.ambientLight),t.environment&&this.setEnvironment(t.environment),this._createGround(),t.ground&&this.setGround(t.ground),this.setCameraControl({distance:20,minDisntance:2,maxDistance:100,center:[0,0,0]}),this._enablePicking=t.picking||!1,this._initHandlers(),n.on("update",function(){this.trigger("updatecamera",{center:n.getCenter(),alpha:n.getAlpha(),beta:n.getBeta(),distance:n.getDistance()}),this.refresh()},this)},vt.prototype._createGround=function(){var e=new Mn({isGround:!0,material:new sr({shader:new L({vertex:L.source("qmv.ground.vertex"),fragment:L.source("qmv.ground.fragment")}),transparent:!0}),castShadow:!1,geometry:new _i,renderOrder:-10});e.material.set("color",[1,1,1,1]),e.scale.set(40,40,1),e.rotation.rotateX(-Math.PI/2),this._groundMesh=e,this._renderMain.scene.add(e)},vt.prototype._addModel=function(e,t,r,n){this.removeModel(),this._renderMain.scene.add(e),this._skeletons=r.slice(),this._modelNode=e,this._setAnimationClips(n),t&&t.length&&(this._nodes=t);var i={};e.traverse(function(e){if(e.material){var t=e.material;i[t.name]=i[t.name]||[],i[t.name].push(t)}},this),this._materialsMap=i,this._updateMaterialsSRGB(),this._stopAccumulating()},vt.prototype._removeAnimationClips=function(){this._clips.forEach(function(e){this._timeline.removeClip(e)},this),this._clips=[],this._takes=[]},vt.prototype._setAnimationClips=function(e){function t(){r.refresh()}var r=this;e.forEach(function(e){e.tracks.forEach(function(e){e.target||(e.target=this._nodes[e.targetNodeIndex])},this),e.onframe=t,this._timeline.addClip(e),this._takes.push({name:e.name,range:[0,e.life],clip:e})},this),this._clips=e.slice()},vt.prototype._initHandlers=function(){this._picking=new gi({renderer:this._renderer,scene:this._renderMain.scene,camera:this._renderMain.camera}),this._clickHandler=this._clickHandler.bind(this),this._mouseDownHandler=this._mouseDownHandler.bind(this),this.root.addEventListener("mousedown",this._mouseDownHandler),this.root.addEventListener("click",this._clickHandler)},vt.prototype._mouseDownHandler=function(e){this._startX=e.clientX,this._startY=e.clientY},vt.prototype._clickHandler=function(e){if(this._enablePicking||this._renderMain.isDOFEnabled()){var t=e.clientX-this._startX,r=e.clientY-this._startY;if(!(Math.sqrt(t*t+r*r)>=5)){var n=this._picking.pick(e.clientX,e.clientY,!0);n&&!n.target.isGround?(this._renderMain.setDOFFocusOnPoint(n.distance),this.trigger("doffocus",n),this._selectResult=n,this.trigger("select",n),this.refresh()):(this._selectResult&&this.trigger("unselect",this._selectResult),this._selectResult=null)}}},vt.prototype.enablePicking=function(){this._enablePicking=!0},vt.prototype.disablePicking=function(){this._enablePicking=!1},vt.prototype.setModelUpAxis=function(e){var t=this._modelNode;t&&(t.position.set(0,0,0),t.scale.set(1,1,1),t.rotation.identity(),"z"===e.toLowerCase()&&t.rotation.identity().rotateX(-Math.PI/2),this.autoFitModel())},vt.prototype.setTextureFlipY=function(e){if(this._modelNode){for(var t in this._materialsMap)for(var r=0;r 0) { - //TODO: evaluate use of glm_invsqrt here? - len = 1 / Math.sqrt(len); - out[0] = a[0] * len; - out[1] = a[1] * len; - } - return out; -}; - -/** - * Calculates the dot product of two vec2's - * - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @returns {Number} dot product of a and b - */ -vec2.dot = function (a, b) { - return a[0] * b[0] + a[1] * b[1]; -}; - -/** - * Computes the cross product of two vec2's - * Note that the cross product must by definition produce a 3D vector - * - * @param {vec3} out the receiving vector - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @returns {vec3} out - */ -vec2.cross = function(out, a, b) { - var z = a[0] * b[1] - a[1] * b[0]; - out[0] = out[1] = 0; - out[2] = z; - return out; -}; - -/** - * Performs a linear interpolation between two vec2's - * - * @param {vec2} out the receiving vector - * @param {vec2} a the first operand - * @param {vec2} b the second operand - * @param {Number} t interpolation amount between the two inputs - * @returns {vec2} out - */ -vec2.lerp = function (out, a, b, t) { - var ax = a[0], - ay = a[1]; - out[0] = ax + t * (b[0] - ax); - out[1] = ay + t * (b[1] - ay); - return out; -}; - -/** - * Generates a random vector with the given scale - * - * @param {vec2} out the receiving vector - * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned - * @returns {vec2} out - */ -vec2.random = function (out, scale) { - scale = scale || 1.0; - var r = GLMAT_RANDOM() * 2.0 * Math.PI; - out[0] = Math.cos(r) * scale; - out[1] = Math.sin(r) * scale; - return out; -}; - -/** - * Transforms the vec2 with a mat2 - * - * @param {vec2} out the receiving vector - * @param {vec2} a the vector to transform - * @param {mat2} m matrix to transform with - * @returns {vec2} out - */ -vec2.transformMat2 = function(out, a, m) { - var x = a[0], - y = a[1]; - out[0] = m[0] * x + m[2] * y; - out[1] = m[1] * x + m[3] * y; - return out; -}; - -/** - * Transforms the vec2 with a mat2d - * - * @param {vec2} out the receiving vector - * @param {vec2} a the vector to transform - * @param {mat2d} m matrix to transform with - * @returns {vec2} out - */ -vec2.transformMat2d = function(out, a, m) { - var x = a[0], - y = a[1]; - out[0] = m[0] * x + m[2] * y + m[4]; - out[1] = m[1] * x + m[3] * y + m[5]; - return out; -}; - -/** - * Transforms the vec2 with a mat3 - * 3rd vector component is implicitly '1' - * - * @param {vec2} out the receiving vector - * @param {vec2} a the vector to transform - * @param {mat3} m matrix to transform with - * @returns {vec2} out - */ -vec2.transformMat3 = function(out, a, m) { - var x = a[0], - y = a[1]; - out[0] = m[0] * x + m[3] * y + m[6]; - out[1] = m[1] * x + m[4] * y + m[7]; - return out; -}; - -/** - * Transforms the vec2 with a mat4 - * 3rd vector component is implicitly '0' - * 4th vector component is implicitly '1' - * - * @param {vec2} out the receiving vector - * @param {vec2} a the vector to transform - * @param {mat4} m matrix to transform with - * @returns {vec2} out - */ -vec2.transformMat4 = function(out, a, m) { - var x = a[0], - y = a[1]; - out[0] = m[0] * x + m[4] * y + m[12]; - out[1] = m[1] * x + m[5] * y + m[13]; - return out; -}; - -/** - * Perform some operation over an array of vec2s. - * - * @param {Array} a the array of vectors to iterate over - * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed - * @param {Number} offset Number of elements to skip at the beginning of the array - * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array - * @param {Function} fn Function to call for each vector in the array - * @param {Object} [arg] additional argument to pass to fn - * @returns {Array} a - * @function - */ -vec2.forEach = (function() { - var vec = vec2.create(); - - return function(a, stride, offset, count, fn, arg) { - var i, l; - if(!stride) { - stride = 2; - } - - if(!offset) { - offset = 0; - } - - if(count) { - l = Math.min((count * stride) + offset, a.length); - } else { - l = a.length; - } - - for(i = offset; i < l; i += stride) { - vec[0] = a[i]; vec[1] = a[i+1]; - fn(vec, vec, arg); - a[i] = vec[0]; a[i+1] = vec[1]; - } - - return a; - }; -})(); - -/** - * Returns a string representation of a vector - * - * @param {vec2} vec vector to represent as a string - * @returns {String} string representation of the vector - */ -vec2.str = function (a) { - return 'vec2(' + a[0] + ', ' + a[1] + ')'; -}; - -if(typeof(exports) !== 'undefined') { - exports.vec2 = vec2; -} -; -/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -/** - * @class 3 Dimensional Vector - * @name vec3 - */ - -var vec3 = {}; - -/** - * Creates a new, empty vec3 - * - * @returns {vec3} a new 3D vector - */ -vec3.create = function() { - var out = new GLMAT_ARRAY_TYPE(3); - out[0] = 0; - out[1] = 0; - out[2] = 0; - return out; -}; - -/** - * Creates a new vec3 initialized with values from an existing vector - * - * @param {vec3} a vector to clone - * @returns {vec3} a new 3D vector - */ -vec3.clone = function(a) { - var out = new GLMAT_ARRAY_TYPE(3); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - return out; -}; - -/** - * Creates a new vec3 initialized with the given values - * - * @param {Number} x X component - * @param {Number} y Y component - * @param {Number} z Z component - * @returns {vec3} a new 3D vector - */ -vec3.fromValues = function(x, y, z) { - var out = new GLMAT_ARRAY_TYPE(3); - out[0] = x; - out[1] = y; - out[2] = z; - return out; -}; - -/** - * Copy the values from one vec3 to another - * - * @param {vec3} out the receiving vector - * @param {vec3} a the source vector - * @returns {vec3} out - */ -vec3.copy = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - return out; -}; - -/** - * Set the components of a vec3 to the given values - * - * @param {vec3} out the receiving vector - * @param {Number} x X component - * @param {Number} y Y component - * @param {Number} z Z component - * @returns {vec3} out - */ -vec3.set = function(out, x, y, z) { - out[0] = x; - out[1] = y; - out[2] = z; - return out; -}; - -/** - * Adds two vec3's - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {vec3} out - */ -vec3.add = function(out, a, b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - return out; -}; - -/** - * Subtracts vector b from vector a - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {vec3} out - */ -vec3.subtract = function(out, a, b) { - out[0] = a[0] - b[0]; - out[1] = a[1] - b[1]; - out[2] = a[2] - b[2]; - return out; -}; - -/** - * Alias for {@link vec3.subtract} - * @function - */ -vec3.sub = vec3.subtract; - -/** - * Multiplies two vec3's - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {vec3} out - */ -vec3.multiply = function(out, a, b) { - out[0] = a[0] * b[0]; - out[1] = a[1] * b[1]; - out[2] = a[2] * b[2]; - return out; -}; - -/** - * Alias for {@link vec3.multiply} - * @function - */ -vec3.mul = vec3.multiply; - -/** - * Divides two vec3's - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {vec3} out - */ -vec3.divide = function(out, a, b) { - out[0] = a[0] / b[0]; - out[1] = a[1] / b[1]; - out[2] = a[2] / b[2]; - return out; -}; - -/** - * Alias for {@link vec3.divide} - * @function - */ -vec3.div = vec3.divide; - -/** - * Returns the minimum of two vec3's - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {vec3} out - */ -vec3.min = function(out, a, b) { - out[0] = Math.min(a[0], b[0]); - out[1] = Math.min(a[1], b[1]); - out[2] = Math.min(a[2], b[2]); - return out; -}; - -/** - * Returns the maximum of two vec3's - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {vec3} out - */ -vec3.max = function(out, a, b) { - out[0] = Math.max(a[0], b[0]); - out[1] = Math.max(a[1], b[1]); - out[2] = Math.max(a[2], b[2]); - return out; -}; - -/** - * Scales a vec3 by a scalar number - * - * @param {vec3} out the receiving vector - * @param {vec3} a the vector to scale - * @param {Number} b amount to scale the vector by - * @returns {vec3} out - */ -vec3.scale = function(out, a, b) { - out[0] = a[0] * b; - out[1] = a[1] * b; - out[2] = a[2] * b; - return out; -}; - -/** - * Adds two vec3's after scaling the second operand by a scalar value - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @param {Number} scale the amount to scale b by before adding - * @returns {vec3} out - */ -vec3.scaleAndAdd = function(out, a, b, scale) { - out[0] = a[0] + (b[0] * scale); - out[1] = a[1] + (b[1] * scale); - out[2] = a[2] + (b[2] * scale); - return out; -}; - -/** - * Calculates the euclidian distance between two vec3's - * - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {Number} distance between a and b - */ -vec3.distance = function(a, b) { - var x = b[0] - a[0], - y = b[1] - a[1], - z = b[2] - a[2]; - return Math.sqrt(x*x + y*y + z*z); -}; - -/** - * Alias for {@link vec3.distance} - * @function - */ -vec3.dist = vec3.distance; - -/** - * Calculates the squared euclidian distance between two vec3's - * - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {Number} squared distance between a and b - */ -vec3.squaredDistance = function(a, b) { - var x = b[0] - a[0], - y = b[1] - a[1], - z = b[2] - a[2]; - return x*x + y*y + z*z; -}; - -/** - * Alias for {@link vec3.squaredDistance} - * @function - */ -vec3.sqrDist = vec3.squaredDistance; - -/** - * Calculates the length of a vec3 - * - * @param {vec3} a vector to calculate length of - * @returns {Number} length of a - */ -vec3.length = function (a) { - var x = a[0], - y = a[1], - z = a[2]; - return Math.sqrt(x*x + y*y + z*z); -}; - -/** - * Alias for {@link vec3.length} - * @function - */ -vec3.len = vec3.length; - -/** - * Calculates the squared length of a vec3 - * - * @param {vec3} a vector to calculate squared length of - * @returns {Number} squared length of a - */ -vec3.squaredLength = function (a) { - var x = a[0], - y = a[1], - z = a[2]; - return x*x + y*y + z*z; -}; - -/** - * Alias for {@link vec3.squaredLength} - * @function - */ -vec3.sqrLen = vec3.squaredLength; - -/** - * Negates the components of a vec3 - * - * @param {vec3} out the receiving vector - * @param {vec3} a vector to negate - * @returns {vec3} out - */ -vec3.negate = function(out, a) { - out[0] = -a[0]; - out[1] = -a[1]; - out[2] = -a[2]; - return out; -}; - -/** - * Returns the inverse of the components of a vec3 - * - * @param {vec3} out the receiving vector - * @param {vec3} a vector to invert - * @returns {vec3} out - */ -vec3.inverse = function(out, a) { - out[0] = 1.0 / a[0]; - out[1] = 1.0 / a[1]; - out[2] = 1.0 / a[2]; - return out; -}; - -/** - * Normalize a vec3 - * - * @param {vec3} out the receiving vector - * @param {vec3} a vector to normalize - * @returns {vec3} out - */ -vec3.normalize = function(out, a) { - var x = a[0], - y = a[1], - z = a[2]; - var len = x*x + y*y + z*z; - if (len > 0) { - //TODO: evaluate use of glm_invsqrt here? - len = 1 / Math.sqrt(len); - out[0] = a[0] * len; - out[1] = a[1] * len; - out[2] = a[2] * len; - } - return out; -}; - -/** - * Calculates the dot product of two vec3's - * - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {Number} dot product of a and b - */ -vec3.dot = function (a, b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; -}; - -/** - * Computes the cross product of two vec3's - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @returns {vec3} out - */ -vec3.cross = function(out, a, b) { - var ax = a[0], ay = a[1], az = a[2], - bx = b[0], by = b[1], bz = b[2]; - - out[0] = ay * bz - az * by; - out[1] = az * bx - ax * bz; - out[2] = ax * by - ay * bx; - return out; -}; - -/** - * Performs a linear interpolation between two vec3's - * - * @param {vec3} out the receiving vector - * @param {vec3} a the first operand - * @param {vec3} b the second operand - * @param {Number} t interpolation amount between the two inputs - * @returns {vec3} out - */ -vec3.lerp = function (out, a, b, t) { - var ax = a[0], - ay = a[1], - az = a[2]; - out[0] = ax + t * (b[0] - ax); - out[1] = ay + t * (b[1] - ay); - out[2] = az + t * (b[2] - az); - return out; -}; - -/** - * Generates a random vector with the given scale - * - * @param {vec3} out the receiving vector - * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned - * @returns {vec3} out - */ -vec3.random = function (out, scale) { - scale = scale || 1.0; - - var r = GLMAT_RANDOM() * 2.0 * Math.PI; - var z = (GLMAT_RANDOM() * 2.0) - 1.0; - var zScale = Math.sqrt(1.0-z*z) * scale; - - out[0] = Math.cos(r) * zScale; - out[1] = Math.sin(r) * zScale; - out[2] = z * scale; - return out; -}; - -/** - * Transforms the vec3 with a mat4. - * 4th vector component is implicitly '1' - * - * @param {vec3} out the receiving vector - * @param {vec3} a the vector to transform - * @param {mat4} m matrix to transform with - * @returns {vec3} out - */ -vec3.transformMat4 = function(out, a, m) { - var x = a[0], y = a[1], z = a[2], - w = m[3] * x + m[7] * y + m[11] * z + m[15]; - w = w || 1.0; - out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; - out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; - out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; - return out; -}; - -/** - * Transforms the vec3 with a mat3. - * - * @param {vec3} out the receiving vector - * @param {vec3} a the vector to transform - * @param {mat4} m the 3x3 matrix to transform with - * @returns {vec3} out - */ -vec3.transformMat3 = function(out, a, m) { - var x = a[0], y = a[1], z = a[2]; - out[0] = x * m[0] + y * m[3] + z * m[6]; - out[1] = x * m[1] + y * m[4] + z * m[7]; - out[2] = x * m[2] + y * m[5] + z * m[8]; - return out; -}; - -/** - * Transforms the vec3 with a quat - * - * @param {vec3} out the receiving vector - * @param {vec3} a the vector to transform - * @param {quat} q quaternion to transform with - * @returns {vec3} out - */ -vec3.transformQuat = function(out, a, q) { - // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations - - var x = a[0], y = a[1], z = a[2], - qx = q[0], qy = q[1], qz = q[2], qw = q[3], - - // calculate quat * vec - ix = qw * x + qy * z - qz * y, - iy = qw * y + qz * x - qx * z, - iz = qw * z + qx * y - qy * x, - iw = -qx * x - qy * y - qz * z; - - // calculate result * inverse quat - out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; - out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; - out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; - return out; -}; - -/** - * Rotate a 3D vector around the x-axis - * @param {vec3} out The receiving vec3 - * @param {vec3} a The vec3 point to rotate - * @param {vec3} b The origin of the rotation - * @param {Number} c The angle of rotation - * @returns {vec3} out - */ -vec3.rotateX = function(out, a, b, c){ - var p = [], r=[]; - //Translate point to the origin - p[0] = a[0] - b[0]; - p[1] = a[1] - b[1]; - p[2] = a[2] - b[2]; - - //perform rotation - r[0] = p[0]; - r[1] = p[1]*Math.cos(c) - p[2]*Math.sin(c); - r[2] = p[1]*Math.sin(c) + p[2]*Math.cos(c); - - //translate to correct position - out[0] = r[0] + b[0]; - out[1] = r[1] + b[1]; - out[2] = r[2] + b[2]; - - return out; -}; - -/** - * Rotate a 3D vector around the y-axis - * @param {vec3} out The receiving vec3 - * @param {vec3} a The vec3 point to rotate - * @param {vec3} b The origin of the rotation - * @param {Number} c The angle of rotation - * @returns {vec3} out - */ -vec3.rotateY = function(out, a, b, c){ - var p = [], r=[]; - //Translate point to the origin - p[0] = a[0] - b[0]; - p[1] = a[1] - b[1]; - p[2] = a[2] - b[2]; - - //perform rotation - r[0] = p[2]*Math.sin(c) + p[0]*Math.cos(c); - r[1] = p[1]; - r[2] = p[2]*Math.cos(c) - p[0]*Math.sin(c); - - //translate to correct position - out[0] = r[0] + b[0]; - out[1] = r[1] + b[1]; - out[2] = r[2] + b[2]; - - return out; -}; - -/** - * Rotate a 3D vector around the z-axis - * @param {vec3} out The receiving vec3 - * @param {vec3} a The vec3 point to rotate - * @param {vec3} b The origin of the rotation - * @param {Number} c The angle of rotation - * @returns {vec3} out - */ -vec3.rotateZ = function(out, a, b, c){ - var p = [], r=[]; - //Translate point to the origin - p[0] = a[0] - b[0]; - p[1] = a[1] - b[1]; - p[2] = a[2] - b[2]; - - //perform rotation - r[0] = p[0]*Math.cos(c) - p[1]*Math.sin(c); - r[1] = p[0]*Math.sin(c) + p[1]*Math.cos(c); - r[2] = p[2]; - - //translate to correct position - out[0] = r[0] + b[0]; - out[1] = r[1] + b[1]; - out[2] = r[2] + b[2]; - - return out; -}; - -/** - * Perform some operation over an array of vec3s. - * - * @param {Array} a the array of vectors to iterate over - * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed - * @param {Number} offset Number of elements to skip at the beginning of the array - * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array - * @param {Function} fn Function to call for each vector in the array - * @param {Object} [arg] additional argument to pass to fn - * @returns {Array} a - * @function - */ -vec3.forEach = (function() { - var vec = vec3.create(); - - return function(a, stride, offset, count, fn, arg) { - var i, l; - if(!stride) { - stride = 3; - } - - if(!offset) { - offset = 0; - } - - if(count) { - l = Math.min((count * stride) + offset, a.length); - } else { - l = a.length; - } - - for(i = offset; i < l; i += stride) { - vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; - fn(vec, vec, arg); - a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; - } - - return a; - }; -})(); - -/** - * Get the angle between two 3D vectors - * @param {vec3} a The first operand - * @param {vec3} b The second operand - * @returns {Number} The angle in radians - */ -vec3.angle = function(a, b) { - - var tempA = vec3.fromValues(a[0], a[1], a[2]); - var tempB = vec3.fromValues(b[0], b[1], b[2]); - - vec3.normalize(tempA, tempA); - vec3.normalize(tempB, tempB); - - var cosine = vec3.dot(tempA, tempB); - - if(cosine > 1.0){ - return 0; - } else { - return Math.acos(cosine); - } -}; - -/** - * Returns a string representation of a vector - * - * @param {vec3} vec vector to represent as a string - * @returns {String} string representation of the vector - */ -vec3.str = function (a) { - return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')'; -}; - -if(typeof(exports) !== 'undefined') { - exports.vec3 = vec3; -} -; -/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -/** - * @class 4 Dimensional Vector - * @name vec4 - */ - -var vec4 = {}; - -/** - * Creates a new, empty vec4 - * - * @returns {vec4} a new 4D vector - */ -vec4.create = function() { - var out = new GLMAT_ARRAY_TYPE(4); - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 0; - return out; -}; - -/** - * Creates a new vec4 initialized with values from an existing vector - * - * @param {vec4} a vector to clone - * @returns {vec4} a new 4D vector - */ -vec4.clone = function(a) { - var out = new GLMAT_ARRAY_TYPE(4); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - return out; -}; - -/** - * Creates a new vec4 initialized with the given values - * - * @param {Number} x X component - * @param {Number} y Y component - * @param {Number} z Z component - * @param {Number} w W component - * @returns {vec4} a new 4D vector - */ -vec4.fromValues = function(x, y, z, w) { - var out = new GLMAT_ARRAY_TYPE(4); - out[0] = x; - out[1] = y; - out[2] = z; - out[3] = w; - return out; -}; - -/** - * Copy the values from one vec4 to another - * - * @param {vec4} out the receiving vector - * @param {vec4} a the source vector - * @returns {vec4} out - */ -vec4.copy = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - return out; -}; - -/** - * Set the components of a vec4 to the given values - * - * @param {vec4} out the receiving vector - * @param {Number} x X component - * @param {Number} y Y component - * @param {Number} z Z component - * @param {Number} w W component - * @returns {vec4} out - */ -vec4.set = function(out, x, y, z, w) { - out[0] = x; - out[1] = y; - out[2] = z; - out[3] = w; - return out; -}; - -/** - * Adds two vec4's - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {vec4} out - */ -vec4.add = function(out, a, b) { - out[0] = a[0] + b[0]; - out[1] = a[1] + b[1]; - out[2] = a[2] + b[2]; - out[3] = a[3] + b[3]; - return out; -}; - -/** - * Subtracts vector b from vector a - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {vec4} out - */ -vec4.subtract = function(out, a, b) { - out[0] = a[0] - b[0]; - out[1] = a[1] - b[1]; - out[2] = a[2] - b[2]; - out[3] = a[3] - b[3]; - return out; -}; - -/** - * Alias for {@link vec4.subtract} - * @function - */ -vec4.sub = vec4.subtract; - -/** - * Multiplies two vec4's - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {vec4} out - */ -vec4.multiply = function(out, a, b) { - out[0] = a[0] * b[0]; - out[1] = a[1] * b[1]; - out[2] = a[2] * b[2]; - out[3] = a[3] * b[3]; - return out; -}; - -/** - * Alias for {@link vec4.multiply} - * @function - */ -vec4.mul = vec4.multiply; - -/** - * Divides two vec4's - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {vec4} out - */ -vec4.divide = function(out, a, b) { - out[0] = a[0] / b[0]; - out[1] = a[1] / b[1]; - out[2] = a[2] / b[2]; - out[3] = a[3] / b[3]; - return out; -}; - -/** - * Alias for {@link vec4.divide} - * @function - */ -vec4.div = vec4.divide; - -/** - * Returns the minimum of two vec4's - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {vec4} out - */ -vec4.min = function(out, a, b) { - out[0] = Math.min(a[0], b[0]); - out[1] = Math.min(a[1], b[1]); - out[2] = Math.min(a[2], b[2]); - out[3] = Math.min(a[3], b[3]); - return out; -}; - -/** - * Returns the maximum of two vec4's - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {vec4} out - */ -vec4.max = function(out, a, b) { - out[0] = Math.max(a[0], b[0]); - out[1] = Math.max(a[1], b[1]); - out[2] = Math.max(a[2], b[2]); - out[3] = Math.max(a[3], b[3]); - return out; -}; - -/** - * Scales a vec4 by a scalar number - * - * @param {vec4} out the receiving vector - * @param {vec4} a the vector to scale - * @param {Number} b amount to scale the vector by - * @returns {vec4} out - */ -vec4.scale = function(out, a, b) { - out[0] = a[0] * b; - out[1] = a[1] * b; - out[2] = a[2] * b; - out[3] = a[3] * b; - return out; -}; - -/** - * Adds two vec4's after scaling the second operand by a scalar value - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @param {Number} scale the amount to scale b by before adding - * @returns {vec4} out - */ -vec4.scaleAndAdd = function(out, a, b, scale) { - out[0] = a[0] + (b[0] * scale); - out[1] = a[1] + (b[1] * scale); - out[2] = a[2] + (b[2] * scale); - out[3] = a[3] + (b[3] * scale); - return out; -}; - -/** - * Calculates the euclidian distance between two vec4's - * - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {Number} distance between a and b - */ -vec4.distance = function(a, b) { - var x = b[0] - a[0], - y = b[1] - a[1], - z = b[2] - a[2], - w = b[3] - a[3]; - return Math.sqrt(x*x + y*y + z*z + w*w); -}; - -/** - * Alias for {@link vec4.distance} - * @function - */ -vec4.dist = vec4.distance; - -/** - * Calculates the squared euclidian distance between two vec4's - * - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {Number} squared distance between a and b - */ -vec4.squaredDistance = function(a, b) { - var x = b[0] - a[0], - y = b[1] - a[1], - z = b[2] - a[2], - w = b[3] - a[3]; - return x*x + y*y + z*z + w*w; -}; - -/** - * Alias for {@link vec4.squaredDistance} - * @function - */ -vec4.sqrDist = vec4.squaredDistance; - -/** - * Calculates the length of a vec4 - * - * @param {vec4} a vector to calculate length of - * @returns {Number} length of a - */ -vec4.length = function (a) { - var x = a[0], - y = a[1], - z = a[2], - w = a[3]; - return Math.sqrt(x*x + y*y + z*z + w*w); -}; - -/** - * Alias for {@link vec4.length} - * @function - */ -vec4.len = vec4.length; - -/** - * Calculates the squared length of a vec4 - * - * @param {vec4} a vector to calculate squared length of - * @returns {Number} squared length of a - */ -vec4.squaredLength = function (a) { - var x = a[0], - y = a[1], - z = a[2], - w = a[3]; - return x*x + y*y + z*z + w*w; -}; - -/** - * Alias for {@link vec4.squaredLength} - * @function - */ -vec4.sqrLen = vec4.squaredLength; - -/** - * Negates the components of a vec4 - * - * @param {vec4} out the receiving vector - * @param {vec4} a vector to negate - * @returns {vec4} out - */ -vec4.negate = function(out, a) { - out[0] = -a[0]; - out[1] = -a[1]; - out[2] = -a[2]; - out[3] = -a[3]; - return out; -}; - -/** - * Returns the inverse of the components of a vec4 - * - * @param {vec4} out the receiving vector - * @param {vec4} a vector to invert - * @returns {vec4} out - */ -vec4.inverse = function(out, a) { - out[0] = 1.0 / a[0]; - out[1] = 1.0 / a[1]; - out[2] = 1.0 / a[2]; - out[3] = 1.0 / a[3]; - return out; -}; - -/** - * Normalize a vec4 - * - * @param {vec4} out the receiving vector - * @param {vec4} a vector to normalize - * @returns {vec4} out - */ -vec4.normalize = function(out, a) { - var x = a[0], - y = a[1], - z = a[2], - w = a[3]; - var len = x*x + y*y + z*z + w*w; - if (len > 0) { - len = 1 / Math.sqrt(len); - out[0] = a[0] * len; - out[1] = a[1] * len; - out[2] = a[2] * len; - out[3] = a[3] * len; - } - return out; -}; - -/** - * Calculates the dot product of two vec4's - * - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @returns {Number} dot product of a and b - */ -vec4.dot = function (a, b) { - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; -}; - -/** - * Performs a linear interpolation between two vec4's - * - * @param {vec4} out the receiving vector - * @param {vec4} a the first operand - * @param {vec4} b the second operand - * @param {Number} t interpolation amount between the two inputs - * @returns {vec4} out - */ -vec4.lerp = function (out, a, b, t) { - var ax = a[0], - ay = a[1], - az = a[2], - aw = a[3]; - out[0] = ax + t * (b[0] - ax); - out[1] = ay + t * (b[1] - ay); - out[2] = az + t * (b[2] - az); - out[3] = aw + t * (b[3] - aw); - return out; -}; - -/** - * Generates a random vector with the given scale - * - * @param {vec4} out the receiving vector - * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned - * @returns {vec4} out - */ -vec4.random = function (out, scale) { - scale = scale || 1.0; - - //TODO: This is a pretty awful way of doing this. Find something better. - out[0] = GLMAT_RANDOM(); - out[1] = GLMAT_RANDOM(); - out[2] = GLMAT_RANDOM(); - out[3] = GLMAT_RANDOM(); - vec4.normalize(out, out); - vec4.scale(out, out, scale); - return out; -}; - -/** - * Transforms the vec4 with a mat4. - * - * @param {vec4} out the receiving vector - * @param {vec4} a the vector to transform - * @param {mat4} m matrix to transform with - * @returns {vec4} out - */ -vec4.transformMat4 = function(out, a, m) { - var x = a[0], y = a[1], z = a[2], w = a[3]; - out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w; - out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w; - out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w; - out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w; - return out; -}; - -/** - * Transforms the vec4 with a quat - * - * @param {vec4} out the receiving vector - * @param {vec4} a the vector to transform - * @param {quat} q quaternion to transform with - * @returns {vec4} out - */ -vec4.transformQuat = function(out, a, q) { - var x = a[0], y = a[1], z = a[2], - qx = q[0], qy = q[1], qz = q[2], qw = q[3], - - // calculate quat * vec - ix = qw * x + qy * z - qz * y, - iy = qw * y + qz * x - qx * z, - iz = qw * z + qx * y - qy * x, - iw = -qx * x - qy * y - qz * z; - - // calculate result * inverse quat - out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; - out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; - out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; - return out; -}; - -/** - * Perform some operation over an array of vec4s. - * - * @param {Array} a the array of vectors to iterate over - * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed - * @param {Number} offset Number of elements to skip at the beginning of the array - * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array - * @param {Function} fn Function to call for each vector in the array - * @param {Object} [arg] additional argument to pass to fn - * @returns {Array} a - * @function - */ -vec4.forEach = (function() { - var vec = vec4.create(); - - return function(a, stride, offset, count, fn, arg) { - var i, l; - if(!stride) { - stride = 4; - } - - if(!offset) { - offset = 0; - } - - if(count) { - l = Math.min((count * stride) + offset, a.length); - } else { - l = a.length; - } - - for(i = offset; i < l; i += stride) { - vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3]; - fn(vec, vec, arg); - a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3]; - } - - return a; - }; -})(); - -/** - * Returns a string representation of a vector - * - * @param {vec4} vec vector to represent as a string - * @returns {String} string representation of the vector - */ -vec4.str = function (a) { - return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; -}; - -if(typeof(exports) !== 'undefined') { - exports.vec4 = vec4; -} -; -/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -/** - * @class 2x2 Matrix - * @name mat2 - */ - -var mat2 = {}; - -/** - * Creates a new identity mat2 - * - * @returns {mat2} a new 2x2 matrix - */ -mat2.create = function() { - var out = new GLMAT_ARRAY_TYPE(4); - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 1; - return out; -}; - -/** - * Creates a new mat2 initialized with values from an existing matrix - * - * @param {mat2} a matrix to clone - * @returns {mat2} a new 2x2 matrix - */ -mat2.clone = function(a) { - var out = new GLMAT_ARRAY_TYPE(4); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - return out; -}; - -/** - * Copy the values from one mat2 to another - * - * @param {mat2} out the receiving matrix - * @param {mat2} a the source matrix - * @returns {mat2} out - */ -mat2.copy = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - return out; -}; - -/** - * Set a mat2 to the identity matrix - * - * @param {mat2} out the receiving matrix - * @returns {mat2} out - */ -mat2.identity = function(out) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 1; - return out; -}; - -/** - * Transpose the values of a mat2 - * - * @param {mat2} out the receiving matrix - * @param {mat2} a the source matrix - * @returns {mat2} out - */ -mat2.transpose = function(out, a) { - // If we are transposing ourselves we can skip a few steps but have to cache some values - if (out === a) { - var a1 = a[1]; - out[1] = a[2]; - out[2] = a1; - } else { - out[0] = a[0]; - out[1] = a[2]; - out[2] = a[1]; - out[3] = a[3]; - } - - return out; -}; - -/** - * Inverts a mat2 - * - * @param {mat2} out the receiving matrix - * @param {mat2} a the source matrix - * @returns {mat2} out - */ -mat2.invert = function(out, a) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], - - // Calculate the determinant - det = a0 * a3 - a2 * a1; - - if (!det) { - return null; - } - det = 1.0 / det; - - out[0] = a3 * det; - out[1] = -a1 * det; - out[2] = -a2 * det; - out[3] = a0 * det; - - return out; -}; - -/** - * Calculates the adjugate of a mat2 - * - * @param {mat2} out the receiving matrix - * @param {mat2} a the source matrix - * @returns {mat2} out - */ -mat2.adjoint = function(out, a) { - // Caching this value is nessecary if out == a - var a0 = a[0]; - out[0] = a[3]; - out[1] = -a[1]; - out[2] = -a[2]; - out[3] = a0; - - return out; -}; - -/** - * Calculates the determinant of a mat2 - * - * @param {mat2} a the source matrix - * @returns {Number} determinant of a - */ -mat2.determinant = function (a) { - return a[0] * a[3] - a[2] * a[1]; -}; - -/** - * Multiplies two mat2's - * - * @param {mat2} out the receiving matrix - * @param {mat2} a the first operand - * @param {mat2} b the second operand - * @returns {mat2} out - */ -mat2.multiply = function (out, a, b) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; - var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; - out[0] = a0 * b0 + a2 * b1; - out[1] = a1 * b0 + a3 * b1; - out[2] = a0 * b2 + a2 * b3; - out[3] = a1 * b2 + a3 * b3; - return out; -}; - -/** - * Alias for {@link mat2.multiply} - * @function - */ -mat2.mul = mat2.multiply; - -/** - * Rotates a mat2 by the given angle - * - * @param {mat2} out the receiving matrix - * @param {mat2} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat2} out - */ -mat2.rotate = function (out, a, rad) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], - s = Math.sin(rad), - c = Math.cos(rad); - out[0] = a0 * c + a2 * s; - out[1] = a1 * c + a3 * s; - out[2] = a0 * -s + a2 * c; - out[3] = a1 * -s + a3 * c; - return out; -}; - -/** - * Scales the mat2 by the dimensions in the given vec2 - * - * @param {mat2} out the receiving matrix - * @param {mat2} a the matrix to rotate - * @param {vec2} v the vec2 to scale the matrix by - * @returns {mat2} out - **/ -mat2.scale = function(out, a, v) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], - v0 = v[0], v1 = v[1]; - out[0] = a0 * v0; - out[1] = a1 * v0; - out[2] = a2 * v1; - out[3] = a3 * v1; - return out; -}; - -/** - * Returns a string representation of a mat2 - * - * @param {mat2} mat matrix to represent as a string - * @returns {String} string representation of the matrix - */ -mat2.str = function (a) { - return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; -}; - -/** - * Returns Frobenius norm of a mat2 - * - * @param {mat2} a the matrix to calculate Frobenius norm of - * @returns {Number} Frobenius norm - */ -mat2.frob = function (a) { - return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2))) -}; - -/** - * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix - * @param {mat2} L the lower triangular matrix - * @param {mat2} D the diagonal matrix - * @param {mat2} U the upper triangular matrix - * @param {mat2} a the input matrix to factorize - */ - -mat2.LDU = function (L, D, U, a) { - L[2] = a[2]/a[0]; - U[0] = a[0]; - U[1] = a[1]; - U[3] = a[3] - L[2] * U[1]; - return [L, D, U]; -}; - -if(typeof(exports) !== 'undefined') { - exports.mat2 = mat2; -} -; -/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -/** - * @class 2x3 Matrix - * @name mat2d - * - * @description - * A mat2d contains six elements defined as: - *
- * [a, c, tx,
- *  b, d, ty]
- * 
- * This is a short form for the 3x3 matrix: - *
- * [a, c, tx,
- *  b, d, ty,
- *  0, 0, 1]
- * 
- * The last row is ignored so the array is shorter and operations are faster. - */ - -var mat2d = {}; - -/** - * Creates a new identity mat2d - * - * @returns {mat2d} a new 2x3 matrix - */ -mat2d.create = function() { - var out = new GLMAT_ARRAY_TYPE(6); - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 1; - out[4] = 0; - out[5] = 0; - return out; -}; - -/** - * Creates a new mat2d initialized with values from an existing matrix - * - * @param {mat2d} a matrix to clone - * @returns {mat2d} a new 2x3 matrix - */ -mat2d.clone = function(a) { - var out = new GLMAT_ARRAY_TYPE(6); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - return out; -}; - -/** - * Copy the values from one mat2d to another - * - * @param {mat2d} out the receiving matrix - * @param {mat2d} a the source matrix - * @returns {mat2d} out - */ -mat2d.copy = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - return out; -}; - -/** - * Set a mat2d to the identity matrix - * - * @param {mat2d} out the receiving matrix - * @returns {mat2d} out - */ -mat2d.identity = function(out) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 1; - out[4] = 0; - out[5] = 0; - return out; -}; - -/** - * Inverts a mat2d - * - * @param {mat2d} out the receiving matrix - * @param {mat2d} a the source matrix - * @returns {mat2d} out - */ -mat2d.invert = function(out, a) { - var aa = a[0], ab = a[1], ac = a[2], ad = a[3], - atx = a[4], aty = a[5]; - - var det = aa * ad - ab * ac; - if(!det){ - return null; - } - det = 1.0 / det; - - out[0] = ad * det; - out[1] = -ab * det; - out[2] = -ac * det; - out[3] = aa * det; - out[4] = (ac * aty - ad * atx) * det; - out[5] = (ab * atx - aa * aty) * det; - return out; -}; - -/** - * Calculates the determinant of a mat2d - * - * @param {mat2d} a the source matrix - * @returns {Number} determinant of a - */ -mat2d.determinant = function (a) { - return a[0] * a[3] - a[1] * a[2]; -}; - -/** - * Multiplies two mat2d's - * - * @param {mat2d} out the receiving matrix - * @param {mat2d} a the first operand - * @param {mat2d} b the second operand - * @returns {mat2d} out - */ -mat2d.multiply = function (out, a, b) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], - b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5]; - out[0] = a0 * b0 + a2 * b1; - out[1] = a1 * b0 + a3 * b1; - out[2] = a0 * b2 + a2 * b3; - out[3] = a1 * b2 + a3 * b3; - out[4] = a0 * b4 + a2 * b5 + a4; - out[5] = a1 * b4 + a3 * b5 + a5; - return out; -}; - -/** - * Alias for {@link mat2d.multiply} - * @function - */ -mat2d.mul = mat2d.multiply; - - -/** - * Rotates a mat2d by the given angle - * - * @param {mat2d} out the receiving matrix - * @param {mat2d} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat2d} out - */ -mat2d.rotate = function (out, a, rad) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], - s = Math.sin(rad), - c = Math.cos(rad); - out[0] = a0 * c + a2 * s; - out[1] = a1 * c + a3 * s; - out[2] = a0 * -s + a2 * c; - out[3] = a1 * -s + a3 * c; - out[4] = a4; - out[5] = a5; - return out; -}; - -/** - * Scales the mat2d by the dimensions in the given vec2 - * - * @param {mat2d} out the receiving matrix - * @param {mat2d} a the matrix to translate - * @param {vec2} v the vec2 to scale the matrix by - * @returns {mat2d} out - **/ -mat2d.scale = function(out, a, v) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], - v0 = v[0], v1 = v[1]; - out[0] = a0 * v0; - out[1] = a1 * v0; - out[2] = a2 * v1; - out[3] = a3 * v1; - out[4] = a4; - out[5] = a5; - return out; -}; - -/** - * Translates the mat2d by the dimensions in the given vec2 - * - * @param {mat2d} out the receiving matrix - * @param {mat2d} a the matrix to translate - * @param {vec2} v the vec2 to translate the matrix by - * @returns {mat2d} out - **/ -mat2d.translate = function(out, a, v) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], - v0 = v[0], v1 = v[1]; - out[0] = a0; - out[1] = a1; - out[2] = a2; - out[3] = a3; - out[4] = a0 * v0 + a2 * v1 + a4; - out[5] = a1 * v0 + a3 * v1 + a5; - return out; -}; - -/** - * Returns a string representation of a mat2d - * - * @param {mat2d} a matrix to represent as a string - * @returns {String} string representation of the matrix - */ -mat2d.str = function (a) { - return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + - a[3] + ', ' + a[4] + ', ' + a[5] + ')'; -}; - -/** - * Returns Frobenius norm of a mat2d - * - * @param {mat2d} a the matrix to calculate Frobenius norm of - * @returns {Number} Frobenius norm - */ -mat2d.frob = function (a) { - return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1)) -}; - -if(typeof(exports) !== 'undefined') { - exports.mat2d = mat2d; -} -; -/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -/** - * @class 3x3 Matrix - * @name mat3 - */ - -var mat3 = {}; - -/** - * Creates a new identity mat3 - * - * @returns {mat3} a new 3x3 matrix - */ -mat3.create = function() { - var out = new GLMAT_ARRAY_TYPE(9); - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 1; - out[5] = 0; - out[6] = 0; - out[7] = 0; - out[8] = 1; - return out; -}; - -/** - * Copies the upper-left 3x3 values into the given mat3. - * - * @param {mat3} out the receiving 3x3 matrix - * @param {mat4} a the source 4x4 matrix - * @returns {mat3} out - */ -mat3.fromMat4 = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[4]; - out[4] = a[5]; - out[5] = a[6]; - out[6] = a[8]; - out[7] = a[9]; - out[8] = a[10]; - return out; -}; - -/** - * Creates a new mat3 initialized with values from an existing matrix - * - * @param {mat3} a matrix to clone - * @returns {mat3} a new 3x3 matrix - */ -mat3.clone = function(a) { - var out = new GLMAT_ARRAY_TYPE(9); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[8] = a[8]; - return out; -}; - -/** - * Copy the values from one mat3 to another - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the source matrix - * @returns {mat3} out - */ -mat3.copy = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[8] = a[8]; - return out; -}; - -/** - * Set a mat3 to the identity matrix - * - * @param {mat3} out the receiving matrix - * @returns {mat3} out - */ -mat3.identity = function(out) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 1; - out[5] = 0; - out[6] = 0; - out[7] = 0; - out[8] = 1; - return out; -}; - -/** - * Transpose the values of a mat3 - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the source matrix - * @returns {mat3} out - */ -mat3.transpose = function(out, a) { - // If we are transposing ourselves we can skip a few steps but have to cache some values - if (out === a) { - var a01 = a[1], a02 = a[2], a12 = a[5]; - out[1] = a[3]; - out[2] = a[6]; - out[3] = a01; - out[5] = a[7]; - out[6] = a02; - out[7] = a12; - } else { - out[0] = a[0]; - out[1] = a[3]; - out[2] = a[6]; - out[3] = a[1]; - out[4] = a[4]; - out[5] = a[7]; - out[6] = a[2]; - out[7] = a[5]; - out[8] = a[8]; - } - - return out; -}; - -/** - * Inverts a mat3 - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the source matrix - * @returns {mat3} out - */ -mat3.invert = function(out, a) { - var a00 = a[0], a01 = a[1], a02 = a[2], - a10 = a[3], a11 = a[4], a12 = a[5], - a20 = a[6], a21 = a[7], a22 = a[8], - - b01 = a22 * a11 - a12 * a21, - b11 = -a22 * a10 + a12 * a20, - b21 = a21 * a10 - a11 * a20, - - // Calculate the determinant - det = a00 * b01 + a01 * b11 + a02 * b21; - - if (!det) { - return null; - } - det = 1.0 / det; - - out[0] = b01 * det; - out[1] = (-a22 * a01 + a02 * a21) * det; - out[2] = (a12 * a01 - a02 * a11) * det; - out[3] = b11 * det; - out[4] = (a22 * a00 - a02 * a20) * det; - out[5] = (-a12 * a00 + a02 * a10) * det; - out[6] = b21 * det; - out[7] = (-a21 * a00 + a01 * a20) * det; - out[8] = (a11 * a00 - a01 * a10) * det; - return out; -}; - -/** - * Calculates the adjugate of a mat3 - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the source matrix - * @returns {mat3} out - */ -mat3.adjoint = function(out, a) { - var a00 = a[0], a01 = a[1], a02 = a[2], - a10 = a[3], a11 = a[4], a12 = a[5], - a20 = a[6], a21 = a[7], a22 = a[8]; - - out[0] = (a11 * a22 - a12 * a21); - out[1] = (a02 * a21 - a01 * a22); - out[2] = (a01 * a12 - a02 * a11); - out[3] = (a12 * a20 - a10 * a22); - out[4] = (a00 * a22 - a02 * a20); - out[5] = (a02 * a10 - a00 * a12); - out[6] = (a10 * a21 - a11 * a20); - out[7] = (a01 * a20 - a00 * a21); - out[8] = (a00 * a11 - a01 * a10); - return out; -}; - -/** - * Calculates the determinant of a mat3 - * - * @param {mat3} a the source matrix - * @returns {Number} determinant of a - */ -mat3.determinant = function (a) { - var a00 = a[0], a01 = a[1], a02 = a[2], - a10 = a[3], a11 = a[4], a12 = a[5], - a20 = a[6], a21 = a[7], a22 = a[8]; - - return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); -}; - -/** - * Multiplies two mat3's - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the first operand - * @param {mat3} b the second operand - * @returns {mat3} out - */ -mat3.multiply = function (out, a, b) { - var a00 = a[0], a01 = a[1], a02 = a[2], - a10 = a[3], a11 = a[4], a12 = a[5], - a20 = a[6], a21 = a[7], a22 = a[8], - - b00 = b[0], b01 = b[1], b02 = b[2], - b10 = b[3], b11 = b[4], b12 = b[5], - b20 = b[6], b21 = b[7], b22 = b[8]; - - out[0] = b00 * a00 + b01 * a10 + b02 * a20; - out[1] = b00 * a01 + b01 * a11 + b02 * a21; - out[2] = b00 * a02 + b01 * a12 + b02 * a22; - - out[3] = b10 * a00 + b11 * a10 + b12 * a20; - out[4] = b10 * a01 + b11 * a11 + b12 * a21; - out[5] = b10 * a02 + b11 * a12 + b12 * a22; - - out[6] = b20 * a00 + b21 * a10 + b22 * a20; - out[7] = b20 * a01 + b21 * a11 + b22 * a21; - out[8] = b20 * a02 + b21 * a12 + b22 * a22; - return out; -}; - -/** - * Alias for {@link mat3.multiply} - * @function - */ -mat3.mul = mat3.multiply; - -/** - * Translate a mat3 by the given vector - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the matrix to translate - * @param {vec2} v vector to translate by - * @returns {mat3} out - */ -mat3.translate = function(out, a, v) { - var a00 = a[0], a01 = a[1], a02 = a[2], - a10 = a[3], a11 = a[4], a12 = a[5], - a20 = a[6], a21 = a[7], a22 = a[8], - x = v[0], y = v[1]; - - out[0] = a00; - out[1] = a01; - out[2] = a02; - - out[3] = a10; - out[4] = a11; - out[5] = a12; - - out[6] = x * a00 + y * a10 + a20; - out[7] = x * a01 + y * a11 + a21; - out[8] = x * a02 + y * a12 + a22; - return out; -}; - -/** - * Rotates a mat3 by the given angle - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat3} out - */ -mat3.rotate = function (out, a, rad) { - var a00 = a[0], a01 = a[1], a02 = a[2], - a10 = a[3], a11 = a[4], a12 = a[5], - a20 = a[6], a21 = a[7], a22 = a[8], - - s = Math.sin(rad), - c = Math.cos(rad); - - out[0] = c * a00 + s * a10; - out[1] = c * a01 + s * a11; - out[2] = c * a02 + s * a12; - - out[3] = c * a10 - s * a00; - out[4] = c * a11 - s * a01; - out[5] = c * a12 - s * a02; - - out[6] = a20; - out[7] = a21; - out[8] = a22; - return out; -}; - -/** - * Scales the mat3 by the dimensions in the given vec2 - * - * @param {mat3} out the receiving matrix - * @param {mat3} a the matrix to rotate - * @param {vec2} v the vec2 to scale the matrix by - * @returns {mat3} out - **/ -mat3.scale = function(out, a, v) { - var x = v[0], y = v[1]; - - out[0] = x * a[0]; - out[1] = x * a[1]; - out[2] = x * a[2]; - - out[3] = y * a[3]; - out[4] = y * a[4]; - out[5] = y * a[5]; - - out[6] = a[6]; - out[7] = a[7]; - out[8] = a[8]; - return out; -}; - -/** - * Copies the values from a mat2d into a mat3 - * - * @param {mat3} out the receiving matrix - * @param {mat2d} a the matrix to copy - * @returns {mat3} out - **/ -mat3.fromMat2d = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = 0; - - out[3] = a[2]; - out[4] = a[3]; - out[5] = 0; - - out[6] = a[4]; - out[7] = a[5]; - out[8] = 1; - return out; -}; - -/** -* Calculates a 3x3 matrix from the given quaternion -* -* @param {mat3} out mat3 receiving operation result -* @param {quat} q Quaternion to create matrix from -* -* @returns {mat3} out -*/ -mat3.fromQuat = function (out, q) { - var x = q[0], y = q[1], z = q[2], w = q[3], - x2 = x + x, - y2 = y + y, - z2 = z + z, - - xx = x * x2, - yx = y * x2, - yy = y * y2, - zx = z * x2, - zy = z * y2, - zz = z * z2, - wx = w * x2, - wy = w * y2, - wz = w * z2; - - out[0] = 1 - yy - zz; - out[3] = yx - wz; - out[6] = zx + wy; - - out[1] = yx + wz; - out[4] = 1 - xx - zz; - out[7] = zy - wx; - - out[2] = zx - wy; - out[5] = zy + wx; - out[8] = 1 - xx - yy; - - return out; -}; - -/** -* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix -* -* @param {mat3} out mat3 receiving operation result -* @param {mat4} a Mat4 to derive the normal matrix from -* -* @returns {mat3} out -*/ -mat3.normalFromMat4 = function (out, a) { - var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], - a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], - a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], - a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], - - b00 = a00 * a11 - a01 * a10, - b01 = a00 * a12 - a02 * a10, - b02 = a00 * a13 - a03 * a10, - b03 = a01 * a12 - a02 * a11, - b04 = a01 * a13 - a03 * a11, - b05 = a02 * a13 - a03 * a12, - b06 = a20 * a31 - a21 * a30, - b07 = a20 * a32 - a22 * a30, - b08 = a20 * a33 - a23 * a30, - b09 = a21 * a32 - a22 * a31, - b10 = a21 * a33 - a23 * a31, - b11 = a22 * a33 - a23 * a32, - - // Calculate the determinant - det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; - - if (!det) { - return null; - } - det = 1.0 / det; - - out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; - out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det; - out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det; - - out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det; - out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det; - out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det; - - out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det; - out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det; - out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det; - - return out; -}; - -/** - * Returns a string representation of a mat3 - * - * @param {mat3} mat matrix to represent as a string - * @returns {String} string representation of the matrix - */ -mat3.str = function (a) { - return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + - a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + - a[6] + ', ' + a[7] + ', ' + a[8] + ')'; -}; - -/** - * Returns Frobenius norm of a mat3 - * - * @param {mat3} a the matrix to calculate Frobenius norm of - * @returns {Number} Frobenius norm - */ -mat3.frob = function (a) { - return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2))) -}; - - -if(typeof(exports) !== 'undefined') { - exports.mat3 = mat3; -} -; -/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -/** - * @class 4x4 Matrix - * @name mat4 - */ - -var mat4 = {}; - -/** - * Creates a new identity mat4 - * - * @returns {mat4} a new 4x4 matrix - */ -mat4.create = function() { - var out = new GLMAT_ARRAY_TYPE(16); - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = 1; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 1; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - return out; -}; - -/** - * Creates a new mat4 initialized with values from an existing matrix - * - * @param {mat4} a matrix to clone - * @returns {mat4} a new 4x4 matrix - */ -mat4.clone = function(a) { - var out = new GLMAT_ARRAY_TYPE(16); - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[8] = a[8]; - out[9] = a[9]; - out[10] = a[10]; - out[11] = a[11]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - return out; -}; - -/** - * Copy the values from one mat4 to another - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the source matrix - * @returns {mat4} out - */ -mat4.copy = function(out, a) { - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[8] = a[8]; - out[9] = a[9]; - out[10] = a[10]; - out[11] = a[11]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - return out; -}; - -/** - * Set a mat4 to the identity matrix - * - * @param {mat4} out the receiving matrix - * @returns {mat4} out - */ -mat4.identity = function(out) { - out[0] = 1; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = 1; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 1; - out[11] = 0; - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - return out; -}; - -/** - * Transpose the values of a mat4 - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the source matrix - * @returns {mat4} out - */ -mat4.transpose = function(out, a) { - // If we are transposing ourselves we can skip a few steps but have to cache some values - if (out === a) { - var a01 = a[1], a02 = a[2], a03 = a[3], - a12 = a[6], a13 = a[7], - a23 = a[11]; - - out[1] = a[4]; - out[2] = a[8]; - out[3] = a[12]; - out[4] = a01; - out[6] = a[9]; - out[7] = a[13]; - out[8] = a02; - out[9] = a12; - out[11] = a[14]; - out[12] = a03; - out[13] = a13; - out[14] = a23; - } else { - out[0] = a[0]; - out[1] = a[4]; - out[2] = a[8]; - out[3] = a[12]; - out[4] = a[1]; - out[5] = a[5]; - out[6] = a[9]; - out[7] = a[13]; - out[8] = a[2]; - out[9] = a[6]; - out[10] = a[10]; - out[11] = a[14]; - out[12] = a[3]; - out[13] = a[7]; - out[14] = a[11]; - out[15] = a[15]; - } - - return out; -}; - -/** - * Inverts a mat4 - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the source matrix - * @returns {mat4} out - */ -mat4.invert = function(out, a) { - var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], - a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], - a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], - a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], - - b00 = a00 * a11 - a01 * a10, - b01 = a00 * a12 - a02 * a10, - b02 = a00 * a13 - a03 * a10, - b03 = a01 * a12 - a02 * a11, - b04 = a01 * a13 - a03 * a11, - b05 = a02 * a13 - a03 * a12, - b06 = a20 * a31 - a21 * a30, - b07 = a20 * a32 - a22 * a30, - b08 = a20 * a33 - a23 * a30, - b09 = a21 * a32 - a22 * a31, - b10 = a21 * a33 - a23 * a31, - b11 = a22 * a33 - a23 * a32, - - // Calculate the determinant - det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; - - if (!det) { - return null; - } - det = 1.0 / det; - - out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; - out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; - out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; - out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; - out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; - out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; - out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; - out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; - out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; - out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; - out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; - out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; - out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; - out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; - out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; - out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; - - return out; -}; - -/** - * Calculates the adjugate of a mat4 - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the source matrix - * @returns {mat4} out - */ -mat4.adjoint = function(out, a) { - var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], - a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], - a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], - a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; - - out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22)); - out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)); - out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12)); - out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)); - out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)); - out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22)); - out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)); - out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12)); - out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21)); - out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)); - out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11)); - out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)); - out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)); - out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21)); - out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)); - out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11)); - return out; -}; - -/** - * Calculates the determinant of a mat4 - * - * @param {mat4} a the source matrix - * @returns {Number} determinant of a - */ -mat4.determinant = function (a) { - var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], - a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], - a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], - a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15], - - b00 = a00 * a11 - a01 * a10, - b01 = a00 * a12 - a02 * a10, - b02 = a00 * a13 - a03 * a10, - b03 = a01 * a12 - a02 * a11, - b04 = a01 * a13 - a03 * a11, - b05 = a02 * a13 - a03 * a12, - b06 = a20 * a31 - a21 * a30, - b07 = a20 * a32 - a22 * a30, - b08 = a20 * a33 - a23 * a30, - b09 = a21 * a32 - a22 * a31, - b10 = a21 * a33 - a23 * a31, - b11 = a22 * a33 - a23 * a32; - - // Calculate the determinant - return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; -}; - -/** - * Multiplies two mat4's - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the first operand - * @param {mat4} b the second operand - * @returns {mat4} out - */ -mat4.multiply = function (out, a, b) { - var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3], - a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7], - a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11], - a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; - - // Cache only the current line of the second matrix - var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; - out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7]; - out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11]; - out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - - b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15]; - out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30; - out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31; - out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32; - out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33; - return out; -}; - -/** - * Multiplies two affine mat4's - * Add by https://github.com/pissang - * @param {mat4} out the receiving matrix - * @param {mat4} a the first operand - * @param {mat4} b the second operand - * @returns {mat4} out - */ -mat4.multiplyAffine = function (out, a, b) { - var a00 = a[0], a01 = a[1], a02 = a[2], - a10 = a[4], a11 = a[5], a12 = a[6], - a20 = a[8], a21 = a[9], a22 = a[10], - a30 = a[12], a31 = a[13], a32 = a[14]; - - // Cache only the current line of the second matrix - var b0 = b[0], b1 = b[1], b2 = b[2]; - out[0] = b0*a00 + b1*a10 + b2*a20; - out[1] = b0*a01 + b1*a11 + b2*a21; - out[2] = b0*a02 + b1*a12 + b2*a22; - // out[3] = 0; - - b0 = b[4]; b1 = b[5]; b2 = b[6]; - out[4] = b0*a00 + b1*a10 + b2*a20; - out[5] = b0*a01 + b1*a11 + b2*a21; - out[6] = b0*a02 + b1*a12 + b2*a22; - // out[7] = 0; - - b0 = b[8]; b1 = b[9]; b2 = b[10]; - out[8] = b0*a00 + b1*a10 + b2*a20; - out[9] = b0*a01 + b1*a11 + b2*a21; - out[10] = b0*a02 + b1*a12 + b2*a22; - // out[11] = 0; - - b0 = b[12]; b1 = b[13]; b2 = b[14]; - out[12] = b0*a00 + b1*a10 + b2*a20 + a30; - out[13] = b0*a01 + b1*a11 + b2*a21 + a31; - out[14] = b0*a02 + b1*a12 + b2*a22 + a32; - // out[15] = 1; - return out; -}; - -/** - * Alias for {@link mat4.multiply} - * @function - */ -mat4.mul = mat4.multiply; - -/** - * Alias for {@link mat4.multiplyAffine} - * @function - */ -mat4.mulAffine = mat4.multiplyAffine; -/** - * Translate a mat4 by the given vector - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to translate - * @param {vec3} v vector to translate by - * @returns {mat4} out - */ -mat4.translate = function (out, a, v) { - var x = v[0], y = v[1], z = v[2], - a00, a01, a02, a03, - a10, a11, a12, a13, - a20, a21, a22, a23; - - if (a === out) { - out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; - out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; - out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; - out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; - } else { - a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; - a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; - a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; - - out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a03; - out[4] = a10; out[5] = a11; out[6] = a12; out[7] = a13; - out[8] = a20; out[9] = a21; out[10] = a22; out[11] = a23; - - out[12] = a00 * x + a10 * y + a20 * z + a[12]; - out[13] = a01 * x + a11 * y + a21 * z + a[13]; - out[14] = a02 * x + a12 * y + a22 * z + a[14]; - out[15] = a03 * x + a13 * y + a23 * z + a[15]; - } - - return out; -}; - -/** - * Scales the mat4 by the dimensions in the given vec3 - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to scale - * @param {vec3} v the vec3 to scale the matrix by - * @returns {mat4} out - **/ -mat4.scale = function(out, a, v) { - var x = v[0], y = v[1], z = v[2]; - - out[0] = a[0] * x; - out[1] = a[1] * x; - out[2] = a[2] * x; - out[3] = a[3] * x; - out[4] = a[4] * y; - out[5] = a[5] * y; - out[6] = a[6] * y; - out[7] = a[7] * y; - out[8] = a[8] * z; - out[9] = a[9] * z; - out[10] = a[10] * z; - out[11] = a[11] * z; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - return out; -}; - -/** - * Rotates a mat4 by the given angle - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @param {vec3} axis the axis to rotate around - * @returns {mat4} out - */ -mat4.rotate = function (out, a, rad, axis) { - var x = axis[0], y = axis[1], z = axis[2], - len = Math.sqrt(x * x + y * y + z * z), - s, c, t, - a00, a01, a02, a03, - a10, a11, a12, a13, - a20, a21, a22, a23, - b00, b01, b02, - b10, b11, b12, - b20, b21, b22; - - if (Math.abs(len) < GLMAT_EPSILON) { return null; } - - len = 1 / len; - x *= len; - y *= len; - z *= len; - - s = Math.sin(rad); - c = Math.cos(rad); - t = 1 - c; - - a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3]; - a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7]; - a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11]; - - // Construct the elements of the rotation matrix - b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s; - b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s; - b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c; - - // Perform rotation-specific matrix multiplication - out[0] = a00 * b00 + a10 * b01 + a20 * b02; - out[1] = a01 * b00 + a11 * b01 + a21 * b02; - out[2] = a02 * b00 + a12 * b01 + a22 * b02; - out[3] = a03 * b00 + a13 * b01 + a23 * b02; - out[4] = a00 * b10 + a10 * b11 + a20 * b12; - out[5] = a01 * b10 + a11 * b11 + a21 * b12; - out[6] = a02 * b10 + a12 * b11 + a22 * b12; - out[7] = a03 * b10 + a13 * b11 + a23 * b12; - out[8] = a00 * b20 + a10 * b21 + a20 * b22; - out[9] = a01 * b20 + a11 * b21 + a21 * b22; - out[10] = a02 * b20 + a12 * b21 + a22 * b22; - out[11] = a03 * b20 + a13 * b21 + a23 * b22; - - if (a !== out) { // If the source and destination differ, copy the unchanged last row - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - } - return out; -}; - -/** - * Rotates a matrix by the given angle around the X axis - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat4} out - */ -mat4.rotateX = function (out, a, rad) { - var s = Math.sin(rad), - c = Math.cos(rad), - a10 = a[4], - a11 = a[5], - a12 = a[6], - a13 = a[7], - a20 = a[8], - a21 = a[9], - a22 = a[10], - a23 = a[11]; - - if (a !== out) { // If the source and destination differ, copy the unchanged rows - out[0] = a[0]; - out[1] = a[1]; - out[2] = a[2]; - out[3] = a[3]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - } - - // Perform axis-specific matrix multiplication - out[4] = a10 * c + a20 * s; - out[5] = a11 * c + a21 * s; - out[6] = a12 * c + a22 * s; - out[7] = a13 * c + a23 * s; - out[8] = a20 * c - a10 * s; - out[9] = a21 * c - a11 * s; - out[10] = a22 * c - a12 * s; - out[11] = a23 * c - a13 * s; - return out; -}; - -/** - * Rotates a matrix by the given angle around the Y axis - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat4} out - */ -mat4.rotateY = function (out, a, rad) { - var s = Math.sin(rad), - c = Math.cos(rad), - a00 = a[0], - a01 = a[1], - a02 = a[2], - a03 = a[3], - a20 = a[8], - a21 = a[9], - a22 = a[10], - a23 = a[11]; - - if (a !== out) { // If the source and destination differ, copy the unchanged rows - out[4] = a[4]; - out[5] = a[5]; - out[6] = a[6]; - out[7] = a[7]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - } - - // Perform axis-specific matrix multiplication - out[0] = a00 * c - a20 * s; - out[1] = a01 * c - a21 * s; - out[2] = a02 * c - a22 * s; - out[3] = a03 * c - a23 * s; - out[8] = a00 * s + a20 * c; - out[9] = a01 * s + a21 * c; - out[10] = a02 * s + a22 * c; - out[11] = a03 * s + a23 * c; - return out; -}; - -/** - * Rotates a matrix by the given angle around the Z axis - * - * @param {mat4} out the receiving matrix - * @param {mat4} a the matrix to rotate - * @param {Number} rad the angle to rotate the matrix by - * @returns {mat4} out - */ -mat4.rotateZ = function (out, a, rad) { - var s = Math.sin(rad), - c = Math.cos(rad), - a00 = a[0], - a01 = a[1], - a02 = a[2], - a03 = a[3], - a10 = a[4], - a11 = a[5], - a12 = a[6], - a13 = a[7]; - - if (a !== out) { // If the source and destination differ, copy the unchanged last row - out[8] = a[8]; - out[9] = a[9]; - out[10] = a[10]; - out[11] = a[11]; - out[12] = a[12]; - out[13] = a[13]; - out[14] = a[14]; - out[15] = a[15]; - } - - // Perform axis-specific matrix multiplication - out[0] = a00 * c + a10 * s; - out[1] = a01 * c + a11 * s; - out[2] = a02 * c + a12 * s; - out[3] = a03 * c + a13 * s; - out[4] = a10 * c - a00 * s; - out[5] = a11 * c - a01 * s; - out[6] = a12 * c - a02 * s; - out[7] = a13 * c - a03 * s; - return out; -}; - -/** - * Creates a matrix from a quaternion rotation and vector translation - * This is equivalent to (but much faster than): - * - * mat4.identity(dest); - * mat4.translate(dest, vec); - * var quatMat = mat4.create(); - * quat4.toMat4(quat, quatMat); - * mat4.multiply(dest, quatMat); - * - * @param {mat4} out mat4 receiving operation result - * @param {quat4} q Rotation quaternion - * @param {vec3} v Translation vector - * @returns {mat4} out - */ -mat4.fromRotationTranslation = function (out, q, v) { - // Quaternion math - var x = q[0], y = q[1], z = q[2], w = q[3], - x2 = x + x, - y2 = y + y, - z2 = z + z, - - xx = x * x2, - xy = x * y2, - xz = x * z2, - yy = y * y2, - yz = y * z2, - zz = z * z2, - wx = w * x2, - wy = w * y2, - wz = w * z2; - - out[0] = 1 - (yy + zz); - out[1] = xy + wz; - out[2] = xz - wy; - out[3] = 0; - out[4] = xy - wz; - out[5] = 1 - (xx + zz); - out[6] = yz + wx; - out[7] = 0; - out[8] = xz + wy; - out[9] = yz - wx; - out[10] = 1 - (xx + yy); - out[11] = 0; - out[12] = v[0]; - out[13] = v[1]; - out[14] = v[2]; - out[15] = 1; - - return out; -}; - -mat4.fromQuat = function (out, q) { - var x = q[0], y = q[1], z = q[2], w = q[3], - x2 = x + x, - y2 = y + y, - z2 = z + z, - - xx = x * x2, - yx = y * x2, - yy = y * y2, - zx = z * x2, - zy = z * y2, - zz = z * z2, - wx = w * x2, - wy = w * y2, - wz = w * z2; - - out[0] = 1 - yy - zz; - out[1] = yx + wz; - out[2] = zx - wy; - out[3] = 0; - - out[4] = yx - wz; - out[5] = 1 - xx - zz; - out[6] = zy + wx; - out[7] = 0; - - out[8] = zx + wy; - out[9] = zy - wx; - out[10] = 1 - xx - yy; - out[11] = 0; - - out[12] = 0; - out[13] = 0; - out[14] = 0; - out[15] = 1; - - return out; -}; - -/** - * Generates a frustum matrix with the given bounds - * - * @param {mat4} out mat4 frustum matrix will be written into - * @param {Number} left Left bound of the frustum - * @param {Number} right Right bound of the frustum - * @param {Number} bottom Bottom bound of the frustum - * @param {Number} top Top bound of the frustum - * @param {Number} near Near bound of the frustum - * @param {Number} far Far bound of the frustum - * @returns {mat4} out - */ -mat4.frustum = function (out, left, right, bottom, top, near, far) { - var rl = 1 / (right - left), - tb = 1 / (top - bottom), - nf = 1 / (near - far); - out[0] = (near * 2) * rl; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = (near * 2) * tb; - out[6] = 0; - out[7] = 0; - out[8] = (right + left) * rl; - out[9] = (top + bottom) * tb; - out[10] = (far + near) * nf; - out[11] = -1; - out[12] = 0; - out[13] = 0; - out[14] = (far * near * 2) * nf; - out[15] = 0; - return out; -}; - -/** - * Generates a perspective projection matrix with the given bounds - * - * @param {mat4} out mat4 frustum matrix will be written into - * @param {number} fovy Vertical field of view in radians - * @param {number} aspect Aspect ratio. typically viewport width/height - * @param {number} near Near bound of the frustum - * @param {number} far Far bound of the frustum - * @returns {mat4} out - */ -mat4.perspective = function (out, fovy, aspect, near, far) { - var f = 1.0 / Math.tan(fovy / 2), - nf = 1 / (near - far); - out[0] = f / aspect; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = f; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = (far + near) * nf; - out[11] = -1; - out[12] = 0; - out[13] = 0; - out[14] = (2 * far * near) * nf; - out[15] = 0; - return out; -}; - -/** - * Generates a orthogonal projection matrix with the given bounds - * - * @param {mat4} out mat4 frustum matrix will be written into - * @param {number} left Left bound of the frustum - * @param {number} right Right bound of the frustum - * @param {number} bottom Bottom bound of the frustum - * @param {number} top Top bound of the frustum - * @param {number} near Near bound of the frustum - * @param {number} far Far bound of the frustum - * @returns {mat4} out - */ -mat4.ortho = function (out, left, right, bottom, top, near, far) { - var lr = 1 / (left - right), - bt = 1 / (bottom - top), - nf = 1 / (near - far); - out[0] = -2 * lr; - out[1] = 0; - out[2] = 0; - out[3] = 0; - out[4] = 0; - out[5] = -2 * bt; - out[6] = 0; - out[7] = 0; - out[8] = 0; - out[9] = 0; - out[10] = 2 * nf; - out[11] = 0; - out[12] = (left + right) * lr; - out[13] = (top + bottom) * bt; - out[14] = (far + near) * nf; - out[15] = 1; - return out; -}; - -/** - * Generates a look-at matrix with the given eye position, focal point, and up axis - * - * @param {mat4} out mat4 frustum matrix will be written into - * @param {vec3} eye Position of the viewer - * @param {vec3} center Point the viewer is looking at - * @param {vec3} up vec3 pointing up - * @returns {mat4} out - */ -mat4.lookAt = function (out, eye, center, up) { - var x0, x1, x2, y0, y1, y2, z0, z1, z2, len, - eyex = eye[0], - eyey = eye[1], - eyez = eye[2], - upx = up[0], - upy = up[1], - upz = up[2], - centerx = center[0], - centery = center[1], - centerz = center[2]; - - if (Math.abs(eyex - centerx) < GLMAT_EPSILON && - Math.abs(eyey - centery) < GLMAT_EPSILON && - Math.abs(eyez - centerz) < GLMAT_EPSILON) { - return mat4.identity(out); - } - - z0 = eyex - centerx; - z1 = eyey - centery; - z2 = eyez - centerz; - - len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); - z0 *= len; - z1 *= len; - z2 *= len; - - x0 = upy * z2 - upz * z1; - x1 = upz * z0 - upx * z2; - x2 = upx * z1 - upy * z0; - len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); - if (!len) { - x0 = 0; - x1 = 0; - x2 = 0; - } else { - len = 1 / len; - x0 *= len; - x1 *= len; - x2 *= len; - } - - y0 = z1 * x2 - z2 * x1; - y1 = z2 * x0 - z0 * x2; - y2 = z0 * x1 - z1 * x0; - - len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); - if (!len) { - y0 = 0; - y1 = 0; - y2 = 0; - } else { - len = 1 / len; - y0 *= len; - y1 *= len; - y2 *= len; - } - - out[0] = x0; - out[1] = y0; - out[2] = z0; - out[3] = 0; - out[4] = x1; - out[5] = y1; - out[6] = z1; - out[7] = 0; - out[8] = x2; - out[9] = y2; - out[10] = z2; - out[11] = 0; - out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); - out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); - out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); - out[15] = 1; - - return out; -}; - -/** - * Returns a string representation of a mat4 - * - * @param {mat4} mat matrix to represent as a string - * @returns {String} string representation of the matrix - */ -mat4.str = function (a) { - return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + - a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + - a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + - a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')'; -}; - -/** - * Returns Frobenius norm of a mat4 - * - * @param {mat4} a the matrix to calculate Frobenius norm of - * @returns {Number} Frobenius norm - */ -mat4.frob = function (a) { - return(Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2) )) -}; - - -if(typeof(exports) !== 'undefined') { - exports.mat4 = mat4; -} -; -/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - -/** - * @class Quaternion - * @name quat - */ - -var quat = {}; - -/** - * Creates a new identity quat - * - * @returns {quat} a new quaternion - */ -quat.create = function() { - var out = new GLMAT_ARRAY_TYPE(4); - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 1; - return out; -}; - -/** - * Sets a quaternion to represent the shortest rotation from one - * vector to another. - * - * Both vectors are assumed to be unit length. - * - * @param {quat} out the receiving quaternion. - * @param {vec3} a the initial vector - * @param {vec3} b the destination vector - * @returns {quat} out - */ -quat.rotationTo = (function() { - var tmpvec3 = vec3.create(); - var xUnitVec3 = vec3.fromValues(1,0,0); - var yUnitVec3 = vec3.fromValues(0,1,0); - - return function(out, a, b) { - var dot = vec3.dot(a, b); - if (dot < -0.999999) { - vec3.cross(tmpvec3, xUnitVec3, a); - if (vec3.length(tmpvec3) < 0.000001) - vec3.cross(tmpvec3, yUnitVec3, a); - vec3.normalize(tmpvec3, tmpvec3); - quat.setAxisAngle(out, tmpvec3, Math.PI); - return out; - } else if (dot > 0.999999) { - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 1; - return out; - } else { - vec3.cross(tmpvec3, a, b); - out[0] = tmpvec3[0]; - out[1] = tmpvec3[1]; - out[2] = tmpvec3[2]; - out[3] = 1 + dot; - return quat.normalize(out, out); - } - }; -})(); - -/** - * Sets the specified quaternion with values corresponding to the given - * axes. Each axis is a vec3 and is expected to be unit length and - * perpendicular to all other specified axes. - * - * @param {vec3} view the vector representing the viewing direction - * @param {vec3} right the vector representing the local "right" direction - * @param {vec3} up the vector representing the local "up" direction - * @returns {quat} out - */ -quat.setAxes = (function() { - var matr = mat3.create(); - - return function(out, view, right, up) { - matr[0] = right[0]; - matr[3] = right[1]; - matr[6] = right[2]; - - matr[1] = up[0]; - matr[4] = up[1]; - matr[7] = up[2]; - - matr[2] = -view[0]; - matr[5] = -view[1]; - matr[8] = -view[2]; - - return quat.normalize(out, quat.fromMat3(out, matr)); - }; -})(); - -/** - * Creates a new quat initialized with values from an existing quaternion - * - * @param {quat} a quaternion to clone - * @returns {quat} a new quaternion - * @function - */ -quat.clone = vec4.clone; - -/** - * Creates a new quat initialized with the given values - * - * @param {Number} x X component - * @param {Number} y Y component - * @param {Number} z Z component - * @param {Number} w W component - * @returns {quat} a new quaternion - * @function - */ -quat.fromValues = vec4.fromValues; - -/** - * Copy the values from one quat to another - * - * @param {quat} out the receiving quaternion - * @param {quat} a the source quaternion - * @returns {quat} out - * @function - */ -quat.copy = vec4.copy; - -/** - * Set the components of a quat to the given values - * - * @param {quat} out the receiving quaternion - * @param {Number} x X component - * @param {Number} y Y component - * @param {Number} z Z component - * @param {Number} w W component - * @returns {quat} out - * @function - */ -quat.set = vec4.set; - -/** - * Set a quat to the identity quaternion - * - * @param {quat} out the receiving quaternion - * @returns {quat} out - */ -quat.identity = function(out) { - out[0] = 0; - out[1] = 0; - out[2] = 0; - out[3] = 1; - return out; -}; - -/** - * Sets a quat from the given angle and rotation axis, - * then returns it. - * - * @param {quat} out the receiving quaternion - * @param {vec3} axis the axis around which to rotate - * @param {Number} rad the angle in radians - * @returns {quat} out - **/ -quat.setAxisAngle = function(out, axis, rad) { - rad = rad * 0.5; - var s = Math.sin(rad); - out[0] = s * axis[0]; - out[1] = s * axis[1]; - out[2] = s * axis[2]; - out[3] = Math.cos(rad); - return out; -}; - -/** - * Adds two quat's - * - * @param {quat} out the receiving quaternion - * @param {quat} a the first operand - * @param {quat} b the second operand - * @returns {quat} out - * @function - */ -quat.add = vec4.add; - -/** - * Multiplies two quat's - * - * @param {quat} out the receiving quaternion - * @param {quat} a the first operand - * @param {quat} b the second operand - * @returns {quat} out - */ -quat.multiply = function(out, a, b) { - var ax = a[0], ay = a[1], az = a[2], aw = a[3], - bx = b[0], by = b[1], bz = b[2], bw = b[3]; - - out[0] = ax * bw + aw * bx + ay * bz - az * by; - out[1] = ay * bw + aw * by + az * bx - ax * bz; - out[2] = az * bw + aw * bz + ax * by - ay * bx; - out[3] = aw * bw - ax * bx - ay * by - az * bz; - return out; -}; - -/** - * Alias for {@link quat.multiply} - * @function - */ -quat.mul = quat.multiply; - -/** - * Scales a quat by a scalar number - * - * @param {quat} out the receiving vector - * @param {quat} a the vector to scale - * @param {Number} b amount to scale the vector by - * @returns {quat} out - * @function - */ -quat.scale = vec4.scale; - -/** - * Rotates a quaternion by the given angle about the X axis - * - * @param {quat} out quat receiving operation result - * @param {quat} a quat to rotate - * @param {number} rad angle (in radians) to rotate - * @returns {quat} out - */ -quat.rotateX = function (out, a, rad) { - rad *= 0.5; - - var ax = a[0], ay = a[1], az = a[2], aw = a[3], - bx = Math.sin(rad), bw = Math.cos(rad); - - out[0] = ax * bw + aw * bx; - out[1] = ay * bw + az * bx; - out[2] = az * bw - ay * bx; - out[3] = aw * bw - ax * bx; - return out; -}; - -/** - * Rotates a quaternion by the given angle about the Y axis - * - * @param {quat} out quat receiving operation result - * @param {quat} a quat to rotate - * @param {number} rad angle (in radians) to rotate - * @returns {quat} out - */ -quat.rotateY = function (out, a, rad) { - rad *= 0.5; - - var ax = a[0], ay = a[1], az = a[2], aw = a[3], - by = Math.sin(rad), bw = Math.cos(rad); - - out[0] = ax * bw - az * by; - out[1] = ay * bw + aw * by; - out[2] = az * bw + ax * by; - out[3] = aw * bw - ay * by; - return out; -}; - -/** - * Rotates a quaternion by the given angle about the Z axis - * - * @param {quat} out quat receiving operation result - * @param {quat} a quat to rotate - * @param {number} rad angle (in radians) to rotate - * @returns {quat} out - */ -quat.rotateZ = function (out, a, rad) { - rad *= 0.5; - - var ax = a[0], ay = a[1], az = a[2], aw = a[3], - bz = Math.sin(rad), bw = Math.cos(rad); - - out[0] = ax * bw + ay * bz; - out[1] = ay * bw - ax * bz; - out[2] = az * bw + aw * bz; - out[3] = aw * bw - az * bz; - return out; -}; - -/** - * Calculates the W component of a quat from the X, Y, and Z components. - * Assumes that quaternion is 1 unit in length. - * Any existing W component will be ignored. - * - * @param {quat} out the receiving quaternion - * @param {quat} a quat to calculate W component of - * @returns {quat} out - */ -quat.calculateW = function (out, a) { - var x = a[0], y = a[1], z = a[2]; - - out[0] = x; - out[1] = y; - out[2] = z; - out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); - return out; -}; - -/** - * Calculates the dot product of two quat's - * - * @param {quat} a the first operand - * @param {quat} b the second operand - * @returns {Number} dot product of a and b - * @function - */ -quat.dot = vec4.dot; - -/** - * Performs a linear interpolation between two quat's - * - * @param {quat} out the receiving quaternion - * @param {quat} a the first operand - * @param {quat} b the second operand - * @param {Number} t interpolation amount between the two inputs - * @returns {quat} out - * @function - */ -quat.lerp = vec4.lerp; - -/** - * Performs a spherical linear interpolation between two quat - * - * @param {quat} out the receiving quaternion - * @param {quat} a the first operand - * @param {quat} b the second operand - * @param {Number} t interpolation amount between the two inputs - * @returns {quat} out - */ -quat.slerp = function (out, a, b, t) { - // benchmarks: - // http://jsperf.com/quaternion-slerp-implementations - - var ax = a[0], ay = a[1], az = a[2], aw = a[3], - bx = b[0], by = b[1], bz = b[2], bw = b[3]; - - var omega, cosom, sinom, scale0, scale1; - - // calc cosine - cosom = ax * bx + ay * by + az * bz + aw * bw; - // adjust signs (if necessary) - if ( cosom < 0.0 ) { - cosom = -cosom; - bx = - bx; - by = - by; - bz = - bz; - bw = - bw; - } - // calculate coefficients - if ( (1.0 - cosom) > 0.000001 ) { - // standard case (slerp) - omega = Math.acos(cosom); - sinom = Math.sin(omega); - scale0 = Math.sin((1.0 - t) * omega) / sinom; - scale1 = Math.sin(t * omega) / sinom; - } else { - // "from" and "to" quaternions are very close - // ... so we can do a linear interpolation - scale0 = 1.0 - t; - scale1 = t; - } - // calculate final values - out[0] = scale0 * ax + scale1 * bx; - out[1] = scale0 * ay + scale1 * by; - out[2] = scale0 * az + scale1 * bz; - out[3] = scale0 * aw + scale1 * bw; - - return out; -}; - -/** - * Calculates the inverse of a quat - * - * @param {quat} out the receiving quaternion - * @param {quat} a quat to calculate inverse of - * @returns {quat} out - */ -quat.invert = function(out, a) { - var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], - dot = a0*a0 + a1*a1 + a2*a2 + a3*a3, - invDot = dot ? 1.0/dot : 0; - - // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 - - out[0] = -a0*invDot; - out[1] = -a1*invDot; - out[2] = -a2*invDot; - out[3] = a3*invDot; - return out; -}; - -/** - * Calculates the conjugate of a quat - * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result. - * - * @param {quat} out the receiving quaternion - * @param {quat} a quat to calculate conjugate of - * @returns {quat} out - */ -quat.conjugate = function (out, a) { - out[0] = -a[0]; - out[1] = -a[1]; - out[2] = -a[2]; - out[3] = a[3]; - return out; -}; - -/** - * Calculates the length of a quat - * - * @param {quat} a vector to calculate length of - * @returns {Number} length of a - * @function - */ -quat.length = vec4.length; - -/** - * Alias for {@link quat.length} - * @function - */ -quat.len = quat.length; - -/** - * Calculates the squared length of a quat - * - * @param {quat} a vector to calculate squared length of - * @returns {Number} squared length of a - * @function - */ -quat.squaredLength = vec4.squaredLength; - -/** - * Alias for {@link quat.squaredLength} - * @function - */ -quat.sqrLen = quat.squaredLength; - -/** - * Normalize a quat - * - * @param {quat} out the receiving quaternion - * @param {quat} a quaternion to normalize - * @returns {quat} out - * @function - */ -quat.normalize = vec4.normalize; - -/** - * Creates a quaternion from the given 3x3 rotation matrix. - * - * NOTE: The resultant quaternion is not normalized, so you should be sure - * to renormalize the quaternion yourself where necessary. - * - * @param {quat} out the receiving quaternion - * @param {mat3} m rotation matrix - * @returns {quat} out - * @function - */ -quat.fromMat3 = function(out, m) { - // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes - // article "Quaternion Calculus and Fast Animation". - var fTrace = m[0] + m[4] + m[8]; - var fRoot; - - if ( fTrace > 0.0 ) { - // |w| > 1/2, may as well choose w > 1/2 - fRoot = Math.sqrt(fTrace + 1.0); // 2w - out[3] = 0.5 * fRoot; - fRoot = 0.5/fRoot; // 1/(4w) - out[0] = (m[5]-m[7])*fRoot; - out[1] = (m[6]-m[2])*fRoot; - out[2] = (m[1]-m[3])*fRoot; - } else { - // |w| <= 1/2 - var i = 0; - if ( m[4] > m[0] ) - i = 1; - if ( m[8] > m[i*3+i] ) - i = 2; - var j = (i+1)%3; - var k = (i+2)%3; - - fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); - out[i] = 0.5 * fRoot; - fRoot = 0.5 / fRoot; - out[3] = (m[j*3+k] - m[k*3+j]) * fRoot; - out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; - out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; - } - - return out; -}; - -/** - * Returns a string representation of a quatenion - * - * @param {quat} vec vector to represent as a string - * @returns {String} string representation of the vector - */ -quat.str = function (a) { - return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; -}; - -if(typeof(exports) !== 'undefined') { - exports.quat = quat; -} -; - - - - - - - - - - - - - - })(shim.exports); -})(this); - -/***/ }), -/* 1 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__mixin_extend__ = __webpack_require__(70); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__mixin_notifier__ = __webpack_require__(20); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__util__ = __webpack_require__(7); - - - - -/** - * Base class of all objects - * @constructor - * @alias clay.core.Base - * @mixes clay.core.mixin.notifier - */ -var Base = function () { - /** - * @type {number} - */ - this.__uid__ = __WEBPACK_IMPORTED_MODULE_2__util__["a" /* default */].genGUID(); -}; - -Base.__initializers__ = [ - function (opts) { - __WEBPACK_IMPORTED_MODULE_2__util__["a" /* default */].extend(this, opts); - } -]; - -__WEBPACK_IMPORTED_MODULE_2__util__["a" /* default */].extend(Base, __WEBPACK_IMPORTED_MODULE_0__mixin_extend__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_2__util__["a" /* default */].extend(Base.prototype, __WEBPACK_IMPORTED_MODULE_1__mixin_notifier__["a" /* default */]); - -/* harmony default export */ __webpack_exports__["a"] = (Base); - - -/***/ }), -/* 2 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__dep_glmatrix__); - -var vec3 = __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix___default.a.vec3; - -/** - * @constructor - * @alias clay.math.Vector3 - * @param {number} x - * @param {number} y - * @param {number} z - */ -var Vector3 = function(x, y, z) { - - x = x || 0; - y = y || 0; - z = z || 0; - - /** - * Storage of Vector3, read and write of x, y, z will change the values in array - * All methods also operate on the array instead of x, y, z components - * @name array - * @type {Float32Array} - * @memberOf clay.math.Vector3# - */ - this.array = vec3.fromValues(x, y, z); - - /** - * Dirty flag is used by the Node to determine - * if the matrix is updated to latest - * @name _dirty - * @type {boolean} - * @memberOf clay.math.Vector3# - */ - this._dirty = true; -}; - -Vector3.prototype = { - - constructor : Vector3, - - /** - * Add b to self - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ - add: function (b) { - vec3.add(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Set x, y and z components - * @param {number} x - * @param {number} y - * @param {number} z - * @return {clay.math.Vector3} - */ - set: function (x, y, z) { - this.array[0] = x; - this.array[1] = y; - this.array[2] = z; - this._dirty = true; - return this; - }, - - /** - * Set x, y and z components from array - * @param {Float32Array|number[]} arr - * @return {clay.math.Vector3} - */ - setArray: function (arr) { - this.array[0] = arr[0]; - this.array[1] = arr[1]; - this.array[2] = arr[2]; - - this._dirty = true; - return this; - }, - - /** - * Clone a new Vector3 - * @return {clay.math.Vector3} - */ - clone: function () { - return new Vector3(this.x, this.y, this.z); - }, - - /** - * Copy from b - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ - copy: function (b) { - vec3.copy(this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Cross product of self and b, written to a Vector3 out - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ - cross: function (a, b) { - vec3.cross(this.array, a.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Alias for distance - * @param {clay.math.Vector3} b - * @return {number} - */ - dist: function (b) { - return vec3.dist(this.array, b.array); - }, - - /** - * Distance between self and b - * @param {clay.math.Vector3} b - * @return {number} - */ - distance: function (b) { - return vec3.distance(this.array, b.array); - }, - - /** - * Alias for divide - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ - div: function (b) { - vec3.div(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Divide self by b - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ - divide: function (b) { - vec3.divide(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Dot product of self and b - * @param {clay.math.Vector3} b - * @return {number} - */ - dot: function (b) { - return vec3.dot(this.array, b.array); - }, - - /** - * Alias of length - * @return {number} - */ - len: function () { - return vec3.len(this.array); - }, - - /** - * Calculate the length - * @return {number} - */ - length: function () { - return vec3.length(this.array); - }, - /** - * Linear interpolation between a and b - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @param {number} t - * @return {clay.math.Vector3} - */ - lerp: function (a, b, t) { - vec3.lerp(this.array, a.array, b.array, t); - this._dirty = true; - return this; - }, - - /** - * Minimum of self and b - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ - min: function (b) { - vec3.min(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Maximum of self and b - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ - max: function (b) { - vec3.max(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Alias for multiply - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ - mul: function (b) { - vec3.mul(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Mutiply self and b - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ - multiply: function (b) { - vec3.multiply(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Negate self - * @return {clay.math.Vector3} - */ - negate: function () { - vec3.negate(this.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Normalize self - * @return {clay.math.Vector3} - */ - normalize: function () { - vec3.normalize(this.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Generate random x, y, z components with a given scale - * @param {number} scale - * @return {clay.math.Vector3} - */ - random: function (scale) { - vec3.random(this.array, scale); - this._dirty = true; - return this; - }, - - /** - * Scale self - * @param {number} scale - * @return {clay.math.Vector3} - */ - scale: function (s) { - vec3.scale(this.array, this.array, s); - this._dirty = true; - return this; - }, - - /** - * Scale b and add to self - * @param {clay.math.Vector3} b - * @param {number} scale - * @return {clay.math.Vector3} - */ - scaleAndAdd: function (b, s) { - vec3.scaleAndAdd(this.array, this.array, b.array, s); - this._dirty = true; - return this; - }, - - /** - * Alias for squaredDistance - * @param {clay.math.Vector3} b - * @return {number} - */ - sqrDist: function (b) { - return vec3.sqrDist(this.array, b.array); - }, - - /** - * Squared distance between self and b - * @param {clay.math.Vector3} b - * @return {number} - */ - squaredDistance: function (b) { - return vec3.squaredDistance(this.array, b.array); - }, - - /** - * Alias for squaredLength - * @return {number} - */ - sqrLen: function () { - return vec3.sqrLen(this.array); - }, - - /** - * Squared length of self - * @return {number} - */ - squaredLength: function () { - return vec3.squaredLength(this.array); - }, - - /** - * Alias for subtract - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ - sub: function (b) { - vec3.sub(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Subtract b from self - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ - subtract: function (b) { - vec3.subtract(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Transform self with a Matrix3 m - * @param {clay.math.Matrix3} m - * @return {clay.math.Vector3} - */ - transformMat3: function (m) { - vec3.transformMat3(this.array, this.array, m.array); - this._dirty = true; - return this; - }, - - /** - * Transform self with a Matrix4 m - * @param {clay.math.Matrix4} m - * @return {clay.math.Vector3} - */ - transformMat4: function (m) { - vec3.transformMat4(this.array, this.array, m.array); - this._dirty = true; - return this; - }, - /** - * Transform self with a Quaternion q - * @param {clay.math.Quaternion} q - * @return {clay.math.Vector3} - */ - transformQuat: function (q) { - vec3.transformQuat(this.array, this.array, q.array); - this._dirty = true; - return this; - }, - - /** - * Trasnform self into projection space with m - * @param {clay.math.Matrix4} m - * @return {clay.math.Vector3} - */ - applyProjection: function (m) { - var v = this.array; - m = m.array; - - // Perspective projection - if (m[15] === 0) { - var w = -1 / v[2]; - v[0] = m[0] * v[0] * w; - v[1] = m[5] * v[1] * w; - v[2] = (m[10] * v[2] + m[14]) * w; - } - else { - v[0] = m[0] * v[0] + m[12]; - v[1] = m[5] * v[1] + m[13]; - v[2] = m[10] * v[2] + m[14]; - } - this._dirty = true; - - return this; - }, - - eulerFromQuat: function(q, order) { - Vector3.eulerFromQuat(this, q, order); - }, - - eulerFromMat3: function (m, order) { - Vector3.eulerFromMat3(this, m, order); - }, - - toString: function() { - return '[' + Array.prototype.join.call(this.array, ',') + ']'; - }, - - toArray: function () { - return Array.prototype.slice.call(this.array); - } -}; - -var defineProperty = Object.defineProperty; -// Getter and Setter -if (defineProperty) { - - var proto = Vector3.prototype; - /** - * @name x - * @type {number} - * @memberOf clay.math.Vector3 - * @instance - */ - defineProperty(proto, 'x', { - get: function () { - return this.array[0]; - }, - set: function (value) { - this.array[0] = value; - this._dirty = true; - } - }); - - /** - * @name y - * @type {number} - * @memberOf clay.math.Vector3 - * @instance - */ - defineProperty(proto, 'y', { - get: function () { - return this.array[1]; - }, - set: function (value) { - this.array[1] = value; - this._dirty = true; - } - }); - - /** - * @name z - * @type {number} - * @memberOf clay.math.Vector3 - * @instance - */ - defineProperty(proto, 'z', { - get: function () { - return this.array[2]; - }, - set: function (value) { - this.array[2] = value; - this._dirty = true; - } - }); -} - - -// Supply methods that are not in place - -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ -Vector3.add = function(out, a, b) { - vec3.add(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector3} out - * @param {number} x - * @param {number} y - * @param {number} z - * @return {clay.math.Vector3} - */ -Vector3.set = function(out, x, y, z) { - vec3.set(out.array, x, y, z); - out._dirty = true; -}; - -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ -Vector3.copy = function(out, b) { - vec3.copy(out.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ -Vector3.cross = function(out, a, b) { - vec3.cross(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {number} - */ -Vector3.dist = function(a, b) { - return vec3.distance(a.array, b.array); -}; - -/** - * @function - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {number} - */ -Vector3.distance = Vector3.dist; - -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ -Vector3.div = function(out, a, b) { - vec3.divide(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @function - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ -Vector3.divide = Vector3.div; - -/** - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {number} - */ -Vector3.dot = function(a, b) { - return vec3.dot(a.array, b.array); -}; - -/** - * @param {clay.math.Vector3} a - * @return {number} - */ -Vector3.len = function(b) { - return vec3.length(b.array); -}; - -// Vector3.length = Vector3.len; - -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @param {number} t - * @return {clay.math.Vector3} - */ -Vector3.lerp = function(out, a, b, t) { - vec3.lerp(out.array, a.array, b.array, t); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ -Vector3.min = function(out, a, b) { - vec3.min(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ -Vector3.max = function(out, a, b) { - vec3.max(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ -Vector3.mul = function(out, a, b) { - vec3.multiply(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @function - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ -Vector3.multiply = Vector3.mul; -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @return {clay.math.Vector3} - */ -Vector3.negate = function(out, a) { - vec3.negate(out.array, a.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @return {clay.math.Vector3} - */ -Vector3.normalize = function(out, a) { - vec3.normalize(out.array, a.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector3} out - * @param {number} scale - * @return {clay.math.Vector3} - */ -Vector3.random = function(out, scale) { - vec3.random(out.array, scale); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {number} scale - * @return {clay.math.Vector3} - */ -Vector3.scale = function(out, a, scale) { - vec3.scale(out.array, a.array, scale); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @param {number} scale - * @return {clay.math.Vector3} - */ -Vector3.scaleAndAdd = function(out, a, b, scale) { - vec3.scaleAndAdd(out.array, a.array, b.array, scale); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {number} - */ -Vector3.sqrDist = function(a, b) { - return vec3.sqrDist(a.array, b.array); -}; -/** - * @function - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {number} - */ -Vector3.squaredDistance = Vector3.sqrDist; -/** - * @param {clay.math.Vector3} a - * @return {number} - */ -Vector3.sqrLen = function(a) { - return vec3.sqrLen(a.array); -}; -/** - * @function - * @param {clay.math.Vector3} a - * @return {number} - */ -Vector3.squaredLength = Vector3.sqrLen; - -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ -Vector3.sub = function(out, a, b) { - vec3.subtract(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @function - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {clay.math.Vector3} - */ -Vector3.subtract = Vector3.sub; - -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {Matrix3} m - * @return {clay.math.Vector3} - */ -Vector3.transformMat3 = function(out, a, m) { - vec3.transformMat3(out.array, a.array, m.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {clay.math.Matrix4} m - * @return {clay.math.Vector3} - */ -Vector3.transformMat4 = function(out, a, m) { - vec3.transformMat4(out.array, a.array, m.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector3} a - * @param {clay.math.Quaternion} q - * @return {clay.math.Vector3} - */ -Vector3.transformQuat = function(out, a, q) { - vec3.transformQuat(out.array, a.array, q.array); - out._dirty = true; - return out; -}; - -function clamp(val, min, max) { - return val < min ? min : (val > max ? max : val); -} -var atan2 = Math.atan2; -var asin = Math.asin; -var abs = Math.abs; -/** - * Convert quaternion to euler angle - * Quaternion must be normalized - * From three.js - */ -Vector3.eulerFromQuat = function (out, q, order) { - out._dirty = true; - q = q.array; - - var target = out.array; - var x = q[0], y = q[1], z = q[2], w = q[3]; - var x2 = x * x; - var y2 = y * y; - var z2 = z * z; - var w2 = w * w; - - var order = (order || 'XYZ').toUpperCase(); - - switch (order) { - case 'XYZ': - target[0] = atan2(2 * (x * w - y * z), (w2 - x2 - y2 + z2)); - target[1] = asin(clamp(2 * (x * z + y * w), - 1, 1)); - target[2] = atan2(2 * (z * w - x * y), (w2 + x2 - y2 - z2)); - break; - case 'YXZ': - target[0] = asin(clamp(2 * (x * w - y * z), - 1, 1)); - target[1] = atan2(2 * (x * z + y * w), (w2 - x2 - y2 + z2)); - target[2] = atan2(2 * (x * y + z * w), (w2 - x2 + y2 - z2)); - break; - case 'ZXY': - target[0] = asin(clamp(2 * (x * w + y * z), - 1, 1)); - target[1] = atan2(2 * (y * w - z * x), (w2 - x2 - y2 + z2)); - target[2] = atan2(2 * (z * w - x * y), (w2 - x2 + y2 - z2)); - break; - case 'ZYX': - target[0] = atan2(2 * (x * w + z * y), (w2 - x2 - y2 + z2)); - target[1] = asin(clamp(2 * (y * w - x * z), - 1, 1)); - target[2] = atan2(2 * (x * y + z * w), (w2 + x2 - y2 - z2)); - break; - case 'YZX': - target[0] = atan2(2 * (x * w - z * y), (w2 - x2 + y2 - z2)); - target[1] = atan2(2 * (y * w - x * z), (w2 + x2 - y2 - z2)); - target[2] = asin(clamp(2 * (x * y + z * w), - 1, 1)); - break; - case 'XZY': - target[0] = atan2(2 * (x * w + y * z), (w2 - x2 + y2 - z2)); - target[1] = atan2(2 * (x * z + y * w), (w2 + x2 - y2 - z2)); - target[2] = asin(clamp(2 * (z * w - x * y), - 1, 1)); - break; - default: - console.warn('Unkown order: ' + order); - } - return out; -}; - -/** - * Convert rotation matrix to euler angle - * from three.js - */ -Vector3.eulerFromMat3 = function (out, m, order) { - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - var te = m.array; - var m11 = te[0], m12 = te[3], m13 = te[6]; - var m21 = te[1], m22 = te[4], m23 = te[7]; - var m31 = te[2], m32 = te[5], m33 = te[8]; - var target = out.array; - - var order = (order || 'XYZ').toUpperCase(); - - switch (order) { - case 'XYZ': - target[1] = asin(clamp(m13, -1, 1)); - if (abs(m13) < 0.99999) { - target[0] = atan2(-m23, m33); - target[2] = atan2(-m12, m11); - } - else { - target[0] = atan2(m32, m22); - target[2] = 0; - } - break; - case 'YXZ': - target[0] = asin(-clamp(m23, -1, 1)); - if (abs(m23) < 0.99999) { - target[1] = atan2(m13, m33); - target[2] = atan2(m21, m22); - } - else { - target[1] = atan2(-m31, m11); - target[2] = 0; - } - break; - case 'ZXY': - target[0] = asin(clamp(m32, -1, 1)); - if (abs(m32) < 0.99999) { - target[1] = atan2(-m31, m33); - target[2] = atan2(-m12, m22); - } - else { - target[1] = 0; - target[2] = atan2(m21, m11); - } - break; - case 'ZYX': - target[1] = asin(-clamp(m31, -1, 1)); - if (abs(m31) < 0.99999) { - target[0] = atan2(m32, m33); - target[2] = atan2(m21, m11); - } - else { - target[0] = 0; - target[2] = atan2(-m12, m22); - } - break; - case 'YZX': - target[2] = asin(clamp(m21, -1, 1)); - if (abs(m21) < 0.99999) { - target[0] = atan2(-m23, m22); - target[1] = atan2(-m31, m11); - } - else { - target[0] = 0; - target[1] = atan2(m13, m33); - } - break; - case 'XZY': - target[2] = asin(-clamp(m12, -1, 1)); - if (abs(m12) < 0.99999) { - target[0] = atan2(m32, m22); - target[1] = atan2(m13, m11); - } - else { - target[0] = atan2(-m23, m33); - target[1] = 0; - } - break; - default: - console.warn('Unkown order: ' + order); - } - out._dirty = true; - - return out; -}; - -// TODO return new. -/** - * @type {clay.math.Vector3} - */ -Vector3.POSITIVE_X = new Vector3(1, 0, 0); -/** - * @type {clay.math.Vector3} - */ -Vector3.NEGATIVE_X = new Vector3(-1, 0, 0); -/** - * @type {clay.math.Vector3} - */ -Vector3.POSITIVE_Y = new Vector3(0, 1, 0); -/** - * @type {clay.math.Vector3} - */ -Vector3.NEGATIVE_Y = new Vector3(0, -1, 0); -/** - * @type {clay.math.Vector3} - */ -Vector3.POSITIVE_Z = new Vector3(0, 0, 1); -/** - * @type {clay.math.Vector3} - */ -Vector3.NEGATIVE_Z = new Vector3(0, 0, -1); -/** - * @type {clay.math.Vector3} - */ -Vector3.UP = new Vector3(0, 1, 0); -/** - * @type {clay.math.Vector3} - */ -Vector3.ZERO = new Vector3(0, 0, 0); - -/* harmony default export */ __webpack_exports__["a"] = (Vector3); - - -/***/ }), -/* 3 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_glenum__ = __webpack_require__(6); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__core_Cache__ = __webpack_require__(28); -/** - * Base class for all textures like compressed texture, texture2d, texturecube - * TODO mapping - */ - - - - -/** - * @constructor - * @alias clay.Texture - * @extends clay.core.Base - */ -var Texture = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend( -/** @lends clay.Texture# */ -{ - /** - * Texture width, readonly when the texture source is image - * @type {number} - */ - width: 512, - /** - * Texture height, readonly when the texture source is image - * @type {number} - */ - height: 512, - /** - * Texel data type. - * Possible values: - * + {@link clay.Texture.UNSIGNED_BYTE} - * + {@link clay.Texture.HALF_FLOAT} - * + {@link clay.Texture.FLOAT} - * + {@link clay.Texture.UNSIGNED_INT_24_8_WEBGL} - * + {@link clay.Texture.UNSIGNED_INT} - * @type {number} - */ - type: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].UNSIGNED_BYTE, - /** - * Format of texel data - * Possible values: - * + {@link clay.Texture.RGBA} - * + {@link clay.Texture.DEPTH_COMPONENT} - * + {@link clay.Texture.DEPTH_STENCIL} - * @type {number} - */ - format: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].RGBA, - /** - * Texture wrap. Default to be REPEAT. - * Possible values: - * + {@link clay.Texture.CLAMP_TO_EDGE} - * + {@link clay.Texture.REPEAT} - * + {@link clay.Texture.MIRRORED_REPEAT} - * @type {number} - */ - wrapS: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].REPEAT, - /** - * Texture wrap. Default to be REPEAT. - * Possible values: - * + {@link clay.Texture.CLAMP_TO_EDGE} - * + {@link clay.Texture.REPEAT} - * + {@link clay.Texture.MIRRORED_REPEAT} - * @type {number} - */ - wrapT: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].REPEAT, - /** - * Possible values: - * + {@link clay.Texture.NEAREST} - * + {@link clay.Texture.LINEAR} - * + {@link clay.Texture.NEAREST_MIPMAP_NEAREST} - * + {@link clay.Texture.LINEAR_MIPMAP_NEAREST} - * + {@link clay.Texture.NEAREST_MIPMAP_LINEAR} - * + {@link clay.Texture.LINEAR_MIPMAP_LINEAR} - * @type {number} - */ - minFilter: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINEAR_MIPMAP_LINEAR, - /** - * Possible values: - * + {@link clay.Texture.NEAREST} - * + {@link clay.Texture.LINEAR} - * @type {number} - */ - magFilter: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINEAR, - /** - * If enable mimap. - * @type {boolean} - */ - useMipmap: true, - - /** - * Anisotropic filtering, enabled if value is larger than 1 - * @see https://developer.mozilla.org/en-US/docs/Web/API/EXT_texture_filter_anisotropic - * @type {number} - */ - anisotropic: 1, - // pixelStorei parameters, not available when texture is used as render target - // http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml - /** - * If flip in y axis for given image source - * @type {boolean} - * @default true - */ - flipY: true, - - /** - * A flag to indicate if texture source is sRGB - */ - sRGB: true, - /** - * @type {number} - * @default 4 - */ - unpackAlignment: 4, - /** - * @type {boolean} - * @default false - */ - premultiplyAlpha: false, - - /** - * Dynamic option for texture like video - * @type {boolean} - */ - dynamic: false, - - NPOT: false -}, function () { - this._cache = new __WEBPACK_IMPORTED_MODULE_2__core_Cache__["a" /* default */](); -}, -/** @lends clay.Texture.prototype */ -{ - - getWebGLTexture: function (renderer) { - var _gl = renderer.gl; - var cache = this._cache; - cache.use(renderer.__uid__); - - if (cache.miss('webgl_texture')) { - // In a new gl context, create new texture and set dirty true - cache.put('webgl_texture', _gl.createTexture()); - } - if (this.dynamic) { - this.update(renderer); - } - else if (cache.isDirty()) { - this.update(renderer); - cache.fresh(); - } - - return cache.get('webgl_texture'); - }, - - bind: function () {}, - unbind: function () {}, - - /** - * Mark texture is dirty and update in the next frame - */ - dirty: function () { - if (this._cache) { - this._cache.dirtyAll(); - } - }, - - update: function (renderer) {}, - - // Update the common parameters of texture - updateCommon: function (renderer) { - var _gl = renderer.gl; - _gl.pixelStorei(_gl.UNPACK_FLIP_Y_WEBGL, this.flipY); - _gl.pixelStorei(_gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, this.premultiplyAlpha); - _gl.pixelStorei(_gl.UNPACK_ALIGNMENT, this.unpackAlignment); - - // Use of none-power of two texture - // http://www.khronos.org/webgl/wiki/WebGL_and_OpenGL_Differences - if (this.format === __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].DEPTH_COMPONENT) { - this.useMipmap = false; - } - - var sRGBExt = renderer.getGLExtension('EXT_sRGB'); - // Fallback - if (this.format === Texture.SRGB && !sRGBExt) { - this.format = Texture.RGB; - } - if (this.format === Texture.SRGB_ALPHA && !sRGBExt) { - this.format = Texture.RGBA; - } - - this.NPOT = !this.isPowerOfTwo(); - }, - - getAvailableWrapS: function () { - if (this.NPOT) { - return __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].CLAMP_TO_EDGE; - } - return this.wrapS; - }, - getAvailableWrapT: function () { - if (this.NPOT) { - return __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].CLAMP_TO_EDGE; - } - return this.wrapT; - }, - getAvailableMinFilter: function () { - var minFilter = this.minFilter; - if (this.NPOT || !this.useMipmap) { - if (minFilter == __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].NEAREST_MIPMAP_NEAREST || - minFilter == __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].NEAREST_MIPMAP_LINEAR - ) { - return __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].NEAREST; - } - else if (minFilter == __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINEAR_MIPMAP_LINEAR || - minFilter == __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINEAR_MIPMAP_NEAREST - ) { - return __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINEAR; - } - else { - return minFilter; - } - } - else { - return minFilter; - } - }, - getAvailableMagFilter: function () { - return this.magFilter; - }, - - nextHighestPowerOfTwo: function (x) { - --x; - for (var i = 1; i < 32; i <<= 1) { - x = x | x >> i; - } - return x + 1; - }, - /** - * @param {clay.Renderer} renderer - */ - dispose: function (renderer) { - - var cache = this._cache; - - cache.use(renderer.__uid__); - - var webglTexture = cache.get('webgl_texture'); - if (webglTexture){ - renderer.gl.deleteTexture(webglTexture); - } - cache.deleteContext(renderer.__uid__); - - }, - /** - * Test if image of texture is valid and loaded. - * @return {boolean} - */ - isRenderable: function () {}, - - /** - * Test if texture size is power of two - * @return {boolean} - */ - isPowerOfTwo: function () {} -}); - -Object.defineProperty(Texture.prototype, 'width', { - get: function () { - return this._width; - }, - set: function (value) { - this._width = value; - } -}); -Object.defineProperty(Texture.prototype, 'height', { - get: function () { - return this._height; - }, - set: function (value) { - this._height = value; - } -}); - -/* DataType */ - -/** - * @type {number} - */ -Texture.BYTE = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].BYTE; -/** - * @type {number} - */ -Texture.UNSIGNED_BYTE = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].UNSIGNED_BYTE; -/** - * @type {number} - */ -Texture.SHORT = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].SHORT; -/** - * @type {number} - */ -Texture.UNSIGNED_SHORT = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].UNSIGNED_SHORT; -/** - * @type {number} - */ -Texture.INT = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].INT; -/** - * @type {number} - */ -Texture.UNSIGNED_INT = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].UNSIGNED_INT; -/** - * @type {number} - */ -Texture.FLOAT = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].FLOAT; -/** - * @type {number} - */ -Texture.HALF_FLOAT = 0x8D61; - -/** - * UNSIGNED_INT_24_8_WEBGL for WEBGL_depth_texture extension - * @type {number} - */ -Texture.UNSIGNED_INT_24_8_WEBGL = 34042; - -/* PixelFormat */ -/** - * @type {number} - */ -Texture.DEPTH_COMPONENT = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].DEPTH_COMPONENT; -/** - * @type {number} - */ -Texture.DEPTH_STENCIL = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].DEPTH_STENCIL; -/** - * @type {number} - */ -Texture.ALPHA = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].ALPHA; -/** - * @type {number} - */ -Texture.RGB = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].RGB; -/** - * @type {number} - */ -Texture.RGBA = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].RGBA; -/** - * @type {number} - */ -Texture.LUMINANCE = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LUMINANCE; -/** - * @type {number} - */ -Texture.LUMINANCE_ALPHA = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LUMINANCE_ALPHA; - -/** - * @see https://www.khronos.org/registry/webgl/extensions/EXT_sRGB/ - * @type {number} - */ -Texture.SRGB = 0x8C40; -/** - * @see https://www.khronos.org/registry/webgl/extensions/EXT_sRGB/ - * @type {number} - */ -Texture.SRGB_ALPHA = 0x8C42; - -/* Compressed Texture */ -Texture.COMPRESSED_RGB_S3TC_DXT1_EXT = 0x83F0; -Texture.COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1; -Texture.COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2; -Texture.COMPRESSED_RGBA_S3TC_DXT5_EXT = 0x83F3; - -/* TextureMagFilter */ -/** - * @type {number} - */ -Texture.NEAREST = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].NEAREST; -/** - * @type {number} - */ -Texture.LINEAR = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINEAR; - -/* TextureMinFilter */ -/** - * @type {number} - */ -Texture.NEAREST_MIPMAP_NEAREST = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].NEAREST_MIPMAP_NEAREST; -/** - * @type {number} - */ -Texture.LINEAR_MIPMAP_NEAREST = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINEAR_MIPMAP_NEAREST; -/** - * @type {number} - */ -Texture.NEAREST_MIPMAP_LINEAR = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].NEAREST_MIPMAP_LINEAR; -/** - * @type {number} - */ -Texture.LINEAR_MIPMAP_LINEAR = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINEAR_MIPMAP_LINEAR; - -/* TextureWrapMode */ -/** - * @type {number} - */ -Texture.REPEAT = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].REPEAT; -/** - * @type {number} - */ -Texture.CLAMP_TO_EDGE = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].CLAMP_TO_EDGE; -/** - * @type {number} - */ -Texture.MIRRORED_REPEAT = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].MIRRORED_REPEAT; - - -/* harmony default export */ __webpack_exports__["a"] = (Texture); - - -/***/ }), -/* 4 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_util__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_vendor__ = __webpack_require__(12); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2__dep_glmatrix__); -/** - * Mainly do the parse and compile of shader string - * Support shader code chunk import and export - * Support shader semantics - * http://www.nvidia.com/object/using_sas.html - * https://github.com/KhronosGroup/collada2json/issues/45 - * - * TODO: Use etpl or other string template engine - */ - - - -var mat2 = __WEBPACK_IMPORTED_MODULE_2__dep_glmatrix___default.a.mat2; -var mat3 = __WEBPACK_IMPORTED_MODULE_2__dep_glmatrix___default.a.mat3; -var mat4 = __WEBPACK_IMPORTED_MODULE_2__dep_glmatrix___default.a.mat4; - -var uniformRegex = /uniform\s+(bool|float|int|vec2|vec3|vec4|ivec2|ivec3|ivec4|mat2|mat3|mat4|sampler2D|samplerCube)\s+([\w\,]+)?(\[.*?\])?\s*(:\s*([\S\s]+?))?;/g; -var attributeRegex = /attribute\s+(float|int|vec2|vec3|vec4)\s+(\w*)\s*(:\s*(\w+))?;/g; -var defineRegex = /#define\s+(\w+)?(\s+[\w-.]+)?\s*;?\s*\n/g; - -var uniformTypeMap = { - 'bool': '1i', - 'int': '1i', - 'sampler2D': 't', - 'samplerCube': 't', - 'float': '1f', - 'vec2': '2f', - 'vec3': '3f', - 'vec4': '4f', - 'ivec2': '2i', - 'ivec3': '3i', - 'ivec4': '4i', - 'mat2': 'm2', - 'mat3': 'm3', - 'mat4': 'm4' -}; - -var uniformValueConstructor = { - 'bool': function () {return true;}, - 'int': function () {return 0;}, - 'float': function () {return 0;}, - 'sampler2D': function () {return null;}, - 'samplerCube': function () {return null;}, - - 'vec2': function () {return [0, 0];}, - 'vec3': function () {return [0, 0, 0];}, - 'vec4': function () {return [0, 0, 0, 0];}, - - 'ivec2': function () {return [0, 0];}, - 'ivec3': function () {return [0, 0, 0];}, - 'ivec4': function () {return [0, 0, 0, 0];}, - - 'mat2': function () {return mat2.create();}, - 'mat3': function () {return mat3.create();}, - 'mat4': function () {return mat4.create();}, - - 'array': function () {return [];} -}; - -var attributeSemantics = [ - 'POSITION', - 'NORMAL', - 'BINORMAL', - 'TANGENT', - 'TEXCOORD', - 'TEXCOORD_0', - 'TEXCOORD_1', - 'COLOR', - // Skinning - // https://github.com/KhronosGroup/glTF/blob/master/specification/README.md#semantics - 'JOINT', - 'WEIGHT' -]; -var uniformSemantics = [ - 'SKIN_MATRIX', - // Information about viewport - 'VIEWPORT_SIZE', - 'VIEWPORT', - 'DEVICEPIXELRATIO', - // Window size for window relative coordinate - // https://www.opengl.org/sdk/docs/man/html/gl_FragCoord.xhtml - 'WINDOW_SIZE', - // Infomation about camera - 'NEAR', - 'FAR', - // Time - 'TIME' -]; -var matrixSemantics = [ - 'WORLD', - 'VIEW', - 'PROJECTION', - 'WORLDVIEW', - 'VIEWPROJECTION', - 'WORLDVIEWPROJECTION', - 'WORLDINVERSE', - 'VIEWINVERSE', - 'PROJECTIONINVERSE', - 'WORLDVIEWINVERSE', - 'VIEWPROJECTIONINVERSE', - 'WORLDVIEWPROJECTIONINVERSE', - 'WORLDTRANSPOSE', - 'VIEWTRANSPOSE', - 'PROJECTIONTRANSPOSE', - 'WORLDVIEWTRANSPOSE', - 'VIEWPROJECTIONTRANSPOSE', - 'WORLDVIEWPROJECTIONTRANSPOSE', - 'WORLDINVERSETRANSPOSE', - 'VIEWINVERSETRANSPOSE', - 'PROJECTIONINVERSETRANSPOSE', - 'WORLDVIEWINVERSETRANSPOSE', - 'VIEWPROJECTIONINVERSETRANSPOSE', - 'WORLDVIEWPROJECTIONINVERSETRANSPOSE' -]; - - -var shaderIDCache = {}; -var shaderCodeCache = {}; - -function getShaderID(vertex, fragment) { - var key = 'vertex:' + vertex + 'fragment:' + fragment; - if (shaderIDCache[key]) { - return shaderIDCache[key]; - } - var id = __WEBPACK_IMPORTED_MODULE_0__core_util__["a" /* default */].genGUID(); - shaderIDCache[key] = id; - - shaderCodeCache[id] = { - vertex: vertex, - fragment: fragment - }; - - return id; -} - -/** - * @constructor - * @extends clay.core.Base - * @alias clay.Shader - * @example - * // Create a phong shader - * var shader = new clay.Shader( - * clay.Shader.source('clay.standard.vertex'), - * clay.Shader.source('clay.standard.fragment') - * ); - */ -function Shader(vertex, fragment) { - // First argument can be { vertex, fragment } - if (typeof vertex === 'object') { - fragment = vertex.fragment; - vertex = vertex.vertex; - } - - this._shaderID = getShaderID(vertex, fragment); - - this._vertexCode = Shader.parseImport(vertex); - this._fragmentCode = Shader.parseImport(fragment); - - /** - * @readOnly - */ - this.attributeSemantics = {}; - /** - * @readOnly - */ - this.matrixSemantics = {}; - /** - * @readOnly - */ - this.uniformSemantics = {}; - /** - * @readOnly - */ - this.matrixSemanticKeys = []; - /** - * @readOnly - */ - this.uniformTemplates = {}; - /** - * @readOnly - */ - this.attributes = {}; - /** - * @readOnly - */ - this.textures = {}; - /** - * @readOnly - */ - this.vertexDefines = {}; - /** - * @readOnly - */ - this.fragmentDefines = {}; - - this._parseAttributes(); - this._parseUniforms(); - this._parseDefines(); -} - -Shader.prototype = { - - constructor: Shader, - - // Create a new uniform instance for material - createUniforms: function () { - var uniforms = {}; - - for (var symbol in this.uniformTemplates){ - var uniformTpl = this.uniformTemplates[symbol]; - uniforms[symbol] = { - type: uniformTpl.type, - value: uniformTpl.value() - }; - } - - return uniforms; - }, - - _parseImport: function () { - this._vertexCode = Shader.parseImport(this.vertex); - this._fragmentCode = Shader.parseImport(this.fragment); - }, - - _parseUniforms: function () { - var uniforms = {}; - var self = this; - var shaderType = 'vertex'; - this._uniformList = []; - - this._vertexCode = this._vertexCode.replace(uniformRegex, _uniformParser); - shaderType = 'fragment'; - this._fragmentCode = this._fragmentCode.replace(uniformRegex, _uniformParser); - - self.matrixSemanticKeys = Object.keys(this.matrixSemantics); - - function _uniformParser(str, type, symbol, isArray, semanticWrapper, semantic) { - if (type && symbol) { - var uniformType = uniformTypeMap[type]; - var isConfigurable = true; - var defaultValueFunc; - if (uniformType) { - self._uniformList.push(symbol); - if (type === 'sampler2D' || type === 'samplerCube') { - // Texture is default disabled - self.textures[symbol] = { - shaderType: shaderType, - type: type - }; - } - if (isArray) { - uniformType += 'v'; - } - if (semantic) { - // This case is only for SKIN_MATRIX - // TODO - if (attributeSemantics.indexOf(semantic) >= 0) { - self.attributeSemantics[semantic] = { - symbol: symbol, - type: uniformType - }; - isConfigurable = false; - } - else if (matrixSemantics.indexOf(semantic) >= 0) { - var isTranspose = false; - var semanticNoTranspose = semantic; - if (semantic.match(/TRANSPOSE$/)) { - isTranspose = true; - semanticNoTranspose = semantic.slice(0, -9); - } - self.matrixSemantics[semantic] = { - symbol: symbol, - type: uniformType, - isTranspose: isTranspose, - semanticNoTranspose: semanticNoTranspose - }; - isConfigurable = false; - } - else if (uniformSemantics.indexOf(semantic) >= 0) { - self.uniformSemantics[semantic] = { - symbol: symbol, - type: uniformType - }; - isConfigurable = false; - } - else { - // The uniform is not configurable, which means it will not appear - // in the material uniform properties - if (semantic === 'unconfigurable') { - isConfigurable = false; - } - else { - // Uniform have a defalut value, like - // uniform vec3 color: [1, 1, 1]; - defaultValueFunc = self._parseDefaultValue(type, semantic); - if (!defaultValueFunc) { - throw new Error('Unkown semantic "' + semantic + '"'); - } - else { - semantic = ''; - } - } - } - } - - if (isConfigurable) { - uniforms[symbol] = { - type: uniformType, - value: isArray ? uniformValueConstructor['array'] : (defaultValueFunc || uniformValueConstructor[type]), - semantic: semantic || null - }; - } - } - return ['uniform', type, symbol, isArray].join(' ') + ';\n'; - } - } - - this.uniformTemplates = uniforms; - }, - - _parseDefaultValue: function (type, str) { - var arrayRegex = /\[\s*(.*)\s*\]/; - if (type === 'vec2' || type === 'vec3' || type === 'vec4') { - var arrayStr = arrayRegex.exec(str)[1]; - if (arrayStr) { - var arr = arrayStr.split(/\s*,\s*/); - return function () { - return new __WEBPACK_IMPORTED_MODULE_1__core_vendor__["a" /* default */].Float32Array(arr); - }; - } - else { - // Invalid value - return; - } - } - else if (type === 'bool') { - return function () { - return str.toLowerCase() === 'true' ? true : false; - }; - } - else if (type === 'float') { - return function () { - return parseFloat(str); - }; - } - else if (type === 'int') { - return function () { - return parseInt(str); - }; - } - }, - - _parseAttributes: function () { - var attributes = {}; - var self = this; - this._vertexCode = this._vertexCode.replace(attributeRegex, _attributeParser); - - function _attributeParser(str, type, symbol, semanticWrapper, semantic) { - if (type && symbol) { - var size = 1; - switch (type) { - case 'vec4': - size = 4; - break; - case 'vec3': - size = 3; - break; - case 'vec2': - size = 2; - break; - case 'float': - size = 1; - break; - } - - attributes[symbol] = { - // Can only be float - type: 'float', - size: size, - semantic: semantic || null - }; - - if (semantic) { - if (attributeSemantics.indexOf(semantic) < 0) { - throw new Error('Unkown semantic "' + semantic + '"'); - } - else { - self.attributeSemantics[semantic] = { - symbol: symbol, - type: type - }; - } - } - } - - return ['attribute', type, symbol].join(' ') + ';\n'; - } - - this.attributes = attributes; - }, - - _parseDefines: function () { - var self = this; - var shaderType = 'vertex'; - this._vertexCode = this._vertexCode.replace(defineRegex, _defineParser); - shaderType = 'fragment'; - this._fragmentCode = this._fragmentCode.replace(defineRegex, _defineParser); - - function _defineParser(str, symbol, value) { - var defines = shaderType === 'vertex' ? self.vertexDefines : self.fragmentDefines; - if (!defines[symbol]) { // Haven't been defined by user - if (value == 'false') { - defines[symbol] = false; - } - else if (value == 'true') { - defines[symbol] = true; - } - else { - defines[symbol] = value - // If can parse to float - ? (isNaN(parseFloat(value)) ? value.trim() : parseFloat(value)) - : null; - } - } - return ''; - } - }, - - /** - * Clone a new shader - * @return {clay.Shader} - */ - clone: function () { - var code = shaderCodeCache[this._shaderID]; - var shader = new Shader(code.vertex, code.fragment); - return shader; - } -}; - -if (Object.defineProperty) { - Object.defineProperty(Shader.prototype, 'shaderID', { - get: function () { - return this._shaderID; - } - }); - Object.defineProperty(Shader.prototype, 'vertex', { - get: function () { - return this._vertexCode; - } - }); - Object.defineProperty(Shader.prototype, 'fragment', { - get: function () { - return this._fragmentCode; - } - }); - Object.defineProperty(Shader.prototype, 'uniforms', { - get: function () { - return this._uniformList; - } - }); -} - -var importRegex = /(@import)\s*([0-9a-zA-Z_\-\.]*)/g; -Shader.parseImport = function (shaderStr) { - shaderStr = shaderStr.replace(importRegex, function (str, importSymbol, importName) { - var str = Shader.source(importName); - if (str) { - // Recursively parse - return Shader.parseImport(str); - } - else { - console.error('Shader chunk "' + importName + '" not existed in library'); - return ''; - } - }); - return shaderStr; -}; - -var exportRegex = /(@export)\s*([0-9a-zA-Z_\-\.]*)\s*\n([\s\S]*?)@end/g; - -/** - * Import shader source - * @param {string} shaderStr - * @memberOf clay.Shader - */ -Shader['import'] = function (shaderStr) { - shaderStr.replace(exportRegex, function (str, exportSymbol, exportName, code) { - var code = code.replace(/(^[\s\t\xa0\u3000]+)|([\u3000\xa0\s\t]+\x24)/g, ''); - if (code) { - var parts = exportName.split('.'); - var obj = Shader.codes; - var i = 0; - var key; - while (i < parts.length - 1) { - key = parts[i++]; - if (!obj[key]) { - obj[key] = {}; - } - obj = obj[key]; - } - key = parts[i]; - obj[key] = code; - } - return code; - }); -}; - -/** - * Library to store all the loaded shader codes - * @type {Object} - * @readOnly - * @memberOf clay.Shader - */ -Shader.codes = {}; - -/** - * Get shader source - * @param {string} name - * @return {string} - */ -Shader.source = function (name) { - var parts = name.split('.'); - var obj = Shader.codes; - var i = 0; - while (obj && i < parts.length) { - var key = parts[i++]; - obj = obj[key]; - } - if (typeof obj !== 'string') { - // FIXME Use default instead - console.error('Shader "' + name + '" not existed in library'); - return ''; - } - return obj; -}; - -/* harmony default export */ __webpack_exports__["a"] = (Shader); - - -/***/ }), -/* 5 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_glenum__ = __webpack_require__(6); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__math_util__ = __webpack_require__(47); - - - -var isPowerOfTwo = __WEBPACK_IMPORTED_MODULE_2__math_util__["a" /* default */].isPowerOfTwo; - -/** - * @constructor clay.Texture2D - * @extends clay.Texture - * - * @example - * ... - * var mat = new clay.Material({ - * shader: clay.shader.library.get('clay.phong', 'diffuseMap') - * }); - * var diffuseMap = new clay.Texture2D(); - * diffuseMap.load('assets/textures/diffuse.jpg'); - * mat.set('diffuseMap', diffuseMap); - * ... - * diffuseMap.success(function () { - * // Wait for the diffuse texture loaded - * animation.on('frame', function (frameTime) { - * renderer.render(scene, camera); - * }); - * }); - */ -var Texture2D = __WEBPACK_IMPORTED_MODULE_0__Texture__["a" /* default */].extend(function () { - return /** @lends clay.Texture2D# */ { - /** - * @type {?HTMLImageElement|HTMLCanvasElemnet} - */ - image: null, - /** - * Pixels data. Will be ignored if image is set. - * @type {?Uint8Array|Float32Array} - */ - pixels: null, - /** - * @type {Array.} - * @example - * [{ - * image: mipmap0, - * pixels: null - * }, { - * image: mipmap1, - * pixels: null - * }, ....] - */ - mipmaps: [] - }; -}, { - update: function (renderer) { - - var _gl = renderer.gl; - _gl.bindTexture(_gl.TEXTURE_2D, this._cache.get('webgl_texture')); - - this.updateCommon(renderer); - - var glFormat = this.format; - var glType = this.type; - - _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, this.getAvailableWrapS()); - _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, this.getAvailableWrapT()); - - _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, this.getAvailableMagFilter()); - _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, this.getAvailableMinFilter()); - - var anisotropicExt = renderer.getGLExtension('EXT_texture_filter_anisotropic'); - if (anisotropicExt && this.anisotropic > 1) { - _gl.texParameterf(_gl.TEXTURE_2D, anisotropicExt.TEXTURE_MAX_ANISOTROPY_EXT, this.anisotropic); - } - - // Fallback to float type if browser don't have half float extension - if (glType === 36193) { - var halfFloatExt = renderer.getGLExtension('OES_texture_half_float'); - if (!halfFloatExt) { - glType = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].FLOAT; - } - } - - if (this.mipmaps.length) { - var width = this.width; - var height = this.height; - for (var i = 0; i < this.mipmaps.length; i++) { - var mipmap = this.mipmaps[i]; - this._updateTextureData(_gl, mipmap, i, width, height, glFormat, glType); - width /= 2; - height /= 2; - } - } - else { - this._updateTextureData(_gl, this, 0, this.width, this.height, glFormat, glType); - - if (this.useMipmap && !this.NPOT) { - _gl.generateMipmap(_gl.TEXTURE_2D); - } - } - - _gl.bindTexture(_gl.TEXTURE_2D, null); - }, - - _updateTextureData: function (_gl, data, level, width, height, glFormat, glType) { - if (data.image) { - _gl.texImage2D(_gl.TEXTURE_2D, level, glFormat, glFormat, glType, data.image); - } - else { - // Can be used as a blank texture when writing render to texture(RTT) - if ( - glFormat <= __WEBPACK_IMPORTED_MODULE_0__Texture__["a" /* default */].COMPRESSED_RGBA_S3TC_DXT5_EXT - && glFormat >= __WEBPACK_IMPORTED_MODULE_0__Texture__["a" /* default */].COMPRESSED_RGB_S3TC_DXT1_EXT - ) { - _gl.compressedTexImage2D(_gl.TEXTURE_2D, level, glFormat, width, height, 0, data.pixels); - } - else { - // Is a render target if pixels is null - _gl.texImage2D(_gl.TEXTURE_2D, level, glFormat, width, height, 0, glFormat, glType, data.pixels); - } - } - }, - - /** - * @param {clay.Renderer} renderer - * @memberOf clay.Texture2D.prototype - */ - generateMipmap: function (renderer) { - var _gl = renderer.gl; - if (this.useMipmap && !this.NPOT) { - _gl.bindTexture(_gl.TEXTURE_2D, this._cache.get('webgl_texture')); - _gl.generateMipmap(_gl.TEXTURE_2D); - } - }, - - isPowerOfTwo: function () { - var width; - var height; - if (this.image) { - width = this.image.width; - height = this.image.height; - } - else { - width = this.width; - height = this.height; - } - return isPowerOfTwo(width) && isPowerOfTwo(height); - }, - - isRenderable: function () { - if (this.image) { - return this.image.nodeName === 'CANVAS' - || this.image.nodeName === 'VIDEO' - || this.image.complete; - } - else { - return !!(this.width && this.height); - } - }, - - bind: function (renderer) { - renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, this.getWebGLTexture(renderer)); - }, - - unbind: function (renderer) { - renderer.gl.bindTexture(renderer.gl.TEXTURE_2D, null); - }, - - load: function (src, crossOrigin) { - var image = new Image(); - if (crossOrigin) { - image.crossOrigin = crossOrigin; - } - var self = this; - image.onload = function () { - self.dirty(); - self.trigger('success', self); - image.onload = null; - }; - image.onerror = function () { - self.trigger('error', self); - image.onerror = null; - }; - - image.src = src; - this.image = image; - - return this; - } -}); - -Object.defineProperty(Texture2D.prototype, 'width', { - get: function () { - if (this.image) { - return this.image.width; - } - return this._width; - }, - set: function (value) { - if (this.image) { - console.warn('Texture from image can\'t set width'); - } - else { - if (this._width !== value) { - this.dirty(); - } - this._width = value; - } - } -}); -Object.defineProperty(Texture2D.prototype, 'height', { - get: function () { - if (this.image) { - return this.image.height; - } - return this._height; - }, - set: function (value) { - if (this.image) { - console.warn('Texture from image can\'t set height'); - } - else { - if (this._height !== value) { - this.dirty(); - } - this._height = value; - } - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (Texture2D); - - -/***/ }), -/* 6 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/** - * @namespace clay.core.glenum - * @see http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14 - */ -/* harmony default export */ __webpack_exports__["a"] = ({ - /* ClearBufferMask */ - DEPTH_BUFFER_BIT : 0x00000100, - STENCIL_BUFFER_BIT : 0x00000400, - COLOR_BUFFER_BIT : 0x00004000, - - /* BeginMode */ - POINTS : 0x0000, - LINES : 0x0001, - LINE_LOOP : 0x0002, - LINE_STRIP : 0x0003, - TRIANGLES : 0x0004, - TRIANGLE_STRIP : 0x0005, - TRIANGLE_FAN : 0x0006, - - /* AlphaFunction (not supported in ES20) */ - /* NEVER */ - /* LESS */ - /* EQUAL */ - /* LEQUAL */ - /* GREATER */ - /* NOTEQUAL */ - /* GEQUAL */ - /* ALWAYS */ - - /* BlendingFactorDest */ - ZERO : 0, - ONE : 1, - SRC_COLOR : 0x0300, - ONE_MINUS_SRC_COLOR : 0x0301, - SRC_ALPHA : 0x0302, - ONE_MINUS_SRC_ALPHA : 0x0303, - DST_ALPHA : 0x0304, - ONE_MINUS_DST_ALPHA : 0x0305, - - /* BlendingFactorSrc */ - /* ZERO */ - /* ONE */ - DST_COLOR : 0x0306, - ONE_MINUS_DST_COLOR : 0x0307, - SRC_ALPHA_SATURATE : 0x0308, - /* SRC_ALPHA */ - /* ONE_MINUS_SRC_ALPHA */ - /* DST_ALPHA */ - /* ONE_MINUS_DST_ALPHA */ - - /* BlendEquationSeparate */ - FUNC_ADD : 0x8006, - BLEND_EQUATION : 0x8009, - BLEND_EQUATION_RGB : 0x8009, /* same as BLEND_EQUATION */ - BLEND_EQUATION_ALPHA : 0x883D, - - /* BlendSubtract */ - FUNC_SUBTRACT : 0x800A, - FUNC_REVERSE_SUBTRACT : 0x800B, - - /* Separate Blend Functions */ - BLEND_DST_RGB : 0x80C8, - BLEND_SRC_RGB : 0x80C9, - BLEND_DST_ALPHA : 0x80CA, - BLEND_SRC_ALPHA : 0x80CB, - CONSTANT_COLOR : 0x8001, - ONE_MINUS_CONSTANT_COLOR : 0x8002, - CONSTANT_ALPHA : 0x8003, - ONE_MINUS_CONSTANT_ALPHA : 0x8004, - BLEND_COLOR : 0x8005, - - /* Buffer Objects */ - ARRAY_BUFFER : 0x8892, - ELEMENT_ARRAY_BUFFER : 0x8893, - ARRAY_BUFFER_BINDING : 0x8894, - ELEMENT_ARRAY_BUFFER_BINDING : 0x8895, - - STREAM_DRAW : 0x88E0, - STATIC_DRAW : 0x88E4, - DYNAMIC_DRAW : 0x88E8, - - BUFFER_SIZE : 0x8764, - BUFFER_USAGE : 0x8765, - - CURRENT_VERTEX_ATTRIB : 0x8626, - - /* CullFaceMode */ - FRONT : 0x0404, - BACK : 0x0405, - FRONT_AND_BACK : 0x0408, - - /* DepthFunction */ - /* NEVER */ - /* LESS */ - /* EQUAL */ - /* LEQUAL */ - /* GREATER */ - /* NOTEQUAL */ - /* GEQUAL */ - /* ALWAYS */ - - /* EnableCap */ - /* TEXTURE_2D */ - CULL_FACE : 0x0B44, - BLEND : 0x0BE2, - DITHER : 0x0BD0, - STENCIL_TEST : 0x0B90, - DEPTH_TEST : 0x0B71, - SCISSOR_TEST : 0x0C11, - POLYGON_OFFSET_FILL : 0x8037, - SAMPLE_ALPHA_TO_COVERAGE : 0x809E, - SAMPLE_COVERAGE : 0x80A0, - - /* ErrorCode */ - NO_ERROR : 0, - INVALID_ENUM : 0x0500, - INVALID_VALUE : 0x0501, - INVALID_OPERATION : 0x0502, - OUT_OF_MEMORY : 0x0505, - - /* FrontFaceDirection */ - CW : 0x0900, - CCW : 0x0901, - - /* GetPName */ - LINE_WIDTH : 0x0B21, - ALIASED_POINT_SIZE_RANGE : 0x846D, - ALIASED_LINE_WIDTH_RANGE : 0x846E, - CULL_FACE_MODE : 0x0B45, - FRONT_FACE : 0x0B46, - DEPTH_RANGE : 0x0B70, - DEPTH_WRITEMASK : 0x0B72, - DEPTH_CLEAR_VALUE : 0x0B73, - DEPTH_FUNC : 0x0B74, - STENCIL_CLEAR_VALUE : 0x0B91, - STENCIL_FUNC : 0x0B92, - STENCIL_FAIL : 0x0B94, - STENCIL_PASS_DEPTH_FAIL : 0x0B95, - STENCIL_PASS_DEPTH_PASS : 0x0B96, - STENCIL_REF : 0x0B97, - STENCIL_VALUE_MASK : 0x0B93, - STENCIL_WRITEMASK : 0x0B98, - STENCIL_BACK_FUNC : 0x8800, - STENCIL_BACK_FAIL : 0x8801, - STENCIL_BACK_PASS_DEPTH_FAIL : 0x8802, - STENCIL_BACK_PASS_DEPTH_PASS : 0x8803, - STENCIL_BACK_REF : 0x8CA3, - STENCIL_BACK_VALUE_MASK : 0x8CA4, - STENCIL_BACK_WRITEMASK : 0x8CA5, - VIEWPORT : 0x0BA2, - SCISSOR_BOX : 0x0C10, - /* SCISSOR_TEST */ - COLOR_CLEAR_VALUE : 0x0C22, - COLOR_WRITEMASK : 0x0C23, - UNPACK_ALIGNMENT : 0x0CF5, - PACK_ALIGNMENT : 0x0D05, - MAX_TEXTURE_SIZE : 0x0D33, - MAX_VIEWPORT_DIMS : 0x0D3A, - SUBPIXEL_BITS : 0x0D50, - RED_BITS : 0x0D52, - GREEN_BITS : 0x0D53, - BLUE_BITS : 0x0D54, - ALPHA_BITS : 0x0D55, - DEPTH_BITS : 0x0D56, - STENCIL_BITS : 0x0D57, - POLYGON_OFFSET_UNITS : 0x2A00, - /* POLYGON_OFFSET_FILL */ - POLYGON_OFFSET_FACTOR : 0x8038, - TEXTURE_BINDING_2D : 0x8069, - SAMPLE_BUFFERS : 0x80A8, - SAMPLES : 0x80A9, - SAMPLE_COVERAGE_VALUE : 0x80AA, - SAMPLE_COVERAGE_INVERT : 0x80AB, - - /* GetTextureParameter */ - /* TEXTURE_MAG_FILTER */ - /* TEXTURE_MIN_FILTER */ - /* TEXTURE_WRAP_S */ - /* TEXTURE_WRAP_T */ - - COMPRESSED_TEXTURE_FORMATS : 0x86A3, - - /* HintMode */ - DONT_CARE : 0x1100, - FASTEST : 0x1101, - NICEST : 0x1102, - - /* HintTarget */ - GENERATE_MIPMAP_HINT : 0x8192, - - /* DataType */ - BYTE : 0x1400, - UNSIGNED_BYTE : 0x1401, - SHORT : 0x1402, - UNSIGNED_SHORT : 0x1403, - INT : 0x1404, - UNSIGNED_INT : 0x1405, - FLOAT : 0x1406, - - /* PixelFormat */ - DEPTH_COMPONENT : 0x1902, - ALPHA : 0x1906, - RGB : 0x1907, - RGBA : 0x1908, - LUMINANCE : 0x1909, - LUMINANCE_ALPHA : 0x190A, - - /* PixelType */ - /* UNSIGNED_BYTE */ - UNSIGNED_SHORT_4_4_4_4 : 0x8033, - UNSIGNED_SHORT_5_5_5_1 : 0x8034, - UNSIGNED_SHORT_5_6_5 : 0x8363, - - /* Shaders */ - FRAGMENT_SHADER : 0x8B30, - VERTEX_SHADER : 0x8B31, - MAX_VERTEX_ATTRIBS : 0x8869, - MAX_VERTEX_UNIFORM_VECTORS : 0x8DFB, - MAX_VARYING_VECTORS : 0x8DFC, - MAX_COMBINED_TEXTURE_IMAGE_UNITS : 0x8B4D, - MAX_VERTEX_TEXTURE_IMAGE_UNITS : 0x8B4C, - MAX_TEXTURE_IMAGE_UNITS : 0x8872, - MAX_FRAGMENT_UNIFORM_VECTORS : 0x8DFD, - SHADER_TYPE : 0x8B4F, - DELETE_STATUS : 0x8B80, - LINK_STATUS : 0x8B82, - VALIDATE_STATUS : 0x8B83, - ATTACHED_SHADERS : 0x8B85, - ACTIVE_UNIFORMS : 0x8B86, - ACTIVE_ATTRIBUTES : 0x8B89, - SHADING_LANGUAGE_VERSION : 0x8B8C, - CURRENT_PROGRAM : 0x8B8D, - - /* StencilFunction */ - NEVER : 0x0200, - LESS : 0x0201, - EQUAL : 0x0202, - LEQUAL : 0x0203, - GREATER : 0x0204, - NOTEQUAL : 0x0205, - GEQUAL : 0x0206, - ALWAYS : 0x0207, - - /* StencilOp */ - /* ZERO */ - KEEP : 0x1E00, - REPLACE : 0x1E01, - INCR : 0x1E02, - DECR : 0x1E03, - INVERT : 0x150A, - INCR_WRAP : 0x8507, - DECR_WRAP : 0x8508, - - /* StringName */ - VENDOR : 0x1F00, - RENDERER : 0x1F01, - VERSION : 0x1F02, - - /* TextureMagFilter */ - NEAREST : 0x2600, - LINEAR : 0x2601, - - /* TextureMinFilter */ - /* NEAREST */ - /* LINEAR */ - NEAREST_MIPMAP_NEAREST : 0x2700, - LINEAR_MIPMAP_NEAREST : 0x2701, - NEAREST_MIPMAP_LINEAR : 0x2702, - LINEAR_MIPMAP_LINEAR : 0x2703, - - /* TextureParameterName */ - TEXTURE_MAG_FILTER : 0x2800, - TEXTURE_MIN_FILTER : 0x2801, - TEXTURE_WRAP_S : 0x2802, - TEXTURE_WRAP_T : 0x2803, - - /* TextureTarget */ - TEXTURE_2D : 0x0DE1, - TEXTURE : 0x1702, - - TEXTURE_CUBE_MAP : 0x8513, - TEXTURE_BINDING_CUBE_MAP : 0x8514, - TEXTURE_CUBE_MAP_POSITIVE_X : 0x8515, - TEXTURE_CUBE_MAP_NEGATIVE_X : 0x8516, - TEXTURE_CUBE_MAP_POSITIVE_Y : 0x8517, - TEXTURE_CUBE_MAP_NEGATIVE_Y : 0x8518, - TEXTURE_CUBE_MAP_POSITIVE_Z : 0x8519, - TEXTURE_CUBE_MAP_NEGATIVE_Z : 0x851A, - MAX_CUBE_MAP_TEXTURE_SIZE : 0x851C, - - /* TextureUnit */ - TEXTURE0 : 0x84C0, - TEXTURE1 : 0x84C1, - TEXTURE2 : 0x84C2, - TEXTURE3 : 0x84C3, - TEXTURE4 : 0x84C4, - TEXTURE5 : 0x84C5, - TEXTURE6 : 0x84C6, - TEXTURE7 : 0x84C7, - TEXTURE8 : 0x84C8, - TEXTURE9 : 0x84C9, - TEXTURE10 : 0x84CA, - TEXTURE11 : 0x84CB, - TEXTURE12 : 0x84CC, - TEXTURE13 : 0x84CD, - TEXTURE14 : 0x84CE, - TEXTURE15 : 0x84CF, - TEXTURE16 : 0x84D0, - TEXTURE17 : 0x84D1, - TEXTURE18 : 0x84D2, - TEXTURE19 : 0x84D3, - TEXTURE20 : 0x84D4, - TEXTURE21 : 0x84D5, - TEXTURE22 : 0x84D6, - TEXTURE23 : 0x84D7, - TEXTURE24 : 0x84D8, - TEXTURE25 : 0x84D9, - TEXTURE26 : 0x84DA, - TEXTURE27 : 0x84DB, - TEXTURE28 : 0x84DC, - TEXTURE29 : 0x84DD, - TEXTURE30 : 0x84DE, - TEXTURE31 : 0x84DF, - ACTIVE_TEXTURE : 0x84E0, - - /* TextureWrapMode */ - REPEAT : 0x2901, - CLAMP_TO_EDGE : 0x812F, - MIRRORED_REPEAT : 0x8370, - - /* Uniform Types */ - FLOAT_VEC2 : 0x8B50, - FLOAT_VEC3 : 0x8B51, - FLOAT_VEC4 : 0x8B52, - INT_VEC2 : 0x8B53, - INT_VEC3 : 0x8B54, - INT_VEC4 : 0x8B55, - BOOL : 0x8B56, - BOOL_VEC2 : 0x8B57, - BOOL_VEC3 : 0x8B58, - BOOL_VEC4 : 0x8B59, - FLOAT_MAT2 : 0x8B5A, - FLOAT_MAT3 : 0x8B5B, - FLOAT_MAT4 : 0x8B5C, - SAMPLER_2D : 0x8B5E, - SAMPLER_CUBE : 0x8B60, - - /* Vertex Arrays */ - VERTEX_ATTRIB_ARRAY_ENABLED : 0x8622, - VERTEX_ATTRIB_ARRAY_SIZE : 0x8623, - VERTEX_ATTRIB_ARRAY_STRIDE : 0x8624, - VERTEX_ATTRIB_ARRAY_TYPE : 0x8625, - VERTEX_ATTRIB_ARRAY_NORMALIZED : 0x886A, - VERTEX_ATTRIB_ARRAY_POINTER : 0x8645, - VERTEX_ATTRIB_ARRAY_BUFFER_BINDING : 0x889F, - - /* Shader Source */ - COMPILE_STATUS : 0x8B81, - - /* Shader Precision-Specified Types */ - LOW_FLOAT : 0x8DF0, - MEDIUM_FLOAT : 0x8DF1, - HIGH_FLOAT : 0x8DF2, - LOW_INT : 0x8DF3, - MEDIUM_INT : 0x8DF4, - HIGH_INT : 0x8DF5, - - /* Framebuffer Object. */ - FRAMEBUFFER : 0x8D40, - RENDERBUFFER : 0x8D41, - - RGBA4 : 0x8056, - RGB5_A1 : 0x8057, - RGB565 : 0x8D62, - DEPTH_COMPONENT16 : 0x81A5, - STENCIL_INDEX : 0x1901, - STENCIL_INDEX8 : 0x8D48, - DEPTH_STENCIL : 0x84F9, - - RENDERBUFFER_WIDTH : 0x8D42, - RENDERBUFFER_HEIGHT : 0x8D43, - RENDERBUFFER_INTERNAL_FORMAT : 0x8D44, - RENDERBUFFER_RED_SIZE : 0x8D50, - RENDERBUFFER_GREEN_SIZE : 0x8D51, - RENDERBUFFER_BLUE_SIZE : 0x8D52, - RENDERBUFFER_ALPHA_SIZE : 0x8D53, - RENDERBUFFER_DEPTH_SIZE : 0x8D54, - RENDERBUFFER_STENCIL_SIZE : 0x8D55, - - FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE : 0x8CD0, - FRAMEBUFFER_ATTACHMENT_OBJECT_NAME : 0x8CD1, - FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL : 0x8CD2, - FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE : 0x8CD3, - - COLOR_ATTACHMENT0 : 0x8CE0, - DEPTH_ATTACHMENT : 0x8D00, - STENCIL_ATTACHMENT : 0x8D20, - DEPTH_STENCIL_ATTACHMENT : 0x821A, - - NONE : 0, - - FRAMEBUFFER_COMPLETE : 0x8CD5, - FRAMEBUFFER_INCOMPLETE_ATTACHMENT : 0x8CD6, - FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT : 0x8CD7, - FRAMEBUFFER_INCOMPLETE_DIMENSIONS : 0x8CD9, - FRAMEBUFFER_UNSUPPORTED : 0x8CDD, - - FRAMEBUFFER_BINDING : 0x8CA6, - RENDERBUFFER_BINDING : 0x8CA7, - MAX_RENDERBUFFER_SIZE : 0x84E8, - - INVALID_FRAMEBUFFER_OPERATION : 0x0506, - - /* WebGL-specific enums */ - UNPACK_FLIP_Y_WEBGL : 0x9240, - UNPACK_PREMULTIPLY_ALPHA_WEBGL : 0x9241, - CONTEXT_LOST_WEBGL : 0x9242, - UNPACK_COLORSPACE_CONVERSION_WEBGL : 0x9243, - BROWSER_DEFAULT_WEBGL : 0x9244, -}); - - -/***/ }), -/* 7 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -var guid = 0; - -var ArrayProto = Array.prototype; -var nativeForEach = ArrayProto.forEach; - -/** - * Util functions - * @namespace clay.core.util - */ -var util = { - - /** - * Generate GUID - * @return {number} - * @memberOf clay.core.util - */ - genGUID: function () { - return ++guid; - }, - /** - * Relative path to absolute path - * @param {string} path - * @param {string} basePath - * @return {string} - * @memberOf clay.core.util - */ - relative2absolute: function (path, basePath) { - if (!basePath || path.match(/^\//)) { - return path; - } - var pathParts = path.split('/'); - var basePathParts = basePath.split('/'); - - var item = pathParts[0]; - while(item === '.' || item === '..') { - if (item === '..') { - basePathParts.pop(); - } - pathParts.shift(); - item = pathParts[0]; - } - return basePathParts.join('/') + '/' + pathParts.join('/'); - }, - - /** - * Extend target with source - * @param {Object} target - * @param {Object} source - * @return {Object} - * @memberOf clay.core.util - */ - extend: function (target, source) { - if (source) { - for (var name in source) { - if (source.hasOwnProperty(name)) { - target[name] = source[name]; - } - } - } - return target; - }, - - /** - * Extend properties to target if not exist. - * @param {Object} target - * @param {Object} source - * @return {Object} - * @memberOf clay.core.util - */ - defaults: function (target, source) { - if (source) { - for (var propName in source) { - if (target[propName] === undefined) { - target[propName] = source[propName]; - } - } - } - return target; - }, - /** - * Extend properties with a given property list to avoid for..in.. iteration. - * @param {Object} target - * @param {Object} source - * @param {Array.} propList - * @return {Object} - * @memberOf clay.core.util - */ - extendWithPropList: function (target, source, propList) { - if (source) { - for (var i = 0; i < propList.length; i++) { - var propName = propList[i]; - target[propName] = source[propName]; - } - } - return target; - }, - /** - * Extend properties to target if not exist. With a given property list avoid for..in.. iteration. - * @param {Object} target - * @param {Object} source - * @param {Array.} propList - * @return {Object} - * @memberOf clay.core.util - */ - defaultsWithPropList: function (target, source, propList) { - if (source) { - for (var i = 0; i < propList.length; i++) { - var propName = propList[i]; - if (target[propName] == null) { - target[propName] = source[propName]; - } - } - } - return target; - }, - /** - * @param {Object|Array} obj - * @param {Function} iterator - * @param {Object} [context] - * @memberOf clay.core.util - */ - each: function (obj, iterator, context) { - if (!(obj && iterator)) { - return; - } - if (obj.forEach && obj.forEach === nativeForEach) { - obj.forEach(iterator, context); - } - else if (obj.length === + obj.length) { - for (var i = 0, len = obj.length; i < len; i++) { - iterator.call(context, obj[i], i, obj); - } - } - else { - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - iterator.call(context, obj[key], key, obj); - } - } - } - }, - - /** - * Is object - * @param {} obj - * @return {boolean} - * @memberOf clay.core.util - */ - isObject: function (obj) { - return obj === Object(obj); - }, - - /** - * Is array ? - * @param {} obj - * @return {boolean} - * @memberOf clay.core.util - */ - isArray: function (obj) { - return Array.isArray(obj); - }, - - /** - * Is array like, which have a length property - * @param {} obj - * @return {boolean} - * @memberOf clay.core.util - */ - isArrayLike: function (obj) { - if (!obj) { - return false; - } - else { - return obj.length === + obj.length; - } - }, - - /** - * @param {} obj - * @return {} - * @memberOf clay.core.util - */ - clone: function (obj) { - if (!util.isObject(obj)) { - return obj; - } - else if (util.isArray(obj)) { - return obj.slice(); - } - else if (util.isArrayLike(obj)) { // is typed array - var ret = new obj.constructor(obj.length); - for (var i = 0; i < obj.length; i++) { - ret[i] = obj[i]; - } - return ret; - } - else { - return util.extend({}, obj); - } - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (util); - - -/***/ }), -/* 8 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1__dep_glmatrix__); - - -var vec3 = __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default.a.vec3; - -var vec3Copy = vec3.copy; -var vec3Set = vec3.set; - -/** - * Axis aligned bounding box - * @constructor - * @alias clay.math.BoundingBox - * @param {clay.math.Vector3} [min] - * @param {clay.math.Vector3} [max] - */ -var BoundingBox = function (min, max) { - - /** - * Minimum coords of bounding box - * @type {clay.math.Vector3} - */ - this.min = min || new __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */](Infinity, Infinity, Infinity); - - /** - * Maximum coords of bounding box - * @type {clay.math.Vector3} - */ - this.max = max || new __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */](-Infinity, -Infinity, -Infinity); -}; - -BoundingBox.prototype = { - - constructor: BoundingBox, - /** - * Update min and max coords from a vertices array - * @param {array} vertices - */ - updateFromVertices: function (vertices) { - if (vertices.length > 0) { - var min = this.min; - var max = this.max; - var minArr = min.array; - var maxArr = max.array; - vec3Copy(minArr, vertices[0]); - vec3Copy(maxArr, vertices[0]); - for (var i = 1; i < vertices.length; i++) { - var vertex = vertices[i]; - - if (vertex[0] < minArr[0]) { minArr[0] = vertex[0]; } - if (vertex[1] < minArr[1]) { minArr[1] = vertex[1]; } - if (vertex[2] < minArr[2]) { minArr[2] = vertex[2]; } - - if (vertex[0] > maxArr[0]) { maxArr[0] = vertex[0]; } - if (vertex[1] > maxArr[1]) { maxArr[1] = vertex[1]; } - if (vertex[2] > maxArr[2]) { maxArr[2] = vertex[2]; } - } - min._dirty = true; - max._dirty = true; - } - }, - - /** - * Union operation with another bounding box - * @param {clay.math.BoundingBox} bbox - */ - union: function (bbox) { - var min = this.min; - var max = this.max; - vec3.min(min.array, min.array, bbox.min.array); - vec3.max(max.array, max.array, bbox.max.array); - min._dirty = true; - max._dirty = true; - return this; - }, - - /** - * Intersection operation with another bounding box - * @param {clay.math.BoundingBox} bbox - */ - intersection: function (bbox) { - var min = this.min; - var max = this.max; - vec3.max(min.array, min.array, bbox.min.array); - vec3.min(max.array, max.array, bbox.max.array); - min._dirty = true; - max._dirty = true; - return this; - }, - - /** - * If intersect with another bounding box - * @param {clay.math.BoundingBox} bbox - * @return {boolean} - */ - intersectBoundingBox: function (bbox) { - var _min = this.min.array; - var _max = this.max.array; - - var _min2 = bbox.min.array; - var _max2 = bbox.max.array; - - return ! (_min[0] > _max2[0] || _min[1] > _max2[1] || _min[2] > _max2[2] - || _max[0] < _min2[0] || _max[1] < _min2[1] || _max[2] < _min2[2]); - }, - - /** - * If contain another bounding box entirely - * @param {clay.math.BoundingBox} bbox - * @return {boolean} - */ - containBoundingBox: function (bbox) { - - var _min = this.min.array; - var _max = this.max.array; - - var _min2 = bbox.min.array; - var _max2 = bbox.max.array; - - return _min[0] <= _min2[0] && _min[1] <= _min2[1] && _min[2] <= _min2[2] - && _max[0] >= _max2[0] && _max[1] >= _max2[1] && _max[2] >= _max2[2]; - }, - - /** - * If contain point entirely - * @param {clay.math.Vector3} point - * @return {boolean} - */ - containPoint: function (p) { - var _min = this.min.array; - var _max = this.max.array; - - var _p = p.array; - - return _min[0] <= _p[0] && _min[1] <= _p[1] && _min[2] <= _p[2] - && _max[0] >= _p[0] && _max[1] >= _p[1] && _max[2] >= _p[2]; - }, - - /** - * If bounding box is finite - */ - isFinite: function () { - var _min = this.min.array; - var _max = this.max.array; - return isFinite(_min[0]) && isFinite(_min[1]) && isFinite(_min[2]) - && isFinite(_max[0]) && isFinite(_max[1]) && isFinite(_max[2]); - }, - - /** - * Apply an affine transform matrix to the bounding box - * @param {clay.math.Matrix4} matrix - */ - applyTransform: (function () { - // http://dev.theomader.com/transform-bounding-boxes/ - var xa = vec3.create(); - var xb = vec3.create(); - var ya = vec3.create(); - var yb = vec3.create(); - var za = vec3.create(); - var zb = vec3.create(); - - return function (matrix) { - var min = this.min.array; - var max = this.max.array; - - var m = matrix.array; - - xa[0] = m[0] * min[0]; xa[1] = m[1] * min[0]; xa[2] = m[2] * min[0]; - xb[0] = m[0] * max[0]; xb[1] = m[1] * max[0]; xb[2] = m[2] * max[0]; - - ya[0] = m[4] * min[1]; ya[1] = m[5] * min[1]; ya[2] = m[6] * min[1]; - yb[0] = m[4] * max[1]; yb[1] = m[5] * max[1]; yb[2] = m[6] * max[1]; - - za[0] = m[8] * min[2]; za[1] = m[9] * min[2]; za[2] = m[10] * min[2]; - zb[0] = m[8] * max[2]; zb[1] = m[9] * max[2]; zb[2] = m[10] * max[2]; - - min[0] = Math.min(xa[0], xb[0]) + Math.min(ya[0], yb[0]) + Math.min(za[0], zb[0]) + m[12]; - min[1] = Math.min(xa[1], xb[1]) + Math.min(ya[1], yb[1]) + Math.min(za[1], zb[1]) + m[13]; - min[2] = Math.min(xa[2], xb[2]) + Math.min(ya[2], yb[2]) + Math.min(za[2], zb[2]) + m[14]; - - max[0] = Math.max(xa[0], xb[0]) + Math.max(ya[0], yb[0]) + Math.max(za[0], zb[0]) + m[12]; - max[1] = Math.max(xa[1], xb[1]) + Math.max(ya[1], yb[1]) + Math.max(za[1], zb[1]) + m[13]; - max[2] = Math.max(xa[2], xb[2]) + Math.max(ya[2], yb[2]) + Math.max(za[2], zb[2]) + m[14]; - - this.min._dirty = true; - this.max._dirty = true; - - return this; - }; - })(), - - /** - * Apply a projection matrix to the bounding box - * @param {clay.math.Matrix4} matrix - */ - applyProjection: function (matrix) { - var min = this.min.array; - var max = this.max.array; - - var m = matrix.array; - // min in min z - var v10 = min[0]; - var v11 = min[1]; - var v12 = min[2]; - // max in min z - var v20 = max[0]; - var v21 = max[1]; - var v22 = min[2]; - // max in max z - var v30 = max[0]; - var v31 = max[1]; - var v32 = max[2]; - - if (m[15] === 1) { // Orthographic projection - min[0] = m[0] * v10 + m[12]; - min[1] = m[5] * v11 + m[13]; - max[2] = m[10] * v12 + m[14]; - - max[0] = m[0] * v30 + m[12]; - max[1] = m[5] * v31 + m[13]; - min[2] = m[10] * v32 + m[14]; - } - else { - var w = -1 / v12; - min[0] = m[0] * v10 * w; - min[1] = m[5] * v11 * w; - max[2] = (m[10] * v12 + m[14]) * w; - - w = -1 / v22; - max[0] = m[0] * v20 * w; - max[1] = m[5] * v21 * w; - - w = -1 / v32; - min[2] = (m[10] * v32 + m[14]) * w; - } - this.min._dirty = true; - this.max._dirty = true; - - return this; - }, - - updateVertices: function () { - var vertices = this.vertices; - if (!vertices) { - // Cube vertices - var vertices = []; - for (var i = 0; i < 8; i++) { - vertices[i] = vec3.fromValues(0, 0, 0); - } - - /** - * Eight coords of bounding box - * @type {Float32Array[]} - */ - this.vertices = vertices; - } - var min = this.min.array; - var max = this.max.array; - //--- min z - // min x - vec3Set(vertices[0], min[0], min[1], min[2]); - vec3Set(vertices[1], min[0], max[1], min[2]); - // max x - vec3Set(vertices[2], max[0], min[1], min[2]); - vec3Set(vertices[3], max[0], max[1], min[2]); - - //-- max z - vec3Set(vertices[4], min[0], min[1], max[2]); - vec3Set(vertices[5], min[0], max[1], max[2]); - vec3Set(vertices[6], max[0], min[1], max[2]); - vec3Set(vertices[7], max[0], max[1], max[2]); - - return this; - }, - /** - * Copy values from another bounding box - * @param {clay.math.BoundingBox} bbox - */ - copy: function (bbox) { - var min = this.min; - var max = this.max; - vec3Copy(min.array, bbox.min.array); - vec3Copy(max.array, bbox.max.array); - min._dirty = true; - max._dirty = true; - return this; - }, - - /** - * Clone a new bounding box - * @return {clay.math.BoundingBox} - */ - clone: function () { - var boundingBox = new BoundingBox(); - boundingBox.copy(this); - return boundingBox; - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (BoundingBox); - - -/***/ }), -/* 9 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__dep_glmatrix__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Vector3__ = __webpack_require__(2); - - -var mat4 = __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix___default.a.mat4; -var vec3 = __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix___default.a.vec3; -var mat3 = __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix___default.a.mat3; -var quat = __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix___default.a.quat; - -/** - * @constructor - * @alias clay.math.Matrix4 - */ -var Matrix4 = function() { - - this._axisX = new __WEBPACK_IMPORTED_MODULE_1__Vector3__["a" /* default */](); - this._axisY = new __WEBPACK_IMPORTED_MODULE_1__Vector3__["a" /* default */](); - this._axisZ = new __WEBPACK_IMPORTED_MODULE_1__Vector3__["a" /* default */](); - - /** - * Storage of Matrix4 - * @name array - * @type {Float32Array} - * @memberOf clay.math.Matrix4# - */ - this.array = mat4.create(); - - /** - * @name _dirty - * @type {boolean} - * @memberOf clay.math.Matrix4# - */ - this._dirty = true; -}; - -Matrix4.prototype = { - - constructor: Matrix4, - - /** - * Set components from array - * @param {Float32Array|number[]} arr - */ - setArray: function (arr) { - for (var i = 0; i < this.array.length; i++) { - this.array[i] = arr[i]; - } - this._dirty = true; - return this; - }, - /** - * Calculate the adjugate of self, in-place - * @return {clay.math.Matrix4} - */ - adjoint: function() { - mat4.adjoint(this.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Clone a new Matrix4 - * @return {clay.math.Matrix4} - */ - clone: function() { - return (new Matrix4()).copy(this); - }, - - /** - * Copy from b - * @param {clay.math.Matrix4} b - * @return {clay.math.Matrix4} - */ - copy: function(a) { - mat4.copy(this.array, a.array); - this._dirty = true; - return this; - }, - - /** - * Calculate matrix determinant - * @return {number} - */ - determinant: function() { - return mat4.determinant(this.array); - }, - - /** - * Set upper 3x3 part from quaternion - * @param {clay.math.Quaternion} q - * @return {clay.math.Matrix4} - */ - fromQuat: function(q) { - mat4.fromQuat(this.array, q.array); - this._dirty = true; - return this; - }, - - /** - * Set from a quaternion rotation and a vector translation - * @param {clay.math.Quaternion} q - * @param {clay.math.Vector3} v - * @return {clay.math.Matrix4} - */ - fromRotationTranslation: function(q, v) { - mat4.fromRotationTranslation(this.array, q.array, v.array); - this._dirty = true; - return this; - }, - - /** - * Set from Matrix2d, it is used when converting a 2d shape to 3d space. - * In 3d space it is equivalent to ranslate on xy plane and rotate about z axis - * @param {clay.math.Matrix2d} m2d - * @return {clay.math.Matrix4} - */ - fromMat2d: function(m2d) { - Matrix4.fromMat2d(this, m2d); - return this; - }, - - /** - * Set from frustum bounds - * @param {number} left - * @param {number} right - * @param {number} bottom - * @param {number} top - * @param {number} near - * @param {number} far - * @return {clay.math.Matrix4} - */ - frustum: function (left, right, bottom, top, near, far) { - mat4.frustum(this.array, left, right, bottom, top, near, far); - this._dirty = true; - return this; - }, - - /** - * Set to a identity matrix - * @return {clay.math.Matrix4} - */ - identity: function() { - mat4.identity(this.array); - this._dirty = true; - return this; - }, - - /** - * Invert self - * @return {clay.math.Matrix4} - */ - invert: function() { - mat4.invert(this.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Set as a matrix with the given eye position, focal point, and up axis - * @param {clay.math.Vector3} eye - * @param {clay.math.Vector3} center - * @param {clay.math.Vector3} up - * @return {clay.math.Matrix4} - */ - lookAt: function(eye, center, up) { - mat4.lookAt(this.array, eye.array, center.array, up.array); - this._dirty = true; - return this; - }, - - /** - * Alias for mutiply - * @param {clay.math.Matrix4} b - * @return {clay.math.Matrix4} - */ - mul: function(b) { - mat4.mul(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Alias for multiplyLeft - * @param {clay.math.Matrix4} a - * @return {clay.math.Matrix4} - */ - mulLeft: function(a) { - mat4.mul(this.array, a.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Multiply self and b - * @param {clay.math.Matrix4} b - * @return {clay.math.Matrix4} - */ - multiply: function(b) { - mat4.multiply(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Multiply a and self, a is on the left - * @param {clay.math.Matrix3} a - * @return {clay.math.Matrix3} - */ - multiplyLeft: function(a) { - mat4.multiply(this.array, a.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Set as a orthographic projection matrix - * @param {number} left - * @param {number} right - * @param {number} bottom - * @param {number} top - * @param {number} near - * @param {number} far - * @return {clay.math.Matrix4} - */ - ortho: function(left, right, bottom, top, near, far) { - mat4.ortho(this.array, left, right, bottom, top, near, far); - this._dirty = true; - return this; - }, - /** - * Set as a perspective projection matrix - * @param {number} fovy - * @param {number} aspect - * @param {number} near - * @param {number} far - * @return {clay.math.Matrix4} - */ - perspective: function(fovy, aspect, near, far) { - mat4.perspective(this.array, fovy, aspect, near, far); - this._dirty = true; - return this; - }, - - /** - * Rotate self by rad about axis. - * Equal to right-multiply a rotaion matrix - * @param {number} rad - * @param {clay.math.Vector3} axis - * @return {clay.math.Matrix4} - */ - rotate: function(rad, axis) { - mat4.rotate(this.array, this.array, rad, axis.array); - this._dirty = true; - return this; - }, - - /** - * Rotate self by a given radian about X axis. - * Equal to right-multiply a rotaion matrix - * @param {number} rad - * @return {clay.math.Matrix4} - */ - rotateX: function(rad) { - mat4.rotateX(this.array, this.array, rad); - this._dirty = true; - return this; - }, - - /** - * Rotate self by a given radian about Y axis. - * Equal to right-multiply a rotaion matrix - * @param {number} rad - * @return {clay.math.Matrix4} - */ - rotateY: function(rad) { - mat4.rotateY(this.array, this.array, rad); - this._dirty = true; - return this; - }, - - /** - * Rotate self by a given radian about Z axis. - * Equal to right-multiply a rotaion matrix - * @param {number} rad - * @return {clay.math.Matrix4} - */ - rotateZ: function(rad) { - mat4.rotateZ(this.array, this.array, rad); - this._dirty = true; - return this; - }, - - /** - * Scale self by s - * Equal to right-multiply a scale matrix - * @param {clay.math.Vector3} s - * @return {clay.math.Matrix4} - */ - scale: function(v) { - mat4.scale(this.array, this.array, v.array); - this._dirty = true; - return this; - }, - - /** - * Translate self by v. - * Equal to right-multiply a translate matrix - * @param {clay.math.Vector3} v - * @return {clay.math.Matrix4} - */ - translate: function(v) { - mat4.translate(this.array, this.array, v.array); - this._dirty = true; - return this; - }, - - /** - * Transpose self, in-place. - * @return {clay.math.Matrix2} - */ - transpose: function() { - mat4.transpose(this.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Decompose a matrix to SRT - * @param {clay.math.Vector3} [scale] - * @param {clay.math.Quaternion} rotation - * @param {clay.math.Vector} position - * @see http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.matrix.decompose.aspx - */ - decomposeMatrix: (function() { - - var x = vec3.create(); - var y = vec3.create(); - var z = vec3.create(); - - var m3 = mat3.create(); - - return function(scale, rotation, position) { - - var el = this.array; - vec3.set(x, el[0], el[1], el[2]); - vec3.set(y, el[4], el[5], el[6]); - vec3.set(z, el[8], el[9], el[10]); - - var sx = vec3.length(x); - var sy = vec3.length(y); - var sz = vec3.length(z); - - // if determine is negative, we need to invert one scale - var det = this.determinant(); - if (det < 0) { - sx = -sx; - } - - if (scale) { - scale.set(sx, sy, sz); - } - - position.set(el[12], el[13], el[14]); - - mat3.fromMat4(m3, el); - // Not like mat4, mat3 in glmatrix seems to be row-based - // Seems fixed in gl-matrix 2.2.2 - // https://github.com/toji/gl-matrix/issues/114 - // mat3.transpose(m3, m3); - - m3[0] /= sx; - m3[1] /= sx; - m3[2] /= sx; - - m3[3] /= sy; - m3[4] /= sy; - m3[5] /= sy; - - m3[6] /= sz; - m3[7] /= sz; - m3[8] /= sz; - - quat.fromMat3(rotation.array, m3); - quat.normalize(rotation.array, rotation.array); - - rotation._dirty = true; - position._dirty = true; - }; - })(), - - toString: function() { - return '[' + Array.prototype.join.call(this.array, ',') + ']'; - }, - - toArray: function () { - return Array.prototype.slice.call(this.array); - } -}; - -var defineProperty = Object.defineProperty; - -if (defineProperty) { - var proto = Matrix4.prototype; - /** - * Z Axis of local transform - * @name z - * @type {clay.math.Vector3} - * @memberOf clay.math.Matrix4 - * @instance - */ - defineProperty(proto, 'z', { - get: function () { - var el = this.array; - this._axisZ.set(el[8], el[9], el[10]); - return this._axisZ; - }, - set: function (v) { - // TODO Here has a problem - // If only set an item of vector will not work - var el = this.array; - v = v.array; - el[8] = v[0]; - el[9] = v[1]; - el[10] = v[2]; - - this._dirty = true; - } - }); - - /** - * Y Axis of local transform - * @name y - * @type {clay.math.Vector3} - * @memberOf clay.math.Matrix4 - * @instance - */ - defineProperty(proto, 'y', { - get: function () { - var el = this.array; - this._axisY.set(el[4], el[5], el[6]); - return this._axisY; - }, - set: function (v) { - var el = this.array; - v = v.array; - el[4] = v[0]; - el[5] = v[1]; - el[6] = v[2]; - - this._dirty = true; - } - }); - - /** - * X Axis of local transform - * @name x - * @type {clay.math.Vector3} - * @memberOf clay.math.Matrix4 - * @instance - */ - defineProperty(proto, 'x', { - get: function () { - var el = this.array; - this._axisX.set(el[0], el[1], el[2]); - return this._axisX; - }, - set: function (v) { - var el = this.array; - v = v.array; - el[0] = v[0]; - el[1] = v[1]; - el[2] = v[2]; - - this._dirty = true; - } - }) -} - -/** - * @param {clay.math.Matrix4} out - * @param {clay.math.Matrix4} a - * @return {clay.math.Matrix4} - */ -Matrix4.adjoint = function(out, a) { - mat4.adjoint(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} out - * @param {clay.math.Matrix4} a - * @return {clay.math.Matrix4} - */ -Matrix4.copy = function(out, a) { - mat4.copy(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} a - * @return {number} - */ -Matrix4.determinant = function(a) { - return mat4.determinant(a.array); -}; - -/** - * @param {clay.math.Matrix4} out - * @return {clay.math.Matrix4} - */ -Matrix4.identity = function(out) { - mat4.identity(out.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} out - * @param {number} left - * @param {number} right - * @param {number} bottom - * @param {number} top - * @param {number} near - * @param {number} far - * @return {clay.math.Matrix4} - */ -Matrix4.ortho = function(out, left, right, bottom, top, near, far) { - mat4.ortho(out.array, left, right, bottom, top, near, far); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} out - * @param {number} fovy - * @param {number} aspect - * @param {number} near - * @param {number} far - * @return {clay.math.Matrix4} - */ -Matrix4.perspective = function(out, fovy, aspect, near, far) { - mat4.perspective(out.array, fovy, aspect, near, far); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} out - * @param {clay.math.Vector3} eye - * @param {clay.math.Vector3} center - * @param {clay.math.Vector3} up - * @return {clay.math.Matrix4} - */ -Matrix4.lookAt = function(out, eye, center, up) { - mat4.lookAt(out.array, eye.array, center.array, up.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} out - * @param {clay.math.Matrix4} a - * @return {clay.math.Matrix4} - */ -Matrix4.invert = function(out, a) { - mat4.invert(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} out - * @param {clay.math.Matrix4} a - * @param {clay.math.Matrix4} b - * @return {clay.math.Matrix4} - */ -Matrix4.mul = function(out, a, b) { - mat4.mul(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @function - * @param {clay.math.Matrix4} out - * @param {clay.math.Matrix4} a - * @param {clay.math.Matrix4} b - * @return {clay.math.Matrix4} - */ -Matrix4.multiply = Matrix4.mul; - -/** - * @param {clay.math.Matrix4} out - * @param {clay.math.Quaternion} q - * @return {clay.math.Matrix4} - */ -Matrix4.fromQuat = function(out, q) { - mat4.fromQuat(out.array, q.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} out - * @param {clay.math.Quaternion} q - * @param {clay.math.Vector3} v - * @return {clay.math.Matrix4} - */ -Matrix4.fromRotationTranslation = function(out, q, v) { - mat4.fromRotationTranslation(out.array, q.array, v.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} m4 - * @param {clay.math.Matrix2d} m2d - * @return {clay.math.Matrix4} - */ -Matrix4.fromMat2d = function(m4, m2d) { - m4._dirty = true; - var m2d = m2d.array; - var m4 = m4.array; - - m4[0] = m2d[0]; - m4[4] = m2d[2]; - m4[12] = m2d[4]; - - m4[1] = m2d[1]; - m4[5] = m2d[3]; - m4[13] = m2d[5]; - - return m4; -}; - -/** - * @param {clay.math.Matrix4} out - * @param {clay.math.Matrix4} a - * @param {number} rad - * @param {clay.math.Vector3} axis - * @return {clay.math.Matrix4} - */ -Matrix4.rotate = function(out, a, rad, axis) { - mat4.rotate(out.array, a.array, rad, axis.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} out - * @param {clay.math.Matrix4} a - * @param {number} rad - * @return {clay.math.Matrix4} - */ -Matrix4.rotateX = function(out, a, rad) { - mat4.rotateX(out.array, a.array, rad); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} out - * @param {clay.math.Matrix4} a - * @param {number} rad - * @return {clay.math.Matrix4} - */ -Matrix4.rotateY = function(out, a, rad) { - mat4.rotateY(out.array, a.array, rad); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} out - * @param {clay.math.Matrix4} a - * @param {number} rad - * @return {clay.math.Matrix4} - */ -Matrix4.rotateZ = function(out, a, rad) { - mat4.rotateZ(out.array, a.array, rad); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} out - * @param {clay.math.Matrix4} a - * @param {clay.math.Vector3} v - * @return {clay.math.Matrix4} - */ -Matrix4.scale = function(out, a, v) { - mat4.scale(out.array, a.array, v.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} out - * @param {clay.math.Matrix4} a - * @return {clay.math.Matrix4} - */ -Matrix4.transpose = function(out, a) { - mat4.transpose(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Matrix4} out - * @param {clay.math.Matrix4} a - * @param {clay.math.Vector3} v - * @return {clay.math.Matrix4} - */ -Matrix4.translate = function(out, a, v) { - mat4.translate(out.array, a.array, v.array); - out._dirty = true; - return out; -}; - -/* harmony default export */ __webpack_exports__["a"] = (Matrix4); - - -/***/ }), -/* 10 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__core_util__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__core_color__ = __webpack_require__(72); - - - - -var parseColor = __WEBPACK_IMPORTED_MODULE_3__core_color__["a" /* default */].parseToFloat; - -var programKeyCache = {}; - -function getDefineCode(defines, lightsNumbers, enabledTextures) { - var defineKeys = Object.keys(defines); - defineKeys.sort(); - var defineStr = []; - // Custom Defines - for (var i = 0; i < defineKeys.length; i++) { - var key = defineKeys[i]; - var value = defines[key]; - if (value === null) { - defineStr.push(key); - } - else{ - defineStr.push(key + ' ' + value.toString()); - } - } - return defineStr.join('\n'); -} - -function getProgramKey(vertexDefines, fragmentDefines, enabledTextures) { - enabledTextures.sort(); - var defineStr = []; - for (var i = 0; i < enabledTextures.length; i++) { - var symbol = enabledTextures[i]; - defineStr.push(symbol); - } - var key = getDefineCode(vertexDefines) + '\n' - + getDefineCode(fragmentDefines) + '\n' - + defineStr.join('\n'); - - if (programKeyCache[key]) { - return programKeyCache[key]; - } - - var id = __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].genGUID(); - programKeyCache[key] = id; - return id; -} - -/** - * @constructor clay.Material - * @extends clay.core.Base - */ -var Material = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend(function () { - return /** @lends clay.Material# */ { - /** - * @type {string} - */ - name: '', - - /** - * @type {Object} - */ - // uniforms: null, - - /** - * @type {clay.Shader} - */ - // shader: null, - - /** - * @type {boolean} - */ - depthTest: true, - - /** - * @type {boolean} - */ - depthMask: true, - - /** - * @type {boolean} - */ - transparent: false, - /** - * Blend func is a callback function when the material - * have custom blending - * The gl context will be the only argument passed in tho the - * blend function - * Detail of blend function in WebGL: - * http://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf - * - * Example : - * function(_gl) { - * _gl.blendEquation(_gl.FUNC_ADD); - * _gl.blendFunc(_gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA); - * } - */ - blend: null, - - /** - * If update texture status automatically. - */ - autoUpdateTextureStatus: true, - - uniforms: {}, - vertexDefines: {}, - fragmentDefines: {}, - _textureStatus: {}, - - // shadowTransparentMap : null - - // PENDING enable the uniform that only used in shader. - _enabledUniforms: null, - }; -}, function () { - if (!this.name) { - this.name = 'MATERIAL_' + this.__uid__; - } - - if (this.shader) { - // Keep status, mainly preset uniforms, vertexDefines and fragmentDefines - this.attachShader(this.shader, true); - } -}, -/** @lends clay.Material.prototype */ -{ - precision: 'highp', - - bind: function(renderer, program, prevMaterial, prevProgram) { - var _gl = renderer.gl; - // PENDING Same texture in different material take different slot? - - // May use shader of other material if shader code are same - - // var sameProgram = prevProgram === program; - - var currentTextureSlot = program.currentTextureSlot(); - - for (var u = 0; u < this._enabledUniforms.length; u++) { - var symbol = this._enabledUniforms[u]; - var uniformValue = this.uniforms[symbol].value; - if (uniformValue instanceof __WEBPACK_IMPORTED_MODULE_1__Texture__["a" /* default */]) { - // Reset slot - uniformValue.__slot = -1; - } - else if (Array.isArray(uniformValue)) { - for (var i = 0; i < uniformValue.length; i++) { - if (uniformValue[i] instanceof __WEBPACK_IMPORTED_MODULE_1__Texture__["a" /* default */]) { - uniformValue[i].__slot = -1; - } - } - } - } - // Set uniforms - for (var u = 0; u < this._enabledUniforms.length; u++) { - var symbol = this._enabledUniforms[u]; - var uniform = this.uniforms[symbol]; - var uniformValue = uniform.value; - // PENDING - // When binding two materials with the same shader - // Many uniforms will be be set twice even if they have the same value - // So add a evaluation to see if the uniform is really needed to be set - // if (prevMaterial && sameShader) { - // if (prevMaterial.uniforms[symbol].value === uniformValue) { - // continue; - // } - // } - - if (uniformValue === null) { - // FIXME Assume material with same shader have same order uniforms - // Or if different material use same textures, - // the slot will be different and still skipped because optimization - if (uniform.type === 't') { - var slot = program.currentTextureSlot(); - var res = program.setUniform(_gl, '1i', symbol, slot); - if (res) { // Texture is enabled - // Still occupy the slot to make sure same texture in different materials have same slot. - program.takeCurrentTextureSlot(renderer, null); - } - } - continue; - } - else if (uniformValue instanceof __WEBPACK_IMPORTED_MODULE_1__Texture__["a" /* default */]) { - if (uniformValue.__slot < 0) { - var slot = program.currentTextureSlot(); - var res = program.setUniform(_gl, '1i', symbol, slot); - if (!res) { // Texture uniform is not enabled - continue; - } - program.takeCurrentTextureSlot(renderer, uniformValue); - uniformValue.__slot = slot; - } - // Multiple uniform use same texture.. - else { - program.setUniform(_gl, '1i', symbol, uniformValue.__slot); - } - } - else if (Array.isArray(uniformValue)) { - if (uniformValue.length === 0) { - continue; - } - // Texture Array - var exampleValue = uniformValue[0]; - - if (exampleValue instanceof __WEBPACK_IMPORTED_MODULE_1__Texture__["a" /* default */]) { - if (!program.hasUniform(symbol)) { - continue; - } - - var arr = []; - for (var i = 0; i < uniformValue.length; i++) { - var texture = uniformValue[i]; - - if (texture.__slot < 0) { - var slot = program.currentTextureSlot(); - arr.push(slot); - program.takeCurrentTextureSlot(renderer, texture); - texture.__slot = slot; - } - else { - arr.push(texture.__slot); - } - } - - program.setUniform(_gl, '1iv', symbol, arr); - } - else { - program.setUniform(_gl, uniform.type, symbol, uniformValue); - } - } - else{ - program.setUniform(_gl, uniform.type, symbol, uniformValue); - } - } - // Texture slot maybe used out of material. - program.resetTextureSlot(currentTextureSlot); - }, - - /** - * Set material uniform - * @example - * mat.setUniform('color', [1, 1, 1, 1]); - * @param {string} symbol - * @param {number|array|clay.Texture|ArrayBufferView} value - */ - setUniform: function (symbol, value) { - if (value === undefined) { - console.warn('Uniform value "' + symbol + '" is undefined'); - } - var uniform = this.uniforms[symbol]; - if (uniform) { - - if (typeof value === 'string') { - // Try to parse as a color. Invalid color string will return null. - value = parseColor(value) || value; - } - - uniform.value = value; - - if (this.autoUpdateTextureStatus && uniform.type === 't') { - if (value) { - this.enableTexture(symbol); - } - else { - this.disableTexture(symbol); - } - } - } - }, - - /** - * @param {Object} obj - */ - setUniforms: function(obj) { - for (var key in obj) { - var val = obj[key]; - this.setUniform(key, val); - } - }, - - // /** - // * Enable a uniform - // * It only have effect on the uniform exists in shader. - // * @param {string} symbol - // */ - // enableUniform: function (symbol) { - // if (this.uniforms[symbol] && !this.isUniformEnabled(symbol)) { - // this._enabledUniforms.push(symbol); - // } - // }, - - // /** - // * Disable a uniform - // * It will not affect the uniform state in the shader. Because the shader uniforms is parsed from shader code with naive regex. When using micro to disable some uniforms in the shader. It will still try to set these uniforms in each rendering pass. We can disable these uniforms manually if we need this bit performance improvement. Mostly we can simply ignore it. - // * @param {string} symbol - // */ - // disableUniform: function (symbol) { - // var idx = this._enabledUniforms.indexOf(symbol); - // if (idx >= 0) { - // this._enabledUniforms.splice(idx, 1); - // } - // }, - - /** - * @param {string} symbol - * @return {boolean} - */ - isUniformEnabled: function (symbol) { - return this._enabledUniforms.indexOf(symbol) >= 0; - }, - - getEnabledUniforms: function () { - return this._enabledUniforms; - }, - getTextureUniforms: function () { - return this._textureUniforms; - }, - - /** - * Alias of setUniform and setUniforms - * @param {object|string} symbol - * @param {number|array|clay.Texture|ArrayBufferView} [value] - */ - set: function (symbol, value) { - if (typeof(symbol) === 'object') { - for (var key in symbol) { - var val = symbol[key]; - this.setUniform(key, val); - } - } - else { - this.setUniform(symbol, value); - } - }, - /** - * Get uniform value - * @param {string} symbol - * @return {number|array|clay.Texture|ArrayBufferView} - */ - get: function (symbol) { - var uniform = this.uniforms[symbol]; - if (uniform) { - return uniform.value; - } - }, - /** - * Attach a shader instance - * @param {clay.Shader} shader - * @param {boolean} keepStatus If try to keep uniform and texture - */ - attachShader: function(shader, keepStatus) { - var originalUniforms = this.uniforms; - - // Ignore if uniform can use in shader. - this.uniforms = shader.createUniforms(); - this.shader = shader; - - var uniforms = this.uniforms; - this._enabledUniforms = Object.keys(uniforms); - // Make sure uniforms are set in same order to avoid texture slot wrong - this._enabledUniforms.sort(); - this._textureUniforms = this._enabledUniforms.filter(function (uniformName) { - var type = this.uniforms[uniformName].type; - return type === 't' || type === 'tv'; - }, this); - - var originalVertexDefines = this.vertexDefines; - var originalFragmentDefines = this.fragmentDefines; - - this.vertexDefines = __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].clone(shader.vertexDefines); - this.fragmentDefines = __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].clone(shader.fragmentDefines); - - if (keepStatus) { - for (var symbol in originalUniforms) { - if (uniforms[symbol]) { - uniforms[symbol].value = originalUniforms[symbol].value; - } - } - - __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].defaults(this.vertexDefines, originalVertexDefines); - __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].defaults(this.fragmentDefines, originalFragmentDefines); - } - - var textureStatus = {}; - for (var key in shader.textures) { - textureStatus[key] = { - shaderType: shader.textures[key].shaderType, - type: shader.textures[key].type, - enabled: (keepStatus && this._textureStatus[key]) ? this._textureStatus[key].enabled : false - }; - } - - this._textureStatus = textureStatus; - - this._programKey = ''; - }, - - /** - * Clone a new material and keep uniforms, shader will not be cloned - * @return {clay.Material} - */ - clone: function () { - var material = new this.constructor({ - name: this.name, - shader: this.shader - }); - for (var symbol in this.uniforms) { - material.uniforms[symbol].value = this.uniforms[symbol].value; - } - material.depthTest = this.depthTest; - material.depthMask = this.depthMask; - material.transparent = this.transparent; - material.blend = this.blend; - - material.vertexDefines = __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].clone(this.vertexDefines); - material.fragmentDefines = __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].clone(this.fragmentDefines); - material.enableTexture(this.getEnabledTextures()); - material.precision = this.precision; - - return material; - }, - - /** - * Add a #define macro in shader code - * @param {string} shaderType Can be vertex, fragment or both - * @param {string} symbol - * @param {number} [val] - */ - define: function (shaderType, symbol, val) { - var vertexDefines = this.vertexDefines; - var fragmentDefines = this.fragmentDefines; - if (shaderType !== 'vertex' && shaderType !== 'fragment' && shaderType !== 'both' - && arguments.length < 3 - ) { - // shaderType default to be 'both' - val = symbol; - symbol = shaderType; - shaderType = 'both'; - } - val = val != null ? val : null; - if (shaderType === 'vertex' || shaderType === 'both') { - if (vertexDefines[symbol] !== val) { - vertexDefines[symbol] = val; - // Mark as dirty - this._programKey = ''; - } - } - if (shaderType === 'fragment' || shaderType === 'both') { - if (fragmentDefines[symbol] !== val) { - fragmentDefines[symbol] = val; - if (shaderType !== 'both') { - this._programKey = ''; - } - } - } - }, - - /** - * Remove a #define macro in shader code - * @param {string} shaderType Can be vertex, fragment or both - * @param {string} symbol - */ - undefine: function (shaderType, symbol) { - if (shaderType !== 'vertex' && shaderType !== 'fragment' && shaderType !== 'both' - && arguments.length < 2 - ) { - // shaderType default to be 'both' - symbol = shaderType; - shaderType = 'both'; - } - if (shaderType === 'vertex' || shaderType === 'both') { - if (this.isDefined('vertex', symbol)) { - delete this.vertexDefines[symbol]; - // Mark as dirty - this._programKey = ''; - } - } - if (shaderType === 'fragment' || shaderType === 'both') { - if (this.isDefined('fragment', symbol)) { - delete this.fragmentDefines[symbol]; - if (shaderType !== 'both') { - this._programKey = ''; - } - } - } - }, - - /** - * If macro is defined in shader. - * @param {string} shaderType Can be vertex, fragment or both - * @param {string} symbol - */ - isDefined: function (shaderType, symbol) { - // PENDING hasOwnProperty ? - switch (shaderType) { - case 'vertex': - return this.vertexDefines[symbol] !== undefined; - case 'fragment': - return this.fragmentDefines[symbol] !== undefined; - } - }, - /** - * Get macro value defined in shader. - * @param {string} shaderType Can be vertex, fragment or both - * @param {string} symbol - */ - getDefine: function (shaderType, symbol) { - switch(shaderType) { - case 'vertex': - return this.vertexDefines[symbol]; - case 'fragment': - return this.fragmentDefines[symbol]; - } - }, - /** - * Enable a texture, actually it will add a #define macro in the shader code - * For example, if texture symbol is diffuseMap, it will add a line `#define DIFFUSEMAP_ENABLED` in the shader code - * @param {string} symbol - */ - enableTexture: function (symbol) { - if (Array.isArray(symbol)) { - for (var i = 0; i < symbol.length; i++) { - this.enableTexture(symbol[i]); - } - return; - } - - var status = this._textureStatus[symbol]; - if (status) { - var isEnabled = status.enabled; - if (!isEnabled) { - status.enabled = true; - this._programKey = ''; - } - } - }, - /** - * Enable all textures used in the shader - */ - enableTexturesAll: function () { - var textureStatus = this._textureStatus; - for (var symbol in textureStatus) { - textureStatus[symbol].enabled = true; - } - - this._programKey = ''; - }, - /** - * Disable a texture, it remove a #define macro in the shader - * @param {string} symbol - */ - disableTexture: function (symbol) { - if (Array.isArray(symbol)) { - for (var i = 0; i < symbol.length; i++) { - this.disableTexture(symbol[i]); - } - return; - } - - var status = this._textureStatus[symbol]; - if (status) { - var isDisabled = ! status.enabled; - if (!isDisabled) { - status.enabled = false; - this._programKey = ''; - } - } - }, - /** - * Disable all textures used in the shader - */ - disableTexturesAll: function () { - var textureStatus = this._textureStatus; - for (var symbol in textureStatus) { - textureStatus[symbol].enabled = false; - } - - this._programKey = ''; - }, - /** - * If texture of given type is enabled. - * @param {string} symbol - * @return {boolean} - */ - isTextureEnabled: function (symbol) { - var textureStatus = this._textureStatus; - return !!textureStatus[symbol] - && textureStatus[symbol].enabled; - }, - - /** - * Get all enabled textures - * @return {string[]} - */ - getEnabledTextures: function () { - var enabledTextures = []; - var textureStatus = this._textureStatus; - for (var symbol in textureStatus) { - if (textureStatus[symbol].enabled) { - enabledTextures.push(symbol); - } - } - return enabledTextures; - }, - - /** - * Mark defines are updated. - */ - dirtyDefines: function () { - this._programKey = ''; - } -}); - -if (Object.defineProperty) { - Object.defineProperty(Material.prototype, 'shader', { - get: function () { - return this._shader || null; - }, - - set: function (val) { - // TODO - // console.warn('You need to use attachShader to set the shader.'); - this._shader = val; - } - }); - - Object.defineProperty(Material.prototype, 'programKey', { - get: function () { - if (!this._programKey) { - this._programKey = getProgramKey( - this.vertexDefines, this.fragmentDefines, this.getEnabledTextures() - ); - } - return this._programKey; - } - }); -} - -/* harmony default export */ __webpack_exports__["a"] = (Material); - - -/***/ }), -/* 11 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__TextureCube__ = __webpack_require__(17); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__core_glenum__ = __webpack_require__(6); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__core_Cache__ = __webpack_require__(28); - - - - - - -var KEY_FRAMEBUFFER = 'framebuffer'; -var KEY_RENDERBUFFER = 'renderbuffer'; -var KEY_RENDERBUFFER_WIDTH = KEY_RENDERBUFFER + '_width'; -var KEY_RENDERBUFFER_HEIGHT = KEY_RENDERBUFFER + '_height'; -var KEY_RENDERBUFFER_ATTACHED = KEY_RENDERBUFFER + '_attached'; -var KEY_DEPTHTEXTURE_ATTACHED = 'depthtexture_attached'; - -var GL_FRAMEBUFFER = __WEBPACK_IMPORTED_MODULE_3__core_glenum__["a" /* default */].FRAMEBUFFER; -var GL_RENDERBUFFER = __WEBPACK_IMPORTED_MODULE_3__core_glenum__["a" /* default */].RENDERBUFFER; -var GL_DEPTH_ATTACHMENT = __WEBPACK_IMPORTED_MODULE_3__core_glenum__["a" /* default */].DEPTH_ATTACHMENT; -var GL_COLOR_ATTACHMENT0 = __WEBPACK_IMPORTED_MODULE_3__core_glenum__["a" /* default */].COLOR_ATTACHMENT0; -/** - * @constructor clay.FrameBuffer - * @extends clay.core.Base - */ -var FrameBuffer = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend( -/** @lends clay.FrameBuffer# */ -{ - /** - * If use depth buffer - * @type {boolean} - */ - depthBuffer: true, - - /** - * @type {Object} - */ - viewport: null, - - _width: 0, - _height: 0, - - _textures: null, - - _boundRenderer: null, -}, function () { - // Use cache - this._cache = new __WEBPACK_IMPORTED_MODULE_4__core_Cache__["a" /* default */](); - - this._textures = {}; -}, - -/**@lends clay.FrameBuffer.prototype. */ -{ - /** - * Get attached texture width - * {number} - */ - // FIXME Can't use before #bind - getTextureWidth: function () { - return this._width; - }, - - /** - * Get attached texture height - * {number} - */ - getTextureHeight: function () { - return this._height; - }, - - /** - * Bind the framebuffer to given renderer before rendering - * @param {clay.Renderer} renderer - */ - bind: function (renderer) { - - if (renderer.__currentFrameBuffer) { - // Already bound - if (renderer.__currentFrameBuffer === this) { - return; - } - - console.warn('Renderer already bound with another framebuffer. Unbind it first'); - } - renderer.__currentFrameBuffer = this; - - var _gl = renderer.gl; - - _gl.bindFramebuffer(GL_FRAMEBUFFER, this._getFrameBufferGL(renderer)); - this._boundRenderer = renderer; - var cache = this._cache; - - cache.put('viewport', renderer.viewport); - - var hasTextureAttached = false; - var width; - var height; - for (var attachment in this._textures) { - hasTextureAttached = true; - var obj = this._textures[attachment]; - if (obj) { - // TODO Do width, height checking, make sure size are same - width = obj.texture.width; - height = obj.texture.height; - // Attach textures - this._doAttach(renderer, obj.texture, attachment, obj.target); - } - } - - this._width = width; - this._height = height; - - if (!hasTextureAttached && this.depthBuffer) { - console.error('Must attach texture before bind, or renderbuffer may have incorrect width and height.') - } - - if (this.viewport) { - renderer.setViewport(this.viewport); - } - else { - renderer.setViewport(0, 0, width, height, 1); - } - - var attachedTextures = cache.get('attached_textures'); - if (attachedTextures) { - for (var attachment in attachedTextures) { - if (!this._textures[attachment]) { - var target = attachedTextures[attachment]; - this._doDetach(_gl, attachment, target); - } - } - } - if (!cache.get(KEY_DEPTHTEXTURE_ATTACHED) && this.depthBuffer) { - // Create a new render buffer - if (cache.miss(KEY_RENDERBUFFER)) { - cache.put(KEY_RENDERBUFFER, _gl.createRenderbuffer()); - } - var renderbuffer = cache.get(KEY_RENDERBUFFER); - - if (width !== cache.get(KEY_RENDERBUFFER_WIDTH) - || height !== cache.get(KEY_RENDERBUFFER_HEIGHT)) { - _gl.bindRenderbuffer(GL_RENDERBUFFER, renderbuffer); - _gl.renderbufferStorage(GL_RENDERBUFFER, _gl.DEPTH_COMPONENT16, width, height); - cache.put(KEY_RENDERBUFFER_WIDTH, width); - cache.put(KEY_RENDERBUFFER_HEIGHT, height); - _gl.bindRenderbuffer(GL_RENDERBUFFER, null); - } - if (!cache.get(KEY_RENDERBUFFER_ATTACHED)) { - _gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer); - cache.put(KEY_RENDERBUFFER_ATTACHED, true); - } - } - }, - - /** - * Unbind the frame buffer after rendering - * @param {clay.Renderer} renderer - */ - unbind: function (renderer) { - // Remove status record on renderer - renderer.__currentFrameBuffer = null; - - var _gl = renderer.gl; - - _gl.bindFramebuffer(GL_FRAMEBUFFER, null); - this._boundRenderer = null; - - this._cache.use(renderer.__uid__); - var viewport = this._cache.get('viewport'); - // Reset viewport; - if (viewport) { - renderer.setViewport(viewport); - } - - this.updateMipmap(renderer); - }, - - // Because the data of texture is changed over time, - // Here update the mipmaps of texture each time after rendered; - updateMipmap: function (renderer) { - var _gl = renderer.gl; - for (var attachment in this._textures) { - var obj = this._textures[attachment]; - if (obj) { - var texture = obj.texture; - // FIXME some texture format can't generate mipmap - if (!texture.NPOT && texture.useMipmap - && texture.minFilter === __WEBPACK_IMPORTED_MODULE_1__Texture__["a" /* default */].LINEAR_MIPMAP_LINEAR) { - var target = texture instanceof __WEBPACK_IMPORTED_MODULE_2__TextureCube__["a" /* default */] ? __WEBPACK_IMPORTED_MODULE_3__core_glenum__["a" /* default */].TEXTURE_CUBE_MAP : __WEBPACK_IMPORTED_MODULE_3__core_glenum__["a" /* default */].TEXTURE_2D; - _gl.bindTexture(target, texture.getWebGLTexture(renderer)); - _gl.generateMipmap(target); - _gl.bindTexture(target, null); - } - } - } - }, - - - // 0x8CD5, 36053, FRAMEBUFFER_COMPLETE - // 0x8CD6, 36054, FRAMEBUFFER_INCOMPLETE_ATTACHMENT - // 0x8CD7, 36055, FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT - // 0x8CD9, 36057, FRAMEBUFFER_INCOMPLETE_DIMENSIONS - // 0x8CDD, 36061, FRAMEBUFFER_UNSUPPORTED - checkStatus: function (_gl) { - return _gl.checkFramebufferStatus(GL_FRAMEBUFFER); - }, - - _getFrameBufferGL: function (renderer) { - var cache = this._cache; - cache.use(renderer.__uid__); - - if (cache.miss(KEY_FRAMEBUFFER)) { - cache.put(KEY_FRAMEBUFFER, renderer.gl.createFramebuffer()); - } - - return cache.get(KEY_FRAMEBUFFER); - }, - - /** - * Attach a texture(RTT) to the framebuffer - * @param {clay.Texture} texture - * @param {number} [attachment=gl.COLOR_ATTACHMENT0] - * @param {number} [target=gl.TEXTURE_2D] - */ - attach: function (texture, attachment, target) { - - if (!texture.width) { - throw new Error('The texture attached to color buffer is not a valid.'); - } - // TODO width and height check - - // If the depth_texture extension is enabled, developers - // Can attach a depth texture to the depth buffer - // http://blog.tojicode.com/2012/07/using-webgldepthtexture.html - attachment = attachment || GL_COLOR_ATTACHMENT0; - target = target || __WEBPACK_IMPORTED_MODULE_3__core_glenum__["a" /* default */].TEXTURE_2D; - - var boundRenderer = this._boundRenderer; - var _gl = boundRenderer && boundRenderer.gl; - var attachedTextures; - - if (_gl) { - var cache = this._cache; - cache.use(boundRenderer.__uid__); - attachedTextures = cache.get('attached_textures'); - } - - // Check if texture attached - var previous = this._textures[attachment]; - if (previous && previous.target === target - && previous.texture === texture - && (attachedTextures && attachedTextures[attachment] != null) - ) { - return; - } - - var canAttach = true; - if (boundRenderer) { - canAttach = this._doAttach(boundRenderer, texture, attachment, target); - // Set viewport again incase attached to different size textures. - if (!this.viewport) { - boundRenderer.setViewport(0, 0, texture.width, texture.height, 1); - } - } - - if (canAttach) { - this._textures[attachment] = this._textures[attachment] || {}; - this._textures[attachment].texture = texture; - this._textures[attachment].target = target; - } - }, - - _doAttach: function (renderer, texture, attachment, target) { - var _gl = renderer.gl; - // Make sure texture is always updated - // Because texture width or height may be changed and in this we can't be notified - // FIXME awkward; - var webglTexture = texture.getWebGLTexture(renderer); - // Assume cache has been used. - var attachedTextures = this._cache.get('attached_textures'); - if (attachedTextures && attachedTextures[attachment]) { - var obj = attachedTextures[attachment]; - // Check if texture and target not changed - if (obj.texture === texture && obj.target === target) { - return; - } - } - attachment = +attachment; - - var canAttach = true; - if (attachment === GL_DEPTH_ATTACHMENT || attachment === __WEBPACK_IMPORTED_MODULE_3__core_glenum__["a" /* default */].DEPTH_STENCIL_ATTACHMENT) { - var extension = renderer.getGLExtension('WEBGL_depth_texture'); - - if (!extension) { - console.error('Depth texture is not supported by the browser'); - canAttach = false; - } - if (texture.format !== __WEBPACK_IMPORTED_MODULE_3__core_glenum__["a" /* default */].DEPTH_COMPONENT - && texture.format !== __WEBPACK_IMPORTED_MODULE_3__core_glenum__["a" /* default */].DEPTH_STENCIL - ) { - console.error('The texture attached to depth buffer is not a valid.'); - canAttach = false; - } - - // Dispose render buffer created previous - if (canAttach) { - var renderbuffer = this._cache.get(KEY_RENDERBUFFER); - if (renderbuffer) { - _gl.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, null); - _gl.deleteRenderbuffer(renderbuffer); - this._cache.put(KEY_RENDERBUFFER, false); - } - - this._cache.put(KEY_RENDERBUFFER_ATTACHED, false); - this._cache.put(KEY_DEPTHTEXTURE_ATTACHED, true); - } - } - - // Mipmap level can only be 0 - _gl.framebufferTexture2D(GL_FRAMEBUFFER, attachment, target, webglTexture, 0); - - if (!attachedTextures) { - attachedTextures = {}; - this._cache.put('attached_textures', attachedTextures); - } - attachedTextures[attachment] = attachedTextures[attachment] || {}; - attachedTextures[attachment].texture = texture; - attachedTextures[attachment].target = target; - - return canAttach; - }, - - _doDetach: function (_gl, attachment, target) { - // Detach a texture from framebuffer - // https://github.com/KhronosGroup/WebGL/blob/master/conformance-suites/1.0.0/conformance/framebuffer-test.html#L145 - _gl.framebufferTexture2D(GL_FRAMEBUFFER, attachment, target, null, 0); - - // Assume cache has been used. - var attachedTextures = this._cache.get('attached_textures'); - if (attachedTextures && attachedTextures[attachment]) { - attachedTextures[attachment] = null; - } - - if (attachment === GL_DEPTH_ATTACHMENT || attachment === __WEBPACK_IMPORTED_MODULE_3__core_glenum__["a" /* default */].DEPTH_STENCIL_ATTACHMENT) { - this._cache.put(KEY_DEPTHTEXTURE_ATTACHED, false); - } - }, - - /** - * Detach a texture - * @param {number} [attachment=gl.COLOR_ATTACHMENT0] - * @param {number} [target=gl.TEXTURE_2D] - */ - detach: function (attachment, target) { - // TODO depth extension check ? - this._textures[attachment] = null; - if (this._boundRenderer) { - var cache = this._cache; - cache.use(this._boundRenderer.__uid__); - this._doDetach(this._boundRenderer.gl, attachment, target); - } - }, - /** - * Dispose - * @param {WebGLRenderingContext} _gl - */ - dispose: function (renderer) { - - var _gl = renderer.gl; - var cache = this._cache; - - cache.use(renderer.__uid__); - - var renderBuffer = cache.get(KEY_RENDERBUFFER); - if (renderBuffer) { - _gl.deleteRenderbuffer(renderBuffer); - } - var frameBuffer = cache.get(KEY_FRAMEBUFFER); - if (frameBuffer) { - _gl.deleteFramebuffer(frameBuffer); - } - cache.deleteContext(renderer.__uid__); - - // Clear cache for reusing - this._textures = {}; - - } -}); - -FrameBuffer.DEPTH_ATTACHMENT = GL_DEPTH_ATTACHMENT; -FrameBuffer.COLOR_ATTACHMENT0 = GL_COLOR_ATTACHMENT0; -FrameBuffer.STENCIL_ATTACHMENT = __WEBPACK_IMPORTED_MODULE_3__core_glenum__["a" /* default */].STENCIL_ATTACHMENT; -FrameBuffer.DEPTH_STENCIL_ATTACHMENT = __WEBPACK_IMPORTED_MODULE_3__core_glenum__["a" /* default */].DEPTH_STENCIL_ATTACHMENT; - -/* harmony default export */ __webpack_exports__["a"] = (FrameBuffer); - - -/***/ }), -/* 12 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -var supportWebGL = true; -try { - var canvas = document.createElement('canvas'); - var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); - if (!gl) { - throw new Error(); - } -} catch (e) { - supportWebGL = false; -} - -var vendor = {}; - -/** - * If support WebGL - * @return {boolean} - */ -vendor.supportWebGL = function () { - return supportWebGL; -}; - - -vendor.Int8Array = typeof Int8Array == 'undefined' ? Array : Int8Array; - -vendor.Uint8Array = typeof Uint8Array == 'undefined' ? Array : Uint8Array; - -vendor.Uint16Array = typeof Uint16Array == 'undefined' ? Array : Uint16Array; - -vendor.Uint32Array = typeof Uint32Array == 'undefined' ? Array : Uint32Array; - -vendor.Int16Array = typeof Int16Array == 'undefined' ? Array : Int16Array; - -vendor.Float32Array = typeof Float32Array == 'undefined' ? Array : Float32Array; - -vendor.Float64Array = typeof Float64Array == 'undefined' ? Array : Float64Array; - -/* harmony default export */ __webpack_exports__["a"] = (vendor); - - -/***/ }), -/* 13 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__camera_Orthographic__ = __webpack_require__(23); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__geometry_Plane__ = __webpack_require__(33); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__Material__ = __webpack_require__(10); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__Mesh__ = __webpack_require__(16); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__core_glenum__ = __webpack_require__(6); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__shader_source_compositor_vertex_glsl_js__ = __webpack_require__(107); - - - - - - - - - -__WEBPACK_IMPORTED_MODULE_3__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_7__shader_source_compositor_vertex_glsl_js__["a" /* default */]); - -var planeGeo = new __WEBPACK_IMPORTED_MODULE_2__geometry_Plane__["a" /* default */](); -var mesh = new __WEBPACK_IMPORTED_MODULE_5__Mesh__["a" /* default */]({ - geometry: planeGeo, - frustumCulling: false -}); -var camera = new __WEBPACK_IMPORTED_MODULE_1__camera_Orthographic__["a" /* default */](); - -/** - * @constructor clay.compositor.Pass - * @extends clay.core.Base - */ -var Pass = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend(function () { - return /** @lends clay.compositor.Pass# */ { - /** - * Fragment shader string - * @type {string} - */ - // PENDING shader or fragment ? - fragment : '', - - /** - * @type {Object} - */ - outputs : null, - - /** - * @type {clay.Material} - */ - material : null, - - /** - * @type {Boolean} - */ - blendWithPrevious: false, - - /** - * @type {Boolean} - */ - clearColor: false, - - /** - * @type {Boolean} - */ - clearDepth: true - }; -}, function() { - - var shader = new __WEBPACK_IMPORTED_MODULE_3__Shader__["a" /* default */](__WEBPACK_IMPORTED_MODULE_3__Shader__["a" /* default */].source('clay.compositor.vertex'), this.fragment); - var material = new __WEBPACK_IMPORTED_MODULE_4__Material__["a" /* default */]({ - shader: shader - }); - material.enableTexturesAll(); - - this.material = material; - -}, -/** @lends clay.compositor.Pass.prototype */ -{ - /** - * @param {string} name - * @param {} value - */ - setUniform : function(name, value) { - this.material.setUniform(name, value); - }, - /** - * @param {string} name - * @return {} - */ - getUniform : function(name) { - var uniform = this.material.uniforms[name]; - if (uniform) { - return uniform.value; - } - }, - /** - * @param {clay.Texture} texture - * @param {number} attachment - */ - attachOutput : function(texture, attachment) { - if (!this.outputs) { - this.outputs = {}; - } - attachment = attachment || __WEBPACK_IMPORTED_MODULE_6__core_glenum__["a" /* default */].COLOR_ATTACHMENT0; - this.outputs[attachment] = texture; - }, - /** - * @param {clay.Texture} texture - */ - detachOutput : function(texture) { - for (var attachment in this.outputs) { - if (this.outputs[attachment] === texture) { - this.outputs[attachment] = null; - } - } - }, - - bind : function(renderer, frameBuffer) { - - if (this.outputs) { - for (var attachment in this.outputs) { - var texture = this.outputs[attachment]; - if (texture) { - frameBuffer.attach(texture, attachment); - } - } - } - - if (frameBuffer) { - frameBuffer.bind(renderer); - } - }, - - unbind : function(renderer, frameBuffer) { - frameBuffer.unbind(renderer); - }, - /** - * @param {clay.Renderer} renderer - * @param {clay.FrameBuffer} [frameBuffer] - */ - render : function(renderer, frameBuffer) { - - var _gl = renderer.gl; - - if (frameBuffer) { - this.bind(renderer, frameBuffer); - // MRT Support in chrome - // https://www.khronos.org/registry/webgl/sdk/tests/conformance/extensions/ext-draw-buffers.html - var ext = renderer.getGLExtension('EXT_draw_buffers'); - if (ext && this.outputs) { - var bufs = []; - for (var attachment in this.outputs) { - attachment = +attachment; - if (attachment >= _gl.COLOR_ATTACHMENT0 && attachment <= _gl.COLOR_ATTACHMENT0 + 8) { - bufs.push(attachment); - } - } - ext.drawBuffersEXT(bufs); - } - } - - this.trigger('beforerender', this, renderer); - - // FIXME Don't clear in each pass in default, let the color overwrite the buffer - // FIXME pixels may be discard - var clearBit = this.clearDepth ? _gl.DEPTH_BUFFER_BIT : 0; - _gl.depthMask(true); - if (this.clearColor) { - clearBit = clearBit | _gl.COLOR_BUFFER_BIT; - _gl.colorMask(true, true, true, true); - var cc = this.clearColor; - if (Array.isArray(cc)) { - _gl.clearColor(cc[0], cc[1], cc[2], cc[3]); - } - } - _gl.clear(clearBit); - - if (this.blendWithPrevious) { - // Blend with previous rendered scene in the final output - // FIXME Configure blend. - // FIXME It will cause screen blink? - _gl.enable(_gl.BLEND); - this.material.transparent = true; - } - else { - _gl.disable(_gl.BLEND); - this.material.transparent = false; - } - - this.renderQuad(renderer); - - this.trigger('afterrender', this, renderer); - - if (frameBuffer) { - this.unbind(renderer, frameBuffer); - } - }, - - /** - * Simply do quad rendering - */ - renderQuad: function (renderer) { - mesh.material = this.material; - renderer.renderPass([mesh], camera); - }, - - /** - * @param {clay.Renderer} renderer - */ - dispose: function (renderer) {} -}); - -/* harmony default export */ __webpack_exports__["a"] = (Pass); - - -/***/ }), -/* 14 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Node__ = __webpack_require__(15); - - -/** - * @constructor clay.Light - * @extends clay.Node - */ -var Light = __WEBPACK_IMPORTED_MODULE_0__Node__["a" /* default */].extend(function(){ - return /** @lends clay.Light# */ { - /** - * Light RGB color - * @type {number[]} - */ - color: [1, 1, 1], - - /** - * Light intensity - * @type {number} - */ - intensity: 1.0, - - // Config for shadow map - /** - * If light cast shadow - * @type {boolean} - */ - castShadow: true, - - /** - * Shadow map size - * @type {number} - */ - shadowResolution: 512, - - /** - * Light group, shader with same `lightGroup` will be affected - * - * Only useful in forward rendering - * @type {number} - */ - group: 0 - }; -}, -/** @lends clay.Light.prototype. */ -{ - /** - * Light type - * @type {string} - * @memberOf clay.Light# - */ - type: '', - - /** - * @return {clay.Light} - * @memberOf clay.Light.prototype - */ - clone: function() { - var light = __WEBPACK_IMPORTED_MODULE_0__Node__["a" /* default */].prototype.clone.call(this); - light.color = Array.prototype.slice.call(this.color); - light.intensity = this.intensity; - light.castShadow = this.castShadow; - light.shadowResolution = this.shadowResolution; - - return light; - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (Light); - - -/***/ }), -/* 15 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__math_Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__math_Quaternion__ = __webpack_require__(78); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__math_Matrix4__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4__dep_glmatrix__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__math_BoundingBox__ = __webpack_require__(8); - - - - - - -var mat4 = __WEBPACK_IMPORTED_MODULE_4__dep_glmatrix___default.a.mat4; - -var nameId = 0; - -/** - * @constructor clay.Node - * @extends clay.core.Base - */ -var Node = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend( -/** @lends clay.Node# */ -{ - /** - * Scene node name - * @type {string} - */ - name: '', - - /** - * Position relative to its parent node. aka translation. - * @type {clay.math.Vector3} - */ - position: null, - - /** - * Rotation relative to its parent node. Represented by a quaternion - * @type {clay.math.Quaternion} - */ - rotation: null, - - /** - * Scale relative to its parent node - * @type {clay.math.Vector3} - */ - scale: null, - - /** - * Affine transform matrix relative to its root scene. - * @type {clay.math.Matrix4} - */ - worldTransform: null, - - /** - * Affine transform matrix relative to its parent node. - * Composited with position, rotation and scale. - * @type {clay.math.Matrix4} - */ - localTransform: null, - - /** - * If the local transform is update from SRT(scale, rotation, translation, which is position here) each frame - * @type {boolean} - */ - autoUpdateLocalTransform: true, - - /** - * Parent of current scene node - * @type {?clay.Node} - * @private - */ - _parent: null, - /** - * The root scene mounted. Null if it is a isolated node - * @type {?clay.Scene} - * @private - */ - _scene: null, - /** - * @type {boolean} - * @private - */ - _needsUpdateWorldTransform: true, - /** - * @type {boolean} - * @private - */ - _inIterating: false, - - // Depth for transparent list sorting - __depth: 0 - -}, function () { - - if (!this.name) { - this.name = (this.type || 'NODE') + '_' + (nameId++); - } - - if (!this.position) { - this.position = new __WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */](); - } - if (!this.rotation) { - this.rotation = new __WEBPACK_IMPORTED_MODULE_2__math_Quaternion__["a" /* default */](); - } - if (!this.scale) { - this.scale = new __WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */](1, 1, 1); - } - - this.worldTransform = new __WEBPACK_IMPORTED_MODULE_3__math_Matrix4__["a" /* default */](); - this.localTransform = new __WEBPACK_IMPORTED_MODULE_3__math_Matrix4__["a" /* default */](); - - this._children = []; - -}, -/**@lends clay.Node.prototype. */ -{ - - /** - * @type {?clay.math.Vector3} - * @instance - */ - target: null, - /** - * If node and its chilren invisible - * @type {boolean} - * @instance - */ - invisible: false, - - /** - * If Node is a skinned mesh - * @return {boolean} - */ - isSkinnedMesh: function () { - return false; - }, - /** - * Return true if it is a renderable scene node, like Mesh and ParticleSystem - * @return {boolean} - */ - isRenderable: function () { - return false; - }, - - /** - * Set the name of the scene node - * @param {string} name - */ - setName: function (name) { - var scene = this._scene; - if (scene) { - var nodeRepository = scene._nodeRepository; - delete nodeRepository[this.name]; - nodeRepository[name] = this; - } - this.name = name; - }, - - /** - * Add a child node - * @param {clay.Node} node - */ - add: function (node) { - if (this._inIterating) { - console.warn('Add operation can cause unpredictable error when in iterating'); - } - var originalParent = node._parent; - if (originalParent === this) { - return; - } - if (originalParent) { - originalParent.remove(node); - } - node._parent = this; - this._children.push(node); - - var scene = this._scene; - if (scene && scene !== node.scene) { - node.traverse(this._addSelfToScene, this); - } - // Mark children needs update transform - // In case child are remove and added again after parent moved - node._needsUpdateWorldTransform = true; - }, - - /** - * Remove the given child scene node - * @param {clay.Node} node - */ - remove: function (node) { - if (this._inIterating) { - console.warn('Remove operation can cause unpredictable error when in iterating'); - } - var children = this._children; - var idx = children.indexOf(node); - if (idx < 0) { - return; - } - - children.splice(idx, 1); - node._parent = null; - - if (this._scene) { - node.traverse(this._removeSelfFromScene, this); - } - }, - - /** - * Remove all children - */ - removeAll: function () { - var children = this._children; - - for (var idx = 0; idx < children.length; idx++) { - children[idx]._parent = null; - - if (this._scene) { - children[idx].traverse(this._removeSelfFromScene, this); - } - } - - this._children = []; - }, - - /** - * Get the scene mounted - * @return {clay.Scene} - */ - getScene: function () { - return this._scene; - }, - - /** - * Get parent node - * @return {clay.Scene} - */ - getParent: function () { - return this._parent; - }, - - _removeSelfFromScene: function (descendant) { - descendant._scene.removeFromScene(descendant); - descendant._scene = null; - }, - - _addSelfToScene: function (descendant) { - this._scene.addToScene(descendant); - descendant._scene = this._scene; - }, - - /** - * Return true if it is ancestor of the given scene node - * @param {clay.Node} node - */ - isAncestor: function (node) { - var parent = node._parent; - while(parent) { - if (parent === this) { - return true; - } - parent = parent._parent; - } - return false; - }, - - /** - * Get a new created array of all children nodes - * @return {clay.Node[]} - */ - children: function () { - return this._children.slice(); - }, - - /** - * Get child scene node at given index. - * @param {number} idx - * @return {clay.Node} - */ - childAt: function (idx) { - return this._children[idx]; - }, - - /** - * Get first child with the given name - * @param {string} name - * @return {clay.Node} - */ - getChildByName: function (name) { - var children = this._children; - for (var i = 0; i < children.length; i++) { - if (children[i].name === name) { - return children[i]; - } - } - }, - - /** - * Get first descendant have the given name - * @param {string} name - * @return {clay.Node} - */ - getDescendantByName: function (name) { - var children = this._children; - for (var i = 0; i < children.length; i++) { - var child = children[i]; - if (child.name === name) { - return child; - } else { - var res = child.getDescendantByName(name); - if (res) { - return res; - } - } - } - }, - - /** - * Query descendant node by path - * @param {string} path - * @return {clay.Node} - * @example - * node.queryNode('root/parent/child'); - */ - queryNode: function (path) { - if (!path) { - return; - } - // TODO Name have slash ? - var pathArr = path.split('/'); - var current = this; - for (var i = 0; i < pathArr.length; i++) { - var name = pathArr[i]; - // Skip empty - if (!name) { - continue; - } - var found = false; - var children = current._children; - for (var j = 0; j < children.length; j++) { - var child = children[j]; - if (child.name === name) { - current = child; - found = true; - break; - } - } - // Early return if not found - if (!found) { - return; - } - } - - return current; - }, - - /** - * Get query path, relative to rootNode(default is scene) - * @param {clay.Node} [rootNode] - * @return {string} - */ - getPath: function (rootNode) { - if (!this._parent) { - return '/'; - } - - var current = this._parent; - var path = this.name; - while (current._parent) { - path = current.name + '/' + path; - if (current._parent == rootNode) { - break; - } - current = current._parent; - } - if (!current._parent && rootNode) { - return null; - } - return path; - }, - - /** - * Depth first traverse all its descendant scene nodes and - * @param {Function} callback - * @param {Node} [context] - * @param {Function} [filter] - */ - traverse: function (callback, context, filter) { - - this._inIterating = true; - - if (!filter || filter.call(context, this)) { - callback.call(context, this); - } - var _children = this._children; - for(var i = 0, len = _children.length; i < len; i++) { - _children[i].traverse(callback, context, filter); - } - - this._inIterating = false; - }, - - eachChild: function (callback, context, ctor) { - this._inIterating = true; - - var _children = this._children; - var noCtor = ctor == null; - for(var i = 0, len = _children.length; i < len; i++) { - var child = _children[i]; - if (noCtor || child.constructor === ctor) { - callback.call(context, child, i); - } - } - - this._inIterating = false; - }, - - /** - * Set the local transform and decompose to SRT - * @param {clay.math.Matrix4} matrix - */ - setLocalTransform: function (matrix) { - mat4.copy(this.localTransform.array, matrix.array); - this.decomposeLocalTransform(); - }, - - /** - * Decompose the local transform to SRT - */ - decomposeLocalTransform: function (keepScale) { - var scale = !keepScale ? this.scale: null; - this.localTransform.decomposeMatrix(scale, this.rotation, this.position); - }, - - /** - * Set the world transform and decompose to SRT - * @param {clay.math.Matrix4} matrix - */ - setWorldTransform: function (matrix) { - mat4.copy(this.worldTransform.array, matrix.array); - this.decomposeWorldTransform(); - }, - - /** - * Decompose the world transform to SRT - * @function - */ - decomposeWorldTransform: (function () { - - var tmp = mat4.create(); - - return function (keepScale) { - var localTransform = this.localTransform; - var worldTransform = this.worldTransform; - // Assume world transform is updated - if (this._parent) { - mat4.invert(tmp, this._parent.worldTransform.array); - mat4.multiply(localTransform.array, tmp, worldTransform.array); - } else { - mat4.copy(localTransform.array, worldTransform.array); - } - var scale = !keepScale ? this.scale: null; - localTransform.decomposeMatrix(scale, this.rotation, this.position); - }; - })(), - - transformNeedsUpdate: function () { - return this.position._dirty - || this.rotation._dirty - || this.scale._dirty; - }, - - /** - * Update local transform from SRT - * Notice that local transform will not be updated if _dirty mark of position, rotation, scale is all false - */ - updateLocalTransform: function () { - var position = this.position; - var rotation = this.rotation; - var scale = this.scale; - - if (this.transformNeedsUpdate()) { - var m = this.localTransform.array; - - // Transform order, scale->rotation->position - mat4.fromRotationTranslation(m, rotation.array, position.array); - - mat4.scale(m, m, scale.array); - - rotation._dirty = false; - scale._dirty = false; - position._dirty = false; - - this._needsUpdateWorldTransform = true; - } - }, - - /** - * Update world transform, assume its parent world transform have been updated - * @private - */ - _updateWorldTransformTopDown: function () { - var localTransform = this.localTransform.array; - var worldTransform = this.worldTransform.array; - if (this._parent) { - mat4.multiplyAffine( - worldTransform, - this._parent.worldTransform.array, - localTransform - ); - } - else { - mat4.copy(worldTransform, localTransform); - } - }, - - /** - * Update world transform before whole scene is updated. - */ - updateWorldTransform: function () { - // Find the root node which transform needs update; - var rootNodeIsDirty = this; - while (rootNodeIsDirty && rootNodeIsDirty.getParent() - && rootNodeIsDirty.getParent().transformNeedsUpdate() - ) { - rootNodeIsDirty = rootNodeIsDirty.getParent(); - }2 - rootNodeIsDirty.update(); - }, - - /** - * Update local transform and world transform recursively - * @param {boolean} forceUpdateWorld - */ - update: function (forceUpdateWorld) { - if (this.autoUpdateLocalTransform) { - this.updateLocalTransform(); - } - else { - // Transform is manually setted - forceUpdateWorld = true; - } - - if (forceUpdateWorld || this._needsUpdateWorldTransform) { - this._updateWorldTransformTopDown(); - forceUpdateWorld = true; - this._needsUpdateWorldTransform = false; - } - - var children = this._children; - for(var i = 0, len = children.length; i < len; i++) { - children[i].update(forceUpdateWorld); - } - }, - - /** - * Get bounding box of node - * @param {Function} [filter] - * @param {clay.math.BoundingBox} [out] - * @return {clay.math.BoundingBox} - */ - // TODO Skinning - getBoundingBox: (function () { - function defaultFilter (el) { - return !el.invisible && el.geometry; - } - var tmpBBox = new __WEBPACK_IMPORTED_MODULE_5__math_BoundingBox__["a" /* default */](); - var tmpMat4 = new __WEBPACK_IMPORTED_MODULE_3__math_Matrix4__["a" /* default */](); - var invWorldTransform = new __WEBPACK_IMPORTED_MODULE_3__math_Matrix4__["a" /* default */](); - return function (filter, out) { - out = out || new __WEBPACK_IMPORTED_MODULE_5__math_BoundingBox__["a" /* default */](); - filter = filter || defaultFilter; - - if (this._parent) { - __WEBPACK_IMPORTED_MODULE_3__math_Matrix4__["a" /* default */].invert(invWorldTransform, this._parent.worldTransform); - } - else { - __WEBPACK_IMPORTED_MODULE_3__math_Matrix4__["a" /* default */].identity(invWorldTransform); - } - - this.traverse(function (mesh) { - if (mesh.geometry && mesh.geometry.boundingBox) { - tmpBBox.copy(mesh.geometry.boundingBox); - __WEBPACK_IMPORTED_MODULE_3__math_Matrix4__["a" /* default */].multiply(tmpMat4, invWorldTransform, mesh.worldTransform); - tmpBBox.applyTransform(tmpMat4); - out.union(tmpBBox); - } - }, this, defaultFilter); - - return out; - }; - })(), - - /** - * Get world position, extracted from world transform - * @param {clay.math.Vector3} [out] - * @return {clay.math.Vector3} - */ - getWorldPosition: function (out) { - // PENDING - if (this.transformNeedsUpdate()) { - this.updateWorldTransform(); - } - var m = this.worldTransform.array; - if (out) { - var arr = out.array; - arr[0] = m[12]; - arr[1] = m[13]; - arr[2] = m[14]; - return out; - } - else { - return new __WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */](m[12], m[13], m[14]); - } - }, - - /** - * Clone a new node - * @return {Node} - */ - clone: function () { - var node = new this.constructor(); - var children = this._children; - - node.setName(this.name); - node.position.copy(this.position); - node.rotation.copy(this.rotation); - node.scale.copy(this.scale); - - for (var i = 0; i < children.length; i++) { - node.add(children[i].clone()); - } - return node; - }, - - /** - * Rotate the node around a axis by angle degrees, axis passes through point - * @param {clay.math.Vector3} point Center point - * @param {clay.math.Vector3} axis Center axis - * @param {number} angle Rotation angle - * @see http://docs.unity3d.com/Documentation/ScriptReference/Transform.RotateAround.html - * @function - */ - rotateAround: (function () { - var v = new __WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */](); - var RTMatrix = new __WEBPACK_IMPORTED_MODULE_3__math_Matrix4__["a" /* default */](); - - // TODO improve performance - return function (point, axis, angle) { - - v.copy(this.position).subtract(point); - - var localTransform = this.localTransform; - localTransform.identity(); - // parent node - localTransform.translate(point); - localTransform.rotate(angle, axis); - - RTMatrix.fromRotationTranslation(this.rotation, v); - localTransform.multiply(RTMatrix); - localTransform.scale(this.scale); - - this.decomposeLocalTransform(); - this._needsUpdateWorldTransform = true; - }; - })(), - - /** - * @param {clay.math.Vector3} target - * @param {clay.math.Vector3} [up] - * @see http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml - * @function - */ - lookAt: (function () { - var m = new __WEBPACK_IMPORTED_MODULE_3__math_Matrix4__["a" /* default */](); - return function (target, up) { - m.lookAt(this.position, target, up || this.localTransform.y).invert(); - this.setLocalTransform(m); - - this.target = target; - }; - })() -}); - -/* harmony default export */ __webpack_exports__["a"] = (Node); - - -/***/ }), -/* 16 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Renderable__ = __webpack_require__(46); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_glenum__ = __webpack_require__(6); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Texture2D__ = __webpack_require__(5); - - - - -/** - * @constructor clay.Mesh - * @extends clay.Renderable - */ -var Mesh = __WEBPACK_IMPORTED_MODULE_0__Renderable__["a" /* default */].extend( -/** @lends clay.Mesh# */ -{ - /** - * Used when it is a skinned mesh - * @type {clay.Skeleton} - */ - skeleton: null, - /** - * Joints indices Meshes can share the one skeleton instance and each mesh can use one part of joints. Joints indices indicate the index of joint in the skeleton instance - * @type {number[]} - */ - joints: null, - - /** - * If store the skin matrices in vertex texture - * @type {bool} - */ - useSkinMatricesTexture: false - -}, function () { - if (!this.joints) { - this.joints = []; - } -}, { - - isSkinnedMesh: function () { - return !!(this.skeleton && this.joints && this.joints.length > 0); - }, - - render: function (renderer, shader, program) { - var _gl = renderer.gl; - // Set pose matrices of skinned mesh - if (this.skeleton) { - // TODO Multiple mesh share same skeleton - this.skeleton.update(); - - var skinMatricesArray = this.skeleton.getSubSkinMatrices(this.__uid__, this.joints); - - // if (this.useSkinMatricesTexture) { - // var size; - // var numJoints = this.joints.length; - // if (numJoints > 256) { - // size = 64; - // } - // else if (numJoints > 64) { - // size = 32; - // } - // else if (numJoints > 16) { - // size = 16; - // } - // else { - // size = 8; - // } - - // var texture = this.getSkinMatricesTexture(); - // texture.width = size; - // texture.height = size; - - // if (!texture.pixels || texture.pixels.length !== size * size * 4) { - // texture.pixels = new Float32Array(size * size * 4); - // } - // texture.pixels.set(skinMatricesArray); - // texture.dirty(); - - // shader.setUniform(_gl, '1f', 'skinMatricesTextureSize', size); - // } - // else { - program.setUniformOfSemantic(_gl, 'SKIN_MATRIX', skinMatricesArray); - // } - } - - return __WEBPACK_IMPORTED_MODULE_0__Renderable__["a" /* default */].prototype.render.call(this, renderer, shader, program); - }, - - getSkinMatricesTexture: function () { - this._skinMatricesTexture = this._skinMatricesTexture || new __WEBPACK_IMPORTED_MODULE_2__Texture2D__["a" /* default */]({ - type: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].FLOAT, - minFilter: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].NEAREST, - magFilter: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].NEAREST, - useMipmap: false, - flipY: false - }); - - return this._skinMatricesTexture; - } -}); - -// Enums -Mesh.POINTS = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].POINTS; -Mesh.LINES = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINES; -Mesh.LINE_LOOP = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINE_LOOP; -Mesh.LINE_STRIP = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINE_STRIP; -Mesh.TRIANGLES = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].TRIANGLES; -Mesh.TRIANGLE_STRIP = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].TRIANGLE_STRIP; -Mesh.TRIANGLE_FAN = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].TRIANGLE_FAN; - -Mesh.BACK = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].BACK; -Mesh.FRONT = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].FRONT; -Mesh.FRONT_AND_BACK = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].FRONT_AND_BACK; -Mesh.CW = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].CW; -Mesh.CCW = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].CCW; - -/* harmony default export */ __webpack_exports__["a"] = (Mesh); - - -/***/ }), -/* 17 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_glenum__ = __webpack_require__(6); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__core_util__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__math_util__ = __webpack_require__(47); - - - - -var isPowerOfTwo = __WEBPACK_IMPORTED_MODULE_3__math_util__["a" /* default */].isPowerOfTwo; - -var targetList = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; - -/** - * @constructor clay.TextureCube - * @extends clay.Texture - * - * @example - * ... - * var mat = new clay.Material({ - * shader: clay.shader.library.get('clay.phong', 'environmentMap') - * }); - * var envMap = new clay.TextureCube(); - * envMap.load({ - * 'px': 'assets/textures/sky/px.jpg', - * 'nx': 'assets/textures/sky/nx.jpg' - * 'py': 'assets/textures/sky/py.jpg' - * 'ny': 'assets/textures/sky/ny.jpg' - * 'pz': 'assets/textures/sky/pz.jpg' - * 'nz': 'assets/textures/sky/nz.jpg' - * }); - * mat.set('environmentMap', envMap); - * ... - * envMap.success(function () { - * // Wait for the sky texture loaded - * animation.on('frame', function (frameTime) { - * renderer.render(scene, camera); - * }); - * }); - */ -var TextureCube = __WEBPACK_IMPORTED_MODULE_0__Texture__["a" /* default */].extend(function () { - return /** @lends clay.TextureCube# */{ - - /** - * @type {boolean} - * @default false - */ - // PENDING cubemap should not flipY in default. - // flipY: false, - - /** - * @type {Object} - * @property {?HTMLImageElement|HTMLCanvasElemnet} px - * @property {?HTMLImageElement|HTMLCanvasElemnet} nx - * @property {?HTMLImageElement|HTMLCanvasElemnet} py - * @property {?HTMLImageElement|HTMLCanvasElemnet} ny - * @property {?HTMLImageElement|HTMLCanvasElemnet} pz - * @property {?HTMLImageElement|HTMLCanvasElemnet} nz - */ - image: { - px: null, - nx: null, - py: null, - ny: null, - pz: null, - nz: null - }, - /** - * Pixels data of each side. Will be ignored if images are set. - * @type {Object} - * @property {?Uint8Array} px - * @property {?Uint8Array} nx - * @property {?Uint8Array} py - * @property {?Uint8Array} ny - * @property {?Uint8Array} pz - * @property {?Uint8Array} nz - */ - pixels: { - px: null, - nx: null, - py: null, - ny: null, - pz: null, - nz: null - }, - - /** - * @type {Array.} - */ - mipmaps: [] - }; -}, { - update: function (renderer) { - var _gl = renderer.gl; - _gl.bindTexture(_gl.TEXTURE_CUBE_MAP, this._cache.get('webgl_texture')); - - this.updateCommon(renderer); - - var glFormat = this.format; - var glType = this.type; - - _gl.texParameteri(_gl.TEXTURE_CUBE_MAP, _gl.TEXTURE_WRAP_S, this.getAvailableWrapS()); - _gl.texParameteri(_gl.TEXTURE_CUBE_MAP, _gl.TEXTURE_WRAP_T, this.getAvailableWrapT()); - - _gl.texParameteri(_gl.TEXTURE_CUBE_MAP, _gl.TEXTURE_MAG_FILTER, this.getAvailableMagFilter()); - _gl.texParameteri(_gl.TEXTURE_CUBE_MAP, _gl.TEXTURE_MIN_FILTER, this.getAvailableMinFilter()); - - var anisotropicExt = renderer.getGLExtension('EXT_texture_filter_anisotropic'); - if (anisotropicExt && this.anisotropic > 1) { - _gl.texParameterf(_gl.TEXTURE_CUBE_MAP, anisotropicExt.TEXTURE_MAX_ANISOTROPY_EXT, this.anisotropic); - } - - // Fallback to float type if browser don't have half float extension - if (glType === 36193) { - var halfFloatExt = renderer.getGLExtension('OES_texture_half_float'); - if (!halfFloatExt) { - glType = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].FLOAT; - } - } - - if (this.mipmaps.length) { - var width = this.width; - var height = this.height; - for (var i = 0; i < this.mipmaps.length; i++) { - var mipmap = this.mipmaps[i]; - this._updateTextureData(_gl, mipmap, i, width, height, glFormat, glType); - width /= 2; - height /= 2; - } - } - else { - this._updateTextureData(_gl, this, 0, this.width, this.height, glFormat, glType); - - if (!this.NPOT && this.useMipmap) { - _gl.generateMipmap(_gl.TEXTURE_CUBE_MAP); - } - } - - _gl.bindTexture(_gl.TEXTURE_CUBE_MAP, null); - }, - - _updateTextureData: function (_gl, data, level, width, height, glFormat, glType) { - for (var i = 0; i < 6; i++) { - var target = targetList[i]; - var img = data.image && data.image[target]; - if (img) { - _gl.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level, glFormat, glFormat, glType, img); - } - else { - _gl.texImage2D(_gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level, glFormat, width, height, 0, glFormat, glType, data.pixels && data.pixels[target]); - } - } - }, - - /** - * @param {clay.Renderer} renderer - * @memberOf clay.TextureCube.prototype - */ - generateMipmap: function (renderer) { - var _gl = renderer.gl; - if (this.useMipmap && !this.NPOT) { - _gl.bindTexture(_gl.TEXTURE_CUBE_MAP, this._cache.get('webgl_texture')); - _gl.generateMipmap(_gl.TEXTURE_CUBE_MAP); - } - }, - - bind: function (renderer) { - renderer.gl.bindTexture(renderer.gl.TEXTURE_CUBE_MAP, this.getWebGLTexture(renderer)); - }, - - unbind: function (renderer) { - renderer.gl.bindTexture(renderer.gl.TEXTURE_CUBE_MAP, null); - }, - - // Overwrite the isPowerOfTwo method - isPowerOfTwo: function () { - if (this.image.px) { - return isPowerOfTwo(this.image.px.width) - && isPowerOfTwo(this.image.px.height); - } - else { - return isPowerOfTwo(this.width) - && isPowerOfTwo(this.height); - } - }, - - isRenderable: function () { - if (this.image.px) { - return isImageRenderable(this.image.px) - && isImageRenderable(this.image.nx) - && isImageRenderable(this.image.py) - && isImageRenderable(this.image.ny) - && isImageRenderable(this.image.pz) - && isImageRenderable(this.image.nz); - } - else { - return !!(this.width && this.height); - } - }, - - load: function (imageList, crossOrigin) { - var loading = 0; - var self = this; - __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].each(imageList, function (src, target){ - var image = new Image(); - if (crossOrigin) { - image.crossOrigin = crossOrigin; - } - image.onload = function () { - loading --; - if (loading === 0){ - self.dirty(); - self.trigger('success', self); - } - image.onload = null; - }; - image.onerror = function () { - loading --; - image.onerror = null; - }; - - loading++; - image.src = src; - self.image[target] = image; - }); - - return this; - } -}); - -Object.defineProperty(TextureCube.prototype, 'width', { - get: function () { - if (this.image && this.image.px) { - return this.image.px.width; - } - return this._width; - }, - set: function (value) { - if (this.image && this.image.px) { - console.warn('Texture from image can\'t set width'); - } - else { - if (this._width !== value) { - this.dirty(); - } - this._width = value; - } - } -}); -Object.defineProperty(TextureCube.prototype, 'height', { - get: function () { - if (this.image && this.image.px) { - return this.image.px.height; - } - return this._height; - }, - set: function (value) { - if (this.image && this.image.px) { - console.warn('Texture from image can\'t set height'); - } - else { - if (this._height !== value) { - this.dirty(); - } - this._height = value; - } - } -}); -function isImageRenderable(image) { - return image.nodeName === 'CANVAS' || - image.nodeName === 'VIDEO' || - image.complete; -} - -/* harmony default export */ __webpack_exports__["a"] = (TextureCube); - - -/***/ }), -/* 18 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Node__ = __webpack_require__(15); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Light__ = __webpack_require__(14); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Camera__ = __webpack_require__(30); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__math_BoundingBox__ = __webpack_require__(8); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__core_util__ = __webpack_require__(7); - - - - - - -var programKeyCache = {}; - -function getProgramKey(lightNumbers) { - var defineStr = []; - var lightTypes = Object.keys(lightNumbers); - lightTypes.sort(); - for (var i = 0; i < lightTypes.length; i++) { - var lightType = lightNumbers[i]; - defineStr.push(lightType + ' ' + lightNumbers[lightType]); - } - var key = defineStr.join('\n'); - - if (programKeyCache[key]) { - return programKeyCache[key]; - } - - var id = __WEBPACK_IMPORTED_MODULE_4__core_util__["a" /* default */].genGUID(); - programKeyCache[key] = id; - return id; -} - -/** - * @constructor clay.Scene - * @extends clay.Node - */ -var Scene = __WEBPACK_IMPORTED_MODULE_0__Node__["a" /* default */].extend(function () { - return /** @lends clay.Scene# */ { - /** - * Global material of scene - * @type {clay.Material} - */ - material: null, - - /** - * @type {boolean} - */ - autoUpdate: true, - - /** - * Opaque renderable list, it will be updated automatically - * @type {clay.Renderable[]} - * @readonly - */ - opaqueList: [], - - /** - * Opaque renderable list, it will be updated automatically - * @type {clay.Renderable[]} - * @readonly - */ - transparentList: [], - - lights: [], - - - /** - * Scene bounding box in view space. - * Used when camera needs to adujst the near and far plane automatically - * so that the view frustum contains the visible objects as tightly as possible. - * Notice: - * It is updated after rendering (in the step of frustum culling passingly). So may be not so accurate, but saves a lot of calculation - * - * @type {clay.math.BoundingBox} - */ - viewBoundingBoxLastFrame: new __WEBPACK_IMPORTED_MODULE_3__math_BoundingBox__["a" /* default */](), - - // Uniforms for shadow map. - shadowUniforms: {}, - - _cameraList: [], - - // Properties to save the light information in the scene - // Will be set in the render function - _lightUniforms: {}, - - _previousLightNumber: {}, - - _lightNumber: { - // groupId: { - // POINT_LIGHT: 0, - // DIRECTIONAL_LIGHT: 0, - // SPOT_LIGHT: 0, - // AMBIENT_LIGHT: 0, - // AMBIENT_SH_LIGHT: 0 - // } - }, - - _lightProgramKeys: {}, - - _opaqueObjectCount: 0, - _transparentObjectCount: 0, - - _nodeRepository: {}, - - }; -}, function () { - this._scene = this; -}, -/** @lends clay.Scene.prototype. */ -{ - /** - * Add node to scene - * @param {Node} node - */ - addToScene: function (node) { - if (node instanceof __WEBPACK_IMPORTED_MODULE_2__Camera__["a" /* default */]) { - if (this._cameraList.length > 0) { - console.warn('Found multiple camera in one scene. Use the fist one.'); - } - this._cameraList.push(node); - } - if (node.name) { - this._nodeRepository[node.name] = node; - } - }, - - /** - * Remove node from scene - * @param {Node} node - */ - removeFromScene: function (node) { - if (node instanceof __WEBPACK_IMPORTED_MODULE_2__Camera__["a" /* default */]) { - var idx = this._cameraList.indexOf(node); - if (idx >= 0) { - this._cameraList.splice(idx, 1); - } - } - if (node.name) { - delete this._nodeRepository[node.name]; - } - }, - - /** - * Get node by name - * @param {string} name - * @return {Node} - * @DEPRECATED - */ - getNode: function (name) { - return this._nodeRepository[name]; - }, - - /** - * Clone a new scene node recursively, including material, skeleton. - * Shader and geometry instances will not been cloned - * @param {clay.Node} node - * @return {clay.Node} - */ - cloneNode: function (node) { - var newNode = node.clone(); - var materialsMap = {}; - - var cloneSkeleton = function (current, currentNew) { - if (current.skeleton) { - currentNew.skeleton = current.skeleton.clone(node, newNode); - currentNew.joints = current.joints.slice(); - } - if (current.material) { - materialsMap[current.material.__uid__] = { - oldMat: current.material - }; - } - for (var i = 0; i < current._children.length; i++) { - cloneSkeleton(current._children[i], currentNew._children[i]); - } - }; - - cloneSkeleton(node, newNode); - - for (var guid in materialsMap) { - materialsMap[guid].newMat = materialsMap[guid].oldMat.clone(); - } - - // Replace material - newNode.traverse(function (current) { - if (current.material) { - current.material = materialsMap[current.material.__uid__].newMat; - } - }); - - return newNode; - }, - - - /** - * Scene update - * @param {boolean} force - * @param {boolean} notUpdateLights - * Useful in deferred pipeline - */ - update: function (force, notUpdateLights) { - if (!(this.autoUpdate || force)) { - return; - } - __WEBPACK_IMPORTED_MODULE_0__Node__["a" /* default */].prototype.update.call(this, force); - - var lights = this.lights; - var sceneMaterialTransparent = this.material && this.material.transparent; - - this._opaqueObjectCount = 0; - this._transparentObjectCount = 0; - - lights.length = 0; - - this._updateRenderList(this, sceneMaterialTransparent); - - this.opaqueList.length = this._opaqueObjectCount; - this.transparentList.length = this._transparentObjectCount; - - // reset - if (!notUpdateLights) { - this._previousLightNumber = this._lightNumber; - - var lightNumber = {}; - for (var i = 0; i < lights.length; i++) { - var light = lights[i]; - var group = light.group; - if (!lightNumber[group]) { - lightNumber[group] = {}; - } - // User can use any type of light - lightNumber[group][light.type] = lightNumber[group][light.type] || 0; - lightNumber[group][light.type]++; - } - this._lightNumber = lightNumber; - - for (var groupId in lightNumber) { - this._lightProgramKeys[groupId] = getProgramKey(lightNumber[groupId]); - } - - this._updateLightUniforms(); - } - }, - - getMainCamera: function () { - return this._cameraList[0]; - }, - - // Traverse the scene and add the renderable - // object to the render list - _updateRenderList: function (parent, sceneMaterialTransparent) { - if (parent.invisible) { - return; - } - - for (var i = 0; i < parent._children.length; i++) { - var child = parent._children[i]; - - if (child instanceof __WEBPACK_IMPORTED_MODULE_1__Light__["a" /* default */]) { - this.lights.push(child); - } - else if (child.isRenderable()) { - if (child.material.transparent || sceneMaterialTransparent) { - this.transparentList[this._transparentObjectCount++] = child; - } - else { - this.opaqueList[this._opaqueObjectCount++] = child; - } - } - if (child._children.length > 0) { - this._updateRenderList(child); - } - } - }, - - _updateLightUniforms: function () { - var lights = this.lights; - // Put the light cast shadow before the light not cast shadow - lights.sort(lightSortFunc); - - var lightUniforms = this._lightUniforms; - for (var group in lightUniforms) { - for (var symbol in lightUniforms[group]) { - lightUniforms[group][symbol].value.length = 0; - } - } - for (var i = 0; i < lights.length; i++) { - - var light = lights[i]; - var group = light.group; - - for (var symbol in light.uniformTemplates) { - var uniformTpl = light.uniformTemplates[symbol]; - var value = uniformTpl.value(light); - if (value == null) { - continue; - } - if (!lightUniforms[group]) { - lightUniforms[group] = {}; - } - if (!lightUniforms[group][symbol]) { - lightUniforms[group][symbol] = { - type: '', - value: [] - }; - } - var lu = lightUniforms[group][symbol]; - lu.type = uniformTpl.type + 'v'; - switch (uniformTpl.type) { - case '1i': - case '1f': - case 't': - lu.value.push(value); - break; - case '2f': - case '3f': - case '4f': - for (var j = 0; j < value.length; j++) { - lu.value.push(value[j]); - } - break; - default: - console.error('Unkown light uniform type ' + uniformTpl.type); - } - } - } - }, - - getLightGroups: function () { - var lightGroups = []; - for (var groupId in this._lightNumber) { - lightGroups.push(groupId); - } - return lightGroups; - }, - - getNumberChangedLightGroups: function () { - var lightGroups = []; - for (var groupId in this._lightNumber) { - if (this.isLightNumberChanged(groupId)) { - lightGroups.push(groupId); - } - } - return lightGroups; - }, - - /** - * Determine if light group is different with since last frame - * Used to determine whether to update shader and scene's uniforms in Renderer.render - * @param {Shader} shader - * @returns {Boolean} - */ - isLightNumberChanged: function (lightGroup) { - var prevLightNumber = this._previousLightNumber; - var currentLightNumber = this._lightNumber; - // PENDING Performance - for (var type in currentLightNumber[lightGroup]) { - if (!prevLightNumber[lightGroup]) { - return true; - } - if (currentLightNumber[lightGroup][type] !== prevLightNumber[lightGroup][type]) { - return true; - } - } - for (var type in prevLightNumber[lightGroup]) { - if (!currentLightNumber[lightGroup]) { - return true; - } - if (currentLightNumber[lightGroup][type] !== prevLightNumber[lightGroup][type]) { - return true; - } - } - return false; - }, - - /** - * Set shader's light group with scene's - * @param {Shader} shader - */ - getLightsNumbers: function (lightGroup) { - return this._lightNumber[lightGroup]; - }, - - getProgramKey: function (lightGroup) { - return this._lightProgramKeys[lightGroup]; - }, - - setLightUniforms: (function () { - function setUniforms(uniforms, program, renderer) { - for (var symbol in uniforms) { - var lu = uniforms[symbol]; - if (lu.type === 'tv') { - if (!program.hasUniform(symbol)) { - continue; - } - var texSlots = []; - for (var i = 0; i < lu.value.length; i++) { - var texture = lu.value[i]; - var slot = program.takeCurrentTextureSlot(renderer, texture); - texSlots.push(slot); - } - program.setUniform(renderer.gl, '1iv', symbol, texSlots); - } - else { - program.setUniform(renderer.gl, lu.type, symbol, lu.value); - } - } - } - - return function (program, lightGroup, renderer) { - setUniforms(this._lightUniforms[lightGroup], program, renderer); - // Set shadows - setUniforms(this.shadowUniforms, program, renderer); - }; - })(), - - /** - * Dispose self, clear all the scene objects - * But resources of gl like texuture, shader will not be disposed. - * Mostly you should use disposeScene method in Renderer to do dispose. - */ - dispose: function () { - this.material = null; - this.opaqueList = []; - this.transparentList = []; - - this.lights = []; - - this._lightUniforms = {}; - - this._lightNumber = {}; - this._nodeRepository = {}; - } -}); - -function lightSortFunc(a, b) { - if (b.castShadow && !a.castShadow) { - return true; - } -} - -/* harmony default export */ __webpack_exports__["a"] = (Scene); - - -/***/ }), -/* 19 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_glenum__ = __webpack_require__(6); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__core_Cache__ = __webpack_require__(28); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__core_vendor__ = __webpack_require__(12); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4__dep_glmatrix__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__math_BoundingBox__ = __webpack_require__(8); - - - - - - - -var vec3 = __WEBPACK_IMPORTED_MODULE_4__dep_glmatrix___default.a.vec3; -var mat4 = __WEBPACK_IMPORTED_MODULE_4__dep_glmatrix___default.a.mat4; - -var vec3Create = vec3.create; -var vec3Add = vec3.add; -var vec3Set = vec3.set; - -function getArrayCtorByType (type) { - return ({ - 'byte': __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Int8Array, - 'ubyte': __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint8Array, - 'short': __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Int16Array, - 'ushort': __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint16Array - })[type] || __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Float32Array; -} - -function makeAttrKey(attrName) { - return 'attr_' + attrName; -} -/** - * Geometry attribute - * @alias clay.Geometry.Attribute - * @constructor - */ -function Attribute(name, type, size, semantic) { - /** - * Attribute name - * @type {string} - */ - this.name = name; - /** - * Attribute type - * Possible values: - * + `'byte'` - * + `'ubyte'` - * + `'short'` - * + `'ushort'` - * + `'float'` Most commonly used. - * @type {string} - */ - this.type = type; - /** - * Size of attribute component. 1 - 4. - * @type {number} - */ - this.size = size; - /** - * Semantic of this attribute. - * Possible values: - * + `'POSITION'` - * + `'NORMAL'` - * + `'BINORMAL'` - * + `'TANGENT'` - * + `'TEXCOORD'` - * + `'TEXCOORD_0'` - * + `'TEXCOORD_1'` - * + `'COLOR'` - * + `'JOINT'` - * + `'WEIGHT'` - * - * In shader, attribute with same semantic will be automatically mapped. For example: - * ```glsl - * attribute vec3 pos: POSITION - * ``` - * will use the attribute value with semantic POSITION in geometry, no matter what name it used. - * @type {string} - */ - this.semantic = semantic || ''; - - /** - * Value of the attribute. - * @type {TypedArray} - */ - this.value = null; - - // Init getter setter - switch (size) { - case 1: - this.get = function (idx) { - return this.value[idx]; - }; - this.set = function (idx, value) { - this.value[idx] = value; - }; - // Copy from source to target - this.copy = function (target, source) { - this.value[target] = this.value[target]; - }; - break; - case 2: - this.get = function (idx, out) { - var arr = this.value; - out[0] = arr[idx * 2]; - out[1] = arr[idx * 2 + 1]; - return out; - }; - this.set = function (idx, val) { - var arr = this.value; - arr[idx * 2] = val[0]; - arr[idx * 2 + 1] = val[1]; - }; - this.copy = function (target, source) { - var arr = this.value; - source *= 2; - target *= 2; - arr[target] = arr[source]; - arr[target + 1] = arr[source + 1]; - }; - break; - case 3: - this.get = function (idx, out) { - var idx3 = idx * 3; - var arr = this.value; - out[0] = arr[idx3]; - out[1] = arr[idx3 + 1]; - out[2] = arr[idx3 + 2]; - return out; - }; - this.set = function (idx, val) { - var idx3 = idx * 3; - var arr = this.value; - arr[idx3] = val[0]; - arr[idx3 + 1] = val[1]; - arr[idx3 + 2] = val[2]; - }; - this.copy = function (target, source) { - var arr = this.value; - source *= 3; - target *= 3; - arr[target] = arr[source]; - arr[target + 1] = arr[source + 1]; - arr[target + 2] = arr[source + 2]; - }; - break; - case 4: - this.get = function (idx, out) { - var arr = this.value; - var idx4 = idx * 4; - out[0] = arr[idx4]; - out[1] = arr[idx4 + 1]; - out[2] = arr[idx4 + 2]; - out[3] = arr[idx4 + 3]; - return out; - }; - this.set = function (idx, val) { - var arr = this.value; - var idx4 = idx * 4; - arr[idx4] = val[0]; - arr[idx4 + 1] = val[1]; - arr[idx4 + 2] = val[2]; - arr[idx4 + 3] = val[3]; - }; - this.copy = function (target, source) { - var arr = this.value; - source *= 4; - target *= 4; - // copyWithin is extremely slow - arr[target] = arr[source]; - arr[target + 1] = arr[source + 1]; - arr[target + 2] = arr[source + 2]; - arr[target + 3] = arr[source + 3]; - }; - } -} - -/** - * Set item value at give index. Second parameter val is number if size is 1 - * @function - * @name clay.Geometry.Attribute#set - * @param {number} idx - * @param {number[]|number} val - * @example - * geometry.getAttribute('position').set(0, [1, 1, 1]); - */ - -/** - * Get item value at give index. Second parameter out is no need if size is 1 - * @function - * @name clay.Geometry.Attribute#set - * @param {number} idx - * @param {number[]} [out] - * @example - * geometry.getAttribute('position').get(0, out); - */ - -/** - * Initialize attribute with given vertex count - * @param {number} nVertex - */ -Attribute.prototype.init = function (nVertex) { - if (!this.value || this.value.length != nVertex * this.size) { - var ArrayConstructor = getArrayCtorByType(this.type); - this.value = new ArrayConstructor(nVertex * this.size); - } -}; - -/** - * Initialize attribute with given array. Which can be 1 dimensional or 2 dimensional - * @param {Array} array - * @example - * geometry.getAttribute('position').fromArray( - * [-1, 0, 0, 1, 0, 0, 0, 1, 0] - * ); - * geometry.getAttribute('position').fromArray( - * [ [-1, 0, 0], [1, 0, 0], [0, 1, 0] ] - * ); - */ -Attribute.prototype.fromArray = function (array) { - var ArrayConstructor = getArrayCtorByType(this.type); - var value; - // Convert 2d array to flat - if (array[0] && (array[0].length)) { - var n = 0; - var size = this.size; - value = new ArrayConstructor(array.length * size); - for (var i = 0; i < array.length; i++) { - for (var j = 0; j < size; j++) { - value[n++] = array[i][j]; - } - } - } - else { - value = new ArrayConstructor(array); - } - this.value = value; -}; - -Attribute.prototype.clone = function(copyValue) { - var ret = new Attribute(this.name, this.type, this.size, this.semantic); - // FIXME - if (copyValue) { - console.warn('todo'); - } - return ret; -}; - -function AttributeBuffer(name, type, buffer, size, semantic) { - this.name = name; - this.type = type; - this.buffer = buffer; - this.size = size; - this.semantic = semantic; - - // To be set in mesh - // symbol in the shader - this.symbol = ''; - - // Needs remove flag - this.needsRemove = false; -} - -function IndicesBuffer(buffer) { - this.buffer = buffer; - this.count = 0; -} - -/** - * @constructor clay.Geometry - * @extends clay.core.Base - */ -var Geometry = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend(function () { - return /** @lends clay.Geometry# */ { - /** - * Attributes of geometry. Including: - * + `position` - * + `texcoord0` - * + `texcoord1` - * + `normal` - * + `tangent` - * + `color` - * + `weight` - * + `joint` - * + `barycentric` - * @type {Object} - */ - attributes: { - position: new Attribute('position', 'float', 3, 'POSITION'), - texcoord0: new Attribute('texcoord0', 'float', 2, 'TEXCOORD_0'), - texcoord1: new Attribute('texcoord1', 'float', 2, 'TEXCOORD_1'), - normal: new Attribute('normal', 'float', 3, 'NORMAL'), - tangent: new Attribute('tangent', 'float', 4, 'TANGENT'), - color: new Attribute('color', 'float', 4, 'COLOR'), - // Skinning attributes - // Each vertex can be bind to 4 bones, because the - // sum of weights is 1, so the weights is stored in vec3 and the last - // can be calculated by 1-w.x-w.y-w.z - weight: new Attribute('weight', 'float', 3, 'WEIGHT'), - joint: new Attribute('joint', 'float', 4, 'JOINT'), - // For wireframe display - // http://codeflow.org/entries/2012/aug/02/easy-wireframe-display-with-barycentric-coordinates/ - barycentric: new Attribute('barycentric', 'float', 3, null), - }, - /** - * Calculated bounding box of geometry. - * @type {clay.math.BoundingBox} - */ - boundingBox: null, - - /** - * Indices of geometry. - * @type {Uint16Array|Uint32Array} - */ - indices: null, - - /** - * Is vertices data dynamically updated. - * Attributes value can't be changed after first render if dyanmic is false. - * @type {boolean} - */ - dynamic: true, - - _enabledAttributes: null - }; -}, function() { - // Use cache - this._cache = new __WEBPACK_IMPORTED_MODULE_2__core_Cache__["a" /* default */](); - - this._attributeList = Object.keys(this.attributes); -}, -/** @lends clay.Geometry.prototype */ -{ - /** - * Main attribute will be used to count vertex number - * @type {string} - */ - mainAttribute: 'position', - /** - * User defined picking algorithm instead of default - * triangle ray intersection - * x, y are NDC. - * ```typescript - * (x, y, renderer, camera, renderable, out) => boolean - * ``` - * @type {?Function} - */ - pick: null, - - /** - * User defined ray picking algorithm instead of default - * triangle ray intersection - * ```typescript - * (ray: clay.math.Ray, renderable: clay.Renderable, out: Array) => boolean - * ``` - * @type {?Function} - */ - pickByRay: null, - - /** - * Update boundingBox of Geometry - */ - updateBoundingBox: function () { - var bbox = this.boundingBox; - if (!bbox) { - bbox = this.boundingBox = new __WEBPACK_IMPORTED_MODULE_5__math_BoundingBox__["a" /* default */](); - } - var posArr = this.attributes.position.value; - if (posArr && posArr.length) { - var min = bbox.min; - var max = bbox.max; - var minArr = min.array; - var maxArr = max.array; - vec3.set(minArr, posArr[0], posArr[1], posArr[2]); - vec3.set(maxArr, posArr[0], posArr[1], posArr[2]); - for (var i = 3; i < posArr.length;) { - var x = posArr[i++]; - var y = posArr[i++]; - var z = posArr[i++]; - if (x < minArr[0]) { minArr[0] = x; } - if (y < minArr[1]) { minArr[1] = y; } - if (z < minArr[2]) { minArr[2] = z; } - - if (x > maxArr[0]) { maxArr[0] = x; } - if (y > maxArr[1]) { maxArr[1] = y; } - if (z > maxArr[2]) { maxArr[2] = z; } - } - min._dirty = true; - max._dirty = true; - } - }, - /** - * Mark attributes and indices in geometry needs to update. - */ - dirty: function () { - var enabledAttributes = this.getEnabledAttributes(); - for (var i = 0; i < enabledAttributes.length; i++) { - this.dirtyAttribute(enabledAttributes[i]); - } - this.dirtyIndices(); - this._enabledAttributes = null; - - this._cache.dirty('any'); - }, - /** - * Mark the indices needs to update. - */ - dirtyIndices: function () { - this._cache.dirtyAll('indices'); - }, - /** - * Mark the attributes needs to update. - * @param {string} [attrName] - */ - dirtyAttribute: function (attrName) { - this._cache.dirtyAll(makeAttrKey(attrName)); - this._cache.dirtyAll('attributes'); - }, - /** - * Get indices of triangle at given index. - * @param {number} idx - * @param {Array.} out - * @return {Array.} - */ - getTriangleIndices: function (idx, out) { - if (idx < this.triangleCount && idx >= 0) { - if (!out) { - out = vec3Create(); - } - var indices = this.indices; - out[0] = indices[idx * 3]; - out[1] = indices[idx * 3 + 1]; - out[2] = indices[idx * 3 + 2]; - return out; - } - }, - - /** - * Set indices of triangle at given index. - * @param {number} idx - * @param {Array.} arr - */ - setTriangleIndices: function (idx, arr) { - var indices = this.indices; - indices[idx * 3] = arr[0]; - indices[idx * 3 + 1] = arr[1]; - indices[idx * 3 + 2] = arr[2]; - }, - - isUseIndices: function () { - return !!this.indices; - }, - - /** - * Initialize indices from an array. - * @param {Array} array - */ - initIndicesFromArray: function (array) { - var value; - var ArrayConstructor = this.vertexCount > 0xffff - ? __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint32Array : __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint16Array; - // Convert 2d array to flat - if (array[0] && (array[0].length)) { - var n = 0; - var size = 3; - - value = new ArrayConstructor(array.length * size); - for (var i = 0; i < array.length; i++) { - for (var j = 0; j < size; j++) { - value[n++] = array[i][j]; - } - } - } - else { - value = new ArrayConstructor(array); - } - - this.indices = value; - }, - /** - * Create a new attribute - * @param {string} name - * @param {string} type - * @param {number} size - * @param {string} [semantic] - */ - createAttribute: function (name, type, size, semantic) { - var attrib = new Attribute(name, type, size, semantic); - if (this.attributes[name]) { - this.removeAttribute(name); - } - this.attributes[name] = attrib; - this._attributeList.push(name); - return attrib; - }, - /** - * Remove attribute - * @param {string} name - */ - removeAttribute: function (name) { - var attributeList = this._attributeList; - var idx = attributeList.indexOf(name); - if (idx >= 0) { - attributeList.splice(idx, 1); - delete this.attributes[name]; - return true; - } - return false; - }, - - /** - * Get attribute - * @param {string} name - * @return {clay.Geometry.Attribute} - */ - getAttribute: function (name) { - return this.attributes[name]; - }, - - /** - * Get enabled attributes name list - * Attribute which has the same vertex number with position is treated as a enabled attribute - * @return {string[]} - */ - getEnabledAttributes: function () { - var enabledAttributes = this._enabledAttributes; - var attributeList = this._attributeList; - // Cache - if (enabledAttributes) { - return enabledAttributes; - } - - var result = []; - var nVertex = this.vertexCount; - - for (var i = 0; i < attributeList.length; i++) { - var name = attributeList[i]; - var attrib = this.attributes[name]; - if (attrib.value) { - if (attrib.value.length === nVertex * attrib.size) { - result.push(name); - } - } - } - - this._enabledAttributes = result; - - return result; - }, - - getBufferChunks: function (renderer) { - var cache = this._cache; - cache.use(renderer.__uid__); - var isAttributesDirty = cache.isDirty('attributes'); - var isIndicesDirty = cache.isDirty('indices'); - if (isAttributesDirty || isIndicesDirty) { - this._updateBuffer(renderer.gl, isAttributesDirty, isIndicesDirty); - var enabledAttributes = this.getEnabledAttributes(); - for (var i = 0; i < enabledAttributes.length; i++) { - cache.fresh(makeAttrKey(enabledAttributes[i])); - } - cache.fresh('attributes'); - cache.fresh('indices'); - } - cache.fresh('any'); - return cache.get('chunks'); - }, - - _updateBuffer: function (_gl, isAttributesDirty, isIndicesDirty) { - var cache = this._cache; - var chunks = cache.get('chunks'); - var firstUpdate = false; - if (!chunks) { - chunks = []; - // Intialize - chunks[0] = { - attributeBuffers: [], - indicesBuffer: null - }; - cache.put('chunks', chunks); - firstUpdate = true; - } - - var chunk = chunks[0]; - var attributeBuffers = chunk.attributeBuffers; - var indicesBuffer = chunk.indicesBuffer; - - if (isAttributesDirty || firstUpdate) { - var attributeList = this.getEnabledAttributes(); - - var attributeBufferMap = {}; - if (!firstUpdate) { - for (var i = 0; i < attributeBuffers.length; i++) { - attributeBufferMap[attributeBuffers[i].name] = attributeBuffers[i]; - } - } - // FIXME If some attributes removed - for (var k = 0; k < attributeList.length; k++) { - var name = attributeList[k]; - var attribute = this.attributes[name]; - - var bufferInfo; - - if (!firstUpdate) { - bufferInfo = attributeBufferMap[name]; - } - var buffer; - if (bufferInfo) { - buffer = bufferInfo.buffer; - } - else { - buffer = _gl.createBuffer(); - } - if (cache.isDirty(makeAttrKey(name))) { - // Only update when they are dirty. - // TODO: Use BufferSubData? - _gl.bindBuffer(_gl.ARRAY_BUFFER, buffer); - _gl.bufferData(_gl.ARRAY_BUFFER, attribute.value, this.dynamic ? __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].DYNAMIC_DRAW : __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].STATIC_DRAW); - } - - attributeBuffers[k] = new AttributeBuffer(name, attribute.type, buffer, attribute.size, attribute.semantic); - } - // Remove unused attributes buffers. - // PENDING - for (var i = k; i < attributeBuffers.length; i++) { - _gl.deleteBuffer(attributeBuffers[i].buffer); - } - attributeBuffers.length = k; - - } - - if (this.isUseIndices() && (isIndicesDirty || firstUpdate)) { - if (!indicesBuffer) { - indicesBuffer = new IndicesBuffer(_gl.createBuffer()); - chunk.indicesBuffer = indicesBuffer; - } - indicesBuffer.count = this.indices.length; - _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, indicesBuffer.buffer); - _gl.bufferData(_gl.ELEMENT_ARRAY_BUFFER, this.indices, this.dynamic ? __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].DYNAMIC_DRAW : __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].STATIC_DRAW); - } - }, - - /** - * Generate normals per vertex. - */ - generateVertexNormals: function () { - if (!this.vertexCount) { - return; - } - - var indices = this.indices; - var attributes = this.attributes; - var positions = attributes.position.value; - var normals = attributes.normal.value; - - if (!normals || normals.length !== positions.length) { - normals = attributes.normal.value = new __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Float32Array(positions.length); - } - else { - // Reset - for (var i = 0; i < normals.length; i++) { - normals[i] = 0; - } - } - - var p1 = vec3Create(); - var p2 = vec3Create(); - var p3 = vec3Create(); - - var v21 = vec3Create(); - var v32 = vec3Create(); - - var n = vec3Create(); - - var len = indices ? indices.length : this.vertexCount; - var i1, i2, i3; - for (var f = 0; f < len;) { - if (indices) { - i1 = indices[f++]; - i2 = indices[f++]; - i3 = indices[f++]; - } - else { - i1 = f++; - i2 = f++; - i3 = f++; - } - - vec3Set(p1, positions[i1*3], positions[i1*3+1], positions[i1*3+2]); - vec3Set(p2, positions[i2*3], positions[i2*3+1], positions[i2*3+2]); - vec3Set(p3, positions[i3*3], positions[i3*3+1], positions[i3*3+2]); - - vec3.sub(v21, p1, p2); - vec3.sub(v32, p2, p3); - vec3.cross(n, v21, v32); - // Already be weighted by the triangle area - for (var i = 0; i < 3; i++) { - normals[i1*3+i] = normals[i1*3+i] + n[i]; - normals[i2*3+i] = normals[i2*3+i] + n[i]; - normals[i3*3+i] = normals[i3*3+i] + n[i]; - } - } - - for (var i = 0; i < normals.length;) { - vec3Set(n, normals[i], normals[i+1], normals[i+2]); - vec3.normalize(n, n); - normals[i++] = n[0]; - normals[i++] = n[1]; - normals[i++] = n[2]; - } - this.dirty(); - }, - - /** - * Generate normals per face. - */ - generateFaceNormals: function () { - if (!this.vertexCount) { - return; - } - - if (!this.isUniqueVertex()) { - this.generateUniqueVertex(); - } - - var indices = this.indices; - var attributes = this.attributes; - var positions = attributes.position.value; - var normals = attributes.normal.value; - - var p1 = vec3Create(); - var p2 = vec3Create(); - var p3 = vec3Create(); - - var v21 = vec3Create(); - var v32 = vec3Create(); - var n = vec3Create(); - - if (!normals) { - normals = attributes.normal.value = new Float32Array(positions.length); - } - var len = indices ? indices.length : this.vertexCount; - var i1, i2, i3; - for (var f = 0; f < len;) { - if (indices) { - i1 = indices[f++]; - i2 = indices[f++]; - i3 = indices[f++]; - } - else { - i1 = f++; - i2 = f++; - i3 = f++; - } - - vec3Set(p1, positions[i1*3], positions[i1*3+1], positions[i1*3+2]); - vec3Set(p2, positions[i2*3], positions[i2*3+1], positions[i2*3+2]); - vec3Set(p3, positions[i3*3], positions[i3*3+1], positions[i3*3+2]); - - vec3.sub(v21, p1, p2); - vec3.sub(v32, p2, p3); - vec3.cross(n, v21, v32); - - vec3.normalize(n, n); - - for (var i = 0; i < 3; i++) { - normals[i1*3 + i] = n[i]; - normals[i2*3 + i] = n[i]; - normals[i3*3 + i] = n[i]; - } - } - this.dirty(); - }, - - /** - * Generate tangents attributes. - */ - generateTangents: function () { - if (!this.vertexCount) { - return; - } - - var nVertex = this.vertexCount; - var attributes = this.attributes; - if (!attributes.tangent.value) { - attributes.tangent.value = new Float32Array(nVertex * 4); - } - var texcoords = attributes.texcoord0.value; - var positions = attributes.position.value; - var tangents = attributes.tangent.value; - var normals = attributes.normal.value; - - if (!texcoords) { - console.warn('Geometry without texcoords can\'t generate tangents.'); - return; - } - - var tan1 = []; - var tan2 = []; - for (var i = 0; i < nVertex; i++) { - tan1[i] = [0.0, 0.0, 0.0]; - tan2[i] = [0.0, 0.0, 0.0]; - } - - var sdir = [0.0, 0.0, 0.0]; - var tdir = [0.0, 0.0, 0.0]; - var indices = this.indices; - - var len = indices ? indices.length : this.vertexCount; - var i1, i2, i3; - for (var i = 0; i < len;) { - if (indices) { - i1 = indices[i++]; - i2 = indices[i++]; - i3 = indices[i++]; - } - else { - i1 = i++; - i2 = i++; - i3 = i++; - } - - var st1s = texcoords[i1 * 2], - st2s = texcoords[i2 * 2], - st3s = texcoords[i3 * 2], - st1t = texcoords[i1 * 2 + 1], - st2t = texcoords[i2 * 2 + 1], - st3t = texcoords[i3 * 2 + 1], - - p1x = positions[i1 * 3], - p2x = positions[i2 * 3], - p3x = positions[i3 * 3], - p1y = positions[i1 * 3 + 1], - p2y = positions[i2 * 3 + 1], - p3y = positions[i3 * 3 + 1], - p1z = positions[i1 * 3 + 2], - p2z = positions[i2 * 3 + 2], - p3z = positions[i3 * 3 + 2]; - - var x1 = p2x - p1x, - x2 = p3x - p1x, - y1 = p2y - p1y, - y2 = p3y - p1y, - z1 = p2z - p1z, - z2 = p3z - p1z; - - var s1 = st2s - st1s, - s2 = st3s - st1s, - t1 = st2t - st1t, - t2 = st3t - st1t; - - var r = 1.0 / (s1 * t2 - t1 * s2); - sdir[0] = (t2 * x1 - t1 * x2) * r; - sdir[1] = (t2 * y1 - t1 * y2) * r; - sdir[2] = (t2 * z1 - t1 * z2) * r; - - tdir[0] = (s1 * x2 - s2 * x1) * r; - tdir[1] = (s1 * y2 - s2 * y1) * r; - tdir[2] = (s1 * z2 - s2 * z1) * r; - - vec3Add(tan1[i1], tan1[i1], sdir); - vec3Add(tan1[i2], tan1[i2], sdir); - vec3Add(tan1[i3], tan1[i3], sdir); - vec3Add(tan2[i1], tan2[i1], tdir); - vec3Add(tan2[i2], tan2[i2], tdir); - vec3Add(tan2[i3], tan2[i3], tdir); - } - var tmp = vec3Create(); - var nCrossT = vec3Create(); - var n = vec3Create(); - for (var i = 0; i < nVertex; i++) { - n[0] = normals[i * 3]; - n[1] = normals[i * 3 + 1]; - n[2] = normals[i * 3 + 2]; - var t = tan1[i]; - - // Gram-Schmidt orthogonalize - vec3.scale(tmp, n, vec3.dot(n, t)); - vec3.sub(tmp, t, tmp); - vec3.normalize(tmp, tmp); - // Calculate handedness. - vec3.cross(nCrossT, n, t); - tangents[i * 4] = tmp[0]; - tangents[i * 4 + 1] = tmp[1]; - tangents[i * 4 + 2] = tmp[2]; - // PENDING can config ? - tangents[i * 4 + 3] = vec3.dot(nCrossT, tan2[i]) < 0.0 ? -1.0 : 1.0; - } - this.dirty(); - }, - - /** - * If vertices are not shared by different indices. - */ - isUniqueVertex: function () { - if (this.isUseIndices()) { - return this.vertexCount === this.indices.length; - } - else { - return true; - } - }, - /** - * Create a unique vertex for each index. - */ - generateUniqueVertex: function () { - if (!this.vertexCount || !this.indices) { - return; - } - - if (this.indices.length > 0xffff) { - this.indices = new __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint32Array(this.indices); - } - - var attributes = this.attributes; - var indices = this.indices; - - var attributeNameList = this.getEnabledAttributes(); - - var oldAttrValues = {}; - for (var a = 0; a < attributeNameList.length; a++) { - var name = attributeNameList[a]; - oldAttrValues[name] = attributes[name].value; - attributes[name].init(this.indices.length); - } - - var cursor = 0; - for (var i = 0; i < indices.length; i++) { - var ii = indices[i]; - for (var a = 0; a < attributeNameList.length; a++) { - var name = attributeNameList[a]; - var array = attributes[name].value; - var size = attributes[name].size; - - for (var k = 0; k < size; k++) { - array[cursor * size + k] = oldAttrValues[name][ii * size + k]; - } - } - indices[i] = cursor; - cursor++; - } - - this.dirty(); - }, - - /** - * Generate barycentric coordinates for wireframe draw. - */ - generateBarycentric: function () { - if (!this.vertexCount) { - return; - } - - if (!this.isUniqueVertex()) { - this.generateUniqueVertex(); - } - - var attributes = this.attributes; - var array = attributes.barycentric.value; - var indices = this.indices; - // Already existed; - if (array && array.length === indices.length * 3) { - return; - } - array = attributes.barycentric.value = new Float32Array(indices.length * 3); - - for (var i = 0; i < (indices ? indices.length : this.vertexCount / 3);) { - for (var j = 0; j < 3; j++) { - var ii = indices ? indices[i++] : (i * 3 + j); - array[ii * 3 + j] = 1; - } - } - this.dirty(); - }, - - /** - * Apply transform to geometry attributes. - * @param {clay.math.Matrix4} matrix - */ - applyTransform: function (matrix) { - - var attributes = this.attributes; - var positions = attributes.position.value; - var normals = attributes.normal.value; - var tangents = attributes.tangent.value; - - matrix = matrix.array; - // Normal Matrix - var inverseTransposeMatrix = mat4.create(); - mat4.invert(inverseTransposeMatrix, matrix); - mat4.transpose(inverseTransposeMatrix, inverseTransposeMatrix); - - var vec3TransformMat4 = vec3.transformMat4; - var vec3ForEach = vec3.forEach; - vec3ForEach(positions, 3, 0, null, vec3TransformMat4, matrix); - if (normals) { - vec3ForEach(normals, 3, 0, null, vec3TransformMat4, inverseTransposeMatrix); - } - if (tangents) { - vec3ForEach(tangents, 4, 0, null, vec3TransformMat4, inverseTransposeMatrix); - } - - if (this.boundingBox) { - this.updateBoundingBox(); - } - }, - /** - * Dispose geometry data in GL context. - * @param {clay.Renderer} renderer - */ - dispose: function (renderer) { - - var cache = this._cache; - - cache.use(renderer.__uid__); - var chunks = cache.get('chunks'); - if (chunks) { - for (var c = 0; c < chunks.length; c++) { - var chunk = chunks[c]; - - for (var k = 0; k < chunk.attributeBuffers.length; k++) { - var attribs = chunk.attributeBuffers[k]; - renderer.gl.deleteBuffer(attribs.buffer); - } - - if (chunk.indicesBuffer) { - renderer.gl.deleteBuffer(chunk.indicesBuffer.buffer); - } - } - } - cache.deleteContext(renderer.__uid__); - } - -}); - -if (Object.defineProperty) { - /** - * @name clay.Geometry#vertexCount - * @type {number} - * @readOnly - */ - Object.defineProperty(Geometry.prototype, 'vertexCount', { - - enumerable: false, - - get: function () { - var mainAttribute = this.attributes[this.mainAttribute]; - if (!mainAttribute || !mainAttribute.value) { - return 0; - } - return mainAttribute.value.length / mainAttribute.size; - } - }); - /** - * @name clay.Geometry#triangleCount - * @type {number} - * @readOnly - */ - Object.defineProperty(Geometry.prototype, 'triangleCount', { - - enumerable: false, - - get: function () { - var indices = this.indices; - if (!indices) { - return 0; - } - else { - return indices.length / 3; - } - } - }); -} - -Geometry.STATIC_DRAW = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].STATIC_DRAW; -Geometry.DYNAMIC_DRAW = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].DYNAMIC_DRAW; -Geometry.STREAM_DRAW = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].STREAM_DRAW; - -Geometry.AttributeBuffer = AttributeBuffer; -Geometry.IndicesBuffer = IndicesBuffer; - -Geometry.Attribute = Attribute; - -/* harmony default export */ __webpack_exports__["a"] = (Geometry); - - -/***/ }), -/* 20 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -function Handler(action, context) { - this.action = action; - this.context = context; -} -/** - * @mixin - * @alias clay.core.mixin.notifier - */ -var notifier = { - /** - * Trigger event - * @param {string} name - */ - trigger: function(name) { - if (!this.hasOwnProperty('__handlers__')) { - return; - } - if (!this.__handlers__.hasOwnProperty(name)) { - return; - } - - var hdls = this.__handlers__[name]; - var l = hdls.length, i = -1, args = arguments; - // Optimize advise from backbone - switch (args.length) { - case 1: - while (++i < l) { - hdls[i].action.call(hdls[i].context); - } - return; - case 2: - while (++i < l) { - hdls[i].action.call(hdls[i].context, args[1]); - } - return; - case 3: - while (++i < l) { - hdls[i].action.call(hdls[i].context, args[1], args[2]); - } - return; - case 4: - while (++i < l) { - hdls[i].action.call(hdls[i].context, args[1], args[2], args[3]); - } - return; - case 5: - while (++i < l) { - hdls[i].action.call(hdls[i].context, args[1], args[2], args[3], args[4]); - } - return; - default: - while (++i < l) { - hdls[i].action.apply(hdls[i].context, Array.prototype.slice.call(args, 1)); - } - return; - } - }, - /** - * Register event handler - * @param {string} name - * @param {Function} action - * @param {Object} [context] - * @chainable - */ - on: function(name, action, context) { - if (!name || !action) { - return; - } - var handlers = this.__handlers__ || (this.__handlers__={}); - if (!handlers[name]) { - handlers[name] = []; - } - else { - if (this.has(name, action)) { - return; - } - } - var handler = new Handler(action, context || this); - handlers[name].push(handler); - - return this; - }, - - /** - * Register event, event will only be triggered once and then removed - * @param {string} name - * @param {Function} action - * @param {Object} [context] - * @chainable - */ - once: function(name, action, context) { - if (!name || !action) { - return; - } - var self = this; - function wrapper() { - self.off(name, wrapper); - action.apply(this, arguments); - } - return this.on(name, wrapper, context); - }, - - /** - * Alias of once('before' + name) - * @param {string} name - * @param {Function} action - * @param {Object} [context] - * @chainable - */ - before: function(name, action, context) { - if (!name || !action) { - return; - } - name = 'before' + name; - return this.on(name, action, context); - }, - - /** - * Alias of once('after' + name) - * @param {string} name - * @param {Function} action - * @param {Object} [context] - * @chainable - */ - after: function(name, action, context) { - if (!name || !action) { - return; - } - name = 'after' + name; - return this.on(name, action, context); - }, - - /** - * Alias of on('success') - * @param {Function} action - * @param {Object} [context] - * @chainable - */ - success: function(action, context) { - return this.once('success', action, context); - }, - - /** - * Alias of on('error') - * @param {Function} action - * @param {Object} [context] - * @chainable - */ - error: function(action, context) { - return this.once('error', action, context); - }, - - /** - * Remove event listener - * @param {Function} action - * @param {Object} [context] - * @chainable - */ - off: function(name, action) { - - var handlers = this.__handlers__ || (this.__handlers__={}); - - if (!action) { - handlers[name] = []; - return; - } - if (handlers[name]) { - var hdls = handlers[name]; - var retains = []; - for (var i = 0; i < hdls.length; i++) { - if (action && hdls[i].action !== action) { - retains.push(hdls[i]); - } - } - handlers[name] = retains; - } - - return this; - }, - - /** - * If registered the event handler - * @param {string} name - * @param {Function} action - * @return {boolean} - */ - has: function(name, action) { - var handlers = this.__handlers__; - - if (! handlers || - ! handlers[name]) { - return false; - } - var hdls = handlers[name]; - for (var i = 0; i < hdls.length; i++) { - if (hdls[i].action === action) { - return true; - } - } - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (notifier); - -/***/ }), -/* 21 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__dep_glmatrix__); - -var vec2 = __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix___default.a.vec2; - -/** - * @constructor - * @alias clay.math.Vector2 - * @param {number} x - * @param {number} y - */ -var Vector2 = function(x, y) { - - x = x || 0; - y = y || 0; - - /** - * Storage of Vector2, read and write of x, y will change the values in array - * All methods also operate on the array instead of x, y components - * @name array - * @type {Float32Array} - * @memberOf clay.math.Vector2# - */ - this.array = vec2.fromValues(x, y); - - /** - * Dirty flag is used by the Node to determine - * if the matrix is updated to latest - * @name _dirty - * @type {boolean} - * @memberOf clay.math.Vector2# - */ - this._dirty = true; -}; - -Vector2.prototype = { - - constructor: Vector2, - - /** - * Add b to self - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ - add: function(b) { - vec2.add(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Set x and y components - * @param {number} x - * @param {number} y - * @return {clay.math.Vector2} - */ - set: function(x, y) { - this.array[0] = x; - this.array[1] = y; - this._dirty = true; - return this; - }, - - /** - * Set x and y components from array - * @param {Float32Array|number[]} arr - * @return {clay.math.Vector2} - */ - setArray: function(arr) { - this.array[0] = arr[0]; - this.array[1] = arr[1]; - - this._dirty = true; - return this; - }, - - /** - * Clone a new Vector2 - * @return {clay.math.Vector2} - */ - clone: function() { - return new Vector2(this.x, this.y); - }, - - /** - * Copy x, y from b - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ - copy: function(b) { - vec2.copy(this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Cross product of self and b, written to a Vector3 out - * @param {clay.math.Vector3} out - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ - cross: function(out, b) { - vec2.cross(out.array, this.array, b.array); - out._dirty = true; - return this; - }, - - /** - * Alias for distance - * @param {clay.math.Vector2} b - * @return {number} - */ - dist: function(b) { - return vec2.dist(this.array, b.array); - }, - - /** - * Distance between self and b - * @param {clay.math.Vector2} b - * @return {number} - */ - distance: function(b) { - return vec2.distance(this.array, b.array); - }, - - /** - * Alias for divide - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ - div: function(b) { - vec2.div(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Divide self by b - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ - divide: function(b) { - vec2.divide(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Dot product of self and b - * @param {clay.math.Vector2} b - * @return {number} - */ - dot: function(b) { - return vec2.dot(this.array, b.array); - }, - - /** - * Alias of length - * @return {number} - */ - len: function() { - return vec2.len(this.array); - }, - - /** - * Calculate the length - * @return {number} - */ - length: function() { - return vec2.length(this.array); - }, - - /** - * Linear interpolation between a and b - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @param {number} t - * @return {clay.math.Vector2} - */ - lerp: function(a, b, t) { - vec2.lerp(this.array, a.array, b.array, t); - this._dirty = true; - return this; - }, - - /** - * Minimum of self and b - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ - min: function(b) { - vec2.min(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Maximum of self and b - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ - max: function(b) { - vec2.max(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Alias for multiply - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ - mul: function(b) { - vec2.mul(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Mutiply self and b - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ - multiply: function(b) { - vec2.multiply(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Negate self - * @return {clay.math.Vector2} - */ - negate: function() { - vec2.negate(this.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Normalize self - * @return {clay.math.Vector2} - */ - normalize: function() { - vec2.normalize(this.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Generate random x, y components with a given scale - * @param {number} scale - * @return {clay.math.Vector2} - */ - random: function(scale) { - vec2.random(this.array, scale); - this._dirty = true; - return this; - }, - - /** - * Scale self - * @param {number} scale - * @return {clay.math.Vector2} - */ - scale: function(s) { - vec2.scale(this.array, this.array, s); - this._dirty = true; - return this; - }, - - /** - * Scale b and add to self - * @param {clay.math.Vector2} b - * @param {number} scale - * @return {clay.math.Vector2} - */ - scaleAndAdd: function(b, s) { - vec2.scaleAndAdd(this.array, this.array, b.array, s); - this._dirty = true; - return this; - }, - - /** - * Alias for squaredDistance - * @param {clay.math.Vector2} b - * @return {number} - */ - sqrDist: function(b) { - return vec2.sqrDist(this.array, b.array); - }, - - /** - * Squared distance between self and b - * @param {clay.math.Vector2} b - * @return {number} - */ - squaredDistance: function(b) { - return vec2.squaredDistance(this.array, b.array); - }, - - /** - * Alias for squaredLength - * @return {number} - */ - sqrLen: function() { - return vec2.sqrLen(this.array); - }, - - /** - * Squared length of self - * @return {number} - */ - squaredLength: function() { - return vec2.squaredLength(this.array); - }, - - /** - * Alias for subtract - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ - sub: function(b) { - vec2.sub(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Subtract b from self - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ - subtract: function(b) { - vec2.subtract(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Transform self with a Matrix2 m - * @param {clay.math.Matrix2} m - * @return {clay.math.Vector2} - */ - transformMat2: function(m) { - vec2.transformMat2(this.array, this.array, m.array); - this._dirty = true; - return this; - }, - - /** - * Transform self with a Matrix2d m - * @param {clay.math.Matrix2d} m - * @return {clay.math.Vector2} - */ - transformMat2d: function(m) { - vec2.transformMat2d(this.array, this.array, m.array); - this._dirty = true; - return this; - }, - - /** - * Transform self with a Matrix3 m - * @param {clay.math.Matrix3} m - * @return {clay.math.Vector2} - */ - transformMat3: function(m) { - vec2.transformMat3(this.array, this.array, m.array); - this._dirty = true; - return this; - }, - - /** - * Transform self with a Matrix4 m - * @param {clay.math.Matrix4} m - * @return {clay.math.Vector2} - */ - transformMat4: function(m) { - vec2.transformMat4(this.array, this.array, m.array); - this._dirty = true; - return this; - }, - - toString: function() { - return '[' + Array.prototype.join.call(this.array, ',') + ']'; - }, - - toArray: function () { - return Array.prototype.slice.call(this.array); - } -}; - -// Getter and Setter -if (Object.defineProperty) { - - var proto = Vector2.prototype; - /** - * @name x - * @type {number} - * @memberOf clay.math.Vector2 - * @instance - */ - Object.defineProperty(proto, 'x', { - get: function () { - return this.array[0]; - }, - set: function (value) { - this.array[0] = value; - this._dirty = true; - } - }); - - /** - * @name y - * @type {number} - * @memberOf clay.math.Vector2 - * @instance - */ - Object.defineProperty(proto, 'y', { - get: function () { - return this.array[1]; - }, - set: function (value) { - this.array[1] = value; - this._dirty = true; - } - }); -} - -// Supply methods that are not in place - -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ -Vector2.add = function(out, a, b) { - vec2.add(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector2} out - * @param {number} x - * @param {number} y - * @return {clay.math.Vector2} - */ -Vector2.set = function(out, x, y) { - vec2.set(out.array, x, y); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ -Vector2.copy = function(out, b) { - vec2.copy(out.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector3} out - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ -Vector2.cross = function(out, a, b) { - vec2.cross(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {number} - */ -Vector2.dist = function(a, b) { - return vec2.distance(a.array, b.array); -}; -/** - * @function - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {number} - */ -Vector2.distance = Vector2.dist; -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ -Vector2.div = function(out, a, b) { - vec2.divide(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @function - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ -Vector2.divide = Vector2.div; -/** - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {number} - */ -Vector2.dot = function(a, b) { - return vec2.dot(a.array, b.array); -}; - -/** - * @param {clay.math.Vector2} a - * @return {number} - */ -Vector2.len = function(b) { - return vec2.length(b.array); -}; - -// Vector2.length = Vector2.len; - -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @param {number} t - * @return {clay.math.Vector2} - */ -Vector2.lerp = function(out, a, b, t) { - vec2.lerp(out.array, a.array, b.array, t); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ -Vector2.min = function(out, a, b) { - vec2.min(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ -Vector2.max = function(out, a, b) { - vec2.max(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ -Vector2.mul = function(out, a, b) { - vec2.multiply(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @function - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ -Vector2.multiply = Vector2.mul; -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @return {clay.math.Vector2} - */ -Vector2.negate = function(out, a) { - vec2.negate(out.array, a.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @return {clay.math.Vector2} - */ -Vector2.normalize = function(out, a) { - vec2.normalize(out.array, a.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector2} out - * @param {number} scale - * @return {clay.math.Vector2} - */ -Vector2.random = function(out, scale) { - vec2.random(out.array, scale); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {number} scale - * @return {clay.math.Vector2} - */ -Vector2.scale = function(out, a, scale) { - vec2.scale(out.array, a.array, scale); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @param {number} scale - * @return {clay.math.Vector2} - */ -Vector2.scaleAndAdd = function(out, a, b, scale) { - vec2.scaleAndAdd(out.array, a.array, b.array, scale); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {number} - */ -Vector2.sqrDist = function(a, b) { - return vec2.sqrDist(a.array, b.array); -}; -/** - * @function - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {number} - */ -Vector2.squaredDistance = Vector2.sqrDist; - -/** - * @param {clay.math.Vector2} a - * @return {number} - */ -Vector2.sqrLen = function(a) { - return vec2.sqrLen(a.array); -}; -/** - * @function - * @param {clay.math.Vector2} a - * @return {number} - */ -Vector2.squaredLength = Vector2.sqrLen; - -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ -Vector2.sub = function(out, a, b) { - vec2.subtract(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @function - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {clay.math.Vector2} b - * @return {clay.math.Vector2} - */ -Vector2.subtract = Vector2.sub; -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {clay.math.Matrix2} m - * @return {clay.math.Vector2} - */ -Vector2.transformMat2 = function(out, a, m) { - vec2.transformMat2(out.array, a.array, m.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {clay.math.Matrix2d} m - * @return {clay.math.Vector2} - */ -Vector2.transformMat2d = function(out, a, m) { - vec2.transformMat2d(out.array, a.array, m.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {Matrix3} m - * @return {clay.math.Vector2} - */ -Vector2.transformMat3 = function(out, a, m) { - vec2.transformMat3(out.array, a.array, m.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.math.Vector2} out - * @param {clay.math.Vector2} a - * @param {clay.math.Matrix4} m - * @return {clay.math.Vector2} - */ -Vector2.transformMat4 = function(out, a, m) { - vec2.transformMat4(out.array, a.array, m.array); - out._dirty = true; - return out; -}; - -/* harmony default export */ __webpack_exports__["a"] = (Vector2); - - -/***/ }), -/* 22 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Camera__ = __webpack_require__(30); - - -/** - * @constructor clay.camera.Perspective - * @extends clay.Camera - */ -var Perspective = __WEBPACK_IMPORTED_MODULE_0__Camera__["a" /* default */].extend( -/** @lends clay.camera.Perspective# */ -{ - /** - * Vertical field of view in radians - * @type {number} - */ - fov: 50, - /** - * Aspect ratio, typically viewport width / height - * @type {number} - */ - aspect: 1, - /** - * Near bound of the frustum - * @type {number} - */ - near: 0.1, - /** - * Far bound of the frustum - * @type {number} - */ - far: 2000 -}, -/** @lends clay.camera.Perspective.prototype */ -{ - - updateProjectionMatrix: function() { - var rad = this.fov / 180 * Math.PI; - this.projectionMatrix.perspective(rad, this.aspect, this.near, this.far); - }, - decomposeProjectionMatrix: function () { - var m = this.projectionMatrix.array; - var rad = Math.atan(1 / m[5]) * 2; - this.fov = rad / Math.PI * 180; - this.aspect = m[5] / m[0]; - this.near = m[14] / (m[10] - 1); - this.far = m[14] / (m[10] + 1); - }, - /** - * @return {clay.camera.Perspective} - */ - clone: function() { - var camera = __WEBPACK_IMPORTED_MODULE_0__Camera__["a" /* default */].prototype.clone.call(this); - camera.fov = this.fov; - camera.aspect = this.aspect; - camera.near = this.near; - camera.far = this.far; - - return camera; - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (Perspective); - - -/***/ }), -/* 23 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Camera__ = __webpack_require__(30); - -/** - * @constructor clay.camera.Orthographic - * @extends clay.Camera - */ -var Orthographic = __WEBPACK_IMPORTED_MODULE_0__Camera__["a" /* default */].extend( -/** @lends clay.camera.Orthographic# */ -{ - /** - * @type {number} - */ - left: -1, - /** - * @type {number} - */ - right: 1, - /** - * @type {number} - */ - near: -1, - /** - * @type {number} - */ - far: 1, - /** - * @type {number} - */ - top: 1, - /** - * @type {number} - */ - bottom: -1 -}, -/** @lends clay.camera.Orthographic.prototype */ -{ - - updateProjectionMatrix: function() { - this.projectionMatrix.ortho(this.left, this.right, this.bottom, this.top, this.near, this.far); - }, - - decomposeProjectionMatrix: function () { - var m = this.projectionMatrix.array; - this.left = (-1 - m[12]) / m[0]; - this.right = (1 - m[12]) / m[0]; - this.top = (1 - m[13]) / m[5]; - this.bottom = (-1 - m[13]) / m[5]; - this.near = -(-1 - m[14]) / m[10]; - this.far = -(1 - m[14]) / m[10]; - }, - /** - * @return {clay.camera.Orthographic} - */ - clone: function() { - var camera = __WEBPACK_IMPORTED_MODULE_0__Camera__["a" /* default */].prototype.clone.call(this); - camera.left = this.left; - camera.right = this.right; - camera.near = this.near; - camera.far = this.far; - camera.top = this.top; - camera.bottom = this.bottom; - - return camera; - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (Orthographic); - - -/***/ }), -/* 24 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); - - -// PENDING -// Use topological sort ? - -/** - * Node of graph based post processing. - * - * @constructor clay.compositor.Node - * @extends clay.core.Base - * - */ -var Node = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend(function () { - return /** @lends clay.compositor.Node# */ { - /** - * @type {string} - */ - name: '', - - /** - * Input links, will be updated by the graph - * @example: - * inputName: { - * node: someNode, - * pin: 'xxxx' - * } - * @type {Object} - */ - inputLinks: {}, - - /** - * Output links, will be updated by the graph - * @example: - * outputName: { - * node: someNode, - * pin: 'xxxx' - * } - * @type {Object} - */ - outputLinks: {}, - - // Save the output texture of previous frame - // Will be used when there exist a circular reference - _prevOutputTextures: {}, - _outputTextures: {}, - - // Example: { name: 2 } - _outputReferences: {}, - - _rendering: false, - // If rendered in this frame - _rendered: false, - - _compositor: null - }; -}, -/** @lends clay.compositor.Node.prototype */ -{ - - // TODO Remove parameter function callback - updateParameter: function (outputName, renderer) { - var outputInfo = this.outputs[outputName]; - var parameters = outputInfo.parameters; - var parametersCopy = outputInfo._parametersCopy; - if (!parametersCopy) { - parametersCopy = outputInfo._parametersCopy = {}; - } - if (parameters) { - for (var key in parameters) { - if (key !== 'width' && key !== 'height') { - parametersCopy[key] = parameters[key]; - } - } - } - var width, height; - if (parameters.width instanceof Function) { - width = parameters.width.call(this, renderer); - } - else { - width = parameters.width; - } - if (parameters.height instanceof Function) { - height = parameters.height.call(this, renderer); - } - else { - height = parameters.height; - } - if ( - parametersCopy.width !== width - || parametersCopy.height !== height - ) { - if (this._outputTextures[outputName]) { - this._outputTextures[outputName].dispose(renderer.gl); - } - } - parametersCopy.width = width; - parametersCopy.height = height; - - return parametersCopy; - }, - - /** - * Set parameter - * @param {string} name - * @param {} value - */ - setParameter: function (name, value) {}, - /** - * Get parameter value - * @param {string} name - * @return {} - */ - getParameter: function (name) {}, - /** - * Set parameters - * @param {Object} obj - */ - setParameters: function (obj) { - for (var name in obj) { - this.setParameter(name, obj[name]); - } - }, - - render: function () {}, - - getOutput: function (renderer /*optional*/, name) { - if (name == null) { - // Return the output texture without rendering - name = renderer; - return this._outputTextures[name]; - } - var outputInfo = this.outputs[name]; - if (!outputInfo) { - return ; - } - - // Already been rendered in this frame - if (this._rendered) { - // Force return texture in last frame - if (outputInfo.outputLastFrame) { - return this._prevOutputTextures[name]; - } - else { - return this._outputTextures[name]; - } - } - else if ( - // TODO - this._rendering // Solve Circular Reference - ) { - if (!this._prevOutputTextures[name]) { - // Create a blank texture at first pass - this._prevOutputTextures[name] = this._compositor.allocateTexture(outputInfo.parameters || {}); - } - return this._prevOutputTextures[name]; - } - - this.render(renderer); - - return this._outputTextures[name]; - }, - - removeReference: function (outputName) { - this._outputReferences[outputName]--; - if (this._outputReferences[outputName] === 0) { - var outputInfo = this.outputs[outputName]; - if (outputInfo.keepLastFrame) { - if (this._prevOutputTextures[outputName]) { - this._compositor.releaseTexture(this._prevOutputTextures[outputName]); - } - this._prevOutputTextures[outputName] = this._outputTextures[outputName]; - } - else { - // Output of this node have alreay been used by all other nodes - // Put the texture back to the pool. - this._compositor.releaseTexture(this._outputTextures[outputName]); - } - } - }, - - link: function (inputPinName, fromNode, fromPinName) { - - // The relationship from output pin to input pin is one-on-multiple - this.inputLinks[inputPinName] = { - node: fromNode, - pin: fromPinName - }; - if (!fromNode.outputLinks[fromPinName]) { - fromNode.outputLinks[fromPinName] = []; - } - fromNode.outputLinks[fromPinName].push({ - node: this, - pin: inputPinName - }); - - // Enabled the pin texture in shader - this.pass.material.enableTexture(inputPinName); - }, - - clear: function () { - this.inputLinks = {}; - this.outputLinks = {}; - }, - - updateReference: function (outputName) { - if (!this._rendering) { - this._rendering = true; - for (var inputName in this.inputLinks) { - var link = this.inputLinks[inputName]; - link.node.updateReference(link.pin); - } - this._rendering = false; - } - if (outputName) { - this._outputReferences[outputName] ++; - } - }, - - beforeFrame: function () { - this._rendered = false; - - for (var name in this.outputLinks) { - this._outputReferences[name] = 0; - } - }, - - afterFrame: function () { - // Put back all the textures to pool - for (var name in this.outputLinks) { - if (this._outputReferences[name] > 0) { - var outputInfo = this.outputs[name]; - if (outputInfo.keepLastFrame) { - if (this._prevOutputTextures[name]) { - this._compositor.releaseTexture(this._prevOutputTextures[name]); - } - this._prevOutputTextures[name] = this._outputTextures[name]; - } - else { - this._compositor.releaseTexture(this._outputTextures[name]); - } - } - } - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (Node); - - -/***/ }), -/* 25 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; - -// Generate halton sequence -// https://en.wikipedia.org/wiki/Halton_sequence -function halton(index, base) { - - var result = 0; - var f = 1 / base; - var i = index; - while (i > 0) { - result = result + f * (i % base); - i = Math.floor(i / base); - f = f / base; - } - return result; -} - - -/* harmony default export */ __webpack_exports__["a"] = (halton); - -/***/ }), -/* 26 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_claygl_src_Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_claygl_src_Material__ = __webpack_require__(10); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_zrender_src_core_LRU__ = __webpack_require__(65); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_claygl_src_util_texture__ = __webpack_require__(34); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4_claygl_src_light_AmbientCubemap__ = __webpack_require__(126); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5_claygl_src_light_AmbientSH__ = __webpack_require__(127); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6_claygl_src_util_sh__ = __webpack_require__(128); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7_zrender_src_tool_color__ = __webpack_require__(130); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8_claygl_src_Texture2D__ = __webpack_require__(5); - - - - - - - - - - -function isValueNone(value) { - return !value || value === 'none'; -} - -function isValueImage(value) { - return value instanceof HTMLCanvasElement - || value instanceof HTMLImageElement - || value instanceof Image; -} - - -/** - * @param {string} textureName - * @param {string|HTMLImageElement|HTMLCanvasElement} imgValue - * @param {Viewer} app - * @param {Object} [textureOpts] - */ -__WEBPACK_IMPORTED_MODULE_1_claygl_src_Material__["a" /* default */].prototype.setTextureImage = function (textureName, imgValue, app, textureOpts) { - if (!this.shader) { - return; - } - - var material = this; - var texture; - // disableTexture first - material.disableTexture(textureName); - if (!isValueNone(imgValue)) { - texture = helper.loadTexture(imgValue, app, textureOpts, function (texture) { - material.enableTexture(textureName); - app.refresh(); - }); - // Set texture immediately for other code to verify if have this texture. - material.set(textureName, texture); - } - - return texture; -}; - -var helper = {}; - -// Texture utilities -var blankImage = __WEBPACK_IMPORTED_MODULE_3_claygl_src_util_texture__["a" /* default */].createBlank('rgba(255,255,255,0)').image; - - -function nearestPowerOfTwo(val) { - return Math.pow(2, Math.round(Math.log(val) / Math.LN2)); -} -function convertTextureToPowerOfTwo(texture) { - if ((texture.wrapS === __WEBPACK_IMPORTED_MODULE_0_claygl_src_Texture__["a" /* default */].REPEAT || texture.wrapT === __WEBPACK_IMPORTED_MODULE_0_claygl_src_Texture__["a" /* default */].REPEAT) - && texture.image - ) { - // var canvas = document.createElement('canvas'); - var width = nearestPowerOfTwo(texture.width); - var height = nearestPowerOfTwo(texture.height); - if (width !== texture.width || height !== texture.height) { - var canvas = document.createElement('canvas'); - canvas.width = width; - canvas.height = height; - var ctx = canvas.getContext('2d'); - ctx.drawImage(texture.image, 0, 0, width, height); - canvas.srcImage = texture.image; - texture.image = canvas; - texture.dirty(); - } - } -} - -helper.firstNotNull = function () { - for (var i = 0, len = arguments.length; i < len; i++) { - if (arguments[i] != null) { - return arguments[i]; - } - } -}, -/** - * @param {string|HTMLImageElement|HTMLCanvasElement} imgValue - * @param {Viewer} app - * @param {Object} [textureOpts] - * @param {Function} cb - */ -// TODO Promise, test -helper.loadTexture = function (imgValue, app, textureOpts, cb) { - if (typeof textureOpts === 'function') { - cb = textureOpts; - textureOpts = {}; - } - textureOpts = textureOpts || {}; - - var keys = Object.keys(textureOpts).sort(); - var prefix = ''; - for (var i = 0; i < keys.length; i++) { - prefix += keys[i] + '_' + textureOpts[keys[i]] + '_'; - } - - var textureCache = app.__textureCache = app.__textureCache || new __WEBPACK_IMPORTED_MODULE_2_zrender_src_core_LRU__["a" /* default */](20); - - if (isValueImage(imgValue)) { - var id = imgValue.__textureid__; - var textureObj = textureCache.get(prefix + id); - if (!textureObj) { - textureObj = { - texture: new __WEBPACK_IMPORTED_MODULE_8_claygl_src_Texture2D__["a" /* default */]({ - image: imgValue - }) - }; - for (var i = 0; i < keys.length; i++) { - textureObj.texture[keys[i]] = textureOpts[keys[i]]; - } - id = imgValue.__textureid__ || '__ecgl_image__' + textureObj.texture.__GUID__; - imgValue.__textureid__ = id; - textureCache.put(prefix + id, textureObj); - - convertTextureToPowerOfTwo(textureObj.texture); - // TODO Next tick? - cb && cb(textureObj.texture); - } - return textureObj.texture; - } - else { - var textureObj = textureCache.get(prefix + imgValue); - if (textureObj) { - if (textureObj.callbacks) { - // Add to pending callbacks - textureObj.callbacks.push(cb); - } - else { - // TODO Next tick? - cb && cb(textureObj.texture); - } - } - else { - // Maybe base64 - if (imgValue.match(/.hdr$|^data:application\/octet-stream/)) { - textureObj = { - callbacks: [cb] - }; - var texture = __WEBPACK_IMPORTED_MODULE_3_claygl_src_util_texture__["a" /* default */].loadTexture(imgValue, { - exposure: textureOpts.exposure, - fileType: 'hdr' - }, function () { - texture.dirty(); - textureObj.callbacks.forEach(function (cb) { - cb && cb(texture); - }); - textureObj.callbacks = null; - }); - textureObj.texture = texture; - textureCache.put(prefix + imgValue, textureObj); - } - else { - var texture = new __WEBPACK_IMPORTED_MODULE_8_claygl_src_Texture2D__["a" /* default */]({ - image: new Image() - }); - for (var i = 0; i < keys.length; i++) { - texture[keys[i]] = textureOpts[keys[i]]; - } - - textureObj = { - texture: texture, - callbacks: [cb] - }; - var originalImage = texture.image; - originalImage.onload = function () { - texture.image = originalImage; - convertTextureToPowerOfTwo(texture); - - texture.dirty(); - textureObj.callbacks.forEach(function (cb) { - cb && cb(texture); - }); - textureObj.callbacks = null; - }; - originalImage.src = imgValue; - // Use blank image as place holder. - texture.image = blankImage; - - textureCache.put(prefix + imgValue, textureObj); - } - } - - return textureObj.texture; - } -}; - -/** - * Create ambientCubemap and ambientSH light. respectively to have specular and diffuse light - * @return {Object} { specular, diffuse } - */ -helper.createAmbientCubemap = function (opt, app, cb) { - opt = opt || {}; - var renderer = app.getRenderer(); - var textureUrl = opt.texture; - var exposure = helper.firstNotNull(opt.exposure, 1.0); - - var ambientCubemap, ambientSH; - if (opt.diffuseIntensity !== 0) { - ambientSH = new __WEBPACK_IMPORTED_MODULE_5_claygl_src_light_AmbientSH__["a" /* default */]({ - coefficients: [0.844, 0.712, 0.691, -0.037, 0.083, 0.167, 0.343, 0.288, 0.299, -0.041, -0.021, -0.009, -0.003, -0.041, -0.064, -0.011, -0.007, -0.004, -0.031, 0.034, 0.081, -0.060, -0.049, -0.060, 0.046, 0.056, 0.050] - }); - } - - if (opt.specularIntensity !== 0) { - ambientCubemap = new __WEBPACK_IMPORTED_MODULE_4_claygl_src_light_AmbientCubemap__["a" /* default */](); - ambientCubemap.cubemap = helper.loadTexture(textureUrl, app, { - exposure: exposure - }, function (cubemap) { - ambientCubemap.cubemap = cubemap; - // TODO Performance when multiple view - cubemap.flipY = false; - ambientCubemap.prefilter(renderer, 64); - ambientSH.coefficients = __WEBPACK_IMPORTED_MODULE_6_claygl_src_util_sh__["a" /* default */].projectEnvironmentMap(renderer, ambientCubemap.cubemap, { - lod: 1 - }); - - setTimeout(function () { - cb && cb(); - }); - // TODO Refresh ? - }); - } - else { - setTimeout(function () { - cb && cb(); - }); - } - return { - specular: ambientCubemap, - diffuse: ambientSH - }; -}; - -/** - * Create a blank texture for placeholder - */ -helper.createBlankTexture = __WEBPACK_IMPORTED_MODULE_3_claygl_src_util_texture__["a" /* default */].createBlank; - -/** - * If value is image - * @param {*} - * @return {boolean} - */ -helper.isImage = isValueImage; - -helper.additiveBlend = function (gl) { - gl.blendEquation(gl.FUNC_ADD); - gl.blendFunc(gl.SRC_ALPHA, gl.ONE); -}; - -/** - * @param {string|Array.} colorStr - * @param {Array.} [rgba] - * @return {Array.} rgba - */ -helper.parseColor = function (colorStr, rgba) { - if (colorStr instanceof Array) { - if (!rgba) { - rgba = []; - } - // Color has been parsed. - rgba[0] = colorStr[0]; - rgba[1] = colorStr[1]; - rgba[2] = colorStr[2]; - if (colorStr.length > 3) { - rgba[3] = colorStr[3]; - } - else { - rgba[3] = 1; - } - return rgba; - } - - rgba = __WEBPACK_IMPORTED_MODULE_7_zrender_src_tool_color__["a" /* parse */](colorStr || '#000', rgba) || [0, 0, 0, 0]; - rgba[0] /= 255; - rgba[1] /= 255; - rgba[2] /= 255; - return rgba; -}; - -/** - * @param {Array.} colorArr - * @return {string} - */ -helper.stringifyColor = function (colorArr, type) { - colorArr = colorArr.slice(); - colorArr[0] = Math.round(colorArr[0] * 255); - colorArr[1] = Math.round(colorArr[1] * 255); - colorArr[2] = Math.round(colorArr[2] * 255); - if (type === 'hex') { - return '#' + ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + colorArr[2]).toString(16).slice(1); - } - return __WEBPACK_IMPORTED_MODULE_7_zrender_src_tool_color__["b" /* stringify */](colorArr, type); -}; - -/** - * Convert alpha beta rotation to direction. - * @param {number} alpha - * @param {number} beta - * @return {Array.} - */ -helper.directionFromAlphaBeta = function (alpha, beta) { - var theta = alpha / 180 * Math.PI + Math.PI / 2; - var phi = -beta / 180 * Math.PI + Math.PI / 2; - - var dir = []; - var r = Math.sin(theta); - dir[0] = r * Math.cos(phi); - dir[1] = -Math.cos(theta); - dir[2] = r * Math.sin(phi); - - return dir; -}; - -helper.convertTextureToPowerOfTwo = convertTextureToPowerOfTwo; - -/* harmony default export */ __webpack_exports__["a"] = (helper); - -/***/ }), -/* 27 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_GLInfo__ = __webpack_require__(71); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__core_glenum__ = __webpack_require__(6); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__core_vendor__ = __webpack_require__(12); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__math_BoundingBox__ = __webpack_require__(8); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__math_Matrix4__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__Material__ = __webpack_require__(10); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__math_Vector2__ = __webpack_require__(21); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__gpu_ProgramManager__ = __webpack_require__(75); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__shader_source_header_light__ = __webpack_require__(39); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_11__shader_source_prez_glsl_js__ = __webpack_require__(40); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_12__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_12__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_12__dep_glmatrix__); -// TODO Resources like shader, texture, geometry reference management -// Trace and find out which shader, texture, geometry can be destroyed - - - - - - - - - - -// Light header - - - - -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_10__shader_source_header_light__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_11__shader_source_prez_glsl_js__["a" /* default */]); - - -var mat4 = __WEBPACK_IMPORTED_MODULE_12__dep_glmatrix___default.a.mat4; -var vec3 = __WEBPACK_IMPORTED_MODULE_12__dep_glmatrix___default.a.vec3; - -var mat4Create = mat4.create; - -var errorShader = {}; - -function defaultGetMaterial(renderable) { - return renderable.material; -} - -function noop() {} - -/** - * @constructor clay.Renderer - */ -var Renderer = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend(function () { - return /** @lends clay.Renderer# */ { - - /** - * @type {HTMLCanvasElement} - * @readonly - */ - canvas: null, - - /** - * Canvas width, set by resize method - * @type {number} - * @private - */ - _width: 100, - - /** - * Canvas width, set by resize method - * @type {number} - * @private - */ - _height: 100, - - /** - * Device pixel ratio, set by setDevicePixelRatio method - * Specially for high defination display - * @see http://www.khronos.org/webgl/wiki/HandlingHighDPI - * @type {number} - * @private - */ - devicePixelRatio: window.devicePixelRatio || 1.0, - - /** - * Clear color - * @type {number[]} - */ - clearColor: [0.0, 0.0, 0.0, 0.0], - - /** - * Default: - * _gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT | _gl.STENCIL_BUFFER_BIT - * @type {number} - */ - clearBit: 17664, - - // Settings when getting context - // http://www.khronos.org/registry/webgl/specs/latest/#2.4 - - /** - * If enable alpha, default true - * @type {boolean} - */ - alpha: true, - /** - * If enable depth buffer, default true - * @type {boolean} - */ - depth: true, - /** - * If enable stencil buffer, default false - * @type {boolean} - */ - stencil: false, - /** - * If enable antialias, default true - * @type {boolean} - */ - antialias: true, - /** - * If enable premultiplied alpha, default true - * @type {boolean} - */ - premultipliedAlpha: true, - /** - * If preserve drawing buffer, default false - * @type {boolean} - */ - preserveDrawingBuffer: false, - /** - * If throw context error, usually turned on in debug mode - * @type {boolean} - */ - throwError: true, - /** - * WebGL Context created from given canvas - * @type {WebGLRenderingContext} - */ - gl: null, - /** - * Renderer viewport, read-only, can be set by setViewport method - * @type {Object} - */ - viewport: {}, - - // Set by FrameBuffer#bind - __currentFrameBuffer: null, - - _viewportStack: [], - _clearStack: [], - - _sceneRendering: null - }; -}, function () { - - if (!this.canvas) { - this.canvas = document.createElement('canvas'); - } - var canvas = this.canvas; - try { - var opts = { - alpha: this.alpha, - depth: this.depth, - stencil: this.stencil, - antialias: this.antialias, - premultipliedAlpha: this.premultipliedAlpha, - preserveDrawingBuffer: this.preserveDrawingBuffer - }; - - this.gl = canvas.getContext('webgl', opts) - || canvas.getContext('experimental-webgl', opts); - - if (!this.gl) { - throw new Error(); - } - - this._glinfo = new __WEBPACK_IMPORTED_MODULE_1__core_GLInfo__["a" /* default */](this.gl); - - if (this.gl.targetRenderer) { - console.error('Already created a renderer'); - } - this.gl.targetRenderer = this; - - this.resize(); - } - catch (e) { - throw 'Error creating WebGL Context ' + e; - } - - // Init managers - this._programMgr = new __WEBPACK_IMPORTED_MODULE_8__gpu_ProgramManager__["a" /* default */](this); -}, -/** @lends clay.Renderer.prototype. **/ -{ - /** - * Resize the canvas - * @param {number} width - * @param {number} height - */ - resize: function(width, height) { - var canvas = this.canvas; - // http://www.khronos.org/webgl/wiki/HandlingHighDPI - // set the display size of the canvas. - var dpr = this.devicePixelRatio; - if (width != null) { - canvas.style.width = width + 'px'; - canvas.style.height = height + 'px'; - // set the size of the drawingBuffer - canvas.width = width * dpr; - canvas.height = height * dpr; - - this._width = width; - this._height = height; - } - else { - this._width = canvas.width / dpr; - this._height = canvas.height / dpr; - } - - this.setViewport(0, 0, this._width, this._height); - }, - - /** - * Get renderer width - * @return {number} - */ - getWidth: function () { - return this._width; - }, - - /** - * Get renderer height - * @return {number} - */ - getHeight: function () { - return this._height; - }, - - /** - * Get viewport aspect, - * @return {number} - */ - getViewportAspect: function () { - var viewport = this.viewport; - return viewport.width / viewport.height; - }, - - /** - * Set devicePixelRatio - * @param {number} devicePixelRatio - */ - setDevicePixelRatio: function(devicePixelRatio) { - this.devicePixelRatio = devicePixelRatio; - this.resize(this._width, this._height); - }, - - /** - * Get devicePixelRatio - * @param {number} devicePixelRatio - */ - getDevicePixelRatio: function () { - return this.devicePixelRatio; - }, - - /** - * Get WebGL extension - * @param {string} name - * @return {object} - */ - getGLExtension: function (name) { - return this._glinfo.getExtension(name); - }, - - /** - * Get WebGL parameter - * @param {string} name - * @return {*} - */ - getGLParameter: function (name) { - return this._glinfo.getParameter(name); - }, - - /** - * Set rendering viewport - * @param {number|Object} x - * @param {number} [y] - * @param {number} [width] - * @param {number} [height] - * @param {number} [devicePixelRatio] - * Defaultly use the renderere devicePixelRatio - * It needs to be 1 when setViewport is called by frameBuffer - * - * @example - * setViewport(0,0,width,height,1) - * setViewport({ - * x: 0, - * y: 0, - * width: width, - * height: height, - * devicePixelRatio: 1 - * }) - */ - setViewport: function (x, y, width, height, dpr) { - - if (typeof x === 'object') { - var obj = x; - - x = obj.x; - y = obj.y; - width = obj.width; - height = obj.height; - dpr = obj.devicePixelRatio; - } - dpr = dpr || this.devicePixelRatio; - - this.gl.viewport( - x * dpr, y * dpr, width * dpr, height * dpr - ); - // Use a fresh new object, not write property. - this.viewport = { - x: x, - y: y, - width: width, - height: height, - devicePixelRatio: dpr - }; - }, - - /** - * Push current viewport into a stack - */ - saveViewport: function () { - this._viewportStack.push(this.viewport); - }, - - /** - * Pop viewport from stack, restore in the renderer - */ - restoreViewport: function () { - if (this._viewportStack.length > 0) { - this.setViewport(this._viewportStack.pop()); - } - }, - - /** - * Push current clear into a stack - */ - saveClear: function () { - this._clearStack.push({ - clearBit: this.clearBit, - clearColor: this.clearColor - }); - }, - - /** - * Pop clear from stack, restore in the renderer - */ - restoreClear: function () { - if (this._clearStack.length > 0) { - var opt = this._clearStack.pop(); - this.clearColor = opt.clearColor; - this.clearBit = opt.clearBit; - } - }, - - bindSceneRendering: function (scene) { - this._sceneRendering = scene; - }, - - /** - * Render the scene in camera to the screen or binded offline framebuffer - * @param {clay.Scene} scene - * @param {clay.Camera} camera - * @param {boolean} [notUpdateScene] If not call the scene.update methods in the rendering, default true - * @param {boolean} [preZ] If use preZ optimization, default false - * @return {IRenderInfo} - */ - render: function(scene, camera, notUpdateScene, preZ) { - var _gl = this.gl; - - var clearColor = this.clearColor; - - if (this.clearBit) { - - // Must set depth and color mask true before clear - _gl.colorMask(true, true, true, true); - _gl.depthMask(true); - var viewport = this.viewport; - var needsScissor = false; - var viewportDpr = viewport.devicePixelRatio; - if (viewport.width !== this._width || viewport.height !== this._height - || (viewportDpr && viewportDpr !== this.devicePixelRatio) - || viewport.x || viewport.y - ) { - needsScissor = true; - // http://stackoverflow.com/questions/11544608/how-to-clear-a-rectangle-area-in-webgl - // Only clear the viewport - _gl.enable(_gl.SCISSOR_TEST); - _gl.scissor(viewport.x * viewportDpr, viewport.y * viewportDpr, viewport.width * viewportDpr, viewport.height * viewportDpr); - } - _gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); - _gl.clear(this.clearBit); - if (needsScissor) { - _gl.disable(_gl.SCISSOR_TEST); - } - } - - // If the scene have been updated in the prepass like shadow map - // There is no need to update it again - if (!notUpdateScene) { - scene.update(false); - } - camera = camera || scene.getMainCamera(); - if (!camera) { - console.error('Can\'t find camera in the scene.'); - return; - } - // Update if camera not mounted on the scene - if (!camera.getScene()) { - camera.update(true); - } - - this._sceneRendering = scene; - - // Reset the scene bounding box; - scene.viewBoundingBoxLastFrame.min.set(Infinity, Infinity, Infinity); - scene.viewBoundingBoxLastFrame.max.set(-Infinity, -Infinity, -Infinity); - - var opaqueList = this.cullRenderList(scene.opaqueList, scene, camera); - var transparentList = this.cullRenderList(scene.transparentList, scene, camera); - var sceneMaterial = scene.material; - - scene.trigger('beforerender', this, scene, camera); - - // Render pre z - if (preZ) { - this.renderPreZ(opaqueList, scene, camera); - _gl.depthFunc(_gl.LEQUAL); - } - else { - _gl.depthFunc(_gl.LESS); - } - - // Update the depth of transparent list. - var worldViewMat = mat4Create(); - var posViewSpace = vec3.create(); - for (var i = 0; i < transparentList.length; i++) { - var renderable = transparentList[i]; - mat4.multiplyAffine(worldViewMat, camera.viewMatrix.array, renderable.worldTransform.array); - vec3.transformMat4(posViewSpace, renderable.position.array, worldViewMat); - renderable.__depth = posViewSpace[2]; - } - - // Render opaque list - var opaqueRenderInfo = this.renderPass(opaqueList, camera, { - getMaterial: function (renderable) { - return sceneMaterial || renderable.material; - }, - sortCompare: this.opaqueSortCompare - }); - - var transparentRenderInfo = this.renderPass(transparentList, camera, { - getMaterial: function (renderable) { - return sceneMaterial || renderable.material; - }, - sortCompare: this.transparentSortCompare - }); - - var renderInfo = {}; - for (var name in opaqueRenderInfo) { - renderInfo[name] = opaqueRenderInfo[name] + transparentRenderInfo[name]; - } - - scene.trigger('afterrender', this, scene, camera, renderInfo); - - // Cleanup - this._sceneRendering = null; - return renderInfo; - }, - - getProgram: function (renderable, renderMaterial, scene) { - renderMaterial = renderMaterial || renderable.material; - return this._programMgr.getProgram(renderable, renderMaterial, scene); - }, - - validateProgram: function (program) { - if (program.__error) { - var errorMsg = program.__error; - if (errorShader[program.__uid__]) { - return; - } - errorShader[program.__uid__] = true; - - if (this.throwError) { - throw new Error(errorMsg); - } - else { - this.trigger('error', errorMsg); - } - } - - }, - - updatePrograms: function (list, scene, passConfig) { - var getMaterial = (passConfig && passConfig.getMaterial) || defaultGetMaterial; - scene = scene || null; - for (var i = 0; i < list.length; i++) { - var renderable = list[i]; - var renderMaterial = getMaterial.call(this, renderable); - if (i > 0) { - var prevRenderable = list[i - 1]; - var prevJointsLen = prevRenderable.joints ? prevRenderable.joints.length : 0; - var jointsLen = renderable.joints.length ? renderable.joints.length : 0; - // Keep program not change if joints, material, lightGroup are same of two renderables. - if (jointsLen === prevJointsLen - && renderable.material === prevRenderable.material - && renderable.lightGroup === prevRenderable.lightGroup - ) { - renderable.__program = prevRenderable.__program; - continue; - } - } - - var program = this._programMgr.getProgram(renderable, renderMaterial, scene); - - this.validateProgram(program); - - renderable.__program = program; - } - }, - - /** - * Do frustum culling on render list - */ - cullRenderList: function (list, scene, camera) { - var culledRenderList = []; - for (var i = 0; i < list.length; i++) { - var renderable = list[i]; - - var worldM = renderable.isSkinnedMesh() ? matrices.IDENTITY : renderable.worldTransform.array; - var geometry = renderable.geometry; - - mat4.multiplyAffine(matrices.WORLDVIEW, camera.viewMatrix.array , worldM); - if (geometry.boundingBox) { - if (this.isFrustumCulled( - renderable, scene, camera, matrices.WORLDVIEW, camera.projectionMatrix.array - )) { - continue; - } - } - - culledRenderList.push(renderable); - } - - return culledRenderList; - }, - - /** - * Render a single renderable list in camera in sequence - * @param {clay.Renderable[]} list List of all renderables. - * @param {clay.Camera} camera - * @param {Object} [passConfig] - * @param {Function} [passConfig.getMaterial] Get renderable material. - * @param {Function} [passConfig.beforeRender] Before render each renderable. - * @param {Function} [passConfig.afterRender] After render each renderable - * @param {Function} [passConfig.ifRender] If render the renderable. - * @param {Function} [passConfig.sortCompare] Sort compare function. - * @return {IRenderInfo} - */ - renderPass: function(list, camera, passConfig) { - this.trigger('beforerenderpass', this, list, camera, passConfig); - - var renderInfo = { - triangleCount: 0, - vertexCount: 0, - drawCallCount: 0, - meshCount: list.length, - renderedMeshCount: 0 - }; - passConfig = passConfig || {}; - passConfig.getMaterial = passConfig.getMaterial || defaultGetMaterial; - passConfig.beforeRender = passConfig.beforeRender || noop; - passConfig.afterRender = passConfig.afterRender || noop; - - this.updatePrograms(list, this._sceneRendering, passConfig); - if (passConfig.sortCompare) { - list.sort(passConfig.sortCompare); - } - - // Some common builtin uniforms - var viewport = this.viewport; - var vDpr = viewport.devicePixelRatio; - var viewportUniform = [ - viewport.x * vDpr, viewport.y * vDpr, - viewport.width * vDpr, viewport.height * vDpr - ]; - var windowDpr = this.devicePixelRatio; - var windowSizeUniform = this.__currentFrameBuffer - ? [this.__currentFrameBuffer.getTextureWidth(), this.__currentFrameBuffer.getTextureHeight()] - : [this._width * windowDpr, this._height * windowDpr]; - // DEPRECATED - var viewportSizeUniform = [ - viewportUniform[2], viewportUniform[3] - ]; - var time = Date.now(); - - // Calculate view and projection matrix - mat4.copy(matrices.VIEW, camera.viewMatrix.array); - mat4.copy(matrices.PROJECTION, camera.projectionMatrix.array); - mat4.multiply(matrices.VIEWPROJECTION, camera.projectionMatrix.array, matrices.VIEW); - mat4.copy(matrices.VIEWINVERSE, camera.worldTransform.array); - mat4.invert(matrices.PROJECTIONINVERSE, matrices.PROJECTION); - mat4.invert(matrices.VIEWPROJECTIONINVERSE, matrices.VIEWPROJECTION); - - var _gl = this.gl; - var scene = this._sceneRendering; - - var prevMaterial; - var prevProgram; - - // Status - var depthTest, depthMask; - var culling, cullFace, frontFace; - var transparent; - - for (var i = 0; i < list.length; i++) { - var renderable = list[i]; - if (passConfig.ifRender && !passConfig.ifRender(renderable)) { - continue; - } - - // Skinned mesh will transformed to joint space. Ignore the mesh transform - var worldM = renderable.isSkinnedMesh() ? matrices.IDENTITY : renderable.worldTransform.array; - - var material = passConfig.getMaterial.call(this, renderable); - - var program = renderable.__program; - var shader = material.shader; - - mat4.copy(matrices.WORLD, worldM); - mat4.multiply(matrices.WORLDVIEWPROJECTION, matrices.VIEWPROJECTION , worldM); - if (shader.matrixSemantics.WORLDINVERSE || - shader.matrixSemantics.WORLDINVERSETRANSPOSE) { - mat4.invert(matrices.WORLDINVERSE, worldM); - } - if (shader.matrixSemantics.WORLDVIEWINVERSE || - shader.matrixSemantics.WORLDVIEWINVERSETRANSPOSE) { - mat4.invert(matrices.WORLDVIEWINVERSE, matrices.WORLDVIEW); - } - if (shader.matrixSemantics.WORLDVIEWPROJECTIONINVERSE || - shader.matrixSemantics.WORLDVIEWPROJECTIONINVERSETRANSPOSE) { - mat4.invert(matrices.WORLDVIEWPROJECTIONINVERSE, matrices.WORLDVIEWPROJECTION); - } - - // Before render hook - renderable.beforeRender(this); - passConfig.beforeRender.call(this, renderable, material, prevMaterial); - - var programChanged = program !== prevProgram; - if (programChanged) { - // Set lights number - program.bind(this); - // Set some common uniforms - program.setUniformOfSemantic(_gl, 'VIEWPORT', viewportUniform); - program.setUniformOfSemantic(_gl, 'WINDOW_SIZE', windowSizeUniform); - program.setUniformOfSemantic(_gl, 'NEAR', camera.near); - program.setUniformOfSemantic(_gl, 'FAR', camera.far); - program.setUniformOfSemantic(_gl, 'DEVICEPIXELRATIO', vDpr); - program.setUniformOfSemantic(_gl, 'TIME', time); - // DEPRECATED - program.setUniformOfSemantic(_gl, 'VIEWPORT_SIZE', viewportSizeUniform); - - // Set lights uniforms - // TODO needs optimized - if (scene) { - scene.setLightUniforms(program, renderable.lightGroup, this); - } - } - else { - program = prevProgram; - } - - // Program changes also needs reset the materials. - if (prevMaterial !== material || programChanged) { - if (material.depthTest !== depthTest) { - material.depthTest - ? _gl.enable(_gl.DEPTH_TEST) - : _gl.disable(_gl.DEPTH_TEST); - depthTest = material.depthTest; - } - if (material.depthMask !== depthMask) { - _gl.depthMask(material.depthMask); - depthMask = material.depthMask; - } - if (material.transparent !== transparent) { - material.transparent - ? _gl.enable(_gl.BLEND) - : _gl.disable(_gl.BLEND); - transparent = material.transparent; - } - // TODO cache blending - if (material.transparent) { - if (material.blend) { - material.blend(_gl); - } - else { - // Default blend function - _gl.blendEquationSeparate(_gl.FUNC_ADD, _gl.FUNC_ADD); - _gl.blendFuncSeparate(_gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA); - } - } - - material.bind(this, program, prevMaterial, prevProgram); - prevMaterial = material; - } - - var matrixSemanticKeys = shader.matrixSemanticKeys; - for (var k = 0; k < matrixSemanticKeys.length; k++) { - var semantic = matrixSemanticKeys[k]; - var semanticInfo = shader.matrixSemantics[semantic]; - var matrix = matrices[semantic]; - if (semanticInfo.isTranspose) { - var matrixNoTranspose = matrices[semanticInfo.semanticNoTranspose]; - mat4.transpose(matrix, matrixNoTranspose); - } - program.setUniform(_gl, semanticInfo.type, semanticInfo.symbol, matrix); - } - - if (renderable.cullFace !== cullFace) { - cullFace = renderable.cullFace; - _gl.cullFace(cullFace); - } - if (renderable.frontFace !== frontFace) { - frontFace = renderable.frontFace; - _gl.frontFace(frontFace); - } - if (renderable.culling !== culling) { - culling = renderable.culling; - culling ? _gl.enable(_gl.CULL_FACE) : _gl.disable(_gl.CULL_FACE); - } - - var objectRenderInfo = renderable.render(this, material, program); - - if (objectRenderInfo) { - renderInfo.triangleCount += objectRenderInfo.triangleCount; - renderInfo.vertexCount += objectRenderInfo.vertexCount; - renderInfo.drawCallCount += objectRenderInfo.drawCallCount; - renderInfo.renderedMeshCount ++; - } - - // After render hook - passConfig.afterRender.call(this, renderable, objectRenderInfo); - renderable.afterRender(this, objectRenderInfo); - - prevProgram = program; - } - - // Remove programs incase it's not updated in the other passes. - for (var i = 0; i < list.length; i++) { - list[i].__program = null; - } - - this.trigger('afterrenderpass', this, list, camera, passConfig); - - return renderInfo; - }, - - renderPreZ: function (list, scene, camera) { - var _gl = this.gl; - var preZPassMaterial = this._prezMaterial || new __WEBPACK_IMPORTED_MODULE_6__Material__["a" /* default */]({ - shader: new __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */](__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.prez.vertex'), __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.prez.fragment')) - }); - this._prezMaterial = preZPassMaterial; - - _gl.colorMask(false, false, false, false); - _gl.depthMask(true); - - // Status - this.renderPass(list, camera, { - ifRender: function (renderable) { - return !renderable.ignorePreZ; - }, - getMaterial: function () { - return preZPassMaterial; - }, - sort: this.opaqueSortCompare - }); - - _gl.colorMask(true, true, true, true); - _gl.depthMask(true); - }, - - /** - * If an scene object is culled by camera frustum - * - * Object can be a renderable or a light - * - * @param {clay.Node} Scene object - * @param {clay.Camera} camera - * @param {Array.} worldViewMat represented with array - * @param {Array.} projectionMat represented with array - */ - isFrustumCulled: (function () { - // Frustum culling - // http://www.cse.chalmers.se/~uffe/vfc_bbox.pdf - var cullingBoundingBox = new __WEBPACK_IMPORTED_MODULE_4__math_BoundingBox__["a" /* default */](); - var cullingMatrix = new __WEBPACK_IMPORTED_MODULE_5__math_Matrix4__["a" /* default */](); - return function (object, scene, camera, worldViewMat, projectionMat) { - // Bounding box can be a property of object(like light) or renderable.geometry - var geoBBox = object.boundingBox || object.geometry.boundingBox; - cullingMatrix.array = worldViewMat; - cullingBoundingBox.copy(geoBBox); - cullingBoundingBox.applyTransform(cullingMatrix); - - // Passingly update the scene bounding box - // FIXME exclude very large mesh like ground plane or terrain ? - // FIXME Only rendererable which cast shadow ? - - // FIXME boundingBox becomes much larger after transformd. - if (scene && object.isRenderable() && object.castShadow) { - scene.viewBoundingBoxLastFrame.union(cullingBoundingBox); - } - // Ignore frustum culling if object is skinned mesh. - if (object.frustumCulling && !object.isSkinnedMesh()) { - if (!cullingBoundingBox.intersectBoundingBox(camera.frustum.boundingBox)) { - return true; - } - - cullingMatrix.array = projectionMat; - if ( - cullingBoundingBox.max.array[2] > 0 && - cullingBoundingBox.min.array[2] < 0 - ) { - // Clip in the near plane - cullingBoundingBox.max.array[2] = -1e-20; - } - - cullingBoundingBox.applyProjection(cullingMatrix); - - var min = cullingBoundingBox.min.array; - var max = cullingBoundingBox.max.array; - - if ( - max[0] < -1 || min[0] > 1 - || max[1] < -1 || min[1] > 1 - || max[2] < -1 || min[2] > 1 - ) { - return true; - } - } - - return false; - }; - })(), - - /** - * Dispose given scene, including all geometris, textures and shaders in the scene - * @param {clay.Scene} scene - */ - disposeScene: function(scene) { - this.disposeNode(scene, true, true); - scene.dispose(); - }, - - /** - * Dispose given node, including all geometries, textures and shaders attached on it or its descendant - * @param {clay.Node} node - * @param {boolean} [disposeGeometry=false] If dispose the geometries used in the descendant mesh - * @param {boolean} [disposeTexture=false] If dispose the textures used in the descendant mesh - */ - disposeNode: function(root, disposeGeometry, disposeTexture) { - // Dettached from parent - if (root.getParent()) { - root.getParent().remove(root); - } - root.traverse(function(node) { - if (node.geometry && disposeGeometry) { - node.geometry.dispose(this); - } - // Particle system and AmbientCubemap light need to dispose - if (node.dispose) { - node.dispose(this); - } - }, this); - }, - - /** - * Dispose given geometry - * @param {clay.Geometry} geometry - */ - disposeGeometry: function(geometry) { - geometry.dispose(this); - }, - - /** - * Dispose given texture - * @param {clay.Texture} texture - */ - disposeTexture: function(texture) { - texture.dispose(this); - }, - - /** - * Dispose given frame buffer - * @param {clay.FrameBuffer} frameBuffer - */ - disposeFrameBuffer: function(frameBuffer) { - frameBuffer.dispose(this); - }, - - /** - * Dispose renderer - */ - dispose: function () {}, - - /** - * Convert screen coords to normalized device coordinates(NDC) - * Screen coords can get from mouse event, it is positioned relative to canvas element - * NDC can be used in ray casting with Camera.prototype.castRay methods - * - * @param {number} x - * @param {number} y - * @param {clay.math.Vector2} [out] - * @return {clay.math.Vector2} - */ - screenToNDC: function(x, y, out) { - if (!out) { - out = new __WEBPACK_IMPORTED_MODULE_7__math_Vector2__["a" /* default */](); - } - // Invert y; - y = this._height - y; - - var viewport = this.viewport; - var arr = out.array; - arr[0] = (x - viewport.x) / viewport.width; - arr[0] = arr[0] * 2 - 1; - arr[1] = (y - viewport.y) / viewport.height; - arr[1] = arr[1] * 2 - 1; - - return out; - } -}); - -/** - * Opaque renderables compare function - * @param {clay.Renderable} x - * @param {clay.Renderable} y - * @return {boolean} - * @static - */ -Renderer.opaqueSortCompare = Renderer.prototype.opaqueSortCompare = function(x, y) { - // Priority renderOrder -> program -> material -> geometry - if (x.renderOrder === y.renderOrder) { - if (x.__program === y.__program) { - if (x.material === y.material) { - return x.geometry.__uid__ - y.geometry.__uid__; - } - return x.material.__uid__ - y.material.__uid__; - } - if (x.__program && y.__program) { - return x.__program.__uid__ - y.__program.__uid__; - } - return 0; - } - return x.renderOrder - y.renderOrder; -}; - -/** - * Transparent renderables compare function - * @param {clay.Renderable} a - * @param {clay.Renderable} b - * @return {boolean} - * @static - */ -Renderer.transparentSortCompare = Renderer.prototype.transparentSortCompare = function(x, y) { - // Priority renderOrder -> depth -> program -> material -> geometry - - if (x.renderOrder === y.renderOrder) { - if (x.__depth === y.__depth) { - if (x.__program === y.__program) { - if (x.material === y.material) { - return x.geometry.__uid__ - y.geometry.__uid__; - } - return x.material.__uid__ - y.material.__uid__; - } - if (x.__program && y.__program) { - return x.__program.__uid__ - y.__program.__uid__; - } - return 0; - } - // Depth is negative - // So farther object has smaller depth value - return x.__depth - y.__depth; - } - return x.renderOrder - y.renderOrder; -}; - -// Temporary variables -var matrices = { - IDENTITY: mat4Create(), - - WORLD: mat4Create(), - VIEW: mat4Create(), - PROJECTION: mat4Create(), - WORLDVIEW: mat4Create(), - VIEWPROJECTION: mat4Create(), - WORLDVIEWPROJECTION: mat4Create(), - - WORLDINVERSE: mat4Create(), - VIEWINVERSE: mat4Create(), - PROJECTIONINVERSE: mat4Create(), - WORLDVIEWINVERSE: mat4Create(), - VIEWPROJECTIONINVERSE: mat4Create(), - WORLDVIEWPROJECTIONINVERSE: mat4Create(), - - WORLDTRANSPOSE: mat4Create(), - VIEWTRANSPOSE: mat4Create(), - PROJECTIONTRANSPOSE: mat4Create(), - WORLDVIEWTRANSPOSE: mat4Create(), - VIEWPROJECTIONTRANSPOSE: mat4Create(), - WORLDVIEWPROJECTIONTRANSPOSE: mat4Create(), - WORLDINVERSETRANSPOSE: mat4Create(), - VIEWINVERSETRANSPOSE: mat4Create(), - PROJECTIONINVERSETRANSPOSE: mat4Create(), - WORLDVIEWINVERSETRANSPOSE: mat4Create(), - VIEWPROJECTIONINVERSETRANSPOSE: mat4Create(), - WORLDVIEWPROJECTIONINVERSETRANSPOSE: mat4Create() -}; - -/** - * @name clay.Renderer.COLOR_BUFFER_BIT - * @type {number} - */ -Renderer.COLOR_BUFFER_BIT = __WEBPACK_IMPORTED_MODULE_2__core_glenum__["a" /* default */].COLOR_BUFFER_BIT; -/** - * @name clay.Renderer.DEPTH_BUFFER_BIT - * @type {number} - */ -Renderer.DEPTH_BUFFER_BIT = __WEBPACK_IMPORTED_MODULE_2__core_glenum__["a" /* default */].DEPTH_BUFFER_BIT; -/** - * @name clay.Renderer.STENCIL_BUFFER_BIT - * @type {number} - */ -Renderer.STENCIL_BUFFER_BIT = __WEBPACK_IMPORTED_MODULE_2__core_glenum__["a" /* default */].STENCIL_BUFFER_BIT; - -/* harmony default export */ __webpack_exports__["a"] = (Renderer); - - -/***/ }), -/* 28 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -var DIRTY_PREFIX = '__dt__'; - -var Cache = function () { - - this._contextId = 0; - - this._caches = []; - - this._context = {}; -}; - -Cache.prototype = { - - use: function (contextId, documentSchema) { - var caches = this._caches; - if (!caches[contextId]) { - caches[contextId] = {}; - - if (documentSchema) { - caches[contextId] = documentSchema(); - } - } - this._contextId = contextId; - - this._context = caches[contextId]; - }, - - put: function (key, value) { - this._context[key] = value; - }, - - get: function (key) { - return this._context[key]; - }, - - dirty: function (field) { - field = field || ''; - var key = DIRTY_PREFIX + field; - this.put(key, true); - }, - - dirtyAll: function (field) { - field = field || ''; - var key = DIRTY_PREFIX + field; - var caches = this._caches; - for (var i = 0; i < caches.length; i++) { - if (caches[i]) { - caches[i][key] = true; - } - } - }, - - fresh: function (field) { - field = field || ''; - var key = DIRTY_PREFIX + field; - this.put(key, false); - }, - - freshAll: function (field) { - field = field || ''; - var key = DIRTY_PREFIX + field; - var caches = this._caches; - for (var i = 0; i < caches.length; i++) { - if (caches[i]) { - caches[i][key] = false; - } - } - }, - - isDirty: function (field) { - field = field || ''; - var key = DIRTY_PREFIX + field; - var context = this._context; - return !context.hasOwnProperty(key) - || context[key] === true; - }, - - deleteContext: function (contextId) { - delete this._caches[contextId]; - this._context = {}; - }, - - delete: function (key) { - delete this._context[key]; - }, - - clearAll: function () { - this._caches = {}; - }, - - getContext: function () { - return this._context; - }, - - eachContext : function (cb, context) { - var keys = Object.keys(this._caches); - keys.forEach(function (key) { - cb && cb.call(context, key); - }); - }, - - miss: function (key) { - return ! this._context.hasOwnProperty(key); - } -}; - -Cache.prototype.constructor = Cache; - -/* harmony default export */ __webpack_exports__["a"] = (Cache); - - -/***/ }), -/* 29 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -function get(options) { - - var xhr = new XMLHttpRequest(); - - xhr.open('get', options.url); - // With response type set browser can get and put binary data - // https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Sending_and_Receiving_Binary_Data - // Default is text, and it can be set - // arraybuffer, blob, document, json, text - xhr.responseType = options.responseType || 'text'; - - if (options.onprogress) { - //https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest - xhr.onprogress = function(e) { - if (e.lengthComputable) { - var percent = e.loaded / e.total; - options.onprogress(percent, e.loaded, e.total); - } - else { - options.onprogress(null); - } - }; - } - xhr.onload = function(e) { - if (xhr.status >= 400) { - options.onerror && options.onerror(); - } - else { - options.onload && options.onload(xhr.response); - } - }; - if (options.onerror) { - xhr.onerror = options.onerror; - } - xhr.send(null); -} - -/* harmony default export */ __webpack_exports__["a"] = ({ - get : get -}); - - -/***/ }), -/* 30 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Node__ = __webpack_require__(15); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__math_Matrix4__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__math_Frustum__ = __webpack_require__(42); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__math_Ray__ = __webpack_require__(43); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_4__dep_glmatrix__); - - - - - - -var vec3 = __WEBPACK_IMPORTED_MODULE_4__dep_glmatrix___default.a.vec3; -var vec4 = __WEBPACK_IMPORTED_MODULE_4__dep_glmatrix___default.a.vec4; - -/** - * @constructor clay.Camera - * @extends clay.Node - */ -var Camera = __WEBPACK_IMPORTED_MODULE_0__Node__["a" /* default */].extend(function () { - return /** @lends clay.Camera# */ { - /** - * Camera projection matrix - * @type {clay.math.Matrix4} - */ - projectionMatrix: new __WEBPACK_IMPORTED_MODULE_1__math_Matrix4__["a" /* default */](), - - /** - * Inverse of camera projection matrix - * @type {clay.math.Matrix4} - */ - invProjectionMatrix: new __WEBPACK_IMPORTED_MODULE_1__math_Matrix4__["a" /* default */](), - - /** - * View matrix, equal to inverse of camera's world matrix - * @type {clay.math.Matrix4} - */ - viewMatrix: new __WEBPACK_IMPORTED_MODULE_1__math_Matrix4__["a" /* default */](), - - /** - * Camera frustum in view space - * @type {clay.math.Frustum} - */ - frustum: new __WEBPACK_IMPORTED_MODULE_2__math_Frustum__["a" /* default */]() - }; -}, function () { - this.update(true); -}, -/** @lends clay.Camera.prototype */ -{ - - update: function (force) { - __WEBPACK_IMPORTED_MODULE_0__Node__["a" /* default */].prototype.update.call(this, force); - __WEBPACK_IMPORTED_MODULE_1__math_Matrix4__["a" /* default */].invert(this.viewMatrix, this.worldTransform); - - this.updateProjectionMatrix(); - __WEBPACK_IMPORTED_MODULE_1__math_Matrix4__["a" /* default */].invert(this.invProjectionMatrix, this.projectionMatrix); - - this.frustum.setFromProjection(this.projectionMatrix); - }, - - /** - * Set camera view matrix - */ - setViewMatrix: function (viewMatrix) { - __WEBPACK_IMPORTED_MODULE_1__math_Matrix4__["a" /* default */].copy(this.viewMatrix, viewMatrix); - __WEBPACK_IMPORTED_MODULE_1__math_Matrix4__["a" /* default */].invert(this.worldTransform, viewMatrix); - this.decomposeWorldTransform(); - }, - - /** - * Decompose camera projection matrix - */ - decomposeProjectionMatrix: function () {}, - - /** - * Set camera projection matrix - * @param {clay.math.Matrix4} projectionMatrix - */ - setProjectionMatrix: function (projectionMatrix) { - __WEBPACK_IMPORTED_MODULE_1__math_Matrix4__["a" /* default */].copy(this.projectionMatrix, projectionMatrix); - __WEBPACK_IMPORTED_MODULE_1__math_Matrix4__["a" /* default */].invert(this.invProjectionMatrix, projectionMatrix); - this.decomposeProjectionMatrix(); - }, - /** - * Update projection matrix, called after update - */ - updateProjectionMatrix: function () {}, - - /** - * Cast a picking ray from camera near plane to far plane - * @function - * @param {clay.math.Vector2} ndc - * @param {clay.math.Ray} [out] - * @return {clay.math.Ray} - */ - castRay: (function () { - var v4 = vec4.create(); - return function (ndc, out) { - var ray = out !== undefined ? out : new __WEBPACK_IMPORTED_MODULE_3__math_Ray__["a" /* default */](); - var x = ndc.array[0]; - var y = ndc.array[1]; - vec4.set(v4, x, y, -1, 1); - vec4.transformMat4(v4, v4, this.invProjectionMatrix.array); - vec4.transformMat4(v4, v4, this.worldTransform.array); - vec3.scale(ray.origin.array, v4, 1 / v4[3]); - - vec4.set(v4, x, y, 1, 1); - vec4.transformMat4(v4, v4, this.invProjectionMatrix.array); - vec4.transformMat4(v4, v4, this.worldTransform.array); - vec3.scale(v4, v4, 1 / v4[3]); - vec3.sub(ray.direction.array, v4, ray.origin.array); - - vec3.normalize(ray.direction.array, ray.direction.array); - ray.direction._dirty = true; - ray.origin._dirty = true; - - return ray; - }; - })() - - /** - * @function - * @name clone - * @return {clay.Camera} - * @memberOf clay.Camera.prototype - */ -}); - -/* harmony default export */ __webpack_exports__["a"] = (Camera); - - -/***/ }), -/* 31 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Shader__ = __webpack_require__(4); - - -var _library = {}; - -function ShaderLibrary () { - this._pool = {}; -} - -ShaderLibrary.prototype.get = function(name) { - var key = name; - - if (this._pool[key]) { - return this._pool[key]; - } - else { - var source = _library[name]; - if (!source) { - console.error('Shader "' + name + '"' + ' is not in the library'); - return; - } - var shader = new __WEBPACK_IMPORTED_MODULE_0__Shader__["a" /* default */](source.vertex, source.fragment); - this._pool[key] = shader; - return shader; - } -}; - -ShaderLibrary.prototype.clear = function() { - this._pool = {}; -}; - -function template(name, vertex, fragment) { - _library[name] = { - vertex: vertex, - fragment: fragment - }; -} - -var defaultLibrary = new ShaderLibrary(); - -/** - * ### Builin shaders - * + clay.standard - * + clay.basic - * + clay.lambert - * + clay.wireframe - * - * @namespace clay.shader.library - */ -/* harmony default export */ __webpack_exports__["a"] = ({ - /** - * Create a new shader library. - */ - createLibrary: function () { - return new ShaderLibrary(); - }, - /** - * Get shader from default library. - * @param {string} name - * @return {clay.Shader} - * @memberOf clay.shader.library - * @example - * clay.shader.library.get('clay.standard') - */ - get: function () { - return defaultLibrary.get.apply(defaultLibrary, arguments); - }, - /** - * @memberOf clay.shader.library - * @param {string} name - * @param {string} vertex - Vertex shader code - * @param {string} fragment - Fragment shader code - */ - template: template, - clear: function () { - return defaultLibrary.clear(); - } -}); - - -/***/ }), -/* 32 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__easing__ = __webpack_require__(49); - - -function noop () {} -/** - * @constructor - * @alias clay.animation.Clip - * @param {Object} [opts] - * @param {Object} [opts.target] - * @param {number} [opts.life] - * @param {number} [opts.delay] - * @param {number} [opts.gap] - * @param {number} [opts.playbackRate] - * @param {boolean|number} [opts.loop] If loop is a number, it indicate the loop count of animation - * @param {string|Function} [opts.easing] - * @param {Function} [opts.onframe] - * @param {Function} [opts.onfinish] - * @param {Function} [opts.onrestart] - */ -var Clip = function (opts) { - - opts = opts || {}; - - /** - * @type {string} - */ - this.name = opts.name || ''; - - /** - * @type {Object} - */ - this.target = opts.target; - - /** - * @type {number} - */ - this.life = opts.life || 1000; - - /** - * @type {number} - */ - this.delay = opts.delay || 0; - - /** - * @type {number} - */ - this.gap = opts.gap || 0; - - /** - * @type {number} - */ - this.playbackRate = opts.playbackRate || 1; - - - this._initialized = false; - - this._elapsedTime = 0; - - this._loop = opts.loop == null ? false : opts.loop; - this.setLoop(this._loop); - - if (opts.easing != null) { - this.setEasing(opts.easing); - } - - /** - * @type {Function} - */ - this.onframe = opts.onframe || noop; - - /** - * @type {Function} - */ - this.onfinish = opts.onfinish || noop; - - /** - * @type {Function} - */ - this.onrestart = opts.onrestart || noop; - - this._paused = false; -}; - -Clip.prototype = { - - gap: 0, - - life: 0, - - delay: 0, - - /** - * @param {number|boolean} loop - */ - setLoop: function (loop) { - this._loop = loop; - if (loop) { - if (typeof(loop) == 'number') { - this._loopRemained = loop; - } - else { - this._loopRemained = 1e8; - } - } - }, - - /** - * @param {string|Function} easing - */ - setEasing: function (easing) { - if (typeof(easing) === 'string') { - easing = __WEBPACK_IMPORTED_MODULE_0__easing__["a" /* default */][easing]; - } - this.easing = easing; - }, - - /** - * @param {number} time - * @return {string} - */ - step: function (time, deltaTime, silent) { - if (!this._initialized) { - this._startTime = time + this.delay; - this._initialized = true; - } - if (this._currentTime != null) { - deltaTime = time - this._currentTime; - } - this._currentTime = time; - - if (this._paused) { - return 'paused'; - } - - if (time < this._startTime) { - return; - } - - // PENDIGN Sync ? - this._elapse(time, deltaTime); - - var percent = Math.min(this._elapsedTime / this.life, 1); - - if (percent < 0) { - return; - } - - var schedule; - if (this.easing) { - schedule = this.easing(percent); - } - else { - schedule = percent; - } - - if (!silent) { - this.fire('frame', schedule); - } - - if (percent === 1) { - if (this._loop && this._loopRemained > 0) { - this._restartInLoop(time); - this._loopRemained--; - return 'restart'; - } - else { - // Mark this clip to be deleted - // In the animation.update - this._needsRemove = true; - - return 'finish'; - } - } - else { - return null; - } - }, - - /** - * @param {number} time - * @return {string} - */ - setTime: function (time) { - return this.step(time + this._startTime); - }, - - restart: function (time) { - // If user leave the page for a while, when he gets back - // All clips may be expired and all start from the beginning value(position) - // It is clearly wrong, so we use remainder to add a offset - - var remainder = 0; - // Remainder ignored if restart is invoked manually - if (time) { - this._elapse(time); - remainder = this._elapsedTime % this.life; - } - time = time || Date.now(); - - this._startTime = time - remainder + this.delay; - this._elapsedTime = 0; - - this._needsRemove = false; - this._paused = false; - }, - - getElapsedTime: function () { - return this._elapsedTime; - }, - - _restartInLoop: function (time) { - this._startTime = time + this.gap; - this._elapsedTime = 0; - }, - - _elapse: function (time, deltaTime) { - this._elapsedTime += deltaTime * this.playbackRate; - }, - - fire: function (eventType, arg) { - var eventName = 'on' + eventType; - if (this[eventName]) { - this[eventName](this.target, arg); - } - }, - - clone: function () { - var clip = new this.constructor(); - clip.name = this.name; - clip._loop = this._loop; - clip._loopRemained = this._loopRemained; - - clip.life = this.life; - clip.gap = this.gap; - clip.delay = this.delay; - - return clip; - }, - /** - * Pause the clip. - */ - pause: function () { - this._paused = true; - }, - - /** - * Resume the clip. - */ - resume: function () { - this._paused = false; - } -}; -Clip.prototype.constructor = Clip; - -/* harmony default export */ __webpack_exports__["a"] = (Clip); - - -/***/ }), -/* 33 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Geometry__ = __webpack_require__(19); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__math_BoundingBox__ = __webpack_require__(8); - - - -/** - * @constructor clay.geometry.Plane - * @extends clay.Geometry - * @param {Object} [opt] - * @param {number} [opt.widthSegments] - * @param {number} [opt.heightSegments] - */ -var Plane = __WEBPACK_IMPORTED_MODULE_0__Geometry__["a" /* default */].extend( -/** @lends clay.geometry.Plane# */ -{ - dynamic: false, - /** - * @type {number} - */ - widthSegments: 1, - /** - * @type {number} - */ - heightSegments: 1 -}, function() { - this.build(); -}, -/** @lends clay.geometry.Plane.prototype */ -{ - /** - * Build plane geometry - */ - build: function() { - var heightSegments = this.heightSegments; - var widthSegments = this.widthSegments; - var attributes = this.attributes; - var positions = []; - var texcoords = []; - var normals = []; - var faces = []; - - for (var y = 0; y <= heightSegments; y++) { - var t = y / heightSegments; - for (var x = 0; x <= widthSegments; x++) { - var s = x / widthSegments; - - positions.push([2 * s - 1, 2 * t - 1, 0]); - if (texcoords) { - texcoords.push([s, t]); - } - if (normals) { - normals.push([0, 0, 1]); - } - if (x < widthSegments && y < heightSegments) { - var i = x + y * (widthSegments + 1); - faces.push([i, i + 1, i + widthSegments + 1]); - faces.push([i + widthSegments + 1, i + 1, i + widthSegments + 2]); - } - } - } - - attributes.position.fromArray(positions); - attributes.texcoord0.fromArray(texcoords); - attributes.normal.fromArray(normals); - - this.initIndicesFromArray(faces); - - this.boundingBox = new __WEBPACK_IMPORTED_MODULE_1__math_BoundingBox__["a" /* default */](); - this.boundingBox.min.set(-1, -1, 0); - this.boundingBox.max.set(1, 1, 0); - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (Plane); - - -/***/ }), -/* 34 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Texture2D__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__TextureCube__ = __webpack_require__(17); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__core_request__ = __webpack_require__(29); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__prePass_EnvironmentMap__ = __webpack_require__(35); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__plugin_Skydome__ = __webpack_require__(36); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__Scene__ = __webpack_require__(18); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__dds__ = __webpack_require__(101); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__hdr__ = __webpack_require__(102); - - - - - - - - - - -/** - * @alias clay.util.texture - */ -var textureUtil = { - /** - * @param {string|object} path - * @param {object} [option] - * @param {Function} [onsuccess] - * @param {Function} [onerror] - * @return {clay.Texture} - */ - loadTexture: function (path, option, onsuccess, onerror) { - var texture; - if (typeof(option) === 'function') { - onsuccess = option; - onerror = onsuccess; - option = {}; - } - else { - option = option || {}; - } - if (typeof(path) === 'string') { - if (path.match(/.hdr$/) || option.fileType === 'hdr') { - texture = new __WEBPACK_IMPORTED_MODULE_0__Texture2D__["a" /* default */]({ - width: 0, - height: 0, - sRGB: false - }); - textureUtil._fetchTexture( - path, - function (data) { - __WEBPACK_IMPORTED_MODULE_7__hdr__["a" /* default */].parseRGBE(data, texture, option.exposure); - texture.dirty(); - onsuccess && onsuccess(texture); - }, - onerror - ); - return texture; - } - else if (path.match(/.dds$/) || option.fileType === 'dds') { - texture = new __WEBPACK_IMPORTED_MODULE_0__Texture2D__["a" /* default */]({ - width: 0, - height: 0 - }); - textureUtil._fetchTexture( - path, - function (data) { - __WEBPACK_IMPORTED_MODULE_6__dds__["a" /* default */].parse(data, texture); - texture.dirty(); - onsuccess && onsuccess(texture); - }, - onerror - ); - } - else { - texture = new __WEBPACK_IMPORTED_MODULE_0__Texture2D__["a" /* default */](); - texture.load(path); - texture.success(onsuccess); - texture.error(onerror); - } - } - else if (typeof(path) == 'object' && typeof(path.px) !== 'undefined') { - var texture = new __WEBPACK_IMPORTED_MODULE_1__TextureCube__["a" /* default */](); - texture.load(path); - texture.success(onsuccess); - texture.error(onerror); - } - return texture; - }, - - /** - * Load a panorama texture and render it to a cube map - * @param {clay.Renderer} renderer - * @param {string} path - * @param {clay.TextureCube} cubeMap - * @param {object} [option] - * @param {boolean} [option.encodeRGBM] - * @param {number} [option.exposure] - * @param {Function} [onsuccess] - * @param {Function} [onerror] - */ - loadPanorama: function (renderer, path, cubeMap, option, onsuccess, onerror) { - var self = this; - - if (typeof(option) === 'function') { - onsuccess = option; - onerror = onsuccess; - option = {}; - } - else { - option = option || {}; - } - - textureUtil.loadTexture(path, option, function (texture) { - // PENDING - texture.flipY = option.flipY || false; - self.panoramaToCubeMap(renderer, texture, cubeMap, option); - texture.dispose(renderer); - onsuccess && onsuccess(cubeMap); - }, onerror); - }, - - /** - * Render a panorama texture to a cube map - * @param {clay.Renderer} renderer - * @param {clay.Texture2D} panoramaMap - * @param {clay.TextureCube} cubeMap - * @param {Object} option - * @param {boolean} [option.encodeRGBM] - */ - panoramaToCubeMap: function (renderer, panoramaMap, cubeMap, option) { - var environmentMapPass = new __WEBPACK_IMPORTED_MODULE_3__prePass_EnvironmentMap__["a" /* default */](); - var skydome = new __WEBPACK_IMPORTED_MODULE_4__plugin_Skydome__["a" /* default */]({ - scene: new __WEBPACK_IMPORTED_MODULE_5__Scene__["a" /* default */]() - }); - skydome.material.set('diffuseMap', panoramaMap); - - option = option || {}; - if (option.encodeRGBM) { - skydome.material.define('fragment', 'RGBM_ENCODE'); - } - - // Share sRGB - cubeMap.sRGB = panoramaMap.sRGB; - - environmentMapPass.texture = cubeMap; - environmentMapPass.render(renderer, skydome.scene); - environmentMapPass.texture = null; - environmentMapPass.dispose(renderer); - return cubeMap; - }, - - /** - * Convert height map to normal map - * @param {HTMLImageElement|HTMLCanvasElement} image - * @param {boolean} [checkBump=false] - * @return {HTMLCanvasElement} - */ - heightToNormal: function (image, checkBump) { - var canvas = document.createElement('canvas'); - var width = canvas.width = image.width; - var height = canvas.height = image.height; - var ctx = canvas.getContext('2d'); - ctx.drawImage(image, 0, 0, width, height); - checkBump = checkBump || false; - var srcData = ctx.getImageData(0, 0, width, height); - var dstData = ctx.createImageData(width, height); - for (var i = 0; i < srcData.data.length; i += 4) { - if (checkBump) { - var r = srcData.data[i]; - var g = srcData.data[i + 1]; - var b = srcData.data[i + 2]; - var diff = Math.abs(r - g) + Math.abs(g - b); - if (diff > 20) { - console.warn('Given image is not a height map'); - return image; - } - } - // Modified from http://mrdoob.com/lab/javascript/height2normal/ - var x1, y1, x2, y2; - if (i % (width * 4) === 0) { - // left edge - x1 = srcData.data[i]; - x2 = srcData.data[i + 4]; - } - else if (i % (width * 4) === (width - 1) * 4) { - // right edge - x1 = srcData.data[i - 4]; - x2 = srcData.data[i]; - } - else { - x1 = srcData.data[i - 4]; - x2 = srcData.data[i + 4]; - } - - if (i < width * 4) { - // top edge - y1 = srcData.data[i]; - y2 = srcData.data[i + width * 4]; - } - else if (i > width * (height - 1) * 4) { - // bottom edge - y1 = srcData.data[i - width * 4]; - y2 = srcData.data[i]; - } - else { - y1 = srcData.data[i - width * 4]; - y2 = srcData.data[i + width * 4]; - } - - dstData.data[i] = (x1 - x2) + 127; - dstData.data[i + 1] = (y1 - y2) + 127; - dstData.data[i + 2] = 255; - dstData.data[i + 3] = 255; - } - ctx.putImageData(dstData, 0, 0); - return canvas; - }, - - /** - * Convert height map to normal map - * @param {HTMLImageElement|HTMLCanvasElement} image - * @param {boolean} [checkBump=false] - * @param {number} [threshold=20] - * @return {HTMLCanvasElement} - */ - isHeightImage: function (img, downScaleSize, threshold) { - if (!img || !img.width || !img.height) { - return false; - } - - var canvas = document.createElement('canvas'); - var ctx = canvas.getContext('2d'); - var size = downScaleSize || 32; - threshold = threshold || 20; - canvas.width = canvas.height = size; - ctx.drawImage(img, 0, 0, size, size); - var srcData = ctx.getImageData(0, 0, size, size); - for (var i = 0; i < srcData.data.length; i += 4) { - var r = srcData.data[i]; - var g = srcData.data[i + 1]; - var b = srcData.data[i + 2]; - var diff = Math.abs(r - g) + Math.abs(g - b); - if (diff > threshold) { - return false; - } - } - return true; - }, - - _fetchTexture: function (path, onsuccess, onerror) { - __WEBPACK_IMPORTED_MODULE_2__core_request__["a" /* default */].get({ - url: path, - responseType: 'arraybuffer', - onload: onsuccess, - onerror: onerror - }); - }, - - /** - * Create a chessboard texture - * @param {number} [size] - * @param {number} [unitSize] - * @param {string} [color1] - * @param {string} [color2] - * @return {clay.Texture2D} - */ - createChessboard: function (size, unitSize, color1, color2) { - size = size || 512; - unitSize = unitSize || 64; - color1 = color1 || 'black'; - color2 = color2 || 'white'; - - var repeat = Math.ceil(size / unitSize); - - var canvas = document.createElement('canvas'); - canvas.width = size; - canvas.height = size; - var ctx = canvas.getContext('2d'); - ctx.fillStyle = color2; - ctx.fillRect(0, 0, size, size); - - ctx.fillStyle = color1; - for (var i = 0; i < repeat; i++) { - for (var j = 0; j < repeat; j++) { - var isFill = j % 2 ? (i % 2) : (i % 2 - 1); - if (isFill) { - ctx.fillRect(i * unitSize, j * unitSize, unitSize, unitSize); - } - } - } - - var texture = new __WEBPACK_IMPORTED_MODULE_0__Texture2D__["a" /* default */]({ - image: canvas, - anisotropic: 8 - }); - - return texture; - }, - - /** - * Create a blank pure color 1x1 texture - * @param {string} color - * @return {clay.Texture2D} - */ - createBlank: function (color) { - var canvas = document.createElement('canvas'); - canvas.width = 1; - canvas.height = 1; - var ctx = canvas.getContext('2d'); - ctx.fillStyle = color; - ctx.fillRect(0, 0, 1, 1); - - var texture = new __WEBPACK_IMPORTED_MODULE_0__Texture2D__["a" /* default */]({ - image: canvas - }); - - return texture; - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (textureUtil); - - -/***/ }), -/* 35 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__math_Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__camera_Perspective__ = __webpack_require__(22); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__FrameBuffer__ = __webpack_require__(11); - - - - - -var targets = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; - -/** - * Pass rendering scene to a environment cube map - * - * @constructor clay.prePass.EnvironmentMap - * @extends clay.core.Base - * @example - * // Example of car reflection - * var envMap = new clay.TextureCube({ - * width: 256, - * height: 256 - * }); - * var envPass = new clay.prePass.EnvironmentMap({ - * position: car.position, - * texture: envMap - * }); - * var carBody = car.getChildByName('body'); - * carBody.material.enableTexture('environmentMap'); - * carBody.material.set('environmentMap', envMap); - * ... - * animation.on('frame', function(frameTime) { - * envPass.render(renderer, scene); - * renderer.render(scene, camera); - * }); - */ -var EnvironmentMapPass = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend(function() { - var ret = /** @lends clay.prePass.EnvironmentMap# */ { - /** - * Camera position - * @type {clay.math.Vector3} - * @memberOf clay.prePass.EnvironmentMap# - */ - position: new __WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */](), - /** - * Camera far plane - * @type {number} - * @memberOf clay.prePass.EnvironmentMap# - */ - far: 1000, - /** - * Camera near plane - * @type {number} - * @memberOf clay.prePass.EnvironmentMap# - */ - near: 0.1, - /** - * Environment cube map - * @type {clay.TextureCube} - * @memberOf clay.prePass.EnvironmentMap# - */ - texture: null, - - /** - * Used if you wan't have shadow in environment map - * @type {clay.prePass.ShadowMap} - */ - shadowMapPass: null, - }; - var cameras = ret._cameras = { - px: new __WEBPACK_IMPORTED_MODULE_2__camera_Perspective__["a" /* default */]({ fov: 90 }), - nx: new __WEBPACK_IMPORTED_MODULE_2__camera_Perspective__["a" /* default */]({ fov: 90 }), - py: new __WEBPACK_IMPORTED_MODULE_2__camera_Perspective__["a" /* default */]({ fov: 90 }), - ny: new __WEBPACK_IMPORTED_MODULE_2__camera_Perspective__["a" /* default */]({ fov: 90 }), - pz: new __WEBPACK_IMPORTED_MODULE_2__camera_Perspective__["a" /* default */]({ fov: 90 }), - nz: new __WEBPACK_IMPORTED_MODULE_2__camera_Perspective__["a" /* default */]({ fov: 90 }) - }; - cameras.px.lookAt(__WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */].POSITIVE_X, __WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */].NEGATIVE_Y); - cameras.nx.lookAt(__WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */].NEGATIVE_X, __WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */].NEGATIVE_Y); - cameras.py.lookAt(__WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */].POSITIVE_Y, __WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */].POSITIVE_Z); - cameras.ny.lookAt(__WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */].NEGATIVE_Y, __WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */].NEGATIVE_Z); - cameras.pz.lookAt(__WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */].POSITIVE_Z, __WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */].NEGATIVE_Y); - cameras.nz.lookAt(__WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */].NEGATIVE_Z, __WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */].NEGATIVE_Y); - - // FIXME In windows, use one framebuffer only renders one side of cubemap - ret._frameBuffer = new __WEBPACK_IMPORTED_MODULE_3__FrameBuffer__["a" /* default */](); - - return ret; -}, /** @lends clay.prePass.EnvironmentMap# */ { - /** - * @param {string} target - * @return {clay.Camera} - */ - getCamera: function (target) { - return this._cameras[target]; - }, - /** - * @param {clay.Renderer} renderer - * @param {clay.Scene} scene - * @param {boolean} [notUpdateScene=false] - */ - render: function(renderer, scene, notUpdateScene) { - var _gl = renderer.gl; - if (!notUpdateScene) { - scene.update(); - } - // Tweak fov - // http://the-witness.net/news/2012/02/seamless-cube-map-filtering/ - var n = this.texture.width; - var fov = 2 * Math.atan(n / (n - 0.5)) / Math.PI * 180; - - for (var i = 0; i < 6; i++) { - var target = targets[i]; - var camera = this._cameras[target]; - __WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */].copy(camera.position, this.position); - - camera.far = this.far; - camera.near = this.near; - camera.fov = fov; - - if (this.shadowMapPass) { - camera.update(); - - // update boundingBoxLastFrame - var bbox = scene.getBoundingBox(); - bbox.applyTransform(camera.viewMatrix); - scene.viewBoundingBoxLastFrame.copy(bbox); - - this.shadowMapPass.render(renderer, scene, camera, true); - } - this._frameBuffer.attach( - this.texture, _gl.COLOR_ATTACHMENT0, - _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i - ); - this._frameBuffer.bind(renderer); - renderer.render(scene, camera, true); - this._frameBuffer.unbind(renderer); - } - }, - /** - * @param {clay.Renderer} renderer - */ - dispose: function (renderer) { - this._frameBuffer.dispose(renderer); - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (EnvironmentMapPass); - - -/***/ }), -/* 36 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Mesh__ = __webpack_require__(16); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__geometry_Sphere__ = __webpack_require__(100); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Material__ = __webpack_require__(10); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__shader_source_basic_glsl_js__ = __webpack_require__(50); - - - - - - -__WEBPACK_IMPORTED_MODULE_2__Shader__["a" /* default */].import(__WEBPACK_IMPORTED_MODULE_4__shader_source_basic_glsl_js__["a" /* default */]); -/** - * @constructor clay.plugin.Skydome - * - * @example - * var skyTex = new clay.Texture2D(); - * skyTex.load('assets/textures/sky.jpg'); - * var skydome = new clay.plugin.Skydome({ - * scene: scene - * }); - * skydome.material.set('diffuseMap', skyTex); - */ -var Skydome = __WEBPACK_IMPORTED_MODULE_0__Mesh__["a" /* default */].extend(function () { - - var skydomeShader = new __WEBPACK_IMPORTED_MODULE_2__Shader__["a" /* default */](__WEBPACK_IMPORTED_MODULE_2__Shader__["a" /* default */].source('clay.basic.vertex'), __WEBPACK_IMPORTED_MODULE_2__Shader__["a" /* default */].source('clay.basic.fragment')); - - var material = new __WEBPACK_IMPORTED_MODULE_3__Material__["a" /* default */]({ - shader: skydomeShader, - depthMask: false - }); - material.enableTexture('diffuseMap'); - - return { - /** - * @type {clay.Scene} - * @memberOf clay.plugin.Skydome# - */ - scene: null, - - geometry: new __WEBPACK_IMPORTED_MODULE_1__geometry_Sphere__["a" /* default */]({ - widthSegments: 30, - heightSegments: 30, - // thetaLength: Math.PI / 2 - }), - - material: material, - - environmentMap: null, - - culling: false - }; -}, function () { - var scene = this.scene; - if (scene) { - this.attachScene(scene); - } - - if (this.environmentMap) { - this.setEnvironmentMap(this.environmentMap); - } -}, { - /** - * Attach the skybox to the scene - * @param {clay.Scene} scene - * @memberOf clay.plugin.Skydome.prototype - */ - attachScene: function (scene) { - if (this.scene) { - this.detachScene(); - } - scene.skydome = this; - - this.scene = scene; - scene.on('beforerender', this._beforeRenderScene, this); - }, - /** - * Detach from scene - * @memberOf clay.plugin.Skydome.prototype - */ - detachScene: function () { - if (this.scene) { - this.scene.off('beforerender', this._beforeRenderScene); - this.scene.skydome = null; - } - this.scene = null; - }, - - _beforeRenderScene: function (renderer, scene, camera) { - this.position.copy(camera.getWorldPosition()); - this.update(); - renderer.renderPass([this], camera); - }, - - setEnvironmentMap: function (envMap) { - this.material.set('diffuseMap', envMap); - }, - - getEnvironmentMap: function () { - return this.material.get('diffuseMap'); - }, - - dispose: function (renderer) { - this.detachScene(); - this.geometry.dispose(renderer); - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (Skydome); - - -/***/ }), -/* 37 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Mesh__ = __webpack_require__(16); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__geometry_Cube__ = __webpack_require__(119); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Material__ = __webpack_require__(10); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__shader_source_skybox_glsl_js__ = __webpack_require__(51); -// TODO Should not derived from mesh? - - - - - - -__WEBPACK_IMPORTED_MODULE_2__Shader__["a" /* default */].import(__WEBPACK_IMPORTED_MODULE_4__shader_source_skybox_glsl_js__["a" /* default */]); -/** - * @constructor clay.plugin.Skybox - * - * @example - * var skyTex = new clay.TextureCube(); - * skyTex.load({ - * 'px': 'assets/textures/sky/px.jpg', - * 'nx': 'assets/textures/sky/nx.jpg' - * 'py': 'assets/textures/sky/py.jpg' - * 'ny': 'assets/textures/sky/ny.jpg' - * 'pz': 'assets/textures/sky/pz.jpg' - * 'nz': 'assets/textures/sky/nz.jpg' - * }); - * var skybox = new clay.plugin.Skybox({ - * scene: scene - * }); - * skybox.material.set('environmentMap', skyTex); - */ -var Skybox = __WEBPACK_IMPORTED_MODULE_0__Mesh__["a" /* default */].extend(function () { - - var skyboxShader = new __WEBPACK_IMPORTED_MODULE_2__Shader__["a" /* default */]({ - vertex: __WEBPACK_IMPORTED_MODULE_2__Shader__["a" /* default */].source('clay.skybox.vertex'), - fragment: __WEBPACK_IMPORTED_MODULE_2__Shader__["a" /* default */].source('clay.skybox.fragment') - }); - var material = new __WEBPACK_IMPORTED_MODULE_3__Material__["a" /* default */]({ - shader: skyboxShader, - depthMask: false - }); - - return { - /** - * @type {clay.Scene} - * @memberOf clay.plugin.Skybox.prototype - */ - scene: null, - - geometry: new __WEBPACK_IMPORTED_MODULE_1__geometry_Cube__["a" /* default */](), - - material: material, - - environmentMap: null, - - culling: false - }; -}, function () { - var scene = this.scene; - if (scene) { - this.attachScene(scene); - } - if (this.environmentMap) { - this.setEnvironmentMap(this.environmentMap); - } -}, /** @lends clay.plugin.Skybox# */ { - /** - * Attach the skybox to the scene - * @param {clay.Scene} scene - */ - attachScene: function (scene) { - if (this.scene) { - this.detachScene(); - } - scene.skybox = this; - - this.scene = scene; - scene.on('beforerender', this._beforeRenderScene, this); - }, - /** - * Detach from scene - */ - detachScene: function () { - if (this.scene) { - this.scene.off('beforerender', this._beforeRenderScene); - this.scene.skybox = null; - } - this.scene = null; - }, - - /** - * Dispose skybox - * @param {clay.Renderer} renderer - */ - dispose: function (renderer) { - this.detachScene(); - this.geometry.dispose(renderer); - }, - /** - * Set environment map - * @param {clay.TextureCube} envMap - */ - setEnvironmentMap: function (envMap) { - this.material.set('environmentMap', envMap); - }, - /** - * Get environment map - * @return {clay.TextureCube} - */ - getEnvironmentMap: function () { - return this.material.get('environmentMap'); - }, - - _beforeRenderScene: function(renderer, scene, camera) { - this.renderSkybox(renderer, camera); - }, - - renderSkybox: function (renderer, camera) { - this.position.copy(camera.getWorldPosition()); - this.update(); - // Don't remember to disable blend - renderer.gl.disable(renderer.gl.BLEND); - if (this.material.get('lod') > 0) { - this.material.define('fragment', 'LOD'); - } - else { - this.material.undefine('fragment', 'LOD'); - } - renderer.renderPass([this], camera); - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (Skybox); - - -/***/ }), -/* 38 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ({ - ENV_TEXTURE_ROOT: './asset/texture/', - - SUPPORTED_MODEL_FILES: ['fbx', 'obj', 'mtl', 'dae', 'dxf'], - - AUTO_SAVE: true -}); - -/***/ }), -/* 39 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__calcAmbientSHLight_glsl_js__ = __webpack_require__(77); - - -var uniformVec3Prefix = 'uniform vec3 '; -var uniformFloatPrefix = 'uniform float '; -var exportHeaderPrefix = '@export clay.header.'; -var exportEnd = '@end'; -var unconfigurable = ':unconfigurable;'; -/* harmony default export */ __webpack_exports__["a"] = ([ - exportHeaderPrefix + 'directional_light', - uniformVec3Prefix + 'directionalLightDirection[DIRECTIONAL_LIGHT_COUNT]' + unconfigurable, - uniformVec3Prefix + 'directionalLightColor[DIRECTIONAL_LIGHT_COUNT]' + unconfigurable, - exportEnd, - - exportHeaderPrefix + 'ambient_light', - uniformVec3Prefix + 'ambientLightColor[AMBIENT_LIGHT_COUNT]' + unconfigurable, - exportEnd, - - exportHeaderPrefix + 'ambient_sh_light', - uniformVec3Prefix + 'ambientSHLightColor[AMBIENT_SH_LIGHT_COUNT]' + unconfigurable, - uniformVec3Prefix + 'ambientSHLightCoefficients[AMBIENT_SH_LIGHT_COUNT * 9]' + unconfigurable, - __WEBPACK_IMPORTED_MODULE_0__calcAmbientSHLight_glsl_js__["a" /* default */], - exportEnd, - - exportHeaderPrefix + 'ambient_cubemap_light', - uniformVec3Prefix + 'ambientCubemapLightColor[AMBIENT_CUBEMAP_LIGHT_COUNT]' + unconfigurable, - 'uniform samplerCube ambientCubemapLightCubemap[AMBIENT_CUBEMAP_LIGHT_COUNT]' + unconfigurable, - 'uniform sampler2D ambientCubemapLightBRDFLookup[AMBIENT_CUBEMAP_LIGHT_COUNT]' + unconfigurable, - exportEnd, - - exportHeaderPrefix + 'point_light', - uniformVec3Prefix + 'pointLightPosition[POINT_LIGHT_COUNT]' + unconfigurable, - uniformFloatPrefix + 'pointLightRange[POINT_LIGHT_COUNT]' + unconfigurable, - uniformVec3Prefix + 'pointLightColor[POINT_LIGHT_COUNT]' + unconfigurable, - exportEnd, - - exportHeaderPrefix + 'spot_light', - uniformVec3Prefix + 'spotLightPosition[SPOT_LIGHT_COUNT]' + unconfigurable, - uniformVec3Prefix + 'spotLightDirection[SPOT_LIGHT_COUNT]' + unconfigurable, - uniformFloatPrefix + 'spotLightRange[SPOT_LIGHT_COUNT]' + unconfigurable, - uniformFloatPrefix + 'spotLightUmbraAngleCosine[SPOT_LIGHT_COUNT]' + unconfigurable, - uniformFloatPrefix + 'spotLightPenumbraAngleCosine[SPOT_LIGHT_COUNT]' + unconfigurable, - uniformFloatPrefix + 'spotLightFalloffFactor[SPOT_LIGHT_COUNT]' + unconfigurable, - uniformVec3Prefix + 'spotLightColor[SPOT_LIGHT_COUNT]' + unconfigurable, - exportEnd -].join('\n')); - - -/***/ }), -/* 40 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.prez.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\n@import clay.chunk.skinning_header\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n}\n@end\n@export clay.prez.fragment\nvoid main()\n{\n gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n}\n@end"); - - -/***/ }), -/* 41 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_request__ = __webpack_require__(29); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__core_util__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__core_vendor__ = __webpack_require__(12); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__Scene__ = __webpack_require__(18); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__Material__ = __webpack_require__(10); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__StandardMaterial__ = __webpack_require__(44); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__Mesh__ = __webpack_require__(16); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__Node__ = __webpack_require__(15); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__Texture2D__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_11__shader_library__ = __webpack_require__(31); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_12__Skeleton__ = __webpack_require__(80); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_13__Joint__ = __webpack_require__(48); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_14__camera_Perspective__ = __webpack_require__(22); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_15__camera_Orthographic__ = __webpack_require__(23); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_16__core_glenum__ = __webpack_require__(6); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_17__math_BoundingBox__ = __webpack_require__(8); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_18__animation_TrackClip__ = __webpack_require__(81); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_19__animation_SamplerTrack__ = __webpack_require__(82); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_20__Geometry__ = __webpack_require__(19); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_21__shader_builtin__ = __webpack_require__(84); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_22__Shader__ = __webpack_require__(4); -/** - * glTF Loader - * Specification https://github.com/KhronosGroup/glTF/blob/master/specification/README.md - * - * TODO Morph targets - */ - - - - - - - - - - - - - - - - - - - - - - - - - - -// Import builtin shader - - - -var semanticAttributeMap = { - 'NORMAL': 'normal', - 'POSITION': 'position', - 'TEXCOORD_0': 'texcoord0', - 'TEXCOORD_1': 'texcoord1', - 'WEIGHTS_0': 'weight', - 'JOINTS_0': 'joint', - 'COLOR': 'color' -}; - -var ARRAY_CTOR_MAP = { - 5120: __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Int8Array, - 5121: __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint8Array, - 5122: __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Int16Array, - 5123: __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint16Array, - 5125: __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint32Array, - 5126: __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Float32Array -}; -var SIZE_MAP = { - SCALAR: 1, - VEC2: 2, - VEC3: 3, - VEC4: 4, - MAT2: 4, - MAT3: 9, - MAT4: 16 -}; - -function getAccessorData(json, lib, accessorIdx, isIndices) { - var accessorInfo = json.accessors[accessorIdx]; - - var buffer = lib.bufferViews[accessorInfo.bufferView]; - var byteOffset = accessorInfo.byteOffset || 0; - var ArrayCtor = ARRAY_CTOR_MAP[accessorInfo.componentType] || __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Float32Array; - - var size = SIZE_MAP[accessorInfo.type]; - if (size == null && isIndices) { - size = 1; - } - var arr = new ArrayCtor(buffer, byteOffset, size * accessorInfo.count); - - var quantizeExtension = accessorInfo.extensions && accessorInfo.extensions['WEB3D_quantized_attributes']; - if (quantizeExtension) { - var decodedArr = new __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Float32Array(size * accessorInfo.count); - var decodeMatrix = quantizeExtension.decodeMatrix; - var decodeOffset, decodeScale; - var decodeOffset = new Array(size); - var decodeScale = new Array(size); - for (var k = 0; k < size; k++) { - decodeOffset[k] = decodeMatrix[size * (size + 1) + k]; - decodeScale[k] = decodeMatrix[k * (size + 1) + k]; - } - for (var i = 0; i < accessorInfo.count; i++) { - for (var k = 0; k < size; k++) { - decodedArr[i * size + k] = arr[i * size + k] * decodeScale[k] + decodeOffset[k]; - } - } - - arr = decodedArr; - } - return arr; -} - -/** - * @typedef {Object} clay.loader.GLTF.IResult - * @property {Object} json - * @property {clay.Scene} scene - * @property {clay.Node} rootNode - * @property {clay.Camera[]} cameras - * @property {clay.Texture[]} textures - * @property {clay.Material[]} materials - * @property {clay.Skeleton[]} skeletons - * @property {clay.Mesh[]} meshes - * @property {clay.animation.TrackClip[]} clips - * @property {clay.Node[]} nodes - */ - -/** - * @constructor clay.loader.GLTF - * @extends clay.core.Base - */ -var GLTFLoader = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend( -/** @lends clay.loader.GLTF# */ -{ - /** - * - * @type {clay.Node} - */ - rootNode: null, - /** - * Root path for uri parsing. - * @type {string} - */ - rootPath: null, - - /** - * Root path for texture uri parsing. Defaultly use the rootPath - * @type {string} - */ - textureRootPath: null, - - /** - * Root path for buffer uri parsing. Defaultly use the rootPath - * @type {string} - */ - bufferRootPath: null, - - /** - * Shader used when creating the materials. - * @type {string|clay.Shader} - * @default 'clay.standard' - */ - shader: 'clay.standard', - - /** - * If use {@link clay.StandardMaterial} - * @type {string} - */ - useStandardMaterial: false, - - /** - * If loading the cameras. - * @type {boolean} - */ - includeCamera: true, - - /** - * If loading the animations. - * @type {boolean} - */ - includeAnimation: true, - /** - * If loading the meshes - * @type {boolean} - */ - includeMesh: true, - /** - * If loading the textures. - * @type {boolean} - */ - includeTexture: true, - - /** - * @type {string} - */ - crossOrigin: '', - /** - * @type {boolean} - * @see https://github.com/KhronosGroup/glTF/issues/674 - */ - textureFlipY: false, - - shaderLibrary: null -}, -function () { - if (!this.shaderLibrary) { - this.shaderLibrary = __WEBPACK_IMPORTED_MODULE_11__shader_library__["a" /* default */].createLibrary(); - } -}, -/** @lends clay.loader.GLTF.prototype */ -{ - /** - * @param {string} url - */ - load: function (url) { - var self = this; - var isBinary = url.endsWith('.glb'); - - if (this.rootPath == null) { - this.rootPath = url.slice(0, url.lastIndexOf('/')); - } - - __WEBPACK_IMPORTED_MODULE_1__core_request__["a" /* default */].get({ - url: url, - onprogress: function (percent, loaded, total) { - self.trigger('progress', percent, loaded, total); - }, - onerror: function (e) { - self.trigger('error', e); - }, - responseType: isBinary ? 'arraybuffer' : 'text', - onload: function (data) { - if (isBinary) { - self.parseBinary(data); - } - else { - self.parse(JSON.parse(data)); - } - } - }); - }, - - /** - * Parse glTF binary - * @param {ArrayBuffer} buffer - * @return {clay.loader.GLTF.IResult} - */ - parseBinary: function (buffer) { - var header = new Uint32Array(buffer, 0, 4); - if (header[0] !== 0x46546C67) { - this.trigger('error', 'Invalid glTF binary format: Invalid header'); - return; - } - if (header[0] < 2) { - this.trigger('error', 'Only glTF2.0 is supported.'); - return; - } - - var dataView = new DataView(buffer, 12); - - var json; - var buffers = []; - // Read chunks - for (var i = 0; i < dataView.byteLength;) { - var chunkLength = dataView.getUint32(i, true); - i += 4; - var chunkType = dataView.getUint32(i, true); - i += 4; - - // json - if (chunkType === 0x4E4F534A) { - var arr = new Uint8Array(buffer, i + 12, chunkLength); - // TODO, for the browser not support TextDecoder. - var decoder = new TextDecoder(); - var str = decoder.decode(arr); - try { - json = JSON.parse(str); - } - catch (e) { - this.trigger('error', 'JSON Parse error:' + e.toString()); - return; - } - } - else if (chunkType === 0x004E4942) { - buffers.push(buffer.slice(i + 12, i + 12 + chunkLength)); - } - - i += chunkLength; - } - if (!json) { - this.trigger('error', 'Invalid glTF binary format: Can\'t find JSON.'); - return; - } - - return this.parse(json, buffers); - }, - - /** - * @param {Object} json - * @param {ArrayBuffer[]} [buffer] - * @return {clay.loader.GLTF.IResult} - */ - parse: function (json, buffers) { - var self = this; - - var lib = { - json: json, - buffers: [], - bufferViews: [], - materials: [], - textures: [], - meshes: [], - joints: [], - skeletons: [], - cameras: [], - nodes: [], - clips: [] - }; - // Mount on the root node if given - var rootNode = this.rootNode || new __WEBPACK_IMPORTED_MODULE_4__Scene__["a" /* default */](); - - var loading = 0; - function checkLoad() { - loading--; - if (loading === 0) { - afterLoadBuffer(); - } - } - // If already load buffers - if (buffers) { - lib.buffers = buffers.slice(); - afterLoadBuffer(true); - } - else { - // Load buffers - __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].each(json.buffers, function (bufferInfo, idx) { - loading++; - var path = bufferInfo.uri; - - self._loadBuffer(path, function (buffer) { - lib.buffers[idx] = buffer; - checkLoad(); - }, checkLoad); - }); - } - - function getResult() { - return { - json: json, - scene: self.rootNode ? null : rootNode, - rootNode: self.rootNode ? rootNode : null, - cameras: lib.cameras, - textures: lib.textures, - materials: lib.materials, - skeletons: lib.skeletons, - meshes: lib.instancedMeshes, - clips: lib.clips, - nodes: lib.nodes - }; - } - - function afterLoadBuffer(immediately) { - // Buffer not load complete. - if (lib.buffers.length !== json.buffers.length) { - setTimeout(function () { - self.trigger('error', 'Buffer not load complete.'); - }); - return; - } - - json.bufferViews.forEach(function (bufferViewInfo, idx) { - // PENDING Performance - lib.bufferViews[idx] = lib.buffers[bufferViewInfo.buffer] - .slice(bufferViewInfo.byteOffset || 0, (bufferViewInfo.byteOffset || 0) + (bufferViewInfo.byteLength || 0)); - }); - lib.buffers = null; - if (self.includeMesh) { - if (self.includeTexture) { - self._parseTextures(json, lib); - } - self._parseMaterials(json, lib); - self._parseMeshes(json, lib); - } - self._parseNodes(json, lib); - - // Only support one scene. - if (json.scenes) { - var sceneInfo = json.scenes[json.scene || 0]; // Default use the first scene. - if (sceneInfo) { - for (var i = 0; i < sceneInfo.nodes.length; i++) { - var node = lib.nodes[sceneInfo.nodes[i]]; - node.update(); - rootNode.add(node); - } - } - } - - if (self.includeMesh) { - self._parseSkins(json, lib); - } - - if (self.includeAnimation) { - self._parseAnimations(json, lib); - } - if (immediately) { - setTimeout(function () { - self.trigger('success', getResult()); - }); - } - else { - self.trigger('success', getResult()); - } - } - - return getResult(); - }, - - /** - * Binary file path resolver. User can override it - * @param {string} path - */ - resolveBinaryPath: function (path) { - if (path && path.match(/^data:(.*?)base64,/)) { - return path; - } - - var rootPath = this.bufferRootPath; - if (rootPath == null) { - rootPath = this.rootPath; - } - return __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].relative2absolute(path, rootPath); - }, - - /** - * Texture file path resolver. User can override it - * @param {string} path - */ - resolveTexturePath: function (path) { - if (path && path.match(/^data:(.*?)base64,/)) { - return path; - } - - var rootPath = this.textureRootPath; - if (rootPath == null) { - rootPath = this.rootPath; - } - return __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].relative2absolute(path, rootPath); - }, - - _getShader: function () { - if (typeof this.shader === 'string') { - return this.shaderLibrary.get(this.shader); - } - else if (this.shader instanceof __WEBPACK_IMPORTED_MODULE_22__Shader__["a" /* default */]) { - return this.shader; - } - }, - - _loadBuffer: function (path, onsuccess, onerror) { - __WEBPACK_IMPORTED_MODULE_1__core_request__["a" /* default */].get({ - url: this.resolveBinaryPath(path), - responseType: 'arraybuffer', - onload: function (buffer) { - onsuccess && onsuccess(buffer); - }, - onerror: function (buffer) { - onerror && onerror(buffer); - } - }); - }, - - // https://github.com/KhronosGroup/glTF/issues/100 - // https://github.com/KhronosGroup/glTF/issues/193 - _parseSkins: function (json, lib) { - - // Create skeletons and joints - var haveInvBindMatrices = false; - __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].each(json.skins, function (skinInfo, idx) { - var skeleton = new __WEBPACK_IMPORTED_MODULE_12__Skeleton__["a" /* default */]({ - name: skinInfo.name - }); - for (var i = 0; i < skinInfo.joints.length; i++) { - var nodeIdx = skinInfo.joints[i]; - var node = lib.nodes[nodeIdx]; - var joint = new __WEBPACK_IMPORTED_MODULE_13__Joint__["a" /* default */]({ - name: node.name, - node: node, - index: skeleton.joints.length - }); - skeleton.joints.push(joint); - } - skeleton.relativeRootNode = lib.nodes[skinInfo.skeleton] || this.rootNode; - if (skinInfo.inverseBindMatrices) { - haveInvBindMatrices = true; - var IBMInfo = json.accessors[skinInfo.inverseBindMatrices]; - var buffer = lib.bufferViews[IBMInfo.bufferView]; - - var offset = IBMInfo.byteOffset || 0; - var size = IBMInfo.count * 16; - - var array = new __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Float32Array(buffer, offset, size); - - skeleton.setJointMatricesArray(array); - } - else { - skeleton.updateJointMatrices(); - } - lib.skeletons[idx] = skeleton; - }, this); - - function enableSkinningForMesh(mesh, skeleton, jointIndices) { - mesh.skeleton = skeleton; - mesh.joints = jointIndices; - } - - function getJointIndex(joint) { - return joint.index; - } - - __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].each(json.nodes, function (nodeInfo, nodeIdx) { - if (nodeInfo.skin != null) { - var skinIdx = nodeInfo.skin; - var skeleton = lib.skeletons[skinIdx]; - - var node = lib.nodes[nodeIdx]; - var jointIndices = skeleton.joints.map(getJointIndex); - if (node instanceof __WEBPACK_IMPORTED_MODULE_7__Mesh__["a" /* default */]) { - enableSkinningForMesh(node, skeleton, jointIndices); - } - else { - // Mesh have multiple primitives - var children = node.children(); - for (var i = 0; i < children.length; i++) { - enableSkinningForMesh(children[i], skeleton, jointIndices); - } - } - } - }, this); - }, - - _parseTextures: function (json, lib) { - __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].each(json.textures, function (textureInfo, idx){ - // samplers is optional - var samplerInfo = (json.samplers && json.samplers[textureInfo.sampler]) || {}; - var parameters = {}; - ['wrapS', 'wrapT', 'magFilter', 'minFilter'].forEach(function (name) { - var value = samplerInfo[name]; - if (value != null) { - parameters[name] = value; - } - }); - __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].defaults(parameters, { - wrapS: __WEBPACK_IMPORTED_MODULE_9__Texture__["a" /* default */].REPEAT, - wrapT: __WEBPACK_IMPORTED_MODULE_9__Texture__["a" /* default */].REPEAT, - flipY: this.textureFlipY - }); - - var target = textureInfo.target || __WEBPACK_IMPORTED_MODULE_16__core_glenum__["a" /* default */].TEXTURE_2D; - var format = textureInfo.format; - if (format != null) { - parameters.format = format; - } - - if (target === __WEBPACK_IMPORTED_MODULE_16__core_glenum__["a" /* default */].TEXTURE_2D) { - var texture = new __WEBPACK_IMPORTED_MODULE_10__Texture2D__["a" /* default */](parameters); - var imageInfo = json.images[textureInfo.source]; - var uri; - if (imageInfo.uri) { - uri = this.resolveTexturePath(imageInfo.uri); - } - else if (imageInfo.bufferView != null) { - uri = URL.createObjectURL(new Blob([lib.bufferViews[imageInfo.bufferView]], { - type: imageInfo.mimeType - })); - } - if (uri) { - texture.load(uri, this.crossOrigin); - lib.textures[idx] = texture; - } - } - }, this); - }, - - _KHRCommonMaterialToStandard: function (materialInfo, lib) { - var uniforms = {}; - var commonMaterialInfo = materialInfo.extensions['KHR_materials_common']; - uniforms = commonMaterialInfo.values || {}; - - if (typeof uniforms.diffuse === 'number') { - uniforms.diffuse = lib.textures[uniforms.diffuse] || null; - } - if (typeof uniforms.emission === 'number') { - uniforms.emission = lib.textures[uniforms.emission] || null; - } - - var enabledTextures = []; - if (uniforms['diffuse'] instanceof __WEBPACK_IMPORTED_MODULE_10__Texture2D__["a" /* default */]) { - enabledTextures.push('diffuseMap'); - } - if (materialInfo.normalTexture) { - enabledTextures.push('normalMap'); - } - if (uniforms['emission'] instanceof __WEBPACK_IMPORTED_MODULE_10__Texture2D__["a" /* default */]) { - enabledTextures.push('emissiveMap'); - } - var material; - var isStandardMaterial = this.useStandardMaterial; - if (isStandardMaterial) { - material = new __WEBPACK_IMPORTED_MODULE_6__StandardMaterial__["a" /* default */]({ - name: materialInfo.name, - doubleSided: materialInfo.doubleSided - }); - } - else { - material = new __WEBPACK_IMPORTED_MODULE_5__Material__["a" /* default */]({ - name: materialInfo.name, - shader: this._getShader() - }); - - material.define('fragment', 'USE_ROUGHNESS'); - material.define('fragment', 'USE_METALNESS'); - - if (materialInfo.doubleSided) { - material.define('fragment', 'DOUBLE_SIDED'); - } - } - - if (uniforms.transparent) { - material.depthMask = false; - material.depthTest = true; - material.transparent = true; - } - - var diffuseProp = uniforms['diffuse']; - if (diffuseProp) { - // Color - if (Array.isArray(diffuseProp)) { - diffuseProp = diffuseProp.slice(0, 3); - isStandardMaterial ? (material.color = diffuseProp) - : material.set('color', diffuseProp); - } - else { // Texture - isStandardMaterial ? (material.diffuseMap = diffuseProp) - : material.set('diffuseMap', diffuseProp); - } - } - var emissionProp = uniforms['emission']; - if (emissionProp != null) { - // Color - if (Array.isArray(emissionProp)) { - emissionProp = emissionProp.slice(0, 3); - isStandardMaterial ? (material.emission = emissionProp) - : material.set('emission', emissionProp); - } - else { // Texture - isStandardMaterial ? (material.emissiveMap = emissionProp) - : material.set('emissiveMap', emissionProp); - } - } - if (materialInfo.normalTexture != null) { - // TODO texCoord - var normalTextureIndex = materialInfo.normalTexture.index; - if (isStandardMaterial) { - material.normalMap = lib.textures[normalTextureIndex] || null; - } - else { - material.set('normalMap', lib.textures[normalTextureIndex] || null); - } - } - if (uniforms['shininess'] != null) { - var glossiness = Math.log(uniforms['shininess']) / Math.log(8192); - // Uniform glossiness - material.set('glossiness', glossiness); - material.set('roughness', 1 - glossiness); - } - else { - material.set('glossiness', 0.3); - material.set('roughness', 0.3); - } - if (uniforms['specular'] != null) { - material.set('specularColor', uniforms['specular'].slice(0, 3)); - } - if (uniforms['transparency'] != null) { - material.set('alpha', uniforms['transparency']); - } - - return material; - }, - - _pbrMetallicRoughnessToStandard: function (materialInfo, metallicRoughnessMatInfo, lib) { - var alphaTest = materialInfo.alphaMode === 'MASK'; - - var isStandardMaterial = this.useStandardMaterial; - var material; - var diffuseMap, roughnessMap, metalnessMap, normalMap, emissiveMap; - var enabledTextures = []; - // TODO texCoord - if (metallicRoughnessMatInfo.baseColorTexture) { - diffuseMap = lib.textures[metallicRoughnessMatInfo.baseColorTexture.index] || null; - diffuseMap && enabledTextures.push('diffuseMap'); - } - if (metallicRoughnessMatInfo.metallicRoughnessTexture) { - roughnessMap = metalnessMap = lib.textures[metallicRoughnessMatInfo.metallicRoughnessTexture.index] || null; - roughnessMap && enabledTextures.push('metalnessMap', 'roughnessMap'); - } - if (materialInfo.normalTexture) { - normalMap = lib.textures[materialInfo.normalTexture.index] || null; - normalMap && enabledTextures.push('normalMap'); - } - if (materialInfo.emissiveTexture) { - emissiveMap = lib.textures[materialInfo.emissiveTexture.index] || null; - emissiveMap && enabledTextures.push('emissiveMap'); - } - var baseColor = metallicRoughnessMatInfo.baseColorFactor || [1, 1, 1, 1]; - - var commonProperties = { - diffuseMap: diffuseMap || null, - roughnessMap: roughnessMap || null, - metalnessMap: metalnessMap || null, - normalMap: normalMap || null, - emissiveMap: emissiveMap || null, - color: baseColor.slice(0, 3), - alpha: baseColor[3], - metalness: metallicRoughnessMatInfo.metallicFactor || 0, - roughness: metallicRoughnessMatInfo.roughnessFactor || 0, - emission: materialInfo.emissiveFactor || [0, 0, 0], - emissionIntensity: 1, - alphaCutoff: materialInfo.alphaCutoff || 0 - }; - if (commonProperties.roughnessMap) { - // In glTF metallicFactor will do multiply, which is different from StandardMaterial. - // So simply ignore it - commonProperties.metalness = 0.5; - commonProperties.roughness = 0.5; - } - if (isStandardMaterial) { - material = new __WEBPACK_IMPORTED_MODULE_6__StandardMaterial__["a" /* default */](__WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].extend({ - name: materialInfo.name, - alphaTest: alphaTest, - doubleSided: materialInfo.doubleSided, - // G channel - roughnessChannel: 1, - // B Channel - metalnessChannel: 2 - }, commonProperties)); - } - else { - - material = new __WEBPACK_IMPORTED_MODULE_5__Material__["a" /* default */]({ - name: materialInfo.name, - shader: this._getShader() - }); - - material.define('fragment', 'USE_ROUGHNESS'); - material.define('fragment', 'USE_METALNESS'); - material.define('fragment', 'ROUGHNESS_CHANNEL', 1); - material.define('fragment', 'METALNESS_CHANNEL', 2); - - if (alphaTest) { - material.define('fragment', 'ALPHA_TEST'); - } - if (materialInfo.doubleSided) { - material.define('fragment', 'DOUBLE_SIDED'); - } - - material.set(commonProperties); - } - - if (materialInfo.alphaMode === 'BLEND') { - material.depthMask = false; - material.depthTest = true; - material.transparent = true; - } - - return material; - }, - - _pbrSpecularGlossinessToStandard: function (materialInfo, specularGlossinessMatInfo, lib) { - var alphaTest = materialInfo.alphaMode === 'MASK'; - - if (this.useStandardMaterial) { - console.error('StandardMaterial doesn\'t support specular glossiness workflow yet'); - } - - var material; - var diffuseMap, glossinessMap, specularMap, normalMap, emissiveMap; - var enabledTextures = []; - // TODO texCoord - if (specularGlossinessMatInfo.diffuseTexture) { - diffuseMap = lib.textures[specularGlossinessMatInfo.diffuseTexture.index] || null; - diffuseMap && enabledTextures.push('diffuseMap'); - } - if (specularGlossinessMatInfo.specularGlossinessTexture) { - glossinessMap = specularMap = lib.textures[specularGlossinessMatInfo.specularGlossinessTexture.index] || null; - glossinessMap && enabledTextures.push('specularMap', 'glossinessMap'); - } - if (materialInfo.normalTexture) { - normalMap = lib.textures[materialInfo.normalTexture.index] || null; - normalMap && enabledTextures.push('normalMap'); - } - if (materialInfo.emissiveTexture) { - emissiveMap = lib.textures[materialInfo.emissiveTexture.index] || null; - emissiveMap && enabledTextures.push('emissiveMap'); - } - var diffuseColor = specularGlossinessMatInfo.diffuseFactor || [1, 1, 1, 1]; - - var commonProperties = { - diffuseMap: diffuseMap || null, - glossinessMap: glossinessMap || null, - specularMap: specularMap || null, - normalMap: normalMap || null, - emissiveMap: emissiveMap || null, - color: diffuseColor.slice(0, 3), - alpha: diffuseColor[3], - specularColor: specularGlossinessMatInfo.specularFactor || [1, 1, 1], - glossiness: specularGlossinessMatInfo.glossinessFactor || 0, - emission: materialInfo.emissiveFactor || [0, 0, 0], - emissionIntensity: 1, - alphaCutoff: materialInfo.alphaCutoff == null ? 0.9 : materialInfo.alphaCutoff - }; - if (commonProperties.glossinessMap) { - // Ignore specularFactor - commonProperties.glossiness = 0.5; - } - if (commonProperties.specularMap) { - // Ignore specularFactor - commonProperties.specularColor = [1, 1, 1]; - } - - material = new __WEBPACK_IMPORTED_MODULE_5__Material__["a" /* default */]({ - name: materialInfo.name, - shader: this._getShader() - }); - - material.define('fragment', 'GLOSSINESS_CHANNEL', 3); - - if (alphaTest) { - material.define('fragment', 'ALPHA_TEST'); - } - if (materialInfo.doubleSided) { - material.define('fragment', 'DOUBLE_SIDED'); - } - - material.set(commonProperties); - - if (materialInfo.alphaMode === 'BLEND') { - material.depthMask = false; - material.depthTest = true; - material.transparent = true; - } - - return material; - }, - - _parseMaterials: function (json, lib) { - __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].each(json.materials, function (materialInfo, idx) { - if (materialInfo.extensions && materialInfo.extensions['KHR_materials_common']) { - lib.materials[idx] = this._KHRCommonMaterialToStandard(materialInfo, lib); - } - else if (materialInfo.extensions && materialInfo.extensions['KHR_materials_pbrSpecularGlossiness']) { - lib.materials[idx] = this._pbrSpecularGlossinessToStandard(materialInfo, materialInfo.extensions['KHR_materials_pbrSpecularGlossiness'], lib); - } - else { - lib.materials[idx] = this._pbrMetallicRoughnessToStandard(materialInfo, materialInfo.pbrMetallicRoughness || {}, lib); - } - }, this); - }, - - _parseMeshes: function (json, lib) { - var self = this; - - __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].each(json.meshes, function (meshInfo, idx) { - lib.meshes[idx] = []; - // Geometry - for (var pp = 0; pp < meshInfo.primitives.length; pp++) { - var primitiveInfo = meshInfo.primitives[pp]; - var geometry = new __WEBPACK_IMPORTED_MODULE_20__Geometry__["a" /* default */]({ - dynamic: false, - // PENDIGN - name: meshInfo.name, - boundingBox: new __WEBPACK_IMPORTED_MODULE_17__math_BoundingBox__["a" /* default */]() - }); - // Parse attributes - var semantics = Object.keys(primitiveInfo.attributes); - for (var ss = 0; ss < semantics.length; ss++) { - var semantic = semantics[ss]; - var accessorIdx = primitiveInfo.attributes[semantic]; - var attributeInfo = json.accessors[accessorIdx]; - var attributeName = semanticAttributeMap[semantic]; - if (!attributeName) { - continue; - } - var size = SIZE_MAP[attributeInfo.type]; - var attributeArray = getAccessorData(json, lib, accessorIdx); - // WebGL attribute buffer not support uint32. - // Direct use Float32Array may also have issue. - if (attributeArray instanceof __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint32Array) { - attributeArray = new Float32Array(attributeArray); - } - if (semantic === 'WEIGHTS_0' && size === 4) { - // Weight data in QTEK has only 3 component, the last component can be evaluated since it is normalized - var weightArray = new attributeArray.constructor(attributeInfo.count * 3); - for (var i = 0; i < attributeInfo.count; i++) { - var i4 = i * 4, i3 = i * 3; - var w1 = attributeArray[i4], w2 = attributeArray[i4 + 1], w3 = attributeArray[i4 + 2], w4 = attributeArray[i4 + 3]; - var wSum = w1 + w2 + w3 + w4; - weightArray[i3] = w1 / wSum; - weightArray[i3 + 1] = w2 / wSum; - weightArray[i3 + 2] = w3 / wSum; - } - geometry.attributes[attributeName].value = weightArray; - } - else { - geometry.attributes[attributeName].value = attributeArray; - } - var attributeType = 'float'; - if (attributeArray instanceof __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint16Array) { - attributeType = 'ushort'; - } - else if (attributeArray instanceof __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Int16Array) { - attributeType = 'short'; - } - else if (attributeArray instanceof __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint8Array) { - attributeType = 'ubyte'; - } - else if (attributeArray instanceof __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Int8Array) { - attributeType = 'byte'; - } - geometry.attributes[attributeName].type = attributeType; - - if (semantic === 'POSITION') { - // Bounding Box - var min = attributeInfo.min; - var max = attributeInfo.max; - if (min) { - geometry.boundingBox.min.set(min[0], min[1], min[2]); - } - if (max) { - geometry.boundingBox.max.set(max[0], max[1], max[2]); - } - } - } - - // Parse indices - if (primitiveInfo.indices != null) { - geometry.indices = getAccessorData(json, lib, primitiveInfo.indices, true); - if (geometry.vertexCount <= 0xffff && geometry.indices instanceof __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint32Array) { - geometry.indices = new __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint16Array(geometry.indices); - } - if(geometry.indices instanceof __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint8Array) { - geometry.indices = new __WEBPACK_IMPORTED_MODULE_3__core_vendor__["a" /* default */].Uint16Array(geometry.indices); - } - } - - var material = lib.materials[primitiveInfo.material]; - var materialInfo = (json.materials || [])[primitiveInfo.material]; - // Use default material - if (!material) { - material = new __WEBPACK_IMPORTED_MODULE_5__Material__["a" /* default */]({ - shader: self._getShader() - }); - } - var mesh = new __WEBPACK_IMPORTED_MODULE_7__Mesh__["a" /* default */]({ - geometry: geometry, - material: material, - mode: [__WEBPACK_IMPORTED_MODULE_7__Mesh__["a" /* default */].POINTS, __WEBPACK_IMPORTED_MODULE_7__Mesh__["a" /* default */].LINES, __WEBPACK_IMPORTED_MODULE_7__Mesh__["a" /* default */].LINE_LOOP, __WEBPACK_IMPORTED_MODULE_7__Mesh__["a" /* default */].LINE_STRIP, __WEBPACK_IMPORTED_MODULE_7__Mesh__["a" /* default */].TRIANGLES, __WEBPACK_IMPORTED_MODULE_7__Mesh__["a" /* default */].TRIANGLE_STRIP, __WEBPACK_IMPORTED_MODULE_7__Mesh__["a" /* default */].TRIANGLE_FAN][primitiveInfo.mode] || __WEBPACK_IMPORTED_MODULE_7__Mesh__["a" /* default */].TRIANGLES, - ignoreGBuffer: material.transparent - }); - if (materialInfo != null) { - mesh.culling = !materialInfo.doubleSided; - } - if (!mesh.geometry.attributes.normal.value) { - mesh.geometry.generateVertexNormals(); - } - if (((material instanceof __WEBPACK_IMPORTED_MODULE_6__StandardMaterial__["a" /* default */]) && material.normalMap) - || (material.isTextureEnabled('normalMap')) - ) { - if (!mesh.geometry.attributes.tangent.value) { - mesh.geometry.generateTangents(); - } - } - - mesh.name = GLTFLoader.generateMeshName(json.meshes, idx, pp); - - lib.meshes[idx].push(mesh); - } - }, this); - }, - - _instanceCamera: function (json, nodeInfo) { - var cameraInfo = json.cameras[nodeInfo.camera]; - - if (cameraInfo.type === 'perspective') { - var perspectiveInfo = cameraInfo.perspective || {}; - return new __WEBPACK_IMPORTED_MODULE_14__camera_Perspective__["a" /* default */]({ - name: nodeInfo.name, - aspect: perspectiveInfo.aspectRatio, - fov: perspectiveInfo.yfov, - far: perspectiveInfo.zfar, - near: perspectiveInfo.znear - }); - } - else { - var orthographicInfo = cameraInfo.orthographic || {}; - return new __WEBPACK_IMPORTED_MODULE_15__camera_Orthographic__["a" /* default */]({ - name: nodeInfo.name, - top: orthographicInfo.ymag, - right: orthographicInfo.xmag, - left: -orthographicInfo.xmag, - bottom: -orthographicInfo.ymag, - near: orthographicInfo.znear, - far: orthographicInfo.zfar - }); - } - }, - - _parseNodes: function (json, lib) { - - function instanceMesh(mesh) { - return new __WEBPACK_IMPORTED_MODULE_7__Mesh__["a" /* default */]({ - name: mesh.name, - geometry: mesh.geometry, - material: mesh.material, - culling: mesh.culling, - mode: mesh.mode - }); - } - - lib.instancedMeshes = []; - - __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].each(json.nodes, function (nodeInfo, idx) { - var node; - if (nodeInfo.camera != null && this.includeCamera) { - node = this._instanceCamera(json, nodeInfo); - lib.cameras.push(node); - } - else if (nodeInfo.mesh != null && this.includeMesh) { - var primitives = lib.meshes[nodeInfo.mesh]; - if (primitives) { - if (primitives.length === 1) { - // Replace the node with mesh directly - node = instanceMesh(primitives[0]); - node.setName(nodeInfo.name); - lib.instancedMeshes.push(node); - } - else { - node = new __WEBPACK_IMPORTED_MODULE_8__Node__["a" /* default */](); - node.setName(nodeInfo.name); - for (var j = 0; j < primitives.length; j++) { - var newMesh = instanceMesh(primitives[j]); - node.add(newMesh); - lib.instancedMeshes.push(newMesh); - } - } - } - } - else { - node = new __WEBPACK_IMPORTED_MODULE_8__Node__["a" /* default */](); - // PENDING Dulplicate name. - node.setName(nodeInfo.name); - } - if (nodeInfo.matrix) { - node.localTransform.setArray(nodeInfo.matrix); - node.decomposeLocalTransform(); - } - else { - if (nodeInfo.translation) { - node.position.setArray(nodeInfo.translation); - } - if (nodeInfo.rotation) { - node.rotation.setArray(nodeInfo.rotation); - } - if (nodeInfo.scale) { - node.scale.setArray(nodeInfo.scale); - } - } - - lib.nodes[idx] = node; - }, this); - - // Build hierarchy - __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].each(json.nodes, function (nodeInfo, idx) { - var node = lib.nodes[idx]; - if (nodeInfo.children) { - for (var i = 0; i < nodeInfo.children.length; i++) { - var childIdx = nodeInfo.children[i]; - var child = lib.nodes[childIdx]; - node.add(child); - } - } - }); - }, - - _parseAnimations: function (json, lib) { - function checkChannelPath(channelInfo) { - if (channelInfo.path === 'weights') { - console.warn('GLTFLoader not support morph targets yet.'); - return false; - } - return true; - } - - function getChannelHash(channelInfo, animationInfo) { - return channelInfo.target.node + '_' + animationInfo.samplers[channelInfo.sampler].input; - } - - var timeAccessorMultiplied = {}; - __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].each(json.animations, function (animationInfo, idx) { - var channels = animationInfo.channels.filter(checkChannelPath); - - if (!channels.length) { - return; - } - var tracks = {}; - for (var i = 0; i < channels.length; i++) { - var channelInfo = channels[i]; - var channelHash = getChannelHash(channelInfo, animationInfo); - - var targetNode = lib.nodes[channelInfo.target.node]; - var track = tracks[channelHash]; - var samplerInfo = animationInfo.samplers[channelInfo.sampler]; - - if (!track) { - track = tracks[channelHash] = new __WEBPACK_IMPORTED_MODULE_19__animation_SamplerTrack__["a" /* default */]({ - name: targetNode ? targetNode.name : '', - target: targetNode - }); - track.targetNodeIndex = channelInfo.target.node; - track.channels.time = getAccessorData(json, lib, samplerInfo.input); - var frameLen = track.channels.time.length; - if (!timeAccessorMultiplied[samplerInfo.input]) { - for (var k = 0; k < frameLen; k++) { - track.channels.time[k] *= 1000; - } - timeAccessorMultiplied[samplerInfo.input] = true; - } - } - - var interpolation = samplerInfo.interpolation || 'LINEAR'; - if (interpolation !== 'LINEAR') { - console.warn('GLTFLoader only support LINEAR interpolation.'); - } - - var path = channelInfo.target.path; - if (path === 'translation') { - path = 'position'; - } - - track.channels[path] = getAccessorData(json, lib, samplerInfo.output); - } - var clip = new __WEBPACK_IMPORTED_MODULE_18__animation_TrackClip__["a" /* default */]({ - name: animationInfo.name, - loop: true - }); - for (var hash in tracks) { - clip.addTrack(tracks[hash]); - } - clip.calcLifeFromTracks(); - lib.clips.push(clip); - }, this); - - - // PENDING - var maxLife = lib.clips.reduce(function (maxTime, clip) { - return Math.max(maxTime, clip.life); - }, 0); - lib.clips.forEach(function (clip) { - clip.life = maxLife; - }); - - return lib.clips; - } -}); - -GLTFLoader.generateMeshName = function (meshes, idx, primitiveIdx) { - var meshInfo = meshes[idx]; - var meshName = meshInfo.name || ('mesh_' + idx); - return primitiveIdx === 0 ? meshName : (meshName + '$' + primitiveIdx); -}; - -/* harmony default export */ __webpack_exports__["a"] = (GLTFLoader); - - -/***/ }), -/* 42 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__BoundingBox__ = __webpack_require__(8); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Plane__ = __webpack_require__(79); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3__dep_glmatrix__); - - - - - -var vec3 = __WEBPACK_IMPORTED_MODULE_3__dep_glmatrix___default.a.vec3; - -var vec3Set = vec3.set; -var vec3Copy = vec3.copy; -var vec3TranformMat4 = vec3.transformMat4; -var mathMin = Math.min; -var mathMax = Math.max; -/** - * @constructor - * @alias clay.math.Frustum - */ -var Frustum = function() { - - /** - * Eight planes to enclose the frustum - * @type {clay.math.Plane[]} - */ - this.planes = []; - - for (var i = 0; i < 6; i++) { - this.planes.push(new __WEBPACK_IMPORTED_MODULE_2__Plane__["a" /* default */]()); - } - - /** - * Bounding box of frustum - * @type {clay.math.BoundingBox} - */ - this.boundingBox = new __WEBPACK_IMPORTED_MODULE_1__BoundingBox__["a" /* default */](); - - /** - * Eight vertices of frustum - * @type {Float32Array[]} - */ - this.vertices = []; - for (var i = 0; i < 8; i++) { - this.vertices[i] = vec3.fromValues(0, 0, 0); - } -}; - -Frustum.prototype = { - - // http://web.archive.org/web/20120531231005/http://crazyjoke.free.fr/doc/3D/plane%20extraction.pdf - /** - * Set frustum from a projection matrix - * @param {clay.math.Matrix4} projectionMatrix - */ - setFromProjection: function(projectionMatrix) { - - var planes = this.planes; - var m = projectionMatrix.array; - var m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3]; - var m4 = m[4], m5 = m[5], m6 = m[6], m7 = m[7]; - var m8 = m[8], m9 = m[9], m10 = m[10], m11 = m[11]; - var m12 = m[12], m13 = m[13], m14 = m[14], m15 = m[15]; - - // Update planes - vec3Set(planes[0].normal.array, m3 - m0, m7 - m4, m11 - m8); - planes[0].distance = -(m15 - m12); - planes[0].normalize(); - - vec3Set(planes[1].normal.array, m3 + m0, m7 + m4, m11 + m8); - planes[1].distance = -(m15 + m12); - planes[1].normalize(); - - vec3Set(planes[2].normal.array, m3 + m1, m7 + m5, m11 + m9); - planes[2].distance = -(m15 + m13); - planes[2].normalize(); - - vec3Set(planes[3].normal.array, m3 - m1, m7 - m5, m11 - m9); - planes[3].distance = -(m15 - m13); - planes[3].normalize(); - - vec3Set(planes[4].normal.array, m3 - m2, m7 - m6, m11 - m10); - planes[4].distance = -(m15 - m14); - planes[4].normalize(); - - vec3Set(planes[5].normal.array, m3 + m2, m7 + m6, m11 + m10); - planes[5].distance = -(m15 + m14); - planes[5].normalize(); - - // Perspective projection - var boundingBox = this.boundingBox; - if (m15 === 0) { - var aspect = m5 / m0; - var zNear = -m14 / (m10 - 1); - var zFar = -m14 / (m10 + 1); - var farY = -zFar / m5; - var nearY = -zNear / m5; - // Update bounding box - boundingBox.min.set(-farY * aspect, -farY, zFar); - boundingBox.max.set(farY * aspect, farY, zNear); - // update vertices - var vertices = this.vertices; - //--- min z - // min x - vec3Set(vertices[0], -farY * aspect, -farY, zFar); - vec3Set(vertices[1], -farY * aspect, farY, zFar); - // max x - vec3Set(vertices[2], farY * aspect, -farY, zFar); - vec3Set(vertices[3], farY * aspect, farY, zFar); - //-- max z - vec3Set(vertices[4], -nearY * aspect, -nearY, zNear); - vec3Set(vertices[5], -nearY * aspect, nearY, zNear); - vec3Set(vertices[6], nearY * aspect, -nearY, zNear); - vec3Set(vertices[7], nearY * aspect, nearY, zNear); - } - else { // Orthographic projection - var left = (-1 - m12) / m0; - var right = (1 - m12) / m0; - var top = (1 - m13) / m5; - var bottom = (-1 - m13) / m5; - var near = (-1 - m14) / m10; - var far = (1 - m14) / m10; - - - boundingBox.min.set(Math.min(left, right), Math.min(bottom, top), Math.min(far, near)); - boundingBox.max.set(Math.max(right, left), Math.max(top, bottom), Math.max(near, far)); - - var min = boundingBox.min.array; - var max = boundingBox.max.array; - var vertices = this.vertices; - //--- min z - // min x - vec3Set(vertices[0], min[0], min[1], min[2]); - vec3Set(vertices[1], min[0], max[1], min[2]); - // max x - vec3Set(vertices[2], max[0], min[1], min[2]); - vec3Set(vertices[3], max[0], max[1], min[2]); - //-- max z - vec3Set(vertices[4], min[0], min[1], max[2]); - vec3Set(vertices[5], min[0], max[1], max[2]); - vec3Set(vertices[6], max[0], min[1], max[2]); - vec3Set(vertices[7], max[0], max[1], max[2]); - } - }, - - /** - * Apply a affine transform matrix and set to the given bounding box - * @function - * @param {clay.math.BoundingBox} - * @param {clay.math.Matrix4} - * @return {clay.math.BoundingBox} - */ - getTransformedBoundingBox: (function() { - - var tmpVec3 = vec3.create(); - - return function(bbox, matrix) { - var vertices = this.vertices; - - var m4 = matrix.array; - var min = bbox.min; - var max = bbox.max; - var minArr = min.array; - var maxArr = max.array; - var v = vertices[0]; - vec3TranformMat4(tmpVec3, v, m4); - vec3Copy(minArr, tmpVec3); - vec3Copy(maxArr, tmpVec3); - - for (var i = 1; i < 8; i++) { - v = vertices[i]; - vec3TranformMat4(tmpVec3, v, m4); - - minArr[0] = mathMin(tmpVec3[0], minArr[0]); - minArr[1] = mathMin(tmpVec3[1], minArr[1]); - minArr[2] = mathMin(tmpVec3[2], minArr[2]); - - maxArr[0] = mathMax(tmpVec3[0], maxArr[0]); - maxArr[1] = mathMax(tmpVec3[1], maxArr[1]); - maxArr[2] = mathMax(tmpVec3[2], maxArr[2]); - } - - min._dirty = true; - max._dirty = true; - - return bbox; - }; - }) () -}; -/* harmony default export */ __webpack_exports__["a"] = (Frustum); - - -/***/ }), -/* 43 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1__dep_glmatrix__); - - -var vec3 = __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default.a.vec3; - -var EPSILON = 1e-5; - -/** - * @constructor - * @alias clay.math.Ray - * @param {clay.math.Vector3} [origin] - * @param {clay.math.Vector3} [direction] - */ -var Ray = function (origin, direction) { - /** - * @type {clay.math.Vector3} - */ - this.origin = origin || new __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */](); - /** - * @type {clay.math.Vector3} - */ - this.direction = direction || new __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */](); -}; - -Ray.prototype = { - - constructor: Ray, - - // http://www.siggraph.org/education/materials/HyperGraph/raytrace/rayplane_intersection.htm - /** - * Calculate intersection point between ray and a give plane - * @param {clay.math.Plane} plane - * @param {clay.math.Vector3} [out] - * @return {clay.math.Vector3} - */ - intersectPlane: function (plane, out) { - var pn = plane.normal.array; - var d = plane.distance; - var ro = this.origin.array; - var rd = this.direction.array; - - var divider = vec3.dot(pn, rd); - // ray is parallel to the plane - if (divider === 0) { - return null; - } - if (!out) { - out = new __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */](); - } - var t = (vec3.dot(pn, ro) - d) / divider; - vec3.scaleAndAdd(out.array, ro, rd, -t); - out._dirty = true; - return out; - }, - - /** - * Mirror the ray against plane - * @param {clay.math.Plane} plane - */ - mirrorAgainstPlane: function (plane) { - // Distance to plane - var d = vec3.dot(plane.normal.array, this.direction.array); - vec3.scaleAndAdd(this.direction.array, this.direction.array, plane.normal.array, -d * 2); - this.direction._dirty = true; - }, - - distanceToPoint: (function () { - var v = vec3.create(); - return function (point) { - vec3.sub(v, point, this.origin.array); - // Distance from projection point to origin - var b = vec3.dot(v, this.direction.array); - if (b < 0) { - return vec3.distance(this.origin.array, point); - } - // Squared distance from center to origin - var c2 = vec3.lenSquared(v); - // Squared distance from center to projection point - return Math.sqrt(c2 - b * b); - }; - })(), - - /** - * Calculate intersection point between ray and sphere - * @param {clay.math.Vector3} center - * @param {number} radius - * @param {clay.math.Vector3} out - * @return {clay.math.Vector3} - */ - intersectSphere: (function () { - var v = vec3.create(); - return function (center, radius, out) { - var origin = this.origin.array; - var direction = this.direction.array; - center = center.array; - vec3.sub(v, center, origin); - // Distance from projection point to origin - var b = vec3.dot(v, direction); - // Squared distance from center to origin - var c2 = vec3.squaredLength(v); - // Squared distance from center to projection point - var d2 = c2 - b * b; - - var r2 = radius * radius; - // No intersection - if (d2 > r2) { - return; - } - - var a = Math.sqrt(r2 - d2); - // First intersect point - var t0 = b - a; - // Second intersect point - var t1 = b + a; - - if (!out) { - out = new __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */](); - } - if (t0 < 0) { - if (t1 < 0) { - return null; - } - else { - vec3.scaleAndAdd(out.array, origin, direction, t1); - return out; - } - } - else { - vec3.scaleAndAdd(out.array, origin, direction, t0); - return out; - } - }; - })(), - - // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ - /** - * Calculate intersection point between ray and bounding box - * @param {clay.math.BoundingBox} bbox - * @param {clay.math.Vector3} - * @return {clay.math.Vector3} - */ - intersectBoundingBox: function (bbox, out) { - var dir = this.direction.array; - var origin = this.origin.array; - var min = bbox.min.array; - var max = bbox.max.array; - - var invdirx = 1 / dir[0]; - var invdiry = 1 / dir[1]; - var invdirz = 1 / dir[2]; - - var tmin, tmax, tymin, tymax, tzmin, tzmax; - if (invdirx >= 0) { - tmin = (min[0] - origin[0]) * invdirx; - tmax = (max[0] - origin[0]) * invdirx; - } - else { - tmax = (min[0] - origin[0]) * invdirx; - tmin = (max[0] - origin[0]) * invdirx; - } - if (invdiry >= 0) { - tymin = (min[1] - origin[1]) * invdiry; - tymax = (max[1] - origin[1]) * invdiry; - } - else { - tymax = (min[1] - origin[1]) * invdiry; - tymin = (max[1] - origin[1]) * invdiry; - } - - if ((tmin > tymax) || (tymin > tmax)) { - return null; - } - - if (tymin > tmin || tmin !== tmin) { - tmin = tymin; - } - if (tymax < tmax || tmax !== tmax) { - tmax = tymax; - } - - if (invdirz >= 0) { - tzmin = (min[2] - origin[2]) * invdirz; - tzmax = (max[2] - origin[2]) * invdirz; - } - else { - tzmax = (min[2] - origin[2]) * invdirz; - tzmin = (max[2] - origin[2]) * invdirz; - } - - if ((tmin > tzmax) || (tzmin > tmax)) { - return null; - } - - if (tzmin > tmin || tmin !== tmin) { - tmin = tzmin; - } - if (tzmax < tmax || tmax !== tmax) { - tmax = tzmax; - } - if (tmax < 0) { - return null; - } - - var t = tmin >= 0 ? tmin : tmax; - - if (!out) { - out = new __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */](); - } - vec3.scaleAndAdd(out.array, origin, dir, t); - return out; - }, - - // http://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm - /** - * Calculate intersection point between ray and three triangle vertices - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @param {clay.math.Vector3} c - * @param {boolean} singleSided, CW triangle will be ignored - * @param {clay.math.Vector3} [out] - * @param {clay.math.Vector3} [barycenteric] barycentric coords - * @return {clay.math.Vector3} - */ - intersectTriangle: (function () { - - var eBA = vec3.create(); - var eCA = vec3.create(); - var AO = vec3.create(); - var vCross = vec3.create(); - - return function (a, b, c, singleSided, out, barycenteric) { - var dir = this.direction.array; - var origin = this.origin.array; - a = a.array; - b = b.array; - c = c.array; - - vec3.sub(eBA, b, a); - vec3.sub(eCA, c, a); - - vec3.cross(vCross, eCA, dir); - - var det = vec3.dot(eBA, vCross); - - if (singleSided) { - if (det > -EPSILON) { - return null; - } - } - else { - if (det > -EPSILON && det < EPSILON) { - return null; - } - } - - vec3.sub(AO, origin, a); - var u = vec3.dot(vCross, AO) / det; - if (u < 0 || u > 1) { - return null; - } - - vec3.cross(vCross, eBA, AO); - var v = vec3.dot(dir, vCross) / det; - - if (v < 0 || v > 1 || (u + v > 1)) { - return null; - } - - vec3.cross(vCross, eBA, eCA); - var t = -vec3.dot(AO, vCross) / det; - - if (t < 0) { - return null; - } - - if (!out) { - out = new __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */](); - } - if (barycenteric) { - __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */].set(barycenteric, (1 - u - v), u, v); - } - vec3.scaleAndAdd(out.array, origin, dir, t); - - return out; - }; - })(), - - /** - * Apply an affine transform matrix to the ray - * @return {clay.math.Matrix4} matrix - */ - applyTransform: function (matrix) { - __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */].add(this.direction, this.direction, this.origin); - __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */].transformMat4(this.origin, this.origin, matrix); - __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */].transformMat4(this.direction, this.direction, matrix); - - __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */].sub(this.direction, this.direction, this.origin); - __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */].normalize(this.direction, this.direction); - }, - - /** - * Copy values from another ray - * @param {clay.math.Ray} ray - */ - copy: function (ray) { - __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */].copy(this.origin, ray.origin); - __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */].copy(this.direction, ray.direction); - }, - - /** - * Clone a new ray - * @return {clay.math.Ray} - */ - clone: function () { - var ray = new Ray(); - ray.copy(this); - return ray; - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (Ray); - - -/***/ }), -/* 44 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Material__ = __webpack_require__(10); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__shader_source_standard_glsl_js__ = __webpack_require__(45); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__core_util__ = __webpack_require__(7); - - - - - - -// Import standard shader -__WEBPACK_IMPORTED_MODULE_1__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_2__shader_source_standard_glsl_js__["a" /* default */]); - -var TEXTURE_PROPERTIES = ['diffuseMap', 'normalMap', 'roughnessMap', 'metalnessMap', 'emissiveMap', 'environmentMap', 'brdfLookup', 'ssaoMap', 'aoMap']; -var SIMPLE_PROPERTIES = ['color', 'emission', 'emissionIntensity', 'alpha', 'roughness', 'metalness', 'uvRepeat', 'uvOffset', 'aoIntensity', 'alphaCutoff']; -var PROPERTIES_CHANGE_SHADER = ['linear', 'encodeRGBM', 'decodeRGBM', 'doubleSided', 'alphaTest', 'roughnessChannel', 'metalnessChannel', 'environmentMapPrefiltered']; - -var NUM_DEFINE_MAP = { - 'roughnessChannel': 'ROUGHNESS_CHANNEL', - 'metalnessChannel': 'METALNESS_CHANNEL' -}; -var BOOL_DEFINE_MAP = { - 'linear': 'SRGB_DECODE', - 'encodeRGBM': 'RGBM_ENCODE', - 'decodeRGBM': 'RGBM_DECODE', - 'doubleSided': 'DOUBLE_SIDED', - 'alphaTest': 'ALPHA_TEST', - 'environmentMapPrefiltered': 'ENVIRONMENTMAP_PREFILTER' -} - - -var standardShader; -/** - * Standard material without custom shader. - * @constructor clay.StandardMaterial - * @extends clay.Base - * @example - * var mat = new clay.StandardMaterial({ - * color: [1, 1, 1], - * diffuseMap: diffuseTexture - * }); - * mat.roughness = 1; - */ -var StandardMaterial = __WEBPACK_IMPORTED_MODULE_0__Material__["a" /* default */].extend(function () { - if (!standardShader) { - standardShader = new __WEBPACK_IMPORTED_MODULE_1__Shader__["a" /* default */](__WEBPACK_IMPORTED_MODULE_1__Shader__["a" /* default */].source('clay.standard.vertex'), __WEBPACK_IMPORTED_MODULE_1__Shader__["a" /* default */].source('clay.standard.fragment')); - } - return /** @lends clay.StandardMaterial# */ { - shader: standardShader - }; -}, function (option) { - // PENDING - __WEBPACK_IMPORTED_MODULE_3__core_util__["a" /* default */].extend(this, option); - // Extend after shader is created. - __WEBPACK_IMPORTED_MODULE_3__core_util__["a" /* default */].defaults(this, /** @lends clay.StandardMaterial# */ { - /** - * @type {Array.} - * @default [1, 1, 1] - */ - color: [1, 1, 1], - - /** - * @type {Array.} - * @default [0, 0, 0] - */ - emission: [0, 0, 0], - - /** - * @type {number} - * @default 0 - */ - emissionIntensity: 0, - - /** - * @type {number} - * @default 0.5 - */ - roughness: 0.5, - - /** - * @type {number} - * @default 0 - */ - metalness: 0, - - /** - * @type {number} - * @default 1 - */ - alpha: 1, - - /** - * @type {boolean} - */ - alphaTest: false, - - /** - * Cutoff threshold for alpha test - * @type {number} - */ - alphaCutoff: 0.9, - - /** - * @type {boolean} - */ - // TODO Must disable culling. - doubleSided: false, - - /** - * @type {clay.Texture2D} - */ - - /** - * @type {clay.Texture2D} - */ - - /** - * @type {clay.Texture2D} - */ - - /** - * @type {clay.Texture2D} - */ - /** - * @type {clay.Texture2D} - */ - - /** - * @type {clay.TextureCube} - */ - - /** - * @type {clay.math.BoundingBox} - */ - - /** - * BRDF Lookup is generated by clay.util.cubemap.integrateBrdf - * @type {clay.Texture2D} - */ - - /** - * @type {clay.Texture2D} - */ - - /** - * @type {clay.Texture2D} - */ - - /** - * @type {Array.} - * @default [1, 1] - */ - uvRepeat: [1, 1], - - /** - * @type {Array.} - * @default [0, 0] - */ - uvOffset: [0, 0], - - /** - * @type {number} - * @default 1 - */ - aoIntensity: 1, - - /** - * @type {boolean} - */ - environmentMapPrefiltered: false, - - /** - * @type {boolean} - */ - linear: false, - - /** - * @type {boolean} - */ - encodeRGBM: false, - - /** - * @type {boolean} - */ - decodeRGBM: false, - - /** - * @type {Number} - */ - roughnessChannel: 0, - /** - * @type {Number} - */ - metalnessChannel: 1 - }); - - this.define('fragment', 'USE_METALNESS'); - this.define('fragment', 'USE_ROUGHNESS'); -}, { - clone: function () { - var material = new StandardMaterial({ - name: this.name - }); - TEXTURE_PROPERTIES.forEach(function (propName) { - if (this[propName]) { - material[propName] = this[propName]; - } - }, this); - SIMPLE_PROPERTIES.concat(PROPERTIES_CHANGE_SHADER).forEach(function (propName) { - material[propName] = this[propName]; - }, this); - return material; - } -}); - -SIMPLE_PROPERTIES.forEach(function (propName) { - Object.defineProperty(StandardMaterial.prototype, propName, { - get: function () { - return this.get(propName); - }, - set: function (value) { - this.setUniform(propName, value); - } - }); -}); - -TEXTURE_PROPERTIES.forEach(function (propName) { - Object.defineProperty(StandardMaterial.prototype, propName, { - get: function () { - return this.get(propName); - }, - set: function (value) { - this.setUniform(propName, value); - } - }); -}); - -PROPERTIES_CHANGE_SHADER.forEach(function (propName) { - var privateKey = '_' + propName; - Object.defineProperty(StandardMaterial.prototype, propName, { - get: function () { - return this[privateKey]; - }, - set: function (value) { - this[privateKey] = value; - if (propName in NUM_DEFINE_MAP) { - var defineName = NUM_DEFINE_MAP[propName]; - this.define('fragment', defineName, value); - } - else { - var defineName = BOOL_DEFINE_MAP[propName]; - value ? this.define('fragment', defineName) : this.undefine('fragment', defineName); - } - } - }); -}); - -Object.defineProperty(StandardMaterial.prototype, 'environmentBox', { - get: function () { - var envBox = this._environmentBox; - if (envBox) { - envBox.min.setArray(this.get('environmentBoxMin')); - envBox.max.setArray(this.get('environmentBoxMax')); - } - return envBox; - }, - - set: function (value) { - this._environmentBox = value; - - var uniforms = this.uniforms = this.uniforms || {}; - uniforms['environmentBoxMin'] = uniforms['environmentBoxMin'] || { - value: null - }; - uniforms['environmentBoxMax'] = uniforms['environmentBoxMax'] || { - value: null - }; - - // TODO Can't detect operation like box.min = new Vector() - if (value) { - this.setUniform('environmentBoxMin', value.min.array); - this.setUniform('environmentBoxMax', value.max.array); - } - - if (value) { - this.define('fragment', 'PARALLAX_CORRECTED'); - } - else { - this.undefine('fragment', 'PARALLAX_CORRECTED'); - } - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (StandardMaterial); - - -/***/ }), -/* 45 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("\n@export clay.standard.vertex\n#define SHADER_NAME standard\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\n#if defined(AOMAP_ENABLED)\nattribute vec2 texcoord2 : TEXCOORD_1;\n#endif\nattribute vec3 normal : NORMAL;\nattribute vec4 tangent : TANGENT;\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n#endif\nattribute vec3 barycentric;\n@import clay.chunk.skinning_header\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nvarying vec3 v_Barycentric;\n#if defined(PARALLAXOCCLUSIONMAP_ENABLED) || defined(NORMALMAP_ENABLED)\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\n#endif\n#if defined(AOMAP_ENABLED)\nvarying vec2 v_Texcoord2;\n#endif\nvoid main()\n{\n vec3 skinnedPosition = position;\n vec3 skinnedNormal = normal;\n vec3 skinnedTangent = tangent.xyz;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n skinnedTangent = (skinMatrixWS * vec4(tangent.xyz, 0.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_WorldPosition = (world * vec4(skinnedPosition, 1.0)).xyz;\n v_Barycentric = barycentric;\n v_Normal = normalize((worldInverseTranspose * vec4(skinnedNormal, 0.0)).xyz);\n#if defined(PARALLAXOCCLUSIONMAP_ENABLED) || defined(NORMALMAP_ENABLED)\n v_Tangent = normalize((worldInverseTranspose * vec4(skinnedTangent, 0.0)).xyz);\n v_Bitangent = normalize(cross(v_Normal, v_Tangent) * tangent.w);\n#endif\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n#if defined(AOMAP_ENABLED)\n v_Texcoord2 = texcoord2;\n#endif\n}\n@end\n@export clay.standard.fragment\n#define PI 3.14159265358979\n#define GLOSSINESS_CHANNEL 0\n#define ROUGHNESS_CHANNEL 0\n#define METALNESS_CHANNEL 1\nuniform mat4 viewInverse : VIEWINVERSE;\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\n#if defined(PARALLAXOCCLUSIONMAP_ENABLED) || defined(NORMALMAP_ENABLED)\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\n#endif\n#ifdef NORMALMAP_ENABLED\nuniform sampler2D normalMap;\n#endif\n#ifdef DIFFUSEMAP_ENABLED\nuniform sampler2D diffuseMap;\n#endif\n#ifdef SPECULARMAP_ENABLED\nuniform sampler2D specularMap;\n#endif\n#ifdef USE_ROUGHNESS\nuniform float roughness : 0.5;\n #ifdef ROUGHNESSMAP_ENABLED\nuniform sampler2D roughnessMap;\n #endif\n#else\nuniform float glossiness: 0.5;\n #ifdef GLOSSINESSMAP_ENABLED\nuniform sampler2D glossinessMap;\n #endif\n#endif\n#ifdef METALNESSMAP_ENABLED\nuniform sampler2D metalnessMap;\n#endif\n#ifdef ENVIRONMENTMAP_ENABLED\nuniform samplerCube environmentMap;\n #ifdef PARALLAX_CORRECTED\nuniform vec3 environmentBoxMin;\nuniform vec3 environmentBoxMax;\n #endif\n#endif\n#ifdef BRDFLOOKUP_ENABLED\nuniform sampler2D brdfLookup;\n#endif\n#ifdef EMISSIVEMAP_ENABLED\nuniform sampler2D emissiveMap;\n#endif\n#ifdef SSAOMAP_ENABLED\nuniform sampler2D ssaoMap;\nuniform vec4 viewport : VIEWPORT;\n#endif\n#ifdef AOMAP_ENABLED\nuniform sampler2D aoMap;\nuniform float aoIntensity;\nvarying vec2 v_Texcoord2;\n#endif\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\n#ifdef USE_METALNESS\nuniform float metalness : 0.0;\n#else\nuniform vec3 specularColor : [0.1, 0.1, 0.1];\n#endif\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float emissionIntensity: 1;\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\nvarying vec3 v_Barycentric;\n#ifdef ENVIRONMENTMAP_PREFILTER\nuniform float maxMipmapLevel: 5;\n#endif\n#ifdef AMBIENT_LIGHT_COUNT\n@import clay.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import clay.header.ambient_sh_light\n#endif\n#ifdef AMBIENT_CUBEMAP_LIGHT_COUNT\n@import clay.header.ambient_cubemap_light\n#endif\n#ifdef POINT_LIGHT_COUNT\n@import clay.header.point_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n#ifdef SPOT_LIGHT_COUNT\n@import clay.header.spot_light\n#endif\n@import clay.util.calculate_attenuation\n@import clay.util.edge_factor\n@import clay.util.rgbm\n@import clay.util.srgb\n@import clay.plugin.compute_shadow_map\n@import clay.util.parallax_correct\n@import clay.util.ACES\nfloat G_Smith(float g, float ndv, float ndl)\n{\n float roughness = 1.0 - g;\n float k = roughness * roughness / 2.0;\n float G1V = ndv / (ndv * (1.0 - k) + k);\n float G1L = ndl / (ndl * (1.0 - k) + k);\n return G1L * G1V;\n}\nvec3 F_Schlick(float ndv, vec3 spec) {\n return spec + (1.0 - spec) * pow(1.0 - ndv, 5.0);\n}\nfloat D_Phong(float g, float ndh) {\n float a = pow(8192.0, g);\n return (a + 2.0) / 8.0 * pow(ndh, a);\n}\nfloat D_GGX(float g, float ndh) {\n float r = 1.0 - g;\n float a = r * r;\n float tmp = ndh * ndh * (a - 1.0) + 1.0;\n return a / (PI * tmp * tmp);\n}\n#ifdef PARALLAXOCCLUSIONMAP_ENABLED\nuniform float parallaxOcclusionScale : 0.02;\nuniform float parallaxMaxLayers : 20;\nuniform float parallaxMinLayers : 5;\nuniform sampler2D parallaxOcclusionMap;\nmat3 transpose(in mat3 inMat)\n{\n vec3 i0 = inMat[0];\n vec3 i1 = inMat[1];\n vec3 i2 = inMat[2];\n return mat3(\n vec3(i0.x, i1.x, i2.x),\n vec3(i0.y, i1.y, i2.y),\n vec3(i0.z, i1.z, i2.z)\n );\n}\nvec2 parallaxUv(vec2 uv, vec3 viewDir)\n{\n float numLayers = mix(parallaxMaxLayers, parallaxMinLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));\n float layerHeight = 1.0 / numLayers;\n float curLayerHeight = 0.0;\n vec2 deltaUv = viewDir.xy * parallaxOcclusionScale / (viewDir.z * numLayers);\n vec2 curUv = uv;\n float height = 1.0 - texture2D(parallaxOcclusionMap, curUv).r;\n for (int i = 0; i < 30; i++) {\n curLayerHeight += layerHeight;\n curUv -= deltaUv;\n height = 1.0 - texture2D(parallaxOcclusionMap, curUv).r;\n if (height < curLayerHeight) {\n break;\n }\n }\n vec2 prevUv = curUv + deltaUv;\n float next = height - curLayerHeight;\n float prev = 1.0 - texture2D(parallaxOcclusionMap, prevUv).r - curLayerHeight + layerHeight;\n return mix(curUv, prevUv, next / (next - prev));\n}\n#endif\nvoid main() {\n vec4 albedoColor = vec4(color, alpha);\n#ifdef VERTEX_COLOR\n albedoColor *= v_Color;\n#endif\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = normalize(eyePos - v_WorldPosition);\n vec2 uv = v_Texcoord;\n#if defined(PARALLAXOCCLUSIONMAP_ENABLED) || defined(NORMALMAP_ENABLED)\n mat3 tbn = mat3(v_Tangent, v_Bitangent, v_Normal);\n#endif\n#ifdef PARALLAXOCCLUSIONMAP_ENABLED\n uv = parallaxUv(v_Texcoord, normalize(transpose(tbn) * -V));\n#endif\n#ifdef DIFFUSEMAP_ENABLED\n vec4 texel = texture2D(diffuseMap, uv);\n #ifdef SRGB_DECODE\n texel = sRGBToLinear(texel);\n #endif\n albedoColor.rgb *= texel.rgb;\n #ifdef DIFFUSEMAP_ALPHA_ALPHA\n albedoColor.a *= texel.a;\n #endif\n#endif\n#ifdef USE_METALNESS\n float m = metalness;\n #ifdef METALNESSMAP_ENABLED\n float m2 = texture2D(metalnessMap, uv)[METALNESS_CHANNEL];\n m = clamp(m2 + (m - 0.5) * 2.0, 0.0, 1.0);\n #endif\n vec3 baseColor = albedoColor.rgb;\n albedoColor.rgb = baseColor * (1.0 - m);\n vec3 spec = mix(vec3(0.04), baseColor, m);\n#else\n vec3 spec = specularColor;\n#endif\n#ifdef USE_ROUGHNESS\n float g = 1.0 - roughness;\n #ifdef ROUGHNESSMAP_ENABLED\n float g2 = 1.0 - texture2D(roughnessMap, uv)[ROUGHNESS_CHANNEL];\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n #endif\n#else\n float g = glossiness;\n #ifdef GLOSSINESSMAP_ENABLED\n float g2 = texture2D(glossinessMap, uv)[GLOSSINESS_CHANNEL];\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n #endif\n#endif\n#ifdef SPECULARMAP_ENABLED\n spec *= sRGBToLinear(texture2D(specularMap, uv)).rgb;\n#endif\n vec3 N = v_Normal;\n#ifdef DOUBLE_SIDED\n if (dot(N, V) < 0.0) {\n N = -N;\n }\n#endif\n#ifdef NORMALMAP_ENABLED\n if (dot(v_Tangent, v_Tangent) > 0.0) {\n vec3 normalTexel = texture2D(normalMap, uv).xyz;\n if (dot(normalTexel, normalTexel) > 0.0) { N = normalTexel * 2.0 - 1.0;\n tbn[1] = -tbn[1];\n N = normalize(tbn * N);\n }\n }\n#endif\n vec3 diffuseTerm = vec3(0.0, 0.0, 0.0);\n vec3 specularTerm = vec3(0.0, 0.0, 0.0);\n float ndv = clamp(dot(N, V), 0.0, 1.0);\n vec3 fresnelTerm = F_Schlick(ndv, spec);\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {{\n diffuseTerm += ambientLightColor[_idx_];\n }}\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseTerm += calcAmbientSHLight(_idx_, N) * ambientSHLightColor[_idx_];\n }}\n#endif\n#ifdef POINT_LIGHT_COUNT\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsPoint[POINT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfPointLights(v_WorldPosition, shadowContribsPoint);\n }\n#endif\n for(int _idx_ = 0; _idx_ < POINT_LIGHT_COUNT; _idx_++)\n {{\n vec3 lightPosition = pointLightPosition[_idx_];\n vec3 lc = pointLightColor[_idx_];\n float range = pointLightRange[_idx_];\n vec3 L = lightPosition - v_WorldPosition;\n float dist = length(L);\n float attenuation = lightAttenuation(dist, range);\n L /= dist;\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n if(shadowEnabled)\n {\n shadowContrib = shadowContribsPoint[_idx_];\n }\n#endif\n vec3 li = lc * ndl * attenuation * shadowContrib;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }}\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int _idx_ = 0; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++)\n {{\n vec3 L = -normalize(directionalLightDirection[_idx_]);\n vec3 lc = directionalLightColor[_idx_];\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if(shadowEnabled)\n {\n shadowContrib = shadowContribsDir[_idx_];\n }\n#endif\n vec3 li = lc * ndl * shadowContrib;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }}\n#endif\n#ifdef SPOT_LIGHT_COUNT\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsSpot[SPOT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfSpotLights(v_WorldPosition, shadowContribsSpot);\n }\n#endif\n for(int i = 0; i < SPOT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = spotLightPosition[i];\n vec3 spotLightDirection = -normalize(spotLightDirection[i]);\n vec3 lc = spotLightColor[i];\n float range = spotLightRange[i];\n float a = spotLightUmbraAngleCosine[i];\n float b = spotLightPenumbraAngleCosine[i];\n float falloffFactor = spotLightFalloffFactor[i];\n vec3 L = lightPosition - v_WorldPosition;\n float dist = length(L);\n float attenuation = lightAttenuation(dist, range);\n L /= dist;\n float c = dot(spotLightDirection, L);\n float falloff;\n falloff = clamp((c - a) /( b - a), 0.0, 1.0);\n falloff = pow(falloff, falloffFactor);\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n if (shadowEnabled)\n {\n shadowContrib = shadowContribsSpot[i];\n }\n#endif\n vec3 li = lc * attenuation * (1.0 - falloff) * shadowContrib * ndl;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }\n#endif\n vec4 outColor = albedoColor;\n outColor.rgb *= diffuseTerm;\n outColor.rgb += specularTerm;\n#ifdef AMBIENT_CUBEMAP_LIGHT_COUNT\n vec3 L = reflect(-V, N);\n float rough2 = clamp(1.0 - g, 0.0, 1.0);\n float bias2 = rough2 * 5.0;\n vec2 brdfParam2 = texture2D(ambientCubemapLightBRDFLookup[0], vec2(rough2, ndv)).xy;\n vec3 envWeight2 = spec * brdfParam2.x + brdfParam2.y;\n vec3 envTexel2;\n for(int _idx_ = 0; _idx_ < AMBIENT_CUBEMAP_LIGHT_COUNT; _idx_++)\n {{\n envTexel2 = RGBMDecode(textureCubeLodEXT(ambientCubemapLightCubemap[_idx_], L, bias2), 51.5);\n outColor.rgb += ambientCubemapLightColor[_idx_] * envTexel2 * envWeight2;\n }}\n#endif\n#ifdef ENVIRONMENTMAP_ENABLED\n vec3 envWeight = g * fresnelTerm;\n vec3 L = reflect(-V, N);\n #ifdef PARALLAX_CORRECTED\n L = parallaxCorrect(L, v_WorldPosition, environmentBoxMin, environmentBoxMax);\n #endif\n #ifdef ENVIRONMENTMAP_PREFILTER\n float rough = clamp(1.0 - g, 0.0, 1.0);\n float bias = rough * maxMipmapLevel;\n vec3 envTexel = decodeHDR(textureCubeLodEXT(environmentMap, L, bias)).rgb;\n #ifdef BRDFLOOKUP_ENABLED\n vec2 brdfParam = texture2D(brdfLookup, vec2(rough, ndv)).xy;\n envWeight = spec * brdfParam.x + brdfParam.y;\n #endif\n #else\n vec3 envTexel = textureCube(environmentMap, L).xyz;\n #endif\n outColor.rgb += envTexel * envWeight;\n#endif\n float aoFactor = 1.0;\n#ifdef SSAOMAP_ENABLED\n aoFactor = min(texture2D(ssaoMap, (gl_FragCoord.xy - viewport.xy) / viewport.zw).r, aoFactor);\n#endif\n#ifdef AOMAP_ENABLED\n aoFactor = min(1.0 - clamp((1.0 - texture2D(aoMap, v_Texcoord2).r) * aoIntensity, 0.0, 1.0), aoFactor);\n#endif\n outColor.rgb *= aoFactor;\n vec3 lEmission = emission;\n#ifdef EMISSIVEMAP_ENABLED\n lEmission *= texture2D(emissiveMap, uv).rgb;\n#endif\n outColor.rgb += lEmission * emissionIntensity;\n if(lineWidth > 0.)\n {\n outColor.rgb = mix(outColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (outColor.a < alphaCutoff) {\n discard;\n }\n#endif\n#ifdef TONEMAPPING\n outColor.rgb = ACESToneMapping(outColor.rgb);\n#endif\n#ifdef SRGB_ENCODE\n outColor = linearTosRGB(outColor);\n#endif\n gl_FragColor = encodeHDR(outColor);\n}\n@end\n@export clay.standardMR.vertex\n@import clay.standard.vertex\n@end\n@export clay.standardMR.fragment\n#define USE_METALNESS\n#define USE_ROUGHNESS\n@import clay.standard.fragment\n@end"); - - -/***/ }), -/* 46 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Node__ = __webpack_require__(15); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_glenum__ = __webpack_require__(6); - - - -// Cache -var prevDrawID = 0; -var prevDrawIndicesBuffer = null; -var prevDrawIsUseIndices = true; - -var currentDrawID; - -var RenderInfo = function() { - this.triangleCount = 0; - this.vertexCount = 0; - this.drawCallCount = 0; -}; - -function VertexArrayObject( - availableAttributes, - availableAttributeSymbols, - indicesBuffer -) { - this.availableAttributes = availableAttributes; - this.availableAttributeSymbols = availableAttributeSymbols; - this.indicesBuffer = indicesBuffer; - - this.vao = null; -} -/** - * @constructor - * @alias clay.Renderable - * @extends clay.Node - */ -var Renderable = __WEBPACK_IMPORTED_MODULE_0__Node__["a" /* default */].extend( -/** @lends clay.Renderable# */ -{ - /** - * @type {clay.Material} - */ - material: null, - - /** - * @type {clay.Geometry} - */ - geometry: null, - - /** - * @type {number} - */ - mode: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].TRIANGLES, - - _drawCache: null, - - _renderInfo: null -}, function() { - this._drawCache = {}; - this._renderInfo = new RenderInfo(); -}, -/** @lends clay.Renderable.prototype */ -{ - - __program: null, - - /** - * Group of received light. - */ - lightGroup: 0, - /** - * Render order, Nodes with smaller value renders before nodes with larger values. - * @type {Number} - */ - renderOrder: 0, - /** - * Used when mode is LINES, LINE_STRIP or LINE_LOOP - * @type {number} - */ - lineWidth: 1, - - /** - * If enable culling - * @type {boolean} - */ - culling: true, - /** - * Specify which side of polygon will be culled. - * Possible values: - * + {@link clay.Renderable.BACK} - * + {@link clay.Renderable.FRONT} - * + {@link clay.Renderable.FRONT_AND_BACK} - * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/cullFace - * @type {number} - */ - cullFace: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].BACK, - /** - * Specify which side is front face. - * Possible values: - * + {@link clay.Renderable.CW} - * + {@link clay.Renderable.CCW} - * @see https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/frontFace - * @type {number} - */ - frontFace: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].CCW, - - /** - * If enable software frustum culling - * @type {boolean} - */ - frustumCulling: true, - /** - * @type {boolean} - */ - receiveShadow: true, - /** - * @type {boolean} - */ - castShadow: true, - /** - * @type {boolean} - */ - ignorePicking: false, - /** - * @type {boolean} - */ - ignorePreZ: false, - - /** - * @type {boolean} - */ - ignoreGBuffer: false, - - /** - * @return {boolean} - */ - isRenderable: function() { - // TODO Shader ? - return this.geometry && this.material && this.material.shader && !this.invisible - && this.geometry.vertexCount > 0; - }, - - /** - * Before render hook - * @type {Function} - */ - beforeRender: function (_gl) {}, - - /** - * Before render hook - * @type {Function} - */ - afterRender: function (_gl, renderStat) {}, - - getBoundingBox: function (filter, out) { - out = __WEBPACK_IMPORTED_MODULE_0__Node__["a" /* default */].prototype.getBoundingBox.call(this, filter, out); - if (this.geometry && this.geometry.boundingBox) { - out.union(this.geometry.boundingBox); - } - - return out; - }, - - /** - * @param {clay.Renderer} renderer - * @param {clay.Material} [material] - * @return {Object} - */ - render: function (renderer, material, program) { - var _gl = renderer.gl; - material = material || this.material; - // May use shader of other material if shader code are same - var shader = material.shader; - var geometry = this.geometry; - - var glDrawMode = this.mode; - - var nVertex = geometry.vertexCount; - var isUseIndices = geometry.isUseIndices(); - - var uintExt = renderer.getGLExtension('OES_element_index_uint'); - var useUintExt = uintExt && nVertex > 0xffff; - var indicesType = useUintExt ? _gl.UNSIGNED_INT : _gl.UNSIGNED_SHORT; - - var vaoExt = renderer.getGLExtension('OES_vertex_array_object'); - // var vaoExt = null; - - var isStatic = !geometry.dynamic; - - var renderInfo = this._renderInfo; - renderInfo.vertexCount = nVertex; - renderInfo.triangleCount = 0; - renderInfo.drawCallCount = 0; - // Draw each chunk - var drawHashChanged = false; - // Hash with shader id in case previous material has less attributes than next material - currentDrawID = renderer.__uid__ + '-' + geometry.__uid__ + '-' + program.__uid__; - - if (currentDrawID !== prevDrawID) { - drawHashChanged = true; - } - else { - // The cache will be invalid in the following cases - // 1. VAO is enabled and is binded to null after render - // 2. Geometry needs update - if ( - // TODO Optimize - (vaoExt && isStatic) - // PENDING - || geometry._cache.isDirty('any') - ) { - drawHashChanged = true; - } - } - prevDrawID = currentDrawID; - - if (!drawHashChanged) { - // Direct draw - if (prevDrawIsUseIndices) { - _gl.drawElements(glDrawMode, prevDrawIndicesBuffer.count, indicesType, 0); - renderInfo.triangleCount = prevDrawIndicesBuffer.count / 3; - } - else { - // FIXME Use vertex number in buffer - // vertexCount may get the wrong value when geometry forget to mark dirty after update - _gl.drawArrays(glDrawMode, 0, nVertex); - } - renderInfo.drawCallCount = 1; - } - else { - // Use the cache of static geometry - var vaoList = this._drawCache[currentDrawID]; - if (!vaoList) { - var chunks = geometry.getBufferChunks(renderer); - if (!chunks) { // Empty mesh - return; - } - vaoList = []; - for (var c = 0; c < chunks.length; c++) { - var chunk = chunks[c]; - var attributeBuffers = chunk.attributeBuffers; - var indicesBuffer = chunk.indicesBuffer; - - var availableAttributes = []; - var availableAttributeSymbols = []; - for (var a = 0; a < attributeBuffers.length; a++) { - var attributeBufferInfo = attributeBuffers[a]; - var name = attributeBufferInfo.name; - var semantic = attributeBufferInfo.semantic; - var symbol; - if (semantic) { - var semanticInfo = shader.attributeSemantics[semantic]; - symbol = semanticInfo && semanticInfo.symbol; - } - else { - symbol = name; - } - if (symbol && program.attributes[symbol]) { - availableAttributes.push(attributeBufferInfo); - availableAttributeSymbols.push(symbol); - } - } - - var vao = new VertexArrayObject( - availableAttributes, - availableAttributeSymbols, - indicesBuffer - ); - vaoList.push(vao); - } - if (isStatic) { - this._drawCache[currentDrawID] = vaoList; - } - } - - for (var i = 0; i < vaoList.length; i++) { - var vao = vaoList[i]; - var needsBindAttributes = true; - - // Create vertex object array cost a lot - // So we don't use it on the dynamic object - if (vaoExt && isStatic) { - // Use vertex array object - // http://blog.tojicode.com/2012/10/oesvertexarrayobject-extension.html - if (vao.vao == null) { - vao.vao = vaoExt.createVertexArrayOES(); - } - else { - needsBindAttributes = false; - } - vaoExt.bindVertexArrayOES(vao.vao); - } - - var availableAttributes = vao.availableAttributes; - var indicesBuffer = vao.indicesBuffer; - - if (needsBindAttributes) { - var locationList = program.enableAttributes(renderer, vao.availableAttributeSymbols, (vaoExt && isStatic && vao.vao)); - // Setting attributes; - for (var a = 0; a < availableAttributes.length; a++) { - var location = locationList[a]; - if (location === -1) { - continue; - } - var attributeBufferInfo = availableAttributes[a]; - var buffer = attributeBufferInfo.buffer; - var size = attributeBufferInfo.size; - var glType; - switch (attributeBufferInfo.type) { - case 'float': - glType = _gl.FLOAT; - break; - case 'byte': - glType = _gl.BYTE; - break; - case 'ubyte': - glType = _gl.UNSIGNED_BYTE; - break; - case 'short': - glType = _gl.SHORT; - break; - case 'ushort': - glType = _gl.UNSIGNED_SHORT; - break; - default: - glType = _gl.FLOAT; - break; - } - - _gl.bindBuffer(_gl.ARRAY_BUFFER, buffer); - _gl.vertexAttribPointer(location, size, glType, false, 0, 0); - } - } - if ( - glDrawMode == __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINES || - glDrawMode == __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINE_STRIP || - glDrawMode == __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINE_LOOP - ) { - _gl.lineWidth(this.lineWidth); - } - - prevDrawIndicesBuffer = indicesBuffer; - prevDrawIsUseIndices = geometry.isUseIndices(); - // Do drawing - if (prevDrawIsUseIndices) { - if (needsBindAttributes) { - _gl.bindBuffer(_gl.ELEMENT_ARRAY_BUFFER, indicesBuffer.buffer); - } - _gl.drawElements(glDrawMode, indicesBuffer.count, indicesType, 0); - renderInfo.triangleCount += indicesBuffer.count / 3; - } else { - _gl.drawArrays(glDrawMode, 0, nVertex); - } - - if (vaoExt && isStatic) { - vaoExt.bindVertexArrayOES(null); - } - - renderInfo.drawCallCount++; - } - } - - return renderInfo; - }, - - /** - * Clone a new renderable - * @function - * @return {clay.Renderable} - */ - clone: (function() { - var properties = [ - 'castShadow', 'receiveShadow', - 'mode', 'culling', 'cullFace', 'frontFace', - 'frustumCulling', - 'renderOrder', 'lineWidth', - 'ignorePicking', 'ignorePreZ', 'ignoreGBuffer' - ]; - return function() { - var renderable = __WEBPACK_IMPORTED_MODULE_0__Node__["a" /* default */].prototype.clone.call(this); - - renderable.geometry = this.geometry; - renderable.material = this.material; - - for (var i = 0; i < properties.length; i++) { - var name = properties[i]; - // Try not to overwrite the prototype property - if (renderable[name] !== this[name]) { - renderable[name] = this[name]; - } - } - - return renderable; - }; - })() -}); - -/** - * @type {number} - */ -Renderable.POINTS = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].POINTS; -/** - * @type {number} - */ -Renderable.LINES = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINES; -/** - * @type {number} - */ -Renderable.LINE_LOOP = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINE_LOOP; -/** - * @type {number} - */ -Renderable.LINE_STRIP = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINE_STRIP; -/** - * @type {number} - */ -Renderable.TRIANGLES = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].TRIANGLES; -/** - * @type {number} - */ -Renderable.TRIANGLE_STRIP = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].TRIANGLE_STRIP; -/** - * @type {number} - */ -Renderable.TRIANGLE_FAN = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].TRIANGLE_FAN; -/** - * @type {number} - */ -Renderable.BACK = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].BACK; -/** - * @type {number} - */ -Renderable.FRONT = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].FRONT; -/** - * @type {number} - */ -Renderable.FRONT_AND_BACK = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].FRONT_AND_BACK; -/** - * @type {number} - */ -Renderable.CW = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].CW; -/** - * @type {number} - */ -Renderable.CCW = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].CCW; - -Renderable.RenderInfo = RenderInfo; - -/* harmony default export */ __webpack_exports__["a"] = (Renderable); - - -/***/ }), -/* 47 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -var mathUtil = {}; - -mathUtil.isPowerOfTwo = function (value) { - return (value & (value - 1)) === 0; -}; - -mathUtil.nextPowerOfTwo = function (value) { - value --; - value |= value >> 1; - value |= value >> 2; - value |= value >> 4; - value |= value >> 8; - value |= value >> 16; - value ++; - - return value; -}; - -mathUtil.nearestPowerOfTwo = function (value) { - return Math.pow( 2, Math.round( Math.log( value ) / Math.LN2 ) ); -}; - -/* harmony default export */ __webpack_exports__["a"] = (mathUtil); - - -/***/ }), -/* 48 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); - - -/** - * @constructor clay.Joint - * @extends clay.core.Base - */ -var Joint = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend( -/** @lends clay.Joint# */ -{ - // https://github.com/KhronosGroup/glTF/issues/193#issuecomment-29216576 - /** - * Joint name - * @type {string} - */ - name: '', - /** - * Index of joint in the skeleton - * @type {number} - */ - index: -1, - - /** - * Scene node attached to - * @type {clay.Node} - */ - node: null, - - /** - * Root scene node of the skeleton, which parent node is null or don't have a joint - * @type {clay.Node} - */ - rootNode: null -}); - -/* harmony default export */ __webpack_exports__["a"] = (Joint); - - -/***/ }), -/* 49 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -// 缓动函数来自 https://github.com/sole/tween.js/blob/master/src/Tween.js - -/** - * @namespace clay.animation.easing - */ -var easing = { - /** - * @alias clay.animation.easing.linear - * @param {number} k - * @return {number} - */ - linear: function(k) { - return k; - }, - /** - * @alias clay.animation.easing.quadraticIn - * @param {number} k - * @return {number} - */ - quadraticIn: function(k) { - return k * k; - }, - /** - * @alias clay.animation.easing.quadraticOut - * @param {number} k - * @return {number} - */ - quadraticOut: function(k) { - return k * (2 - k); - }, - /** - * @alias clay.animation.easing.quadraticInOut - * @param {number} k - * @return {number} - */ - quadraticInOut: function(k) { - if ((k *= 2) < 1) { - return 0.5 * k * k; - } - return - 0.5 * (--k * (k - 2) - 1); - }, - /** - * @alias clay.animation.easing.cubicIn - * @param {number} k - * @return {number} - */ - cubicIn: function(k) { - return k * k * k; - }, - /** - * @alias clay.animation.easing.cubicOut - * @param {number} k - * @return {number} - */ - cubicOut: function(k) { - return --k * k * k + 1; - }, - /** - * @alias clay.animation.easing.cubicInOut - * @param {number} k - * @return {number} - */ - cubicInOut: function(k) { - if ((k *= 2) < 1) { - return 0.5 * k * k * k; - } - return 0.5 * ((k -= 2) * k * k + 2); - }, - /** - * @alias clay.animation.easing.quarticIn - * @param {number} k - * @return {number} - */ - quarticIn: function(k) { - return k * k * k * k; - }, - /** - * @alias clay.animation.easing.quarticOut - * @param {number} k - * @return {number} - */ - quarticOut: function(k) { - return 1 - (--k * k * k * k); - }, - /** - * @alias clay.animation.easing.quarticInOut - * @param {number} k - * @return {number} - */ - quarticInOut: function(k) { - if ((k *= 2) < 1) { - return 0.5 * k * k * k * k; - } - return - 0.5 * ((k -= 2) * k * k * k - 2); - }, - /** - * @alias clay.animation.easing.quinticIn - * @param {number} k - * @return {number} - */ - quinticIn: function(k) { - return k * k * k * k * k; - }, - /** - * @alias clay.animation.easing.quinticOut - * @param {number} k - * @return {number} - */ - quinticOut: function(k) { - return --k * k * k * k * k + 1; - }, - /** - * @alias clay.animation.easing.quinticInOut - * @param {number} k - * @return {number} - */ - quinticInOut: function(k) { - if ((k *= 2) < 1) { - return 0.5 * k * k * k * k * k; - } - return 0.5 * ((k -= 2) * k * k * k * k + 2); - }, - /** - * @alias clay.animation.easing.sinusoidalIn - * @param {number} k - * @return {number} - */ - sinusoidalIn: function(k) { - return 1 - Math.cos(k * Math.PI / 2); - }, - /** - * @alias clay.animation.easing.sinusoidalOut - * @param {number} k - * @return {number} - */ - sinusoidalOut: function(k) { - return Math.sin(k * Math.PI / 2); - }, - /** - * @alias clay.animation.easing.sinusoidalInOut - * @param {number} k - * @return {number} - */ - sinusoidalInOut: function(k) { - return 0.5 * (1 - Math.cos(Math.PI * k)); - }, - /** - * @alias clay.animation.easing.exponentialIn - * @param {number} k - * @return {number} - */ - exponentialIn: function(k) { - return k === 0 ? 0 : Math.pow(1024, k - 1); - }, - /** - * @alias clay.animation.easing.exponentialOut - * @param {number} k - * @return {number} - */ - exponentialOut: function(k) { - return k === 1 ? 1 : 1 - Math.pow(2, - 10 * k); - }, - /** - * @alias clay.animation.easing.exponentialInOut - * @param {number} k - * @return {number} - */ - exponentialInOut: function(k) { - if (k === 0) { - return 0; - } - if (k === 1) { - return 1; - } - if ((k *= 2) < 1) { - return 0.5 * Math.pow(1024, k - 1); - } - return 0.5 * (- Math.pow(2, - 10 * (k - 1)) + 2); - }, - /** - * @alias clay.animation.easing.circularIn - * @param {number} k - * @return {number} - */ - circularIn: function(k) { - return 1 - Math.sqrt(1 - k * k); - }, - /** - * @alias clay.animation.easing.circularOut - * @param {number} k - * @return {number} - */ - circularOut: function(k) { - return Math.sqrt(1 - (--k * k)); - }, - /** - * @alias clay.animation.easing.circularInOut - * @param {number} k - * @return {number} - */ - circularInOut: function(k) { - if ((k *= 2) < 1) { - return - 0.5 * (Math.sqrt(1 - k * k) - 1); - } - return 0.5 * (Math.sqrt(1 - (k -= 2) * k) + 1); - }, - /** - * @alias clay.animation.easing.elasticIn - * @param {number} k - * @return {number} - */ - elasticIn: function(k) { - var s, a = 0.1, p = 0.4; - if (k === 0) { - return 0; - } - if (k === 1) { - return 1; - } - if (!a || a < 1) { - a = 1; s = p / 4; - }else{ - s = p * Math.asin(1 / a) / (2 * Math.PI); - } - return - (a * Math.pow(2, 10 * (k -= 1)) * - Math.sin((k - s) * (2 * Math.PI) / p)); - }, - /** - * @alias clay.animation.easing.elasticOut - * @param {number} k - * @return {number} - */ - elasticOut: function(k) { - var s, a = 0.1, p = 0.4; - if (k === 0) { - return 0; - } - if (k === 1) { - return 1; - } - if (!a || a < 1) { - a = 1; s = p / 4; - } - else{ - s = p * Math.asin(1 / a) / (2 * Math.PI); - } - return (a * Math.pow(2, - 10 * k) * - Math.sin((k - s) * (2 * Math.PI) / p) + 1); - }, - /** - * @alias clay.animation.easing.elasticInOut - * @param {number} k - * @return {number} - */ - elasticInOut: function(k) { - var s, a = 0.1, p = 0.4; - if (k === 0) { - return 0; - } - if (k === 1) { - return 1; - } - if (!a || a < 1) { - a = 1; s = p / 4; - } - else{ - s = p * Math.asin(1 / a) / (2 * Math.PI); - } - if ((k *= 2) < 1) { - return - 0.5 * (a * Math.pow(2, 10 * (k -= 1)) - * Math.sin((k - s) * (2 * Math.PI) / p)); - } - return a * Math.pow(2, -10 * (k -= 1)) - * Math.sin((k - s) * (2 * Math.PI) / p) * 0.5 + 1; - - }, - /** - * @alias clay.animation.easing.backIn - * @param {number} k - * @return {number} - */ - backIn: function(k) { - var s = 1.70158; - return k * k * ((s + 1) * k - s); - }, - /** - * @alias clay.animation.easing.backOut - * @param {number} k - * @return {number} - */ - backOut: function(k) { - var s = 1.70158; - return --k * k * ((s + 1) * k + s) + 1; - }, - /** - * @alias clay.animation.easing.backInOut - * @param {number} k - * @return {number} - */ - backInOut: function(k) { - var s = 1.70158 * 1.525; - if ((k *= 2) < 1) { - return 0.5 * (k * k * ((s + 1) * k - s)); - } - return 0.5 * ((k -= 2) * k * ((s + 1) * k + s) + 2); - }, - /** - * @alias clay.animation.easing.bounceIn - * @param {number} k - * @return {number} - */ - bounceIn: function(k) { - return 1 - easing.bounceOut(1 - k); - }, - /** - * @alias clay.animation.easing.bounceOut - * @param {number} k - * @return {number} - */ - bounceOut: function(k) { - if (k < (1 / 2.75)) { - return 7.5625 * k * k; - } - else if (k < (2 / 2.75)) { - return 7.5625 * (k -= (1.5 / 2.75)) * k + 0.75; - } else if (k < (2.5 / 2.75)) { - return 7.5625 * (k -= (2.25 / 2.75)) * k + 0.9375; - } else { - return 7.5625 * (k -= (2.625 / 2.75)) * k + 0.984375; - } - }, - /** - * @alias clay.animation.easing.bounceInOut - * @param {number} k - * @return {number} - */ - bounceInOut: function(k) { - if (k < 0.5) { - return easing.bounceIn(k * 2) * 0.5; - } - return easing.bounceOut(k * 2 - 1) * 0.5 + 0.5; - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (easing); - - -/***/ }), -/* 50 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.basic.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec2 texcoord : TEXCOORD_0;\nattribute vec3 position : POSITION;\nattribute vec3 barycentric;\n@import clay.chunk.skinning_header\nvarying vec2 v_Texcoord;\nvarying vec3 v_Barycentric;\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n#endif\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_Barycentric = barycentric;\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n}\n@end\n@export clay.basic.fragment\nvarying vec2 v_Texcoord;\nuniform sampler2D diffuseMap;\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\nvarying vec3 v_Barycentric;\n@import clay.util.edge_factor\n@import clay.util.rgbm\n@import clay.util.srgb\n@import clay.util.ACES\nvoid main()\n{\n#ifdef RENDER_TEXCOORD\n gl_FragColor = vec4(v_Texcoord, 1.0, 1.0);\n return;\n#endif\n gl_FragColor = vec4(color, alpha);\n#ifdef VERTEX_COLOR\n gl_FragColor *= v_Color;\n#endif\n#ifdef DIFFUSEMAP_ENABLED\n vec4 tex = decodeHDR(texture2D(diffuseMap, v_Texcoord));\n#ifdef SRGB_DECODE\n tex = sRGBToLinear(tex);\n#endif\n#if defined(DIFFUSEMAP_ALPHA_ALPHA)\n gl_FragColor.a = tex.a;\n#endif\n gl_FragColor.rgb *= tex.rgb;\n#endif\n gl_FragColor.rgb += emission;\n if( lineWidth > 0.)\n {\n gl_FragColor.rgb = mix(gl_FragColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (gl_FragColor.a < alphaCutoff) {\n discard;\n }\n#endif\n#ifdef TONEMAPPING\n gl_FragColor.rgb = ACESToneMapping(gl_FragColor.rgb);\n#endif\n#ifdef SRGB_ENCODE\n gl_FragColor = linearTosRGB(gl_FragColor);\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n}\n@end"); - - -/***/ }), -/* 51 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.skybox.vertex\nuniform mat4 world : WORLD;\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\nvarying vec3 v_WorldPosition;\nvoid main()\n{\n v_WorldPosition = (world * vec4(position, 1.0)).xyz;\n gl_Position = worldViewProjection * vec4(position, 1.0);\n}\n@end\n@export clay.skybox.fragment\nuniform mat4 viewInverse : VIEWINVERSE;\nuniform samplerCube environmentMap;\nuniform float lod: 0.0;\nvarying vec3 v_WorldPosition;\n@import clay.util.rgbm\n@import clay.util.srgb\n@import clay.util.ACES\nvoid main()\n{\n vec3 eyePos = viewInverse[3].xyz;\n vec3 viewDirection = normalize(v_WorldPosition - eyePos);\n#ifdef LOD\n vec4 texel = decodeHDR(textureCubeLodEXT(environmentMap, viewDirection, lod));\n#else\n vec4 texel = decodeHDR(textureCube(environmentMap, viewDirection));\n#endif\n#ifdef SRGB_DECODE\n texel = sRGBToLinear(texel);\n#endif\n#ifdef TONEMAPPING\n texel.rgb = ACESToneMapping(texel.rgb);\n#endif\n#ifdef SRGB_ENCODE\n texel = linearTosRGB(texel);\n#endif\n gl_FragColor = encodeHDR(vec4(texel.rgb, 1.0));\n}\n@end"); - - -/***/ }), -/* 52 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.compositor.kernel.gaussian_9\nfloat gaussianKernel[9];\ngaussianKernel[0] = 0.07;\ngaussianKernel[1] = 0.09;\ngaussianKernel[2] = 0.12;\ngaussianKernel[3] = 0.14;\ngaussianKernel[4] = 0.16;\ngaussianKernel[5] = 0.14;\ngaussianKernel[6] = 0.12;\ngaussianKernel[7] = 0.09;\ngaussianKernel[8] = 0.07;\n@end\n@export clay.compositor.kernel.gaussian_13\nfloat gaussianKernel[13];\ngaussianKernel[0] = 0.02;\ngaussianKernel[1] = 0.03;\ngaussianKernel[2] = 0.06;\ngaussianKernel[3] = 0.08;\ngaussianKernel[4] = 0.11;\ngaussianKernel[5] = 0.13;\ngaussianKernel[6] = 0.14;\ngaussianKernel[7] = 0.13;\ngaussianKernel[8] = 0.11;\ngaussianKernel[9] = 0.08;\ngaussianKernel[10] = 0.06;\ngaussianKernel[11] = 0.03;\ngaussianKernel[12] = 0.02;\n@end\n@export clay.compositor.gaussian_blur\n#define SHADER_NAME gaussian_blur\nuniform sampler2D texture;varying vec2 v_Texcoord;\nuniform float blurSize : 2.0;\nuniform vec2 textureSize : [512.0, 512.0];\nuniform float blurDir : 0.0;\n@import clay.util.rgbm\n@import clay.util.clamp_sample\nvoid main (void)\n{\n @import clay.compositor.kernel.gaussian_9\n vec2 off = blurSize / textureSize;\n off *= vec2(1.0 - blurDir, blurDir);\n vec4 sum = vec4(0.0);\n float weightAll = 0.0;\n for (int i = 0; i < 9; i++) {\n float w = gaussianKernel[i];\n vec4 texel = decodeHDR(clampSample(texture, v_Texcoord + float(i - 4) * off));\n sum += texel * w;\n weightAll += w;\n }\n gl_FragColor = encodeHDR(sum / max(weightAll, 0.01));\n}\n@end\n"); - - -/***/ }), -/* 53 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.compositor.output\n#define OUTPUT_ALPHA\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\n@import clay.util.rgbm\nvoid main()\n{\n vec4 tex = decodeHDR(texture2D(texture, v_Texcoord));\n gl_FragColor.rgb = tex.rgb;\n#ifdef OUTPUT_ALPHA\n gl_FragColor.a = tex.a;\n#else\n gl_FragColor.a = 1.0;\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n#ifdef PREMULTIPLY_ALPHA\n gl_FragColor.rgb *= gl_FragColor.a;\n#endif\n}\n@end"); - - -/***/ }), -/* 54 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.compositor.bright\nuniform sampler2D texture;\nuniform float threshold : 1;\nuniform float scale : 1.0;\nuniform vec2 textureSize: [512, 512];\nvarying vec2 v_Texcoord;\nconst vec3 lumWeight = vec3(0.2125, 0.7154, 0.0721);\n@import clay.util.rgbm\nvec4 median(vec4 a, vec4 b, vec4 c)\n{\n return a + b + c - min(min(a, b), c) - max(max(a, b), c);\n}\nvoid main()\n{\n vec4 texel = decodeHDR(texture2D(texture, v_Texcoord));\n#ifdef ANTI_FLICKER\n vec3 d = 1.0 / textureSize.xyx * vec3(1.0, 1.0, 0.0);\n vec4 s1 = decodeHDR(texture2D(texture, v_Texcoord - d.xz));\n vec4 s2 = decodeHDR(texture2D(texture, v_Texcoord + d.xz));\n vec4 s3 = decodeHDR(texture2D(texture, v_Texcoord - d.zy));\n vec4 s4 = decodeHDR(texture2D(texture, v_Texcoord + d.zy));\n texel = median(median(texel, s1, s2), s3, s4);\n#endif\n float lum = dot(texel.rgb , lumWeight);\n vec4 color;\n if (lum > threshold && texel.a > 0.0)\n {\n color = vec4(texel.rgb * scale, texel.a * scale);\n }\n else\n {\n color = vec4(0.0);\n }\n gl_FragColor = encodeHDR(color);\n}\n@end\n"); - - -/***/ }), -/* 55 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.compositor.downsample\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\nfloat brightness(vec3 c)\n{\n return max(max(c.r, c.g), c.b);\n}\n@import clay.util.clamp_sample\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n#ifdef ANTI_FLICKER\n vec3 s1 = decodeHDR(clampSample(texture, v_Texcoord + d.xy)).rgb;\n vec3 s2 = decodeHDR(clampSample(texture, v_Texcoord + d.zy)).rgb;\n vec3 s3 = decodeHDR(clampSample(texture, v_Texcoord + d.xw)).rgb;\n vec3 s4 = decodeHDR(clampSample(texture, v_Texcoord + d.zw)).rgb;\n float s1w = 1.0 / (brightness(s1) + 1.0);\n float s2w = 1.0 / (brightness(s2) + 1.0);\n float s3w = 1.0 / (brightness(s3) + 1.0);\n float s4w = 1.0 / (brightness(s4) + 1.0);\n float oneDivideSum = 1.0 / (s1w + s2w + s3w + s4w);\n vec4 color = vec4(\n (s1 * s1w + s2 * s2w + s3 * s3w + s4 * s4w) * oneDivideSum,\n 1.0\n );\n#else\n vec4 color = decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.xw));\n color += decodeHDR(clampSample(texture, v_Texcoord + d.zw));\n color *= 0.25;\n#endif\n gl_FragColor = encodeHDR(color);\n}\n@end"); - - -/***/ }), -/* 56 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("\n@export clay.compositor.upsample\n#define HIGH_QUALITY\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.clamp_sample\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n vec4 s;\n s = decodeHDR(clampSample(texture, v_Texcoord - d.xy));\n s += decodeHDR(clampSample(texture, v_Texcoord - d.wy)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord - d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zw)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord )) * 4.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xw)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.wy)) * 2.0;\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n gl_FragColor = encodeHDR(s / 16.0);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n vec4 s;\n s = decodeHDR(clampSample(texture, v_Texcoord + d.xy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zy));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.xw));\n s += decodeHDR(clampSample(texture, v_Texcoord + d.zw));\n gl_FragColor = encodeHDR(s / 4.0);\n#endif\n}\n@end"); - - -/***/ }), -/* 57 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.compositor.hdr.composite\nuniform sampler2D texture;\n#ifdef BLOOM_ENABLED\nuniform sampler2D bloom;\n#endif\n#ifdef LENSFLARE_ENABLED\nuniform sampler2D lensflare;\nuniform sampler2D lensdirt;\n#endif\n#ifdef LUM_ENABLED\nuniform sampler2D lum;\n#endif\n#ifdef LUT_ENABLED\nuniform sampler2D lut;\n#endif\n#ifdef COLOR_CORRECTION\nuniform float brightness : 0.0;\nuniform float contrast : 1.0;\nuniform float saturation : 1.0;\n#endif\n#ifdef VIGNETTE\nuniform float vignetteDarkness: 1.0;\nuniform float vignetteOffset: 1.0;\n#endif\nuniform float exposure : 1.0;\nuniform float bloomIntensity : 0.25;\nuniform float lensflareIntensity : 1;\nvarying vec2 v_Texcoord;\n@import clay.util.srgb\nvec3 ACESToneMapping(vec3 color)\n{\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\nfloat eyeAdaption(float fLum)\n{\n return mix(0.2, fLum, 0.5);\n}\n#ifdef LUT_ENABLED\nvec3 lutTransform(vec3 color) {\n float blueColor = color.b * 63.0;\n vec2 quad1;\n quad1.y = floor(floor(blueColor) / 8.0);\n quad1.x = floor(blueColor) - (quad1.y * 8.0);\n vec2 quad2;\n quad2.y = floor(ceil(blueColor) / 8.0);\n quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n vec2 texPos1;\n texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.r);\n texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.g);\n vec2 texPos2;\n texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.r);\n texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * color.g);\n vec4 newColor1 = texture2D(lut, texPos1);\n vec4 newColor2 = texture2D(lut, texPos2);\n vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n return newColor.rgb;\n}\n#endif\n@import clay.util.rgbm\nvoid main()\n{\n vec4 texel = vec4(0.0);\n vec4 originalTexel = vec4(0.0);\n#ifdef TEXTURE_ENABLED\n texel = decodeHDR(texture2D(texture, v_Texcoord));\n originalTexel = texel;\n#endif\n#ifdef BLOOM_ENABLED\n vec4 bloomTexel = decodeHDR(texture2D(bloom, v_Texcoord));\n texel.rgb += bloomTexel.rgb * bloomIntensity;\n texel.a += bloomTexel.a * bloomIntensity;\n#endif\n#ifdef LENSFLARE_ENABLED\n texel += decodeHDR(texture2D(lensflare, v_Texcoord)) * texture2D(lensdirt, v_Texcoord) * lensflareIntensity;\n#endif\n texel.a = min(texel.a, 1.0);\n#ifdef LUM_ENABLED\n float fLum = texture2D(lum, vec2(0.5, 0.5)).r;\n float adaptedLumDest = 3.0 / (max(0.1, 1.0 + 10.0*eyeAdaption(fLum)));\n float exposureBias = adaptedLumDest * exposure;\n#else\n float exposureBias = exposure;\n#endif\n texel.rgb *= exposureBias;\n texel.rgb = ACESToneMapping(texel.rgb);\n texel = linearTosRGB(texel);\n#ifdef LUT_ENABLED\n texel.rgb = lutTransform(clamp(texel.rgb,vec3(0.0),vec3(1.0)));\n#endif\n#ifdef COLOR_CORRECTION\n texel.rgb = clamp(texel.rgb + vec3(brightness), 0.0, 1.0);\n texel.rgb = clamp((texel.rgb - vec3(0.5))*contrast+vec3(0.5), 0.0, 1.0);\n float lum = dot(texel.rgb, vec3(0.2125, 0.7154, 0.0721));\n texel.rgb = mix(vec3(lum), texel.rgb, saturation);\n#endif\n#ifdef VIGNETTE\n vec2 uv = (v_Texcoord - vec2(0.5)) * vec2(vignetteOffset);\n texel.rgb = mix(texel.rgb, vec3(1.0 - vignetteDarkness), dot(uv, uv));\n#endif\n gl_FragColor = encodeHDR(texel);\n#ifdef DEBUG\n #if DEBUG == 1\n gl_FragColor = encodeHDR(decodeHDR(texture2D(texture, v_Texcoord)));\n #elif DEBUG == 2\n gl_FragColor = encodeHDR(decodeHDR(texture2D(bloom, v_Texcoord)) * bloomIntensity);\n #elif DEBUG == 3\n gl_FragColor = encodeHDR(decodeHDR(texture2D(lensflare, v_Texcoord) * lensflareIntensity));\n #endif\n#endif\n if (originalTexel.a <= 0.01 && gl_FragColor.a > 1e-5) {\n gl_FragColor.a = dot(gl_FragColor.rgb, vec3(0.2125, 0.7154, 0.0721));\n }\n#ifdef PREMULTIPLY_ALPHA\n gl_FragColor.rgb *= gl_FragColor.a;\n#endif\n}\n@end"); - - -/***/ }), -/* 58 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.compositor.blend\n#define SHADER_NAME blend\n#ifdef TEXTURE1_ENABLED\nuniform sampler2D texture1;\nuniform float weight1 : 1.0;\n#endif\n#ifdef TEXTURE2_ENABLED\nuniform sampler2D texture2;\nuniform float weight2 : 1.0;\n#endif\n#ifdef TEXTURE3_ENABLED\nuniform sampler2D texture3;\nuniform float weight3 : 1.0;\n#endif\n#ifdef TEXTURE4_ENABLED\nuniform sampler2D texture4;\nuniform float weight4 : 1.0;\n#endif\n#ifdef TEXTURE5_ENABLED\nuniform sampler2D texture5;\nuniform float weight5 : 1.0;\n#endif\n#ifdef TEXTURE6_ENABLED\nuniform sampler2D texture6;\nuniform float weight6 : 1.0;\n#endif\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\nvoid main()\n{\n vec4 tex = vec4(0.0);\n#ifdef TEXTURE1_ENABLED\n tex += decodeHDR(texture2D(texture1, v_Texcoord)) * weight1;\n#endif\n#ifdef TEXTURE2_ENABLED\n tex += decodeHDR(texture2D(texture2, v_Texcoord)) * weight2;\n#endif\n#ifdef TEXTURE3_ENABLED\n tex += decodeHDR(texture2D(texture3, v_Texcoord)) * weight3;\n#endif\n#ifdef TEXTURE4_ENABLED\n tex += decodeHDR(texture2D(texture4, v_Texcoord)) * weight4;\n#endif\n#ifdef TEXTURE5_ENABLED\n tex += decodeHDR(texture2D(texture5, v_Texcoord)) * weight5;\n#endif\n#ifdef TEXTURE6_ENABLED\n tex += decodeHDR(texture2D(texture6, v_Texcoord)) * weight6;\n#endif\n gl_FragColor = encodeHDR(tex);\n}\n@end"); - - -/***/ }), -/* 59 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.compositor.fxaa\nuniform sampler2D texture;\nuniform vec4 viewport : VIEWPORT;\nvarying vec2 v_Texcoord;\n#define FXAA_REDUCE_MIN (1.0/128.0)\n#define FXAA_REDUCE_MUL (1.0/8.0)\n#define FXAA_SPAN_MAX 8.0\n@import clay.util.rgbm\nvoid main()\n{\n vec2 resolution = 1.0 / viewport.zw;\n vec3 rgbNW = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( -1.0, -1.0 ) ) * resolution ) ).xyz;\n vec3 rgbNE = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( 1.0, -1.0 ) ) * resolution ) ).xyz;\n vec3 rgbSW = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( -1.0, 1.0 ) ) * resolution ) ).xyz;\n vec3 rgbSE = decodeHDR( texture2D( texture, ( gl_FragCoord.xy + vec2( 1.0, 1.0 ) ) * resolution ) ).xyz;\n vec4 rgbaM = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution ) );\n vec3 rgbM = rgbaM.xyz;\n float opacity = rgbaM.w;\n vec3 luma = vec3( 0.299, 0.587, 0.114 );\n float lumaNW = dot( rgbNW, luma );\n float lumaNE = dot( rgbNE, luma );\n float lumaSW = dot( rgbSW, luma );\n float lumaSE = dot( rgbSE, luma );\n float lumaM = dot( rgbM, luma );\n float lumaMin = min( lumaM, min( min( lumaNW, lumaNE ), min( lumaSW, lumaSE ) ) );\n float lumaMax = max( lumaM, max( max( lumaNW, lumaNE) , max( lumaSW, lumaSE ) ) );\n vec2 dir;\n dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));\n dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));\n float dirReduce = max( ( lumaNW + lumaNE + lumaSW + lumaSE ) * ( 0.25 * FXAA_REDUCE_MUL ), FXAA_REDUCE_MIN );\n float rcpDirMin = 1.0 / ( min( abs( dir.x ), abs( dir.y ) ) + dirReduce );\n dir = min( vec2( FXAA_SPAN_MAX, FXAA_SPAN_MAX),\n max( vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),\n dir * rcpDirMin)) * resolution;\n vec3 rgbA = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * ( 1.0 / 3.0 - 0.5 ) ) ).xyz;\n rgbA += decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * ( 2.0 / 3.0 - 0.5 ) ) ).xyz;\n rgbA *= 0.5;\n vec3 rgbB = decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * -0.5 ) ).xyz;\n rgbB += decodeHDR( texture2D( texture, gl_FragCoord.xy * resolution + dir * 0.5 ) ).xyz;\n rgbB *= 0.25;\n rgbB += rgbA * 0.5;\n float lumaB = dot( rgbB, luma );\n if ( ( lumaB < lumaMin ) || ( lumaB > lumaMax ) )\n {\n gl_FragColor = vec4( rgbA, opacity );\n }\n else {\n gl_FragColor = vec4( rgbB, opacity );\n }\n}\n@end"); - - -/***/ }), -/* 60 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_mixin_notifier__ = __webpack_require__(20); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_request__ = __webpack_require__(29); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__core_util__ = __webpack_require__(7); - - - - -/** - * @constructor - * @alias clay.async.Task - * @mixes clay.core.mixin.notifier - */ -var Task = function() { - this._fullfilled = false; - this._rejected = false; -}; -/** - * Task successed - * @param {} data - */ -Task.prototype.resolve = function(data) { - this._fullfilled = true; - this._rejected = false; - this.trigger('success', data); -}; -/** - * Task failed - * @param {} err - */ -Task.prototype.reject = function(err) { - this._rejected = true; - this._fullfilled = false; - this.trigger('error', err); -}; -/** - * If task successed - * @return {boolean} - */ -Task.prototype.isFullfilled = function() { - return this._fullfilled; -}; -/** - * If task failed - * @return {boolean} - */ -Task.prototype.isRejected = function() { - return this._rejected; -}; -/** - * If task finished, either successed or failed - * @return {boolean} - */ -Task.prototype.isSettled = function() { - return this._fullfilled || this._rejected; -}; - -__WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].extend(Task.prototype, __WEBPACK_IMPORTED_MODULE_0__core_mixin_notifier__["a" /* default */]); - -function makeRequestTask(url, responseType) { - var task = new Task(); - __WEBPACK_IMPORTED_MODULE_1__core_request__["a" /* default */].get({ - url: url, - responseType: responseType, - onload: function(res) { - task.resolve(res); - }, - onerror: function(error) { - task.reject(error); - } - }); - return task; -} -/** - * Make a request task - * @param {string|object|object[]|string[]} url - * @param {string} [responseType] - * @example - * var task = Task.makeRequestTask('./a.json'); - * var task = Task.makeRequestTask({ - * url: 'b.bin', - * responseType: 'arraybuffer' - * }); - * var tasks = Task.makeRequestTask(['./a.json', './b.json']); - * var tasks = Task.makeRequestTask([ - * {url: 'a.json'}, - * {url: 'b.bin', responseType: 'arraybuffer'} - * ]); - * @return {clay.async.Task|clay.async.Task[]} - */ -Task.makeRequestTask = function(url, responseType) { - if (typeof url === 'string') { - return makeRequestTask(url, responseType); - } else if (url.url) { // Configure object - var obj = url; - return makeRequestTask(obj.url, obj.responseType); - } else if (Array.isArray(url)) { // Url list - var urlList = url; - var tasks = []; - urlList.forEach(function(obj) { - var url, responseType; - if (typeof obj === 'string') { - url = obj; - } else if (Object(obj) === obj) { - url = obj.url; - responseType = obj.responseType; - } - tasks.push(makeRequestTask(url, responseType)); - }); - return tasks; - } -}; -/** - * @return {clay.async.Task} - */ -Task.makeTask = function() { - return new Task(); -}; - -__WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].extend(Task.prototype, __WEBPACK_IMPORTED_MODULE_0__core_mixin_notifier__["a" /* default */]); - -/* harmony default export */ __webpack_exports__["a"] = (Task); - - -/***/ }), -/* 61 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Light__ = __webpack_require__(14); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__math_Vector3__ = __webpack_require__(2); - - - -/** - * @constructor clay.light.Directional - * @extends clay.Light - * - * @example - * var light = new clay.light.Directional({ - * intensity: 0.5, - * color: [1.0, 0.0, 0.0] - * }); - * light.position.set(10, 10, 10); - * light.lookAt(clay.math.Vector3.ZERO); - * scene.add(light); - */ -var DirectionalLight = __WEBPACK_IMPORTED_MODULE_0__Light__["a" /* default */].extend( -/** @lends clay.light.Directional# */ -{ - /** - * @type {number} - */ - shadowBias: 0.001, - /** - * @type {number} - */ - shadowSlopeScale: 2.0, - /** - * Shadow cascade. - * Use PSSM technique when it is larger than 1 and have a unique directional light in scene. - * @type {number} - */ - shadowCascade: 1, - - /** - * Available when shadowCascade is larger than 1 and have a unique directional light in scene. - * @type {number} - */ - cascadeSplitLogFactor: 0.2 -}, { - - type: 'DIRECTIONAL_LIGHT', - - uniformTemplates: { - directionalLightDirection: { - type: '3f', - value: function (instance) { - instance.__dir = instance.__dir || new __WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */](); - // Direction is target to eye - return instance.__dir.copy(instance.worldTransform.z).normalize().negate().array; - } - }, - directionalLightColor: { - type: '3f', - value: function (instance) { - var color = instance.color; - var intensity = instance.intensity; - return [color[0] * intensity, color[1] * intensity, color[2] * intensity]; - } - } - }, - /** - * @return {clay.light.Directional} - * @memberOf clay.light.Directional.prototype - */ - clone: function () { - var light = __WEBPACK_IMPORTED_MODULE_0__Light__["a" /* default */].prototype.clone.call(this); - light.shadowBias = this.shadowBias; - light.shadowSlopeScale = this.shadowSlopeScale; - return light; - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (DirectionalLight); - - -/***/ }), -/* 62 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Texture2D__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_glenum__ = __webpack_require__(6); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__core_util__ = __webpack_require__(7); - - - - -var TexturePool = function () { - - this._pool = {}; - - this._allocatedTextures = []; -}; - -TexturePool.prototype = { - - constructor: TexturePool, - - get: function (parameters) { - var key = generateKey(parameters); - if (!this._pool.hasOwnProperty(key)) { - this._pool[key] = []; - } - var list = this._pool[key]; - if (!list.length) { - var texture = new __WEBPACK_IMPORTED_MODULE_0__Texture2D__["a" /* default */](parameters); - this._allocatedTextures.push(texture); - return texture; - } - return list.pop(); - }, - - put: function (texture) { - var key = generateKey(texture); - if (!this._pool.hasOwnProperty(key)) { - this._pool[key] = []; - } - var list = this._pool[key]; - list.push(texture); - }, - - clear: function (renderer) { - for (var i = 0; i < this._allocatedTextures.length; i++) { - this._allocatedTextures[i].dispose(renderer); - } - this._pool = {}; - this._allocatedTextures = []; - } -}; - -var defaultParams = { - width: 512, - height: 512, - type: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].UNSIGNED_BYTE, - format: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].RGBA, - wrapS: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].CLAMP_TO_EDGE, - wrapT: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].CLAMP_TO_EDGE, - minFilter: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINEAR_MIPMAP_LINEAR, - magFilter: __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINEAR, - useMipmap: true, - anisotropic: 1, - flipY: true, - unpackAlignment: 4, - premultiplyAlpha: false -}; - -var defaultParamPropList = Object.keys(defaultParams); - -function generateKey(parameters) { - __WEBPACK_IMPORTED_MODULE_2__core_util__["a" /* default */].defaultsWithPropList(parameters, defaultParams, defaultParamPropList); - fallBack(parameters); - - var key = ''; - for (var i = 0; i < defaultParamPropList.length; i++) { - var name = defaultParamPropList[i]; - var chunk = parameters[name].toString(); - key += chunk; - } - return key; -} - -function fallBack(target) { - - var IPOT = isPowerOfTwo(target.width, target.height); - - if (target.format === __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].DEPTH_COMPONENT) { - target.useMipmap = false; - } - - if (!IPOT || !target.useMipmap) { - if (target.minFilter == __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].NEAREST_MIPMAP_NEAREST || - target.minFilter == __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].NEAREST_MIPMAP_LINEAR) { - target.minFilter = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].NEAREST; - } else if ( - target.minFilter == __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINEAR_MIPMAP_LINEAR || - target.minFilter == __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINEAR_MIPMAP_NEAREST - ) { - target.minFilter = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].LINEAR; - } - } - if (!IPOT) { - target.wrapS = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].CLAMP_TO_EDGE; - target.wrapT = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].CLAMP_TO_EDGE; - } -} - -function isPowerOfTwo(width, height) { - return (width & (width-1)) === 0 && - (height & (height-1)) === 0; -} - -/* harmony default export */ __webpack_exports__["a"] = (TexturePool); - - -/***/ }), -/* 63 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Texture2D__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__TextureCube__ = __webpack_require__(17); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__FrameBuffer__ = __webpack_require__(11); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__compositor_Pass__ = __webpack_require__(13); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__Material__ = __webpack_require__(10); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__plugin_Skybox__ = __webpack_require__(37); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__Scene__ = __webpack_require__(18); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__prePass_EnvironmentMap__ = __webpack_require__(35); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__core_vendor__ = __webpack_require__(12); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_11__texture__ = __webpack_require__(34); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_12__shader_integrateBRDF_glsl_js__ = __webpack_require__(120); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_13__shader_prefilter_glsl_js__ = __webpack_require__(121); -// Cubemap prefilter utility -// http://www.unrealengine.com/files/downloads/2013SiggraphPresentationsNotes.pdf -// http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html - - - - - - - - - - - - - - - - -var cubemapUtil = {}; - -var targets = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; - -/** - * @name clay.util.cubemap.prefilterEnvironmentMap - * @param {clay.Renderer} renderer - * @param {clay.Texture} envMap - * @param {Object} [textureOpts] - * @param {number} [textureOpts.width=64] - * @param {number} [textureOpts.height=64] - * @param {number} [textureOpts.type] - * @param {boolean} [textureOpts.encodeRGBM=false] - * @param {boolean} [textureOpts.decodeRGBM=false] - * @param {clay.Texture2D} [normalDistribution] - * @param {clay.Texture2D} [brdfLookup] - */ -cubemapUtil.prefilterEnvironmentMap = function ( - renderer, envMap, textureOpts, normalDistribution, brdfLookup -) { - // Not create other renderer, it is easy having issue of cross reference of resources like framebuffer - // PENDING preserveDrawingBuffer? - if (!brdfLookup || !normalDistribution) { - normalDistribution = cubemapUtil.generateNormalDistribution(); - brdfLookup = cubemapUtil.integrateBRDF(renderer, normalDistribution); - } - textureOpts = textureOpts || {}; - - var width = textureOpts.width || 64; - var height = textureOpts.height || 64; - - var textureType = textureOpts.type || envMap.type; - - // Use same type with given envMap - var prefilteredCubeMap = new __WEBPACK_IMPORTED_MODULE_1__TextureCube__["a" /* default */]({ - width: width, - height: height, - type: textureType, - flipY: false, - mipmaps: [] - }); - - if (!prefilteredCubeMap.isPowerOfTwo()) { - console.warn('Width and height must be power of two to enable mipmap.'); - } - - var size = Math.min(width, height); - var mipmapNum = Math.log(size) / Math.log(2) + 1; - - var prefilterMaterial = new __WEBPACK_IMPORTED_MODULE_5__Material__["a" /* default */]({ - shader: new __WEBPACK_IMPORTED_MODULE_6__Shader__["a" /* default */]({ - vertex: __WEBPACK_IMPORTED_MODULE_6__Shader__["a" /* default */].source('clay.skybox.vertex'), - fragment: __WEBPACK_IMPORTED_MODULE_13__shader_prefilter_glsl_js__["a" /* default */] - }) - }); - prefilterMaterial.set('normalDistribution', normalDistribution); - - textureOpts.encodeRGBM && prefilterMaterial.define('fragment', 'RGBM_ENCODE'); - textureOpts.decodeRGBM && prefilterMaterial.define('fragment', 'RGBM_DECODE'); - - var dummyScene = new __WEBPACK_IMPORTED_MODULE_8__Scene__["a" /* default */](); - var skyEnv; - - if (envMap instanceof __WEBPACK_IMPORTED_MODULE_0__Texture2D__["a" /* default */]) { - // Convert panorama to cubemap - var envCubemap = new __WEBPACK_IMPORTED_MODULE_1__TextureCube__["a" /* default */]({ - width: width, - height: height, - // FIXME FLOAT type will cause GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT error on iOS - type: textureType === __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].FLOAT ? - __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].HALF_FLOAT : textureType - }); - __WEBPACK_IMPORTED_MODULE_11__texture__["a" /* default */].panoramaToCubeMap(renderer, envMap, envCubemap, { - // PENDING encodeRGBM so it can be decoded as RGBM - encodeRGBM: textureOpts.decodeRGBM - }); - envMap = envCubemap; - } - skyEnv = new __WEBPACK_IMPORTED_MODULE_7__plugin_Skybox__["a" /* default */]({ - scene: dummyScene, - material: prefilterMaterial - }); - skyEnv.material.set('environmentMap', envMap); - - var envMapPass = new __WEBPACK_IMPORTED_MODULE_9__prePass_EnvironmentMap__["a" /* default */]({ - texture: prefilteredCubeMap - }); - - // Force to be UNSIGNED_BYTE - if (textureOpts.encodeRGBM) { - textureType = prefilteredCubeMap.type = __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].UNSIGNED_BYTE; - } - - var renderTargetTmp = new __WEBPACK_IMPORTED_MODULE_0__Texture2D__["a" /* default */]({ - width: width, - height: height, - type: textureType - }); - var frameBuffer = new __WEBPACK_IMPORTED_MODULE_3__FrameBuffer__["a" /* default */]({ - depthBuffer: false - }); - var ArrayCtor = __WEBPACK_IMPORTED_MODULE_10__core_vendor__["a" /* default */][textureType === __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].UNSIGNED_BYTE ? 'Uint8Array' : 'Float32Array']; - for (var i = 0; i < mipmapNum; i++) { - prefilteredCubeMap.mipmaps[i] = { - pixels: {} - }; - skyEnv.material.set('roughness', i / (targets.length - 1)); - - // Tweak fov - // http://the-witness.net/news/2012/02/seamless-cube-map-filtering/ - var n = renderTargetTmp.width; - var fov = 2 * Math.atan(n / (n - 0.5)) / Math.PI * 180; - - for (var j = 0; j < targets.length; j++) { - var pixels = new ArrayCtor(renderTargetTmp.width * renderTargetTmp.height * 4); - frameBuffer.attach(renderTargetTmp); - frameBuffer.bind(renderer); - - var camera = envMapPass.getCamera(targets[j]); - camera.fov = fov; - renderer.render(dummyScene, camera); - renderer.gl.readPixels( - 0, 0, renderTargetTmp.width, renderTargetTmp.height, - __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].RGBA, textureType, pixels - ); - - // var canvas = document.createElement('canvas'); - // var ctx = canvas.getContext('2d'); - // canvas.width = renderTargetTmp.width; - // canvas.height = renderTargetTmp.height; - // var imageData = ctx.createImageData(renderTargetTmp.width, renderTargetTmp.height); - // for (var k = 0; k < pixels.length; k++) { - // imageData.data[k] = pixels[k]; - // } - // ctx.putImageData(imageData, 0, 0); - // document.body.appendChild(canvas); - - frameBuffer.unbind(renderer); - prefilteredCubeMap.mipmaps[i].pixels[targets[j]] = pixels; - } - - renderTargetTmp.width /= 2; - renderTargetTmp.height /= 2; - renderTargetTmp.dirty(); - } - - frameBuffer.dispose(renderer); - renderTargetTmp.dispose(renderer); - skyEnv.dispose(renderer); - // Remove gpu resource allucated in renderer - normalDistribution.dispose(renderer); - - // renderer.dispose(); - - return { - environmentMap: prefilteredCubeMap, - brdfLookup: brdfLookup, - normalDistribution: normalDistribution, - maxMipmapLevel: mipmapNum - }; -}; - -cubemapUtil.integrateBRDF = function (renderer, normalDistribution) { - normalDistribution = normalDistribution || cubemapUtil.generateNormalDistribution(); - var framebuffer = new __WEBPACK_IMPORTED_MODULE_3__FrameBuffer__["a" /* default */]({ - depthBuffer: false - }); - var pass = new __WEBPACK_IMPORTED_MODULE_4__compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_12__shader_integrateBRDF_glsl_js__["a" /* default */] - }); - - var texture = new __WEBPACK_IMPORTED_MODULE_0__Texture2D__["a" /* default */]({ - width: 512, - height: 256, - type: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].HALF_FLOAT, - minFilter: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].NEAREST, - magFilter: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].NEAREST, - useMipmap: false - }); - pass.setUniform('normalDistribution', normalDistribution); - pass.setUniform('viewportSize', [512, 256]); - pass.attachOutput(texture); - pass.render(renderer, framebuffer); - - // FIXME Only chrome and firefox can readPixels with float type. - // framebuffer.bind(renderer); - // var pixels = new Float32Array(512 * 256 * 4); - // renderer.gl.readPixels( - // 0, 0, texture.width, texture.height, - // Texture.RGBA, Texture.FLOAT, pixels - // ); - // texture.pixels = pixels; - // texture.flipY = false; - // texture.dirty(); - // framebuffer.unbind(renderer); - - framebuffer.dispose(renderer); - - return texture; -}; - -cubemapUtil.generateNormalDistribution = function (roughnessLevels, sampleSize) { - - // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html - // GLSL not support bit operation, use lookup instead - // V -> i / N, U -> roughness - var roughnessLevels = roughnessLevels || 256; - var sampleSize = sampleSize || 1024; - - var normalDistribution = new __WEBPACK_IMPORTED_MODULE_0__Texture2D__["a" /* default */]({ - width: roughnessLevels, - height: sampleSize, - type: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].FLOAT, - minFilter: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].NEAREST, - magFilter: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].NEAREST, - useMipmap: false - }); - var pixels = new Float32Array(sampleSize * roughnessLevels * 4); - for (var i = 0; i < sampleSize; i++) { - var x = i / sampleSize; - // http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators - // http://stackoverflow.com/questions/1908492/unsigned-integer-in-javascript - // http://stackoverflow.com/questions/1822350/what-is-the-javascript-operator-and-how-do-you-use-it - var y = (i << 16 | i >>> 16) >>> 0; - y = ((y & 1431655765) << 1 | (y & 2863311530) >>> 1) >>> 0; - y = ((y & 858993459) << 2 | (y & 3435973836) >>> 2) >>> 0; - y = ((y & 252645135) << 4 | (y & 4042322160) >>> 4) >>> 0; - y = (((y & 16711935) << 8 | (y & 4278255360) >>> 8) >>> 0) / 4294967296; - - for (var j = 0; j < roughnessLevels; j++) { - var roughness = j / roughnessLevels; - var a = roughness * roughness; - var phi = 2.0 * Math.PI * x; - // CDF - var cosTheta = Math.sqrt((1 - y) / (1 + (a * a - 1.0) * y)); - var sinTheta = Math.sqrt(1.0 - cosTheta * cosTheta); - var offset = (i * roughnessLevels + j) * 4; - pixels[offset] = sinTheta * Math.cos(phi); - pixels[offset + 1] = sinTheta * Math.sin(phi); - pixels[offset + 2] = cosTheta; - pixels[offset + 3] = 1.0; - } - } - normalDistribution.pixels = pixels; - - return normalDistribution; -}; - -/* harmony default export */ __webpack_exports__["a"] = (cubemapUtil); - - -/***/ }), -/* 64 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.deferred.gbuffer.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat;\nuniform vec2 uvOffset;\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\n#ifdef FIRST_PASS\nattribute vec3 normal : NORMAL;\n#endif\n@import clay.chunk.skinning_header\n#ifdef FIRST_PASS\nvarying vec3 v_Normal;\nattribute vec4 tangent : TANGENT;\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\nvarying vec3 v_WorldPosition;\n#endif\nvarying vec2 v_Texcoord;\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef FIRST_PASS\n vec3 skinnedNormal = normal;\n vec3 skinnedTangent = tangent.xyz;\n bool hasTangent = dot(tangent, tangent) > 0.0;\n#endif\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n #ifdef FIRST_PASS\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n if (hasTangent) {\n skinnedTangent = (skinMatrixWS * vec4(tangent.xyz, 0.0)).xyz;\n }\n #endif\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n#ifdef FIRST_PASS\n v_Normal = normalize((worldInverseTranspose * vec4(skinnedNormal, 0.0)).xyz);\n if (hasTangent) {\n v_Tangent = normalize((worldInverseTranspose * vec4(skinnedTangent, 0.0)).xyz);\n v_Bitangent = normalize(cross(v_Normal, v_Tangent) * tangent.w);\n }\n v_WorldPosition = (world * vec4(skinnedPosition, 1.0)).xyz;\n#endif\n}\n@end\n@export clay.deferred.gbuffer1.fragment\nuniform mat4 viewInverse : VIEWINVERSE;\nuniform float glossiness;\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nuniform sampler2D normalMap;\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\nuniform sampler2D roughGlossMap;\nuniform bool useRoughGlossMap;\nuniform bool useRoughness;\nuniform bool doubleSided;\nuniform int roughGlossChannel: 0;\nfloat indexingTexel(in vec4 texel, in int idx) {\n if (idx == 3) return texel.a;\n else if (idx == 1) return texel.g;\n else if (idx == 2) return texel.b;\n else return texel.r;\n}\nvoid main()\n{\n vec3 N = v_Normal;\n if (doubleSided) {\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = eyePos - v_WorldPosition;\n if (dot(N, V) < 0.0) {\n N = -N;\n }\n }\n if (dot(v_Tangent, v_Tangent) > 0.0) {\n vec3 normalTexel = texture2D(normalMap, v_Texcoord).xyz;\n if (dot(normalTexel, normalTexel) > 0.0) { N = normalTexel * 2.0 - 1.0;\n mat3 tbn = mat3(v_Tangent, v_Bitangent, v_Normal);\n N = normalize(tbn * N);\n }\n }\n gl_FragColor.rgb = (N + 1.0) * 0.5;\n float g = glossiness;\n if (useRoughGlossMap) {\n float g2 = indexingTexel(texture2D(roughGlossMap, v_Texcoord), roughGlossChannel);\n if (useRoughness) {\n g2 = 1.0 - g2;\n }\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n }\n gl_FragColor.a = g + 0.005;\n}\n@end\n@export clay.deferred.gbuffer2.fragment\nuniform sampler2D diffuseMap;\nuniform sampler2D metalnessMap;\nuniform vec3 color;\nuniform float metalness;\nuniform bool useMetalnessMap;\nuniform bool linear;\nvarying vec2 v_Texcoord;\n@import clay.util.srgb\nvoid main ()\n{\n float m = metalness;\n if (useMetalnessMap) {\n vec4 metalnessTexel = texture2D(metalnessMap, v_Texcoord);\n m = clamp(metalnessTexel.r + (m * 2.0 - 1.0), 0.0, 1.0);\n }\n vec4 texel = texture2D(diffuseMap, v_Texcoord);\n if (linear) {\n texel = sRGBToLinear(texel);\n }\n gl_FragColor.rgb = texel.rgb * color;\n gl_FragColor.a = m + 0.005;\n}\n@end\n@export clay.deferred.gbuffer.debug\n@import clay.deferred.chunk.light_head\nuniform int debug: 0;\nvoid main ()\n{\n @import clay.deferred.chunk.gbuffer_read\n if (debug == 0) {\n gl_FragColor = vec4(N, 1.0);\n }\n else if (debug == 1) {\n gl_FragColor = vec4(vec3(z), 1.0);\n }\n else if (debug == 2) {\n gl_FragColor = vec4(position, 1.0);\n }\n else if (debug == 3) {\n gl_FragColor = vec4(vec3(glossiness), 1.0);\n }\n else if (debug == 4) {\n gl_FragColor = vec4(vec3(metalness), 1.0);\n }\n else {\n gl_FragColor = vec4(albedo, 1.0);\n }\n}\n@end"); - - -/***/ }), -/* 65 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -// Simple LRU cache use doubly linked list -// @module zrender/core/LRU - -/** - * Simple double linked list. Compared with array, it has O(1) remove operation. - * @constructor - */ -var LinkedList = function () { - - /** - * @type {module:zrender/core/LRU~Entry} - */ - this.head = null; - - /** - * @type {module:zrender/core/LRU~Entry} - */ - this.tail = null; - - this._len = 0; -}; - -var linkedListProto = LinkedList.prototype; -/** - * Insert a new value at the tail - * @param {} val - * @return {module:zrender/core/LRU~Entry} - */ -linkedListProto.insert = function (val) { - var entry = new Entry(val); - this.insertEntry(entry); - return entry; -}; - -/** - * Insert an entry at the tail - * @param {module:zrender/core/LRU~Entry} entry - */ -linkedListProto.insertEntry = function (entry) { - if (!this.head) { - this.head = this.tail = entry; - } - else { - this.tail.next = entry; - entry.prev = this.tail; - entry.next = null; - this.tail = entry; - } - this._len++; -}; - -/** - * Remove entry. - * @param {module:zrender/core/LRU~Entry} entry - */ -linkedListProto.remove = function (entry) { - var prev = entry.prev; - var next = entry.next; - if (prev) { - prev.next = next; - } - else { - // Is head - this.head = next; - } - if (next) { - next.prev = prev; - } - else { - // Is tail - this.tail = prev; - } - entry.next = entry.prev = null; - this._len--; -}; - -/** - * @return {number} - */ -linkedListProto.len = function () { - return this._len; -}; - -/** - * Clear list - */ -linkedListProto.clear = function () { - this.head = this.tail = null; - this._len = 0; -}; - -/** - * @constructor - * @param {} val - */ -var Entry = function (val) { - /** - * @type {} - */ - this.value = val; - - /** - * @type {module:zrender/core/LRU~Entry} - */ - this.next; - - /** - * @type {module:zrender/core/LRU~Entry} - */ - this.prev; -}; - -/** - * LRU Cache - * @constructor - * @alias module:zrender/core/LRU - */ -var LRU = function (maxSize) { - - this._list = new LinkedList(); - - this._map = {}; - - this._maxSize = maxSize || 10; - - this._lastRemovedEntry = null; -}; - -var LRUProto = LRU.prototype; - -/** - * @param {string} key - * @param {} value - * @return {} Removed value - */ -LRUProto.put = function (key, value) { - var list = this._list; - var map = this._map; - var removed = null; - if (map[key] == null) { - var len = list.len(); - // Reuse last removed entry - var entry = this._lastRemovedEntry; - - if (len >= this._maxSize && len > 0) { - // Remove the least recently used - var leastUsedEntry = list.head; - list.remove(leastUsedEntry); - delete map[leastUsedEntry.key]; - - removed = leastUsedEntry.value; - this._lastRemovedEntry = leastUsedEntry; - } - - if (entry) { - entry.value = value; - } - else { - entry = new Entry(value); - } - entry.key = key; - list.insertEntry(entry); - map[key] = entry; - } - - return removed; -}; - -/** - * @param {string} key - * @return {} - */ -LRUProto.get = function (key) { - var entry = this._map[key]; - var list = this._list; - if (entry != null) { - // Put the latest used entry in the tail - if (entry !== list.tail) { - list.remove(entry); - list.insertEntry(entry); - } - - return entry.value; - } -}; - -/** - * Clear the cache - */ -LRUProto.clear = function () { - this._list.clear(); - this._map = {}; -}; - -/* harmony default export */ __webpack_exports__["a"] = (LRU); - -/***/ }), -/* 66 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return updateAnimationUI; }); -/* unused harmony export setTimeRange */ -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return hideTimeline; }); -/* unused harmony export showTimeline */ - -function showTimeline() { - document.getElementById('timeline').style.display = 'block'; -} -function hideTimeline() { - document.getElementById('timeline').style.display = 'none'; - stopAnimation(); -} - -var isPlay = false; -var currentTime = 0; -var startTime = 0; -var duration; - -var viewer; -var animationToken; -var pauseBtnClickListener; - - -function updateAnimationUI(_viewer) { - viewer = _viewer; - duration = Math.floor(_viewer.getAnimationDuration()); - duration > 0 ? (showTimeline()) : (hideTimeline()); - - if (duration <= 0) { - return; - } - var pauseBtn = document.getElementById('timeline-pause-resume'); - - pauseBtn.removeEventListener('click', pauseBtnClickListener); - pauseBtn.addEventListener('click', pauseBtnClickListener = function () { - if (isPlay) { - stopAnimation(); - } - else { - startAnimation(_animationToken); - } - }); - - - // Reset time - startTime = 0; - currentTime = 0; - - updateControlPosition(); - - var _animationToken = Math.random(); - animationToken = _animationToken; - - if (duration > 0) { - startAnimation(_animationToken); - } - else { - stopAnimation(); - } - var _oldIsPlay = null; - if (!$('#timeline-progress input').data('ionRangeSlider')) { - $('#timeline-progress input').ionRangeSlider({ - from_shadow: true, - force_edges: true, - onChange: function (data) { - currentTime = data.from; - viewer.setPose(currentTime); - if (_oldIsPlay == null) { - _oldIsPlay = isPlay; - } - stopAnimation(); - }, - onFinish: function () { - if (_oldIsPlay) { - startAnimation(_animationToken); - } - _oldIsPlay = null; - } - }); - $('#timeline-range input').ionRangeSlider({ - from_shadow: true, - force_edges: true, - type: 'double', - drag_interval: true, - grid: true, - grid_num: 10, - onChange: function (data) { - duration = data.to - data.from; - startTime = data.from; - currentTime = Math.min(Math.max(data.from, currentTime), data.to); - viewer.setPose(currentTime); - progressSlider.update({ - from_min: data.from, - from_max: data.to - }); - } - }); - - var progressSlider = $('#timeline-progress input').data('ionRangeSlider'); - var rangeSlider = $('#timeline-range input').data('ionRangeSlider'); - progressSlider.update({ - min: 0, - max: duration, - from: currentTime, - from_min: 0, - from_max: duration - }); - rangeSlider.update({ - min: 0, - max: duration, - from: 0, - to: duration - }); - } -} - -function updateControlPosition() { - var slider = $('#timeline-progress input').data('ionRangeSlider'); - if (slider) { - slider.update({ - from: currentTime - }); - } -} - -function startAnimation(_animationToken) { - if (isPlay) { - return; - } - - isPlay = true; - - var _time = Date.now(); - - var pauseBtn = document.getElementById('timeline-pause-resume'); - pauseBtn.classList.remove('icon-resume'); - pauseBtn.classList.add('icon-pause'); - - function update() { - if (!isPlay) { - return; - } - if (_animationToken !== animationToken) { - return; - } - - viewer.setPose(currentTime); - - var dTime = Math.min(Date.now() - _time, 20); - _time = Date.now(); - - updateControlPosition(); - - currentTime += dTime; - if (currentTime > startTime + duration) { - currentTime = startTime; - } - - requestAnimationFrame(update); - } - - requestAnimationFrame(update); -} - -function stopAnimation() { - if (!isPlay) { - return; - } - - isPlay = false; - - var pauseBtn = document.getElementById('timeline-pause-resume'); - pauseBtn.classList.remove('icon-pause'); - pauseBtn.classList.add('icon-resume'); -} - -function setTimeRange(_startTime, _endTime) { - startTime = _startTime; - duration = _endTime - startTime; -} - - - -/***/ }), -/* 67 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__index__ = __webpack_require__(68); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__getDefaultSceneConfig__ = __webpack_require__(145); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__getDefaultMaterialConfig__ = __webpack_require__(146); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__project__ = __webpack_require__(147); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__env__ = __webpack_require__(38); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5_claygl_src_core_util__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6_zrender_lib_core_util__ = __webpack_require__(156); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6_zrender_lib_core_util___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_6_zrender_lib_core_util__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__ui_Texture__ = __webpack_require__(157); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__timeline__ = __webpack_require__(66); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__debug_renderOutline__ = __webpack_require__(158); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10_vendor_openURL__ = __webpack_require__(160); - - - - - - - - - - - - - -var config = Object(__WEBPACK_IMPORTED_MODULE_1__getDefaultSceneConfig__["a" /* default */])(); -var materialConfig = Object(__WEBPACK_IMPORTED_MODULE_2__getDefaultMaterialConfig__["a" /* default */])(); - -var viewer; - -var controlKit = new ControlKit({ - loadAndSave: true, - useExternalStyle: true -}); - -function updateLight() { - ['mainLight', 'secondaryLight', 'tertiaryLight'].forEach(function (lightType) { - config[lightType].alpha = config[lightType].$padAngle[1] * 90; - config[lightType].beta = config[lightType].$padAngle[0] * 180; - }); - viewer.setMainLight(config.mainLight); - viewer.setSecondaryLight(config.secondaryLight); - viewer.setTertiaryLight(config.tertiaryLight); - viewer.setAmbientLight(config.ambientLight); -} - -function updatePostEffect() { - viewer.setPostEffect(config.postEffect); -} - -function updateEnvironment() { - config.ambientCubemapLight.texture = __WEBPACK_IMPORTED_MODULE_4__env__["a" /* default */].ENV_TEXTURE_ROOT + config.ambientCubemapLight.$texture + '.hdr'; - config.ambientCubemapLight.diffuseIntensity = config.ambientCubemapLight.specularIntensity = config.ambientCubemapLight.$intensity; - viewer.setAmbientCubemapLight(config.ambientCubemapLight); -} -function updateGround() { - viewer.setGround(config.ground); -} -function updateAll() { - updateLight(); - updatePostEffect(); - updateEnvironment(); - updateGround(); -} - -function updateMaterial() { - var $textureTiling = Math.max(materialConfig.$textureTiling, 0.01); - materialConfig.uvRepeat = [$textureTiling, $textureTiling]; - materialConfig.transparent = materialConfig.alpha < 1; - viewer.setMaterial(materialConfig.name, materialConfig); -} - -function selectMaterial(mat) { - materialConfig.name = mat.name; - var matConfig = viewer.getMaterial(mat.name); - matConfig.$textureTiling = matConfig.uvRepeat[0]; - __WEBPACK_IMPORTED_MODULE_5_claygl_src_core_util__["a" /* default */].extend(materialConfig, matConfig); - if (matConfig.specularColor == null) { - pbrRoughnessMetallicPanel.enable(); - pbrSpecularGlossinessPanel.disable(); - } - else { - pbrSpecularGlossinessPanel.enable(); - pbrRoughnessMetallicPanel.disable(); - } - controlKit.update(); -} - -function haveTexture(val) { - return val && val !== 'none'; -} - -function changeTexture(type, file, val) { - var uiNeedUpdate = false; - if (haveTexture(val)) { - [ - ['diffuseMap', 'color', '#fff'], - ['metalnessMap', 'metalness', 0.5], - ['roughnessMap', 'roughness', 0.5], - ['glossinessMap', 'glossiness', 0.5], - ['specularMap', 'specularColor', '#fff'], - ['emissiveMap', 'emission', '#fff'] - ].forEach(function (item) { - if (type === item[0]) { - console.warn('Force %s to be %s after set %s', item[1], item[2], item[0]); - materialConfig[item[1]] = item[2]; - - uiNeedUpdate = true; - } - }, this); - - // TODO Remove old textures. - showSaveTip(); - __WEBPACK_IMPORTED_MODULE_4__env__["a" /* default */].AUTO_SAVE && __WEBPACK_IMPORTED_MODULE_3__project__["g" /* writeTextureImage */](file).then(hideBackgroundProgress).catch(hideBackgroundProgress); - filesMapInverse[val] = file.name; - - uiNeedUpdate && controlKit.update(); - } - - updateMaterial(); -} - -var scenePanel; -var pbrRoughnessMetallicPanel; -var pbrSpecularGlossinessPanel; -var selectedMesh; - -function showTip() { - document.getElementById('tip').style.display = 'block'; -} -function hideTip() { - document.getElementById('tip').style.display = 'none'; -} - -function createViewer() { - viewer = new __WEBPACK_IMPORTED_MODULE_0__index__["a" /* default */].Viewer(document.getElementById('viewport'), config); - viewer.enablePicking(); - viewer.setCameraControl(config.viewControl); - viewer.start(); - - viewer.on('select', function (result) { - viewer.refresh(); - selectMaterial(result.target.material); - - selectedMesh = result.target; - }); - viewer.on('doffocus', function (result) { - if (config.postEffect.depthOfField.enable) { - config.postEffect.depthOfField.focalDistance = result.distance; - controlKit.update(); - } - }); - viewer.on('unselect', function () { - viewer.refresh(); - pbrRoughnessMetallicPanel.disable(); - pbrSpecularGlossinessPanel.disable(); - selectedMesh = null; - }); - - viewer.on('afterrender', function (renderer, scene, camera) { - if (selectedMesh) { - Object(__WEBPACK_IMPORTED_MODULE_9__debug_renderOutline__["a" /* default */])(viewer, [selectedMesh], camera); - } - }); - - viewer.on('updatecamera', function (params) { - config.viewControl = { - center: params.center, - alpha: params.alpha, - beta: params.beta, - distance: params.distance - }; - }); -} - - -var loadingEl = document.getElementById('loading'); -var backgroundProgressEl = document.getElementById('background-progress'); -function showLoading(text) { - document.body.appendChild(loadingEl); - loadingEl.querySelector('#loading-text').innerHTML = text || 'LOADING'; -} -function hideLoading() { - // Remove loading - loadingEl.parentNode.removeChild(loadingEl); -} - -function showSaveTip() { - backgroundProgressEl.style.display = 'block'; - backgroundProgressEl.querySelector('#background-progress-text').innerHTML = 'Saving...DONT close the page.'; -} - -function showPrepareTip() { - backgroundProgressEl.style.display = 'block'; - backgroundProgressEl.querySelector('#background-progress-text').innerHTML = 'Preparing for download...DONT close the page.'; -} - -function hideBackgroundProgress () { - backgroundProgressEl.style.display = 'none'; -} - -function init() { - hideLoading(); - - - document.getElementById('toolbar').style.display = 'block'; - document.getElementById('reset').addEventListener('click', reset); - document.getElementById('download').addEventListener('click', download); - - createViewer(); - - ///////////// Drag and drop - FileAPI.event.dnd(document.getElementById('main'), function (over) { - - }, function (files) { - - showLoading('Loading model'); - __WEBPACK_IMPORTED_MODULE_8__timeline__["a" /* hideTimeline */](); - - __WEBPACK_IMPORTED_MODULE_3__project__["a" /* createModelFilesURL */](files).then(function (res) { - var glTF = res.glTF; - var filesMap = res.filesMap; - var buffers = res.buffers; - var files = res.allFiles; - - filesMapInverse = {}; - for (var name in filesMap) { - filesMapInverse[filesMap[name]] = name; - } - var haveViewerConfig = !!(glTF.extras && glTF.extras.clayViewerConfig); - if (haveViewerConfig) { - __WEBPACK_IMPORTED_MODULE_6_zrender_lib_core_util__["merge"](config, glTF.extras.clayViewerConfig, true); - viewer.setCameraControl(config.viewControl); - updateAll(); - controlKit.update(); - } - viewer.loadModel(glTF, { - files: filesMap, - buffers: buffers, - textureFlipY: config.textureFlipY, - doubleSided: true, - upAxis: config.zUpToYUp ? 'z' : 'y', - includeTexture: !haveViewerConfig - }).on('ready', function () { - - hideTip(); - hideLoading(); - - if (haveViewerConfig) { - (glTF.extras.clayViewerConfig.materials || []).forEach(function (matConfig) { - for (var key in matConfig) { - if (filesMap[matConfig[key]]) { - matConfig[key] = filesMap[matConfig[key]]; - } - } - viewer.setMaterial(matConfig.name, matConfig); - }); - } - - setTimeout(function () { - showSaveTip(); - __WEBPACK_IMPORTED_MODULE_4__env__["a" /* default */].AUTO_SAVE && __WEBPACK_IMPORTED_MODULE_3__project__["e" /* saveModelFiles */](files).then(hideBackgroundProgress).catch(hideBackgroundProgress); - }, 200); - }) - .on('loadmodel', afterLoadModel) - .on('error', function () { - hideLoading(); - swal('Model load error'); - }); - - pbrRoughnessMetallicPanel.disable(); - pbrSpecularGlossinessPanel.disable(); - - }).catch(function (err) { - - hideLoading(); - if (!viewer.getModelRoot()) { - showTip(); - } - Object(__WEBPACK_IMPORTED_MODULE_8__timeline__["b" /* updateAnimationUI */])(viewer); - - console.log(err); - swal(err.toString()); - }); - }); - - - initUI(); - - inited = true; -} - -function initUI() { - scenePanel = controlKit.addPanel({ label: 'Settings', width: 250 }); - - scenePanel.addGroup({ label: 'Global' }) - .addSubGroup( { label: 'Load Option'}) - .addCheckbox(config, 'textureFlipY', { label: 'Flip Texture', onChange: function () { - viewer.setTextureFlipY(config.textureFlipY); - } }) - .addCheckbox(config, 'zUpToYUp', { label: 'Z Up', onChange: function () { - viewer.setModelUpAxis(config.zUpToYUp ? 'Z' : 'Y'); - } }) - .addSubGroup( { label: 'Ground' }) - .addCheckbox(config.ground, 'show', { label: 'Show', onChange: updateGround }); - - scenePanel.addGroup({ label: 'Environment', enable: false }) - .addSelect(config.ambientCubemapLight, '$textureOptions', { label: 'HDR Texture', onChange: updateEnvironment, target: '$texture' }) - .addNumberInput(config.ambientCubemapLight, '$intensity', { label: 'Intensity', onChange: updateEnvironment, step: 0.1 }); - - scenePanel.addGroup({ label: 'Light', enable: false }) - .addSubGroup({ label: 'Main', enable: false }) - .addCheckbox(config.mainLight, 'shadow', { label: 'Cast Shadow', onChange: updateLight }) - .addNumberInput(config.mainLight, 'intensity', { label: 'Intensity', step: 0.1, onChange: updateLight }) - .addColor(config.mainLight, 'color', { label: 'Color', onChange: updateLight }) - .addPad(config.mainLight, '$padAngle', { label: 'Direction', onChange: updateLight }) - - .addSubGroup({ label: 'Secondary', enable: false }) - .addNumberInput(config.secondaryLight, 'intensity', { label: 'Intensity', step: 0.1, onChange: updateLight }) - .addColor(config.secondaryLight, 'color', { label: 'Color', onChange: updateLight }) - .addPad(config.secondaryLight, '$padAngle', { label: 'Direction', onChange: updateLight }) - - .addSubGroup({ label: 'Tertiary', enable: false }) - .addNumberInput(config.tertiaryLight, 'intensity', { label: 'Intensity', step: 0.1, onChange: updateLight }) - .addColor(config.tertiaryLight, 'color', { label: 'Color', onChange: updateLight }) - .addPad(config.tertiaryLight, '$padAngle', { label: 'Direction', onChange: updateLight }) - - .addSubGroup({ label: 'Ambient', enable: false }) - .addNumberInput(config.ambientLight, 'intensity', { label: 'Intensity', step: 0.1, onChange: updateLight }) - .addColor(config.ambientLight, 'color', { label: 'Color', onChange: updateLight }); - - scenePanel.addGroup({ label: 'Post Effect', enable: false}) - .addCheckbox(config.postEffect, 'enable', { label: 'Enable', onChange: updatePostEffect }) - .addSubGroup({ label: 'Bloom', enable: false }) - .addCheckbox(config.postEffect.bloom, 'enable', { label: 'Enable', onChange: updatePostEffect }) - .addNumberInput(config.postEffect.bloom, 'intensity', { label: 'Intensity', step: 0.1, onChange: updatePostEffect }) - - .addSubGroup({ label: 'Screen Space Ambient Occulusion', enable: false }) - .addCheckbox(config.postEffect.screenSpaceAmbientOcclusion, 'enable', { label: 'Enable', onChange: updatePostEffect }) - .addNumberInput(config.postEffect.screenSpaceAmbientOcclusion, 'radius', { label: 'Radius', step: 0.1, onChange: updatePostEffect }) - .addNumberInput(config.postEffect.screenSpaceAmbientOcclusion, 'intensity', { label: 'Intensity', step: 0.1, onChange: updatePostEffect }) - .addSelect(config.postEffect.screenSpaceAmbientOcclusion, '$qualityOptions', { label: 'Quality', onChange: updatePostEffect, target: 'quality' }) - - .addSubGroup({ label: 'Screen Space Reflection', enable: false }) - .addCheckbox(config.postEffect.screenSpaceReflection, 'enable', { label: 'Enable', onChange: updatePostEffect }) - .addNumberInput(config.postEffect.screenSpaceReflection, 'maxRoughness', { label: 'Max Roughness', step: 0.01, onChange: updatePostEffect }) - .addSelect(config.postEffect.screenSpaceReflection, '$qualityOptions', { label: 'Quality', onChange: updatePostEffect, target: 'quality' }) - - .addSubGroup({ label: 'Depth of Field', enable: false }) - .addCheckbox(config.postEffect.depthOfField, 'enable', { label: 'Enable', onChange: updatePostEffect }) - .addNumberInput(config.postEffect.depthOfField, 'fstop', { label: 'f-stop', step: 0.1, onChange: updatePostEffect }) - .addNumberInput(config.postEffect.depthOfField, 'focalDistance', { label: 'Focal Distance', step: 0.1, onChange: updatePostEffect }) - .addNumberInput(config.postEffect.depthOfField, 'focalRange', { label: 'Focal Range', step: 0.1, onChange: updatePostEffect }) - .addNumberInput(config.postEffect.depthOfField, 'blurRadius', { label: 'Blur Radius', step: 0.1, onChange: updatePostEffect }) - .addSelect(config.postEffect.depthOfField, '$qualityOptions', { label: 'Quality', onChange: updatePostEffect, target: 'quality' }) - - .addSubGroup({ label: 'Color Correction', enable: false }) - .addNumberInput(config.postEffect.colorCorrection, 'exposure', { label: 'Exposure', step: 0.1, onChange: updatePostEffect }) - .addNumberInput(config.postEffect.colorCorrection, 'brightness', { label: 'Brightness', step: 0.1, onChange: updatePostEffect }) - .addNumberInput(config.postEffect.colorCorrection, 'contrast', { label: 'Contrast', step: 0.1, onChange: updatePostEffect }) - .addNumberInput(config.postEffect.colorCorrection, 'saturation', { label: 'Saturation', step: 0.1, onChange: updatePostEffect }); - - function getTextureFileName(url) { - return filesMapInverse && filesMapInverse[url]; - } - - function addCommmonProperties(panel) { - panel - .addStringOutput(materialConfig, 'name', { label: 'Name' }) - .addColor(materialConfig, 'color', { label: 'Base Color', onChange: updateMaterial }) - .addSlider(materialConfig, 'alpha', '$alphaRange', { label: 'Alpha', onChange: updateMaterial }) - .addSlider(materialConfig, 'alphaCutoff', '$alphaCutoffRange', { label: 'Alpha Cutoff', onChange: updateMaterial }) - .addNumberInput(materialConfig, '$textureTiling', { label: 'Tiling', onChange: updateMaterial, step: 0.5 }) - .addCustomComponent(__WEBPACK_IMPORTED_MODULE_7__ui_Texture__["a" /* default */], materialConfig, 'diffuseMap', { label: 'Base Map', onChange: changeTexture.bind(null, 'diffuseMap'), getFileName: getTextureFileName }) - .addCustomComponent(__WEBPACK_IMPORTED_MODULE_7__ui_Texture__["a" /* default */], materialConfig, 'normalMap', { label: 'Normal/Bump Map', onChange: changeTexture.bind(null, 'normalMap'), getFileName: getTextureFileName }) - } - function addUncommonProperties(panel) { - panel - .addCustomComponent(__WEBPACK_IMPORTED_MODULE_7__ui_Texture__["a" /* default */], materialConfig, 'parallaxOcclusionMap', { label: 'Parallax Occlusion Map', onChange: changeTexture.bind(null, 'parallaxOcclusionMap'), getFileName: getTextureFileName }) - .addSlider(materialConfig, 'parallaxOcclusionScale', '$parallaxOcclusionScaleRange', { label: 'Scale', onChange: updateMaterial }) - .addColor(materialConfig, 'emission', { label: 'Emission', onChange: updateMaterial }) - .addNumberInput(materialConfig, 'emissionIntensity', { label: 'Emission Intensity', onChange: updateMaterial }) - .addCustomComponent(__WEBPACK_IMPORTED_MODULE_7__ui_Texture__["a" /* default */], materialConfig, 'emissiveMap', { label: 'Emissive Map', onChange: changeTexture.bind(null, 'emissiveMap'), getFileName: getTextureFileName }); - } - - pbrRoughnessMetallicPanel = controlKit.addPanel({ label: 'Material - Metalllic Roughness', width: 240, fixed: false, align: 'left', position: [10, 10] }); - addCommmonProperties(pbrRoughnessMetallicPanel); - pbrRoughnessMetallicPanel - .addCustomComponent(__WEBPACK_IMPORTED_MODULE_7__ui_Texture__["a" /* default */], materialConfig, 'metalnessMap', { label: 'Metalness Map', onChange: changeTexture.bind(null, 'metalnessMap'), getFileName: getTextureFileName }) - .addSlider(materialConfig, 'metalness', '$metalnessRange', { label: 'Metalness', onChange: updateMaterial }) - .addCustomComponent(__WEBPACK_IMPORTED_MODULE_7__ui_Texture__["a" /* default */], materialConfig, 'roughnessMap', { label: 'Roughness Map', onChange: changeTexture.bind(null, 'roughnessMap'), getFileName: getTextureFileName }) - .addSlider(materialConfig, 'roughness', '$roughnessRange', { label: 'Roughness', onChange: updateMaterial }); - addUncommonProperties(pbrRoughnessMetallicPanel); - pbrRoughnessMetallicPanel.disable(); - - pbrSpecularGlossinessPanel = controlKit.addPanel({ label: 'Material - Specular Glossiness', width: 240, fixed: false, align: 'left', position: [10, 10] }); - addCommmonProperties(pbrSpecularGlossinessPanel); - pbrSpecularGlossinessPanel - .addCustomComponent(__WEBPACK_IMPORTED_MODULE_7__ui_Texture__["a" /* default */], materialConfig, 'specularMap', { label: 'Specular Map', onChange: changeTexture.bind(null, 'specularMap'), getFileName: getTextureFileName }) - .addColor(materialConfig, 'specularColor', { label: 'Specular Factor', onChange: updateMaterial }) - .addCustomComponent(__WEBPACK_IMPORTED_MODULE_7__ui_Texture__["a" /* default */], materialConfig, 'glossinessMap', { label: 'Glossiness Map', onChange: changeTexture.bind(null, 'glossinessMap'), getFileName: getTextureFileName }) - .addSlider(materialConfig, 'glossiness', '$glossinessRange', { label: 'Glossiness', onChange: updateMaterial }); - addUncommonProperties(pbrSpecularGlossinessPanel); - pbrSpecularGlossinessPanel.disable(); -} - -function reset() { - swal({ - title: 'Reset?', - text: 'Reset the viewer', - type: 'warning', - showCancelButton: true, - confirmButtonColor: '#3085d6', - cancelButtonColor: '#d33', - confirmButtonText: 'Yes!' - }).then(function () { - __WEBPACK_IMPORTED_MODULE_6_zrender_lib_core_util__["merge"](config, Object(__WEBPACK_IMPORTED_MODULE_1__getDefaultSceneConfig__["a" /* default */])(), true); - __WEBPACK_IMPORTED_MODULE_6_zrender_lib_core_util__["merge"](materialConfig, Object(__WEBPACK_IMPORTED_MODULE_2__getDefaultMaterialConfig__["a" /* default */])(), true); - controlKit.update(); - pbrRoughnessMetallicPanel.disable(); - pbrSpecularGlossinessPanel.disable(); - - selectedMesh = null; - viewer.dispose(); - createViewer(); - - __WEBPACK_IMPORTED_MODULE_3__project__["d" /* removeProject */](); - - showTip(); - - __WEBPACK_IMPORTED_MODULE_8__timeline__["b" /* updateAnimationUI */](viewer); - hideBackgroundProgress(); - }).catch(function () {}); -} - -function download() { - swal({ - title: 'Select download format.', - input: 'radio', - inputOptions: { - 'glb': 'GLB', - 'zip': 'ZIP' - } - }).then(function (result) { - showPrepareTip(); - __WEBPACK_IMPORTED_MODULE_3__project__["b" /* downloadProject */](result, hideBackgroundProgress, hideBackgroundProgress); - }); -} - -function afterLoadModel() { - selectedMesh = null; - viewer.stopAnimation(); - __WEBPACK_IMPORTED_MODULE_8__timeline__["b" /* updateAnimationUI */](viewer); -} - -var filesMapInverse; -var inited = false; - -__WEBPACK_IMPORTED_MODULE_3__project__["c" /* init */](function (glTF, filesMap, loadedSceneCfg) { - - if (loadedSceneCfg) { - __WEBPACK_IMPORTED_MODULE_6_zrender_lib_core_util__["merge"](config, loadedSceneCfg, true); - } - if (inited) { - return; - } - - init(); - - if (glTF) { - filesMapInverse = {}; - for (var name in filesMap) { - filesMapInverse[filesMap[name]] = name; - } - viewer.loadModel(glTF, { - files: filesMap, - textureFlipY: config.textureFlipY, - upAxis: config.zUpToYUp ? 'z' : 'y', - doubleSided: true, - // Not load texture, setMaterial will do it. - includeTexture: false - }).on('ready', function () { - if (loadedSceneCfg && loadedSceneCfg.materials) { - loadedSceneCfg.materials.forEach(function (matConfig) { - // From file name to object URL - for (var key in matConfig) { - if (filesMap[matConfig[key]]) { - matConfig[key] = filesMap[matConfig[key]]; - } - } - viewer.setMaterial(matConfig.name, matConfig); - }); - } - }) - .on('loadmodel', afterLoadModel) - .on('error', function () { - showTip(); - swal('Model load error'); - }); - } - else { - showTip(); - } -}); - -setTimeout(function () { - if (inited) { - return; - } - console.warn('Init time out'); - init(); -}, 5000); - -setInterval(function () { - if (viewer && !document.hidden) { - var materialsMap = {}; - config.materials = viewer.getMaterialsNames().map(function (matName) { - var matConfig = viewer.getMaterial(matName); - // From object URL to file name; - for (var key in matConfig) { - if (filesMapInverse[matConfig[key]]) { - matConfig[key] = filesMapInverse[matConfig[key]]; - } - } - matConfig.targetMeshes = []; - materialsMap[matName] = matConfig; - return matConfig; - }); - - if (viewer.getModelRoot()) { - viewer.getModelRoot().traverse(function (mesh) { - if (mesh.material && materialsMap[mesh.material.name]) { - materialsMap[mesh.material.name].targetMeshes.push(mesh.originalMeshName || mesh.name); - } - }); - } - - showSaveTip(); - __WEBPACK_IMPORTED_MODULE_4__env__["a" /* default */].AUTO_SAVE && __WEBPACK_IMPORTED_MODULE_3__project__["f" /* saveSceneConfig */](config).then(function () { - hideBackgroundProgress(); - console.log('Saved'); - }).catch(hideBackgroundProgress); - } -}, 5000); - - -window.addEventListener('resize', function () { viewer.resize(); }); - -window.addEventListener('dragover', function (e) { - e.preventDefault(); -}); -window.addEventListener('drop', function (e) { - e.preventDefault(); -}); - -$(document).on('click', 'a[href^="http"]', function(event) { - event.preventDefault(); - Object(__WEBPACK_IMPORTED_MODULE_10_vendor_openURL__["a" /* default */])(this.href); -}); - -/***/ }), -/* 68 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_Viewer__ = __webpack_require__(69); -/* unused harmony reexport Viewer */ - - -/* harmony default export */ __webpack_exports__["a"] = ({ - Viewer: __WEBPACK_IMPORTED_MODULE_0__src_Viewer__["a" /* default */], - version: '0.1.1' -}); - -/***/ }), -/* 69 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_claygl_src_Renderer__ = __webpack_require__(27); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_claygl_src_loader_GLTF__ = __webpack_require__(41); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_claygl_src_math_Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_claygl_src_animation_Timeline__ = __webpack_require__(95); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4_claygl_src_util_mesh__ = __webpack_require__(97); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5_claygl_src_async_Task__ = __webpack_require__(60); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6_claygl_src_async_TaskGroup__ = __webpack_require__(98); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7_claygl_src_core_util__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8_claygl_src_Node__ = __webpack_require__(15); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9_claygl_src_Mesh__ = __webpack_require__(16); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10_claygl_src_Material__ = __webpack_require__(10); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_11_claygl_src_geometry_Plane__ = __webpack_require__(33); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_12_claygl_src_Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_13_claygl_src_picking_RayPicking__ = __webpack_require__(99); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_14_claygl_src_core_mixin_notifier__ = __webpack_require__(20); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_15_claygl_src_util_texture__ = __webpack_require__(34); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_16__graphic_RenderMain__ = __webpack_require__(103); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_17__graphic_helper__ = __webpack_require__(26); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_18__graphic_SceneHelper__ = __webpack_require__(135); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_19__defaultSceneConfig__ = __webpack_require__(137); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_20_zrender_src_core_util__ = __webpack_require__(138); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_21__util_getBoundingBoxWithSkinning__ = __webpack_require__(139); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_22_claygl_src_plugin_OrbitControl__ = __webpack_require__(140); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_23__HotspotManager__ = __webpack_require__(142); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_24__graphic_ground_glsl_js__ = __webpack_require__(144); - - - - - - - - - - - - - - - - - - - - - - - - - - - - -__WEBPACK_IMPORTED_MODULE_12_claygl_src_Shader__["a" /* default */].import(__WEBPACK_IMPORTED_MODULE_24__graphic_ground_glsl_js__["a" /* default */]); - -var TEXTURES = ['diffuseMap', 'normalMap', 'emissiveMap', 'metalnessMap', 'roughnessMap', 'specularMap', 'glossinessMap']; - -/** - * @constructor - * @param {HTMLDivElement} dom Root node - * @param {Object} [sceneConfig] - * @param {boolean} [sceneConfig.enablePicking] - * @param {Object} [sceneConfig.shadow] - * @param {boolean} [sceneConfig.devicePixelRatio] - * @param {Object} [sceneConfig.postEffect] - * @param {Object} [sceneConfig.mainLight] - * @param {Object} [sceneConfig.ambientLight] - * @param {Object} [sceneConfig.ambientCubemapLight] - */ -function Viewer(dom, sceneConfig) { - - sceneConfig = __WEBPACK_IMPORTED_MODULE_20_zrender_src_core_util__["a" /* clone */](sceneConfig); - __WEBPACK_IMPORTED_MODULE_20_zrender_src_core_util__["b" /* merge */](sceneConfig, __WEBPACK_IMPORTED_MODULE_19__defaultSceneConfig__["a" /* default */]); - - this.init(dom, sceneConfig); -} - -Viewer.prototype.init = function (dom, opts) { - opts = opts || {}; - - /** - * @type {HTMLDivElement} - */ - this.root = dom; - - /** - * @private - */ - this._timeline = new __WEBPACK_IMPORTED_MODULE_3_claygl_src_animation_Timeline__["a" /* default */](); - - var renderer = new __WEBPACK_IMPORTED_MODULE_0_claygl_src_Renderer__["a" /* default */]({ - devicePixelRatio: opts.devicePixelRatio || window.devicePixelRatio - }); - dom.appendChild(renderer.canvas); - renderer.canvas.style.cssText = 'position:absolute;left:0;top:0'; - - /** - * @private - */ - this._renderer = renderer; - - this._renderMain = new __WEBPACK_IMPORTED_MODULE_16__graphic_RenderMain__["a" /* default */](renderer, opts.shadow, 'perspective'); - this._renderMain.afterRenderScene = (function (renderer, scene, camera) { - this.trigger('renderscene', renderer, scene, camera); - }).bind(this); - this._renderMain.afterRenderAll = (function (renderer, scene, camera) { - this.trigger('afterrender', renderer, scene, camera); - }).bind(this); - this._renderMain.preZ = opts.preZ || false; - - var cameraControl = this._cameraControl = new __WEBPACK_IMPORTED_MODULE_22_claygl_src_plugin_OrbitControl__["a" /* default */]({ - renderer: renderer, - timeline: this._timeline, - domElement: dom - }); - cameraControl.target = this._renderMain.camera; - cameraControl.init(); - - this._hotspotManager = new __WEBPACK_IMPORTED_MODULE_23__HotspotManager__["a" /* default */]({ - dom: dom, - renderer: renderer, - camera: this._renderMain.camera - }); - - /** - * List of skeletons - */ - this._skeletons = []; - /** - * List of animation clips - */ - this._clips = []; - - /** - * List of takes. - */ - this._takes = []; - - /** - * Map of materials - */ - this._materialsMap = {}; - - this._sceneHelper = new __WEBPACK_IMPORTED_MODULE_18__graphic_SceneHelper__["a" /* default */](this._renderMain.scene); - this._sceneHelper.initLight(this._renderMain.scene); - - this.resize(); - - if (opts.postEffect) { - this.setPostEffect(opts.postEffect); - } - if (opts.mainLight) { - this.setMainLight(opts.mainLight); - } - if (opts.secondaryLight) { - this.setSecondaryLight(opts.secondaryLight); - } - if (opts.tertiaryLight) { - this.setTertiaryLight(opts.tertiaryLight); - } - if (opts.ambientCubemapLight) { - this.setAmbientCubemapLight(opts.ambientCubemapLight); - } - if (opts.ambientLight) { - this.setAmbientLight(opts.ambientLight); - } - if (opts.environment) { - this.setEnvironment(opts.environment); - } - - this._createGround(); - if (opts.ground) { - this.setGround(opts.ground); - } - - this.setCameraControl({ - distance: 20, - minDisntance: 2, - maxDistance: 100, - center: [0, 0, 0] - }); - - this._enablePicking = opts.picking || false; - - this._initHandlers(); - - cameraControl.on('update', function () { - this.trigger('updatecamera', { - center: cameraControl.getCenter(), - alpha: cameraControl.getAlpha(), - beta: cameraControl.getBeta(), - distance: cameraControl.getDistance() - }); - - this.refresh(); - }, this); - -}; - -Viewer.prototype._createGround = function () { - var groundMesh = new __WEBPACK_IMPORTED_MODULE_9_claygl_src_Mesh__["a" /* default */]({ - isGround: true, - material: new __WEBPACK_IMPORTED_MODULE_10_claygl_src_Material__["a" /* default */]({ - shader: new __WEBPACK_IMPORTED_MODULE_12_claygl_src_Shader__["a" /* default */]({ - vertex: __WEBPACK_IMPORTED_MODULE_12_claygl_src_Shader__["a" /* default */].source('qmv.ground.vertex'), - fragment: __WEBPACK_IMPORTED_MODULE_12_claygl_src_Shader__["a" /* default */].source('qmv.ground.fragment') - }), - transparent: true - }), - castShadow: false, - geometry: new __WEBPACK_IMPORTED_MODULE_11_claygl_src_geometry_Plane__["a" /* default */]() - }); - groundMesh.material.set('color', [1, 1, 1, 1]); - groundMesh.scale.set(40, 40, 1); - groundMesh.rotation.rotateX(-Math.PI / 2); - this._groundMesh = groundMesh; - - this._renderMain.scene.add(groundMesh); -}; - -Viewer.prototype._addModel = function (modelNode, nodes, skeletons, clips) { - // Remove previous loaded - this.removeModel(); - - this._renderMain.scene.add(modelNode); - - this._skeletons = skeletons.slice(); - this._modelNode = modelNode; - - this._setAnimationClips(clips); - - // Not save if glTF has only animation info - if (nodes && nodes.length) { - this._nodes = nodes; - } - var materialsMap = {}; - modelNode.traverse(function (node) { - // Save material - if (node.material) { - var material = node.material; - // Avoid name duplicate - materialsMap[material.name] = materialsMap[material.name] || []; - materialsMap[material.name].push(material); - } - }, this); - this._materialsMap = materialsMap; - - this._updateMaterialsSRGB(); - - this._stopAccumulating(); -}; - -Viewer.prototype._removeAnimationClips = function () { - this._clips.forEach(function (clip) { - this._timeline.removeClip(clip); - }, this); - this._clips = []; - this._takes = []; -}; - -Viewer.prototype._setAnimationClips = function (clips) { - var self = this; - function refresh() { - self.refresh(); - } - clips.forEach(function (clip) { - clip.tracks.forEach(function (track) { - if (!track.target) { - track.target = this._nodes[track.targetNodeIndex]; - } - }, this); - clip.onframe = refresh; - - this._timeline.addClip(clip); - - this._takes.push({ - name: clip.name, - range: [0, clip.life], - clip: clip - }); - }, this); - - this._clips = clips.slice(); -}; - -Viewer.prototype._initHandlers = function () { - - this._picking = new __WEBPACK_IMPORTED_MODULE_13_claygl_src_picking_RayPicking__["a" /* default */]({ - renderer: this._renderer, - scene: this._renderMain.scene, - camera: this._renderMain.camera - }); - - this._clickHandler = this._clickHandler.bind(this); - this._mouseDownHandler = this._mouseDownHandler.bind(this); - - this.root.addEventListener('mousedown', this._mouseDownHandler); - this.root.addEventListener('click', this._clickHandler); -}; - -Viewer.prototype._mouseDownHandler = function (e) { - this._startX = e.clientX; - this._startY = e.clientY; -}; - -Viewer.prototype._clickHandler = function (e) { - if (!this._enablePicking && !this._renderMain.isDOFEnabled()) { - return; - } - var dx = e.clientX - this._startX; - var dy = e.clientY - this._startY; - if (Math.sqrt(dx * dx + dy * dy) >= 40) { - return; - } - - var result = this._picking.pick(e.clientX, e.clientY, true); - - if (result && !result.target.isGround) { - this._renderMain.setDOFFocusOnPoint(result.distance); - this.trigger('doffocus', result); - - this._selectResult = result; - this.trigger('select', result); - - this.refresh(); - } - else { - if (this._selectResult) { - this.trigger('unselect', this._selectResult); - } - this._selectResult = null; - } -}; - -/** - * Enable picking - */ -Viewer.prototype.enablePicking = function () { - this._enablePicking = true; -}; -/** - * Disable picking - */ -Viewer.prototype.disablePicking = function () { - this._enablePicking = false; -}; -/** - * Model coordinate system is y up. - */ -Viewer.prototype.setModelUpAxis = function (upAxis) { - var modelNode = this._modelNode; - if (!modelNode) { - return; - } - modelNode.position.set(0, 0, 0); - modelNode.scale.set(1, 1, 1); - modelNode.rotation.identity(); - if (upAxis.toLowerCase() === 'z') { - modelNode.rotation.identity().rotateX(-Math.PI / 2); - } - - this.autoFitModel(); -}; -Viewer.prototype.setTextureFlipY = function (flipY) { - if (!this._modelNode) { - return; - } - for (var key in this._materialsMap) { - for (var i = 0; i < this._materialsMap[key].length; i++) { - var mat = this._materialsMap[key][i]; - for (var k = 0; k < TEXTURES.length; k++) { - var tex = mat.get(TEXTURES[k]); - if (tex) { - tex.flipY = flipY; - tex.dirty(); - } - } - } - } - this.refresh(); -}; - /** - * Resize the viewport - */ -Viewer.prototype.resize = function () { - var renderer = this._renderer; - renderer.resize(this.root.clientWidth, this.root.clientHeight); - this._renderMain.setViewport(0, 0, renderer.getWidth(), renderer.getHeight(), renderer.getDevicePixelRatio()); - - this.refresh(); -}; - -/** - * Scale model to auto fit the camera. - */ -Viewer.prototype.autoFitModel = function (fitSize) { - fitSize = fitSize || 10; - if (this._modelNode) { - this.setPose(10); - this._modelNode.update(); - // Update skeleton after model node transform updated. - this._skeletons.forEach(function (skeleton) { - skeleton.update(); - }); - var bbox = Object(__WEBPACK_IMPORTED_MODULE_21__util_getBoundingBoxWithSkinning__["a" /* default */])(this._modelNode); - - var size = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_math_Vector3__["a" /* default */](); - size.copy(bbox.max).sub(bbox.min); - - var center = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_math_Vector3__["a" /* default */](); - center.copy(bbox.max).add(bbox.min).scale(0.5); - - // scale may be NaN if mesh is a plane. - var scale = fitSize / Math.max(size.x, size.y, size.z) || 1; - - this._modelNode.scale.set(scale, scale, scale); - this._modelNode.position.copy(center).scale(-scale); - this._modelNode.update(); - - this._hotspotManager.setBoundingBox(bbox.min.array, bbox.max.array); - - // FIXME, Do it in the renderer? - this._modelNode.traverse(function (mesh) { - if (mesh.isSkinnedMesh()) { - mesh.geometry.boundingBox.applyTransform(this._modelNode.worldTransform); - } - }, this); - - // Fit the ground - this._groundMesh.position.y = -size.y * scale / 2; - - this.refresh(); - } -}; - -/** - * Load glTF model resource - * @param {string|Object} gltfFile Model url or json - * @param {Object} [opts] - * @param {Object} [opts.shader='lambert'] 'basic'|'lambert'|'standard' - * @param {boolean} [opts.includeTexture=true] - * @param {Object} [opts.files] Pre-read files map - * @param {Array.} [opts.buffers] - * @param {boolean} [opts.upAxis='y'] Change model to y up if upAxis is 'z' - * @param {boolean} [opts.textureFlipY=false] - * @param {boolean} [opts.regenerateNormal=false] If regenerate per vertex normal. - */ -Viewer.prototype.loadModel = function (gltfFile, opts) { - opts = opts || {}; - if (!gltfFile) { - throw new Error('URL of model is not provided'); - } - var shaderName = opts.shader || 'standard'; - - var pathResolver = null; - if (opts.files) { - pathResolver = function (uri) { - if (uri.match(/^data:(.*?)base64,/)) { - return uri; - } - uri = uri.replace(/[\\\/]+/g, '/'); - var fileName = uri.substr(uri.lastIndexOf('/') + 1); - if (opts.files[fileName]) { - return opts.files[fileName]; - } - else { - return fileName || ''; - } - }; - } - var loaderOpts = { - rootNode: new __WEBPACK_IMPORTED_MODULE_8_claygl_src_Node__["a" /* default */](), - shader: 'clay.' + shaderName, - textureRootPath: opts.textureRootPath, - bufferRootPath: opts.bufferRootPath, - crossOrigin: 'Anonymous', - includeTexture: opts.includeTexture == null ? true : opts.includeTexture, - textureFlipY: opts.textureFlipY - }; - if (pathResolver) { - loaderOpts.resolveTexturePath = - loaderOpts.resolveBinaryPath = pathResolver; - } - - var loader = new __WEBPACK_IMPORTED_MODULE_1_claygl_src_loader_GLTF__["a" /* default */](loaderOpts); - if (typeof gltfFile === 'string') { - loader.load(gltfFile); - } - else if (gltfFile instanceof ArrayBuffer) { - loader.parseBinary(gltfFile); - } - else { - loader.parse(gltfFile, opts.buffers); - } - - if (opts.upAxis && opts.upAxis.toLowerCase() === 'z') { - loader.rootNode.rotation.rotateX(-Math.PI / 2); - } - - var task = new __WEBPACK_IMPORTED_MODULE_5_claygl_src_async_Task__["a" /* default */](); - - var vertexCount = 0; - var triangleCount = 0; - var nodeCount = 0; - - loader.success(function (res) { - res.rootNode.traverse(function (mesh) { - nodeCount++; - if (mesh.geometry) { - triangleCount += mesh.geometry.triangleCount; - vertexCount += mesh.geometry.vertexCount; - } - }); - this._preprocessModel(res.rootNode, opts); - - this._addModel(res.rootNode, res.nodes, res.skeletons, res.clips); - - this.autoFitModel(); - - var stat = { - triangleCount: triangleCount, - vertexCount: vertexCount, - nodeCount: nodeCount, - meshCount: Object.keys(res.meshes).length, - materialCount: Object.keys(res.materials).length, - textureCount: Object.keys(res.textures).length - }; - - task.trigger('loadmodel', stat); - - var loadingTextures = []; - __WEBPACK_IMPORTED_MODULE_7_claygl_src_core_util__["a" /* default */].each(res.textures, function (texture) { - if (!texture.isRenderable()) { - loadingTextures.push(texture); - } - }); - var taskGroup = new __WEBPACK_IMPORTED_MODULE_6_claygl_src_async_TaskGroup__["a" /* default */](); - taskGroup.allSettled(loadingTextures).success(function () { - this._convertToPOT(); - this._convertBumpToNormal(); - task.trigger('ready'); - this.refresh(); - }, this); - - this.refresh(); - }, this); - loader.error(function () { - task.trigger('error'); - }); - - this._textureFlipY = opts.textureFlipY; - this._shaderName = shaderName; - - return task; -}; - -Viewer.prototype._convertBumpToNormal = function () { - for (var key in this._materialsMap) { - for (var i = 0; i < this._materialsMap[key].length; i++) { - var mat = this._materialsMap[key][i]; - var normalTexture = mat.get('normalMap'); - if (normalTexture && __WEBPACK_IMPORTED_MODULE_15_claygl_src_util_texture__["a" /* default */].isHeightImage(normalTexture.image)) { - var normalImage = __WEBPACK_IMPORTED_MODULE_15_claygl_src_util_texture__["a" /* default */].heightToNormal(normalTexture.image); - normalImage.srcImage = normalTexture.image; - normalTexture.image = normalImage; - normalTexture.dirty(); - } - } - } -}; - -Viewer.prototype._convertToPOT = function () { - this._modelNode.traverse(function (mesh) { - if (mesh.material) { - var hasNPOT = false; - var needsConvert = false; - for (var i = 0; i < TEXTURES.length; i++) { - var tex = mesh.material.get(TEXTURES[i]); - if (tex && !tex.isPowerOfTwo()) { - hasNPOT = true; - break; - } - } - if (hasNPOT) { - var texcoordVal = mesh.geometry.attributes.texcoord0.value || []; - for (var i = 0; i < texcoordVal.length; i++) { - var st = texcoordVal[i]; - if (st > 1 || st < 0) { - needsConvert = true; - break; - } - } - } - if (needsConvert) { - for (var i = 0; i < TEXTURES.length; i++) { - var tex = mesh.material.get(TEXTURES[i]); - if (tex) { - __WEBPACK_IMPORTED_MODULE_17__graphic_helper__["a" /* default */].convertTextureToPowerOfTwo(tex); - } - } - } - } - }); -}; - -/** - * Remove current loaded model - */ -Viewer.prototype.removeModel = function () { - var prevModelNode = this._modelNode; - if (prevModelNode) { - this._renderer.disposeNode(prevModelNode); - this._renderMain.scene.remove(prevModelNode); - this._modelNode = null; - this.refresh(); - } - this._removeAnimationClips(); - this._materialsMap = {}; - this._nodes = []; - this._skeletons = []; -}; - -/** - * Return scene. - * @return {clay.Scene} - */ -Viewer.prototype.getScene = function () { - return this._renderMain.scene; -}; - -/** - * @return {clay.Node} - */ -Viewer.prototype.getModelRoot = function () { - return this._modelNode; -}; - -Viewer.prototype._preprocessModel = function (rootNode, opts) { - - var alphaCutoff = opts.alphaCutoff; - var doubleSided = opts.doubleSided; - - var meshNeedsSplit = []; - rootNode.traverse(function (mesh) { - if (mesh.skeleton) { - meshNeedsSplit.push(mesh); - } - }); - meshNeedsSplit.forEach(function (mesh) { - var newNode = __WEBPACK_IMPORTED_MODULE_4_claygl_src_util_mesh__["a" /* default */].splitByJoints(mesh, 15, true); - if (newNode !== mesh) { - newNode.eachChild(function (mesh) { - mesh.originalMeshName = newNode.name; - }); - } - }, this); - rootNode.traverse(function (mesh) { - if (mesh.geometry) { - // TODO Shared geometry? face normal? - if (opts.regenerateNormal) { - mesh.geometry.generateVertexNormals(); - } - mesh.geometry.updateBoundingBox(); - if (doubleSided != null) { - mesh.culling = !doubleSided; - } - } - if (mesh.material) { - mesh.material.define('fragment', 'DIFFUSEMAP_ALPHA_ALPHA'); - mesh.material.define('fragment', 'ALPHA_TEST'); - if (doubleSided != null) { - mesh.material[doubleSided ? 'define' : 'undefine']('fragment', 'DOUBLE_SIDED'); - } - mesh.material.precision = 'mediump'; - - if (alphaCutoff != null) { - mesh.material.set('alphaCutoff', alphaCutoff); - } - - // Transparent mesh not cast shadow - if (mesh.material.transparent) { - mesh.castShadow = false; - } - } - }); - -}; - -/** - * Load animation glTF - * @param {string} url - */ -Viewer.prototype.loadAnimation = function (url) { - var loader = new __WEBPACK_IMPORTED_MODULE_1_claygl_src_loader_GLTF__["a" /* default */]({ - rootNode: new __WEBPACK_IMPORTED_MODULE_8_claygl_src_Node__["a" /* default */](), - crossOrigin: 'Anonymous' - }); - loader.load(url); - loader.success(function (res) { - this._removeAnimationClips(); - this._setAnimationClips(res.clips); - }, this); - - return loader; -}; - -/** - * Pause animation - */ -Viewer.prototype.pauseAnimation = function () { - this._clips.forEach(function (clip) { - clip.pause(); - }); -}; - -Viewer.prototype.stopAnimation = function () { - this._clips.forEach(function (clip) { - this._timeline.removeClip(clip); - }, this); -}; - -/** - * Resume animation - */ -Viewer.prototype.resumeAnimation = function () { - this._clips.forEach(function (clip) { - clip.resume(); - }); -}; - -/** - * @param {Object} [opts] - * @param {number} [opts.distance] - * @param {number} [opts.minDistance] - * @param {number} [opts.maxDistance] - * @param {number} [opts.alpha] - * @param {number} [opts.beta] - * @param {number} [opts.minAlpha] - * @param {number} [opts.maxAlpha] - * @param {number} [opts.minBeta] - * @param {number} [opts.maxBeta] - * @param {number} [opts.rotateSensitivity] - * @param {number} [opts.panSensitivity] - * @param {number} [opts.zoomSensitivity] - */ -Viewer.prototype.setCameraControl = function (opts) { - this._cameraControl.setOption(opts); - this.refresh(); -}; - -/** - * @param {Object} [opts] - * @param {number} [opts.intensity] - * @param {string} [opts.color] - * @param {number} [opts.alpha] - * @param {number} [opts.beta] - * @param {number} [opts.shadow] - * @param {number} [opts.shadowQuality] - */ -Viewer.prototype.setMainLight = function (opts) { - this._sceneHelper.updateMainLight(opts, this); - this.refresh(); -}; - -/** - * @param {Object} [opts] - * @param {number} [opts.intensity] - * @param {string} [opts.color] - * @param {number} [opts.alpha] - * @param {number} [opts.beta] - * @param {number} [opts.shadow] - * @param {number} [opts.shadowQuality] - */ -Viewer.prototype.setSecondaryLight = function (opts) { - this._sceneHelper.updateSecondaryLight(opts, this); - this.refresh(); -}; - -/** - * @param {Object} [opts] - * @param {number} [opts.intensity] - * @param {string} [opts.color] - * @param {number} [opts.alpha] - * @param {number} [opts.beta] - * @param {number} [opts.shadow] - * @param {number} [opts.shadowQuality] - */ -Viewer.prototype.setTertiaryLight = function (opts) { - this._sceneHelper.updateTertiaryLight(opts, this); - this.refresh(); -}; - -/** - * @param {Object} [opts] - * @param {number} [opts.intensity] - * @param {string} [opts.color] - */ -Viewer.prototype.setAmbientLight = function (opts) { - this._sceneHelper.updateAmbientLight(opts, this); - this.refresh(); -}; -/** - * @param {Object} [opts] - * @param {Object} [opts.texture] - * @param {Object} [opts.exposure] - * @param {number} [opts.diffuseIntensity] - * @param {number} [opts.specularIntensity] - */ -Viewer.prototype.setAmbientCubemapLight = function (opts) { - this._sceneHelper.updateAmbientCubemapLight(opts, this); - this.refresh(); -}; - -/** - * @param {string} envUrl - */ -Viewer.prototype.setEnvironment = function (envUrl) { - this._sceneHelper.updateSkybox(envUrl, this._renderMain.isLinearSpace(), this); -}; - -/** - * @param {string} matName - * @param {Object} materialCfg - * @param {boolean} [materialCfg.transparent] - * @param {boolean} [materialCfg.alphaCutoff] - * @param {boolean} [materialCfg.metalness] - * @param {boolean} [materialCfg.roughness] - */ -Viewer.prototype.setMaterial = function (matName, materialCfg) { - materialCfg = materialCfg || {}; - var materials = this._materialsMap[matName]; - var app = this; - var textureFlipY = this._textureFlipY; - if (!materials || !materials.length) { - console.warn('Material %s not exits', matName); - return; - } - - function haveTexture(val) { - return val && val !== 'none'; - } - - var enabledTextures = materials[0].getEnabledTextures(); - - function addTexture(propName) { - // Not change if texture name is not in the config. - if (propName in materialCfg) { - var idx = enabledTextures.indexOf(propName); - if (haveTexture(materialCfg[propName])) { - var texture = __WEBPACK_IMPORTED_MODULE_17__graphic_helper__["a" /* default */].loadTexture(materialCfg[propName], app, { - flipY: textureFlipY, - anisotropic: 8 - }, function (texture) { - if (propName === 'normalMap' && __WEBPACK_IMPORTED_MODULE_15_claygl_src_util_texture__["a" /* default */].isHeightImage(texture.image)) { - var normalImage = __WEBPACK_IMPORTED_MODULE_15_claygl_src_util_texture__["a" /* default */].heightToNormal(texture.image); - normalImage.srcImage = texture.image; - texture.image = normalImage; - } - app.refresh(); - }); - // Enable texture. - if (idx < 0) { - enabledTextures.push(propName); - } - textures[propName] = texture; - } - else { - // Disable texture. - if (idx >= 0) { - enabledTextures.splice(idx, 1); - } - - textures[propName] = null; - } - } - } - var textures = {}; - ['diffuseMap', 'normalMap', 'parallaxOcclusionMap', 'emissiveMap'].forEach(function (propName) { - addTexture(propName); - }, this); - if (materials[0].isDefined('fragment', 'USE_METALNESS')) { - ['metalnessMap', 'roughnessMap'].forEach(function (propName) { - addTexture(propName); - }, this); - } - else { - ['specularMap', 'glossinessMap'].forEach(function (propName) { - addTexture(propName); - }, this); - } - - if (textures.normalMap || textures.parallaxOcclusionMap) { - this._modelNode.traverse(function (mesh) { - if (mesh.material && mesh.material.name === matName) { - if (!mesh.geometry.attributes.tangent.value) { - mesh.geometry.generateTangents(); - } - } - }); - } - materials.forEach(function (mat) { - if (materialCfg.transparent != null) { - mat.transparent = !!materialCfg.transparent; - mat.depthMask = !materialCfg.transparent; - } - ['color', 'emission', 'specularColor'].forEach(function (propName) { - if (materialCfg[propName] != null) { - mat.set(propName, __WEBPACK_IMPORTED_MODULE_17__graphic_helper__["a" /* default */].parseColor(materialCfg[propName])); - } - }); - ['alpha', 'alphaCutoff', 'metalness', 'roughness', 'glossiness', 'emissionIntensity', 'uvRepeat', 'parallaxOcclusionScale'].forEach(function (propName) { - if (materialCfg[propName] != null) { - mat.set(propName, materialCfg[propName]); - } - }); - mat.disableTexturesAll(); - - for (var texName in textures) { - mat.set(texName, textures[texName]); - } - - mat.enableTexture(enabledTextures); - }, this); - this.refresh(); -}; - -/** - * @param {string} name - */ -Viewer.prototype.getMaterial = function (name) { - var materials = this._materialsMap[name]; - if (!materials) { - console.warn('Material %s not exits', name); - return; - } - var mat = materials[0]; - var materialCfg = { - name: name - }; - ['color', 'emission'].forEach(function (propName) { - materialCfg[propName] = __WEBPACK_IMPORTED_MODULE_17__graphic_helper__["a" /* default */].stringifyColor(mat.get(propName), 'hex'); - }); - ['alpha', 'alphaCutoff', 'emissionIntensity', 'uvRepeat', 'parallaxOcclusionScale'].forEach(function (propName) { - materialCfg[propName] = mat.get(propName); - }); - function getTextureUri(propName) { - var texture = mat.get(propName); - if (!texture) { - return ''; - } - var image = texture.image; - while (image.srcImage) { - image = image.srcImage; - } - return (image && image.src) || ''; - } - ['diffuseMap', 'normalMap', 'parallaxOcclusionMap', 'emissiveMap'].forEach(function (propName) { - materialCfg[propName] = getTextureUri(propName); - }); - if (mat.isDefined('fragment', 'USE_METALNESS')) { - ['metalness', 'roughness'].forEach(function (propName) { - materialCfg[propName] = mat.get(propName); - }); - ['metalnessMap', 'roughnessMap'].forEach(function (propName) { - materialCfg[propName] = getTextureUri(propName); - }); - materialCfg.type = 'pbrMetallicRoughness'; - } - else { - materialCfg.specularColor = __WEBPACK_IMPORTED_MODULE_17__graphic_helper__["a" /* default */].stringifyColor(mat.get('specularColor'), 'hex'); - materialCfg.glossiness = mat.get('glossiness'); - ['specularMap', 'glossinessMap'].forEach(function (propName) { - materialCfg[propName] = getTextureUri(propName); - }); - materialCfg.type = 'pbrSpecularGlossiness'; - } - - return materialCfg; -}; - -/** - * @param {Object} opts - * @param {boolean} [opts.show] - */ -Viewer.prototype.setGround = function (opts) { - this._groundMesh.invisible = !opts.show; - this.refresh(); -}; - -/** - * @return {Array.} - */ -Viewer.prototype.getMaterialsNames = function () { - return Object.keys(this._materialsMap); -}; - -/** - * @param {Object} opts - */ -Viewer.prototype.setPostEffect = function (opts) { - this._renderMain.setPostEffect(opts); - - this._updateMaterialsSRGB(); - this.refresh(); -}; - -/** - * Start loop. - */ -Viewer.prototype.start = function () { - if (this._disposed) { - console.warn('Viewer already disposed'); - return; - } - - this._timeline.start(); - this._timeline.on('frame', this._loop, this); -}; - -/** - * Stop loop. - */ -Viewer.prototype.stop = function () { - this._timeline.stop(); - this._timeline.off('frame', this._loop); -}; - -/** - * Add html tip - */ -Viewer.prototype.addHotspot = function (position, tipHTML) { - return this._hotspotManager.add(position, tipHTML); -}; - -Viewer.prototype.setPose = function (time) { - this._clips.forEach(function (clip) { - clip.setTime(time); - }); - this.refresh(); -}; - -/** - * Get duration of clip - */ -Viewer.prototype.getAnimationDuration = function () { - var maxLife = 0; - this._clips.forEach(function (clip) { - maxLife = Math.max(clip.life, maxLife); - }); - return maxLife; -}; - - -Viewer.prototype.refresh = function () { - this._needsRefresh = true; -}; - -Viewer.prototype.getRenderer = function () { - return this._renderer; -}; - -Viewer.prototype._updateMaterialsSRGB = function () { - var isLinearSpace = this._renderMain.isLinearSpace(); - for (var name in this._materialsMap) { - var materials = this._materialsMap[name]; - for (var i = 0; i < materials.length; i++) { - materials[i][isLinearSpace ? 'define' : 'undefine']('fragment', 'SRGB_DECODE'); - } - } -}; - -Viewer.prototype._loop = function (deltaTime) { - if (this._disposed) { - return; - } - if (!this._needsRefresh) { - return; - } - - this._needsRefresh = false; - - this._renderMain.prepareRender(); - this._renderMain.render(); - // this._renderer.render(this._renderMain.scene, this._renderMain.camera); - - this._startAccumulating(); - - this._hotspotManager.update(); -}; - -var accumulatingId = 1; -Viewer.prototype._stopAccumulating = function () { - this._accumulatingId = 0; - clearTimeout(this._accumulatingTimeout); -}; - -Viewer.prototype._startAccumulating = function (immediate) { - var self = this; - this._stopAccumulating(); - - var needsAccumulate = self._renderMain.needsAccumulate(); - if (!needsAccumulate) { - return; - } - - function accumulate(id) { - if (!self._accumulatingId || id !== self._accumulatingId || self._disposed) { - return; - } - - var isFinished = self._renderMain.isAccumulateFinished() && needsAccumulate; - - if (!isFinished) { - self._renderMain.render(true); - - if (immediate) { - accumulate(id); - } - else { - requestAnimationFrame(function () { - accumulate(id); - }); - } - } - } - - this._accumulatingId = accumulatingId++; - - if (immediate) { - accumulate(self._accumulatingId); - } - else { - this._accumulatingTimeout = setTimeout(function () { - accumulate(self._accumulatingId); - }, 50); - } -}; - -/** - * Dispose viewer. - */ -Viewer.prototype.dispose = function () { - this._disposed = true; - - this._renderer.disposeScene(this._renderMain.scene); - this._renderMain.dispose(this._renderer); - this._sceneHelper.dispose(this._renderer); - - this._renderer.dispose(); - this._cameraControl.dispose(); - this.root.removeEventListener('mousedown', this._mouseDownHandler); - this.root.removeEventListener('click', this._clickHandler); - this.root.innerHTML = ''; - - this.off('select'); - this.off('doffocus'); - this.off('unselect'); - this.off('afterrender'); - this.off('updatecamera'); - - this.stop(); -}; - -__WEBPACK_IMPORTED_MODULE_7_claygl_src_core_util__["a" /* default */].extend(Viewer.prototype, __WEBPACK_IMPORTED_MODULE_14_claygl_src_core_mixin_notifier__["a" /* default */]); - -/* harmony default export */ __webpack_exports__["a"] = (Viewer); - - - - - - -/***/ }), -/* 70 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/** - * Extend a sub class from base class - * @param {object|Function} makeDefaultOpt default option of this sub class, method of the sub can use this.xxx to access this option - * @param {Function} [initialize] Initialize after the sub class is instantiated - * @param {Object} [proto] Prototype methods/properties of the sub class - * @memberOf clay.core.mixin.extend - * @return {Function} - */ -function derive(makeDefaultOpt, initialize/*optional*/, proto/*optional*/) { - - if (typeof initialize == 'object') { - proto = initialize; - initialize = null; - } - - var _super = this; - - var propList; - if (!(makeDefaultOpt instanceof Function)) { - // Optimize the property iterate if it have been fixed - propList = []; - for (var propName in makeDefaultOpt) { - if (makeDefaultOpt.hasOwnProperty(propName)) { - propList.push(propName); - } - } - } - - var sub = function(options) { - - // call super constructor - _super.apply(this, arguments); - - if (makeDefaultOpt instanceof Function) { - // Invoke makeDefaultOpt each time if it is a function, So we can make sure each - // property in the object will not be shared by mutiple instances - extend(this, makeDefaultOpt.call(this, options)); - } - else { - extendWithPropList(this, makeDefaultOpt, propList); - } - - if (this.constructor === sub) { - // Initialize function will be called in the order of inherit - var initializers = sub.__initializers__; - for (var i = 0; i < initializers.length; i++) { - initializers[i].apply(this, arguments); - } - } - }; - // save super constructor - sub.__super__ = _super; - // Initialize function will be called after all the super constructor is called - if (!_super.__initializers__) { - sub.__initializers__ = []; - } else { - sub.__initializers__ = _super.__initializers__.slice(); - } - if (initialize) { - sub.__initializers__.push(initialize); - } - - var Ctor = function() {}; - Ctor.prototype = _super.prototype; - sub.prototype = new Ctor(); - sub.prototype.constructor = sub; - extend(sub.prototype, proto); - - // extend the derive method as a static method; - sub.extend = _super.extend; - - // DEPCRATED - sub.derive = _super.extend; - - return sub; -} - -function extend(target, source) { - if (!source) { - return; - } - for (var name in source) { - if (source.hasOwnProperty(name)) { - target[name] = source[name]; - } - } -} - -function extendWithPropList(target, source, propList) { - for (var i = 0; i < propList.length; i++) { - var propName = propList[i]; - target[propName] = source[propName]; - } -} - -/** - * @alias clay.core.mixin.extend - * @mixin - */ -/* harmony default export */ __webpack_exports__["a"] = ({ - - extend: derive, - - // DEPCRATED - derive: derive -}); - - -/***/ }), -/* 71 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -var EXTENSION_LIST = [ - 'OES_texture_float', - 'OES_texture_half_float', - 'OES_texture_float_linear', - 'OES_texture_half_float_linear', - 'OES_standard_derivatives', - 'OES_vertex_array_object', - 'OES_element_index_uint', - 'WEBGL_compressed_texture_s3tc', - 'WEBGL_depth_texture', - 'EXT_texture_filter_anisotropic', - 'EXT_shader_texture_lod', - 'WEBGL_draw_buffers', - 'EXT_frag_depth', - 'EXT_sRGB' -]; - -var PARAMETER_NAMES = [ - 'MAX_TEXTURE_SIZE', - 'MAX_CUBE_MAP_TEXTURE_SIZE' -]; - -function GLInfo(_gl) { - var extensions = {}; - var parameters = {}; - - // Get webgl extension - for (var i = 0; i < EXTENSION_LIST.length; i++) { - var extName = EXTENSION_LIST[i]; - createExtension(extName); - } - // Get parameters - for (var i = 0; i < PARAMETER_NAMES.length; i++) { - var name = PARAMETER_NAMES[i]; - parameters[name] = _gl.getParameter(_gl[name]); - } - - this.getExtension = function (name) { - if (!(name in extensions)) { - createExtension(name); - } - return extensions[name]; - }; - - this.getParameter = function (name) { - return parameters[name]; - }; - - function createExtension(name) { - var ext = _gl.getExtension(name); - if (!ext) { - ext = _gl.getExtension('MOZ_' + name); - } - if (!ext) { - ext = _gl.getExtension('WEBKIT_' + name); - } - extensions[name] = ext; - } -} - -/* harmony default export */ __webpack_exports__["a"] = (GLInfo); - - -/***/ }), -/* 72 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_LRU__ = __webpack_require__(73); -/** - * @namespace clay.core.color - */ - - -var colorUtil = {}; - -var kCSSColorTable = { - 'transparent': [0,0,0,0], 'aliceblue': [240,248,255,1], - 'antiquewhite': [250,235,215,1], 'aqua': [0,255,255,1], - 'aquamarine': [127,255,212,1], 'azure': [240,255,255,1], - 'beige': [245,245,220,1], 'bisque': [255,228,196,1], - 'black': [0,0,0,1], 'blanchedalmond': [255,235,205,1], - 'blue': [0,0,255,1], 'blueviolet': [138,43,226,1], - 'brown': [165,42,42,1], 'burlywood': [222,184,135,1], - 'cadetblue': [95,158,160,1], 'chartreuse': [127,255,0,1], - 'chocolate': [210,105,30,1], 'coral': [255,127,80,1], - 'cornflowerblue': [100,149,237,1], 'cornsilk': [255,248,220,1], - 'crimson': [220,20,60,1], 'cyan': [0,255,255,1], - 'darkblue': [0,0,139,1], 'darkcyan': [0,139,139,1], - 'darkgoldenrod': [184,134,11,1], 'darkgray': [169,169,169,1], - 'darkgreen': [0,100,0,1], 'darkgrey': [169,169,169,1], - 'darkkhaki': [189,183,107,1], 'darkmagenta': [139,0,139,1], - 'darkolivegreen': [85,107,47,1], 'darkorange': [255,140,0,1], - 'darkorchid': [153,50,204,1], 'darkred': [139,0,0,1], - 'darksalmon': [233,150,122,1], 'darkseagreen': [143,188,143,1], - 'darkslateblue': [72,61,139,1], 'darkslategray': [47,79,79,1], - 'darkslategrey': [47,79,79,1], 'darkturquoise': [0,206,209,1], - 'darkviolet': [148,0,211,1], 'deeppink': [255,20,147,1], - 'deepskyblue': [0,191,255,1], 'dimgray': [105,105,105,1], - 'dimgrey': [105,105,105,1], 'dodgerblue': [30,144,255,1], - 'firebrick': [178,34,34,1], 'floralwhite': [255,250,240,1], - 'forestgreen': [34,139,34,1], 'fuchsia': [255,0,255,1], - 'gainsboro': [220,220,220,1], 'ghostwhite': [248,248,255,1], - 'gold': [255,215,0,1], 'goldenrod': [218,165,32,1], - 'gray': [128,128,128,1], 'green': [0,128,0,1], - 'greenyellow': [173,255,47,1], 'grey': [128,128,128,1], - 'honeydew': [240,255,240,1], 'hotpink': [255,105,180,1], - 'indianred': [205,92,92,1], 'indigo': [75,0,130,1], - 'ivory': [255,255,240,1], 'khaki': [240,230,140,1], - 'lavender': [230,230,250,1], 'lavenderblush': [255,240,245,1], - 'lawngreen': [124,252,0,1], 'lemonchiffon': [255,250,205,1], - 'lightblue': [173,216,230,1], 'lightcoral': [240,128,128,1], - 'lightcyan': [224,255,255,1], 'lightgoldenrodyellow': [250,250,210,1], - 'lightgray': [211,211,211,1], 'lightgreen': [144,238,144,1], - 'lightgrey': [211,211,211,1], 'lightpink': [255,182,193,1], - 'lightsalmon': [255,160,122,1], 'lightseagreen': [32,178,170,1], - 'lightskyblue': [135,206,250,1], 'lightslategray': [119,136,153,1], - 'lightslategrey': [119,136,153,1], 'lightsteelblue': [176,196,222,1], - 'lightyellow': [255,255,224,1], 'lime': [0,255,0,1], - 'limegreen': [50,205,50,1], 'linen': [250,240,230,1], - 'magenta': [255,0,255,1], 'maroon': [128,0,0,1], - 'mediumaquamarine': [102,205,170,1], 'mediumblue': [0,0,205,1], - 'mediumorchid': [186,85,211,1], 'mediumpurple': [147,112,219,1], - 'mediumseagreen': [60,179,113,1], 'mediumslateblue': [123,104,238,1], - 'mediumspringgreen': [0,250,154,1], 'mediumturquoise': [72,209,204,1], - 'mediumvioletred': [199,21,133,1], 'midnightblue': [25,25,112,1], - 'mintcream': [245,255,250,1], 'mistyrose': [255,228,225,1], - 'moccasin': [255,228,181,1], 'navajowhite': [255,222,173,1], - 'navy': [0,0,128,1], 'oldlace': [253,245,230,1], - 'olive': [128,128,0,1], 'olivedrab': [107,142,35,1], - 'orange': [255,165,0,1], 'orangered': [255,69,0,1], - 'orchid': [218,112,214,1], 'palegoldenrod': [238,232,170,1], - 'palegreen': [152,251,152,1], 'paleturquoise': [175,238,238,1], - 'palevioletred': [219,112,147,1], 'papayawhip': [255,239,213,1], - 'peachpuff': [255,218,185,1], 'peru': [205,133,63,1], - 'pink': [255,192,203,1], 'plum': [221,160,221,1], - 'powderblue': [176,224,230,1], 'purple': [128,0,128,1], - 'red': [255,0,0,1], 'rosybrown': [188,143,143,1], - 'royalblue': [65,105,225,1], 'saddlebrown': [139,69,19,1], - 'salmon': [250,128,114,1], 'sandybrown': [244,164,96,1], - 'seagreen': [46,139,87,1], 'seashell': [255,245,238,1], - 'sienna': [160,82,45,1], 'silver': [192,192,192,1], - 'skyblue': [135,206,235,1], 'slateblue': [106,90,205,1], - 'slategray': [112,128,144,1], 'slategrey': [112,128,144,1], - 'snow': [255,250,250,1], 'springgreen': [0,255,127,1], - 'steelblue': [70,130,180,1], 'tan': [210,180,140,1], - 'teal': [0,128,128,1], 'thistle': [216,191,216,1], - 'tomato': [255,99,71,1], 'turquoise': [64,224,208,1], - 'violet': [238,130,238,1], 'wheat': [245,222,179,1], - 'white': [255,255,255,1], 'whitesmoke': [245,245,245,1], - 'yellow': [255,255,0,1], 'yellowgreen': [154,205,50,1] -}; - -function clampCssByte(i) { // Clamp to integer 0 .. 255. - i = Math.round(i); // Seems to be what Chrome does (vs truncation). - return i < 0 ? 0 : i > 255 ? 255 : i; -} - -function clampCssAngle(i) { // Clamp to integer 0 .. 360. - i = Math.round(i); // Seems to be what Chrome does (vs truncation). - return i < 0 ? 0 : i > 360 ? 360 : i; -} - -function clampCssFloat(f) { // Clamp to float 0.0 .. 1.0. - return f < 0 ? 0 : f > 1 ? 1 : f; -} - -function parseCssInt(str) { // int or percentage. - if (str.length && str.charAt(str.length - 1) === '%') { - return clampCssByte(parseFloat(str) / 100 * 255); - } - return clampCssByte(parseInt(str, 10)); -} - -function parseCssFloat(str) { // float or percentage. - if (str.length && str.charAt(str.length - 1) === '%') { - return clampCssFloat(parseFloat(str) / 100); - } - return clampCssFloat(parseFloat(str)); -} - -function cssHueToRgb(m1, m2, h) { - if (h < 0) { - h += 1; - } - else if (h > 1) { - h -= 1; - } - - if (h * 6 < 1) { - return m1 + (m2 - m1) * h * 6; - } - if (h * 2 < 1) { - return m2; - } - if (h * 3 < 2) { - return m1 + (m2 - m1) * (2/3 - h) * 6; - } - return m1; -} - -function lerpNumber(a, b, p) { - return a + (b - a) * p; -} - -function setRgba(out, r, g, b, a) { - out[0] = r; out[1] = g; out[2] = b; out[3] = a; - return out; -} -function copyRgba(out, a) { - out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; - return out; -} - -var colorCache = new __WEBPACK_IMPORTED_MODULE_0__core_LRU__["a" /* default */](20); -var lastRemovedArr = null; - -function putToCache(colorStr, rgbaArr) { - // Reuse removed array - if (lastRemovedArr) { - copyRgba(lastRemovedArr, rgbaArr); - } - lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice())); -} - -/** - * @name clay.core.color.parse - * @param {string} colorStr - * @param {Array.} out - * @return {Array.} - */ -colorUtil.parse = function (colorStr, rgbaArr) { - if (!colorStr) { - return; - } - rgbaArr = rgbaArr || []; - - var cached = colorCache.get(colorStr); - if (cached) { - return copyRgba(rgbaArr, cached); - } - - // colorStr may be not string - colorStr = colorStr + ''; - // Remove all whitespace, not compliant, but should just be more accepting. - var str = colorStr.replace(/ /g, '').toLowerCase(); - - // Color keywords (and transparent) lookup. - if (str in kCSSColorTable) { - copyRgba(rgbaArr, kCSSColorTable[str]); - putToCache(colorStr, rgbaArr); - return rgbaArr; - } - - // #abc and #abc123 syntax. - if (str.charAt(0) === '#') { - if (str.length === 4) { - var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. - if (!(iv >= 0 && iv <= 0xfff)) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; // Covers NaN. - } - setRgba(rgbaArr, - ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8), - (iv & 0xf0) | ((iv & 0xf0) >> 4), - (iv & 0xf) | ((iv & 0xf) << 4), - 1 - ); - putToCache(colorStr, rgbaArr); - return rgbaArr; - } - else if (str.length === 7) { - var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. - if (!(iv >= 0 && iv <= 0xffffff)) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; // Covers NaN. - } - setRgba(rgbaArr, - (iv & 0xff0000) >> 16, - (iv & 0xff00) >> 8, - iv & 0xff, - 1 - ); - putToCache(colorStr, rgbaArr); - return rgbaArr; - } - - return; - } - var op = str.indexOf('('), ep = str.indexOf(')'); - if (op !== -1 && ep + 1 === str.length) { - var fname = str.substr(0, op); - var params = str.substr(op + 1, ep - (op + 1)).split(','); - var alpha = 1; // To allow case fallthrough. - switch (fname) { - case 'rgba': - if (params.length !== 4) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; - } - alpha = parseCssFloat(params.pop()); // jshint ignore:line - // Fall through. - case 'rgb': - if (params.length !== 3) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; - } - setRgba(rgbaArr, - parseCssInt(params[0]), - parseCssInt(params[1]), - parseCssInt(params[2]), - alpha - ); - putToCache(colorStr, rgbaArr); - return rgbaArr; - case 'hsla': - if (params.length !== 4) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; - } - params[3] = parseCssFloat(params[3]); - hsla2rgba(params, rgbaArr); - putToCache(colorStr, rgbaArr); - return rgbaArr; - case 'hsl': - if (params.length !== 3) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; - } - hsla2rgba(params, rgbaArr); - putToCache(colorStr, rgbaArr); - return rgbaArr; - default: - return; - } - } - - setRgba(rgbaArr, 0, 0, 0, 1); - return; -}; - -colorUtil.parseToFloat = function (colorStr, rgbaArr) { - rgbaArr = colorUtil.parse(colorStr, rgbaArr); - if (!rgbaArr) { - return; - } - rgbaArr[0] /= 255; - rgbaArr[1] /= 255; - rgbaArr[2] /= 255; - return rgbaArr; -} - -/** - * @name clay.core.color.hsla2rgba - * @param {Array.} hsla - * @param {Array.} rgba - * @return {Array.} rgba - */ -function hsla2rgba(hsla, rgba) { - var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360; // 0 .. 1 - // NOTE(deanm): According to the CSS spec s/l should only be - // percentages, but we don't bother and let float or percentage. - var s = parseCssFloat(hsla[1]); - var l = parseCssFloat(hsla[2]); - var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; - var m1 = l * 2 - m2; - - rgba = rgba || []; - setRgba(rgba, - clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255), - clampCssByte(cssHueToRgb(m1, m2, h) * 255), - clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255), - 1 - ); - - if (hsla.length === 4) { - rgba[3] = hsla[3]; - } - - return rgba; -} - -/** - * @name clay.core.color.rgba2hsla - * @param {Array.} rgba - * @return {Array.} hsla - */ -function rgba2hsla(rgba) { - if (!rgba) { - return; - } - - // RGB from 0 to 255 - var R = rgba[0] / 255; - var G = rgba[1] / 255; - var B = rgba[2] / 255; - - var vMin = Math.min(R, G, B); // Min. value of RGB - var vMax = Math.max(R, G, B); // Max. value of RGB - var delta = vMax - vMin; // Delta RGB value - - var L = (vMax + vMin) / 2; - var H; - var S; - // HSL results from 0 to 1 - if (delta === 0) { - H = 0; - S = 0; - } - else { - if (L < 0.5) { - S = delta / (vMax + vMin); - } - else { - S = delta / (2 - vMax - vMin); - } - - var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta; - var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta; - var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta; - - if (R === vMax) { - H = deltaB - deltaG; - } - else if (G === vMax) { - H = (1 / 3) + deltaR - deltaB; - } - else if (B === vMax) { - H = (2 / 3) + deltaG - deltaR; - } - - if (H < 0) { - H += 1; - } - - if (H > 1) { - H -= 1; - } - } - - var hsla = [H * 360, S, L]; - - if (rgba[3] != null) { - hsla.push(rgba[3]); - } - - return hsla; -} - -/** - * @name clay.core.color.lift - * @param {string} color - * @param {number} level - * @return {string} - */ -colorUtil.lift = function (color, level) { - var colorArr = colorUtil.parse(color); - if (colorArr) { - for (var i = 0; i < 3; i++) { - if (level < 0) { - colorArr[i] = colorArr[i] * (1 - level) | 0; - } - else { - colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0; - } - } - return colorUtil.stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb'); - } -} - -/** - * @name clay.core.color.toHex - * @param {string} color - * @return {string} - */ -colorUtil.toHex = function (color) { - var colorArr = colorUtil.parse(color); - if (colorArr) { - return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1); - } -}; - -/** - * Map value to color. Faster than lerp methods because color is represented by rgba array. - * @name clay.core.color - * @param {number} normalizedValue A float between 0 and 1. - * @param {Array.>} colors List of rgba color array - * @param {Array.} [out] Mapped gba color array - * @return {Array.} will be null/undefined if input illegal. - */ -colorUtil.fastLerp = function (normalizedValue, colors, out) { - if (!(colors && colors.length) - || !(normalizedValue >= 0 && normalizedValue <= 1) - ) { - return; - } - - out = out || []; - - var value = normalizedValue * (colors.length - 1); - var leftIndex = Math.floor(value); - var rightIndex = Math.ceil(value); - var leftColor = colors[leftIndex]; - var rightColor = colors[rightIndex]; - var dv = value - leftIndex; - out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)); - out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)); - out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)); - out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv)); - - return out; -} - -colorUtil.fastMapToColor = colorUtil.fastLerp; - -/** - * @param {number} normalizedValue A float between 0 and 1. - * @param {Array.} colors Color list. - * @param {boolean=} fullOutput Default false. - * @return {(string|Object)} Result color. If fullOutput, - * return {color: ..., leftIndex: ..., rightIndex: ..., value: ...}, - */ -colorUtil.lerp = function (normalizedValue, colors, fullOutput) { - if (!(colors && colors.length) - || !(normalizedValue >= 0 && normalizedValue <= 1) - ) { - return; - } - - var value = normalizedValue * (colors.length - 1); - var leftIndex = Math.floor(value); - var rightIndex = Math.ceil(value); - var leftColor = colorUtil.parse(colors[leftIndex]); - var rightColor = colorUtil.parse(colors[rightIndex]); - var dv = value - leftIndex; - - var color = colorUtil.stringify( - [ - clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)), - clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)), - clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)), - clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv)) - ], - 'rgba' - ); - - return fullOutput - ? { - color: color, - leftIndex: leftIndex, - rightIndex: rightIndex, - value: value - } - : color; -} - -/** - * @deprecated - */ -colorUtil.mapToColor = colorUtil.lerp; - -/** - * @name clay.core.color - * @param {string} color - * @param {number=} h 0 ~ 360, ignore when null. - * @param {number=} s 0 ~ 1, ignore when null. - * @param {number=} l 0 ~ 1, ignore when null. - * @return {string} Color string in rgba format. - */ -colorUtil.modifyHSL = function (color, h, s, l) { - color = colorUtil.parse(color); - - if (color) { - color = rgba2hsla(color); - h != null && (color[0] = clampCssAngle(h)); - s != null && (color[1] = parseCssFloat(s)); - l != null && (color[2] = parseCssFloat(l)); - - return colorUtil.stringify(hsla2rgba(color), 'rgba'); - } -} - -/** - * @param {string} color - * @param {number=} alpha 0 ~ 1 - * @return {string} Color string in rgba format. - */ -colorUtil.modifyAlpha = function (color, alpha) { - color = colorUtil.parse(color); - - if (color && alpha != null) { - color[3] = clampCssFloat(alpha); - return colorUtil.stringify(color, 'rgba'); - } -} - -/** - * @param {Array.} arrColor like [12,33,44,0.4] - * @param {string} type 'rgba', 'hsva', ... - * @return {string} Result color. (If input illegal, return undefined). - */ -colorUtil.stringify = function (arrColor, type) { - if (!arrColor || !arrColor.length) { - return; - } - var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2]; - if (type === 'rgba' || type === 'hsva' || type === 'hsla') { - colorStr += ',' + arrColor[3]; - } - return type + '(' + colorStr + ')'; -}; - - - -/* harmony default export */ __webpack_exports__["a"] = (colorUtil); - -/***/ }), -/* 73 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__LinkedList__ = __webpack_require__(74); - - -/** - * LRU Cache - * @constructor - * @alias clay.core.LRU - */ -var LRU = function(maxSize) { - - this._list = new __WEBPACK_IMPORTED_MODULE_0__LinkedList__["a" /* default */](); - - this._map = {}; - - this._maxSize = maxSize || 10; -}; - -/** - * Set cache max size - * @param {number} size - */ -LRU.prototype.setMaxSize = function(size) { - this._maxSize = size; -}; - -/** - * @param {string} key - * @param {} value - */ -LRU.prototype.put = function(key, value) { - if (typeof(this._map[key]) == 'undefined') { - var len = this._list.length(); - if (len >= this._maxSize && len > 0) { - // Remove the least recently used - var leastUsedEntry = this._list.head; - this._list.remove(leastUsedEntry); - delete this._map[leastUsedEntry.key]; - } - - var entry = this._list.insert(value); - entry.key = key; - this._map[key] = entry; - } -}; - -/** - * @param {string} key - * @return {} - */ -LRU.prototype.get = function(key) { - var entry = this._map[key]; - if (typeof(entry) != 'undefined') { - // Put the latest used entry in the tail - if (entry !== this._list.tail) { - this._list.remove(entry); - this._list.insertEntry(entry); - } - - return entry.value; - } -}; - -/** - * @param {string} key - */ -LRU.prototype.remove = function(key) { - var entry = this._map[key]; - if (typeof(entry) != 'undefined') { - delete this._map[key]; - this._list.remove(entry); - } -}; - -/** - * Clear the cache - */ -LRU.prototype.clear = function() { - this._list.clear(); - this._map = {}; -}; - -/* harmony default export */ __webpack_exports__["a"] = (LRU); - - -/***/ }), -/* 74 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/** - * Simple double linked list. Compared with array, it has O(1) remove operation. - * @constructor - * @alias clay.core.LinkedList - */ -var LinkedList = function () { - - /** - * @type {clay.core.LinkedList.Entry} - */ - this.head = null; - - /** - * @type {clay.core.LinkedList.Entry} - */ - this.tail = null; - - this._length = 0; -}; - -/** - * Insert a new value at the tail - * @param {} val - * @return {clay.core.LinkedList.Entry} - */ -LinkedList.prototype.insert = function (val) { - var entry = new LinkedList.Entry(val); - this.insertEntry(entry); - return entry; -}; - -/** - * Insert a new value at idx - * @param {number} idx - * @param {} val - * @return {clay.core.LinkedList.Entry} - */ -LinkedList.prototype.insertAt = function (idx, val) { - if (idx < 0) { - return; - } - var next = this.head; - var cursor = 0; - while (next && cursor != idx) { - next = next.next; - cursor++; - } - if (next) { - var entry = new LinkedList.Entry(val); - var prev = next.prev; - if (!prev) { //next is head - this.head = entry; - } - else { - prev.next = entry; - entry.prev = prev; - } - entry.next = next; - next.prev = entry; - } - else { - this.insert(val); - } -}; - -LinkedList.prototype.insertBeforeEntry = function (val, next) { - var entry = new LinkedList.Entry(val); - var prev = next.prev; - if (!prev) { //next is head - this.head = entry; - } - else { - prev.next = entry; - entry.prev = prev; - } - entry.next = next; - next.prev = entry; - - this._length++; -}; - -/** - * Insert an entry at the tail - * @param {clay.core.LinkedList.Entry} entry - */ -LinkedList.prototype.insertEntry = function (entry) { - if (!this.head) { - this.head = this.tail = entry; - } - else { - this.tail.next = entry; - entry.prev = this.tail; - this.tail = entry; - } - this._length++; -}; - -/** - * Remove entry. - * @param {clay.core.LinkedList.Entry} entry - */ -LinkedList.prototype.remove = function (entry) { - var prev = entry.prev; - var next = entry.next; - if (prev) { - prev.next = next; - } - else { - // Is head - this.head = next; - } - if (next) { - next.prev = prev; - } - else { - // Is tail - this.tail = prev; - } - entry.next = entry.prev = null; - this._length--; -}; - -/** - * Remove entry at index. - * @param {number} idx - * @return {} - */ -LinkedList.prototype.removeAt = function (idx) { - if (idx < 0) { - return; - } - var curr = this.head; - var cursor = 0; - while (curr && cursor != idx) { - curr = curr.next; - cursor++; - } - if (curr) { - this.remove(curr); - return curr.value; - } -}; -/** - * Get head value - * @return {} - */ -LinkedList.prototype.getHead = function () { - if (this.head) { - return this.head.value; - } -}; -/** - * Get tail value - * @return {} - */ -LinkedList.prototype.getTail = function () { - if (this.tail) { - return this.tail.value; - } -}; -/** - * Get value at idx - * @param {number} idx - * @return {} - */ -LinkedList.prototype.getAt = function (idx) { - if (idx < 0) { - return; - } - var curr = this.head; - var cursor = 0; - while (curr && cursor != idx) { - curr = curr.next; - cursor++; - } - return curr.value; -}; - -/** - * @param {} value - * @return {number} - */ -LinkedList.prototype.indexOf = function (value) { - var curr = this.head; - var cursor = 0; - while (curr) { - if (curr.value === value) { - return cursor; - } - curr = curr.next; - cursor++; - } -}; - -/** - * @return {number} - */ -LinkedList.prototype.length = function () { - return this._length; -}; - -/** - * If list is empty - */ -LinkedList.prototype.isEmpty = function () { - return this._length === 0; -}; - -/** - * @param {Function} cb - * @param {} context - */ -LinkedList.prototype.forEach = function (cb, context) { - var curr = this.head; - var idx = 0; - var haveContext = typeof(context) != 'undefined'; - while (curr) { - if (haveContext) { - cb.call(context, curr.value, idx); - } - else { - cb(curr.value, idx); - } - curr = curr.next; - idx++; - } -}; - -/** - * Clear the list - */ -LinkedList.prototype.clear = function () { - this.tail = this.head = null; - this._length = 0; -}; - -/** - * @constructor - * @param {} val - */ -LinkedList.Entry = function (val) { - /** - * @type {} - */ - this.value = val; - - /** - * @type {clay.core.LinkedList.Entry} - */ - this.next = null; - - /** - * @type {clay.core.LinkedList.Entry} - */ - this.prev = null; -}; - -/* harmony default export */ __webpack_exports__["a"] = (LinkedList); - - -/***/ }), -/* 75 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__GLProgram__ = __webpack_require__(76); - - -var loopRegex = /for\s*?\(int\s*?_idx_\s*\=\s*([\w-]+)\;\s*_idx_\s*<\s*([\w-]+);\s*_idx_\s*\+\+\s*\)\s*\{\{([\s\S]+?)(?=\}\})\}\}/g; - -function unrollLoop(shaderStr, defines, lightsNumbers) { - // Loop unroll from three.js, https://github.com/mrdoob/three.js/blob/master/src/renderers/webgl/WebGLProgram.js#L175 - // In some case like shadowMap in loop use 'i' to index value much slower. - - // Loop use _idx_ and increased with _idx_++ will be unrolled - // Use {{ }} to match the pair so the if statement will not be affected - // Write like following - // for (int _idx_ = 0; _idx_ < 4; _idx_++) {{ - // vec3 color = texture2D(textures[_idx_], uv).rgb; - // }} - function replace(match, start, end, snippet) { - var unroll = ''; - // Try to treat as define - if (isNaN(start)) { - if (start in defines) { - start = defines[start]; - } - else { - start = lightNumberDefines[start]; - } - } - if (isNaN(end)) { - if (end in defines) { - end = defines[end]; - } - else { - end = lightNumberDefines[end]; - } - } - // TODO Error checking - - for (var idx = parseInt(start); idx < parseInt(end); idx++) { - // PENDING Add scope? - unroll += '{' - + snippet - .replace(/float\s*\(\s*_idx_\s*\)/g, idx.toFixed(1)) - .replace(/_idx_/g, idx) - + '}'; - } - - return unroll; - } - - var lightNumberDefines = {}; - for (var lightType in lightsNumbers) { - lightNumberDefines[lightType + '_COUNT'] = lightsNumbers[lightType]; - } - return shaderStr.replace(loopRegex, replace); -} - -function getDefineCode(defines, lightsNumbers, enabledTextures) { - var defineStr = []; - if (lightsNumbers) { - for (var lightType in lightsNumbers) { - var count = lightsNumbers[lightType]; - if (count > 0) { - defineStr.push('#define ' + lightType.toUpperCase() + '_COUNT ' + count); - } - } - } - if (enabledTextures) { - for (var i = 0; i < enabledTextures.length; i++) { - var symbol = enabledTextures[i]; - defineStr.push('#define ' + symbol.toUpperCase() + '_ENABLED'); - } - } - // Custom Defines - for (var symbol in defines) { - var value = defines[symbol]; - if (value === null) { - defineStr.push('#define ' + symbol); - } - else{ - defineStr.push('#define ' + symbol + ' ' + value.toString()); - } - } - return defineStr.join('\n'); -} - -function getExtensionCode(exts) { - // Extension declaration must before all non-preprocessor codes - // TODO vertex ? extension enum ? - var extensionStr = []; - for (var i = 0; i < exts.length; i++) { - extensionStr.push('#extension GL_' + exts[i] + ' : enable'); - } - return extensionStr.join('\n'); -} - -function getPrecisionCode(precision) { - return ['precision', precision, 'float'].join(' ') + ';\n' - + ['precision', precision, 'int'].join(' ') + ';\n' - // depth texture may have precision problem on iOS device. - + ['precision', precision, 'sampler2D'].join(' ') + ';\n'; -} - -function ProgramManager(renderer) { - this._renderer = renderer; - this._cache = {}; -} - -ProgramManager.prototype.getProgram = function (renderable, material, scene) { - var cache = this._cache; - - var key = 's' + material.shader.shaderID + 'm' + material.programKey; - if (scene) { - key += 'se' + scene.getProgramKey(renderable.lightGroup); - } - if (renderable.isSkinnedMesh()) { - key += ',' + renderable.joints.length; - } - var program = cache[key]; - - if (program) { - return program; - } - - var lightsNumbers = scene ? scene.getLightsNumbers(renderable.lightGroup) : {}; - var renderer = this._renderer; - var _gl = renderer.gl; - var enabledTextures = material.getEnabledTextures(); - var skinDefineCode = ''; - if (renderable.isSkinnedMesh()) { - // TODO Add skinning code? - skinDefineCode = '\n' + getDefineCode({ - SKINNING: null, - JOINT_COUNT: renderable.joints.length - }) + '\n'; - } - // TODO Optimize key generation - // VERTEX - var vertexDefineStr = skinDefineCode + getDefineCode(material.vertexDefines, lightsNumbers, enabledTextures); - // FRAGMENT - var fragmentDefineStr = skinDefineCode + getDefineCode(material.fragmentDefines, lightsNumbers, enabledTextures); - - var vertexCode = vertexDefineStr + '\n' + material.shader.vertex; - var fragmentCode = getExtensionCode([ - // TODO Not hard coded - 'OES_standard_derivatives', - 'EXT_shader_texture_lod' - ]) + '\n' - + getPrecisionCode(material.precision) + '\n' - + fragmentDefineStr + '\n' + material.shader.fragment; - - var finalVertexCode = unrollLoop(vertexCode, material.vertexDefines, lightsNumbers); - var finalFragmentCode = unrollLoop(fragmentCode, material.fragmentDefines, lightsNumbers); - - var program = new __WEBPACK_IMPORTED_MODULE_0__GLProgram__["a" /* default */](); - program.uniformSemantics = material.shader.uniformSemantics; - program.attributes = material.shader.attributes; - var errorMsg = program.buildProgram(_gl, material.shader, finalVertexCode, finalFragmentCode); - program.__error = errorMsg; - - cache[key] = program; - - return program; -}; - -/* harmony default export */ __webpack_exports__["a"] = (ProgramManager); - -/***/ }), -/* 76 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_vendor__ = __webpack_require__(12); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_Base__ = __webpack_require__(1); - - - -var SHADER_STATE_TO_ENABLE = 1; -var SHADER_STATE_KEEP_ENABLE = 2; -var SHADER_STATE_PENDING = 3; - -// Enable attribute operation is global to all programs -// Here saved the list of all enabled attribute index -// http://www.mjbshaw.com/2013/03/webgl-fixing-invalidoperation.html -var enabledAttributeList = {}; - -// some util functions -function addLineNumbers(string) { - var chunks = string.split('\n'); - for (var i = 0, il = chunks.length; i < il; i ++) { - // Chrome reports shader errors on lines - // starting counting from 1 - chunks[i] = (i + 1) + ': ' + chunks[i]; - } - return chunks.join('\n'); -} - -// Return true or error msg if error happened -function checkShaderErrorMsg(_gl, shader, shaderString) { - if (!_gl.getShaderParameter(shader, _gl.COMPILE_STATUS)) { - return [_gl.getShaderInfoLog(shader), addLineNumbers(shaderString)].join('\n'); - } -} - -var GLProgram = __WEBPACK_IMPORTED_MODULE_1__core_Base__["a" /* default */].extend({ - - uniformSemantics: {}, - attributes: {} - -}, function () { - this._locations = {}; - - this._textureSlot = 0; - - this._program = null; -}, { - - bind: function (renderer) { - this._textureSlot = 0; - renderer.gl.useProgram(this._program); - }, - - hasUniform: function (symbol) { - var location = this._locations[symbol]; - return location !== null && location !== undefined; - }, - - useTextureSlot: function (renderer, texture, slot) { - if (texture) { - renderer.gl.activeTexture(renderer.gl.TEXTURE0 + slot); - // Maybe texture is not loaded yet; - if (texture.isRenderable()) { - texture.bind(renderer); - } - else { - // Bind texture to null - texture.unbind(renderer); - } - } - }, - - currentTextureSlot: function () { - return this._textureSlot; - }, - - resetTextureSlot: function (slot) { - this._textureSlot = slot || 0; - }, - - takeCurrentTextureSlot: function (renderer, texture) { - var textureSlot = this._textureSlot; - - this.useTextureSlot(renderer, texture, textureSlot); - - this._textureSlot++; - - return textureSlot; - }, - - setUniform: function (_gl, type, symbol, value) { - var locationMap = this._locations; - var location = locationMap[symbol]; - // Uniform is not existed in the shader - if (location === null || location === undefined) { - return false; - } - switch (type) { - case 'm4': - // The matrix must be created by glmatrix and can pass it directly. - _gl.uniformMatrix4fv(location, false, value); - break; - case '2i': - _gl.uniform2i(location, value[0], value[1]); - break; - case '2f': - _gl.uniform2f(location, value[0], value[1]); - break; - case '3i': - _gl.uniform3i(location, value[0], value[1], value[2]); - break; - case '3f': - _gl.uniform3f(location, value[0], value[1], value[2]); - break; - case '4i': - _gl.uniform4i(location, value[0], value[1], value[2], value[3]); - break; - case '4f': - _gl.uniform4f(location, value[0], value[1], value[2], value[3]); - break; - case '1i': - _gl.uniform1i(location, value); - break; - case '1f': - _gl.uniform1f(location, value); - break; - case '1fv': - _gl.uniform1fv(location, value); - break; - case '1iv': - _gl.uniform1iv(location, value); - break; - case '2iv': - _gl.uniform2iv(location, value); - break; - case '2fv': - _gl.uniform2fv(location, value); - break; - case '3iv': - _gl.uniform3iv(location, value); - break; - case '3fv': - _gl.uniform3fv(location, value); - break; - case '4iv': - _gl.uniform4iv(location, value); - break; - case '4fv': - _gl.uniform4fv(location, value); - break; - case 'm2': - case 'm2v': - _gl.uniformMatrix2fv(location, false, value); - break; - case 'm3': - case 'm3v': - _gl.uniformMatrix3fv(location, false, value); - break; - case 'm4v': - // Raw value - if (Array.isArray(value)) { - var array = new __WEBPACK_IMPORTED_MODULE_0__core_vendor__["a" /* default */].Float32Array(value.length * 16); - var cursor = 0; - for (var i = 0; i < value.length; i++) { - var item = value[i]; - for (var j = 0; j < 16; j++) { - array[cursor++] = item[j]; - } - } - _gl.uniformMatrix4fv(location, false, array); - } - else if (value instanceof __WEBPACK_IMPORTED_MODULE_0__core_vendor__["a" /* default */].Float32Array) { // ArrayBufferView - _gl.uniformMatrix4fv(location, false, value); - } - break; - } - return true; - }, - - setUniformOfSemantic: function (_gl, semantic, val) { - var semanticInfo = this.uniformSemantics[semantic]; - if (semanticInfo) { - return this.setUniform(_gl, semanticInfo.type, semanticInfo.symbol, val); - } - return false; - }, - - // Used for creating VAO - // Enable the attributes passed in and disable the rest - // Example Usage: - // enableAttributes(renderer, ["position", "texcoords"]) - enableAttributes: function (renderer, attribList, vao) { - var _gl = renderer.gl; - var program = this._program; - - var locationMap = this._locations; - - var enabledAttributeListInContext; - if (vao) { - enabledAttributeListInContext = vao.__enabledAttributeList; - } - else { - enabledAttributeListInContext = enabledAttributeList[renderer.__uid__]; - } - if (!enabledAttributeListInContext) { - // In vertex array object context - // PENDING Each vao object needs to enable attributes again? - if (vao) { - enabledAttributeListInContext - = vao.__enabledAttributeList - = []; - } - else { - enabledAttributeListInContext - = enabledAttributeList[renderer.__uid__] - = []; - } - } - var locationList = []; - for (var i = 0; i < attribList.length; i++) { - var symbol = attribList[i]; - if (!this.attributes[symbol]) { - locationList[i] = -1; - continue; - } - var location = locationMap[symbol]; - if (location == null) { - location = _gl.getAttribLocation(program, symbol); - // Attrib location is a number from 0 to ... - if (location === -1) { - locationList[i] = -1; - continue; - } - locationMap[symbol] = location; - } - locationList[i] = location; - - if (!enabledAttributeListInContext[location]) { - enabledAttributeListInContext[location] = SHADER_STATE_TO_ENABLE; - } - else { - enabledAttributeListInContext[location] = SHADER_STATE_KEEP_ENABLE; - } - } - - for (var i = 0; i < enabledAttributeListInContext.length; i++) { - switch(enabledAttributeListInContext[i]){ - case SHADER_STATE_TO_ENABLE: - _gl.enableVertexAttribArray(i); - enabledAttributeListInContext[i] = SHADER_STATE_PENDING; - break; - case SHADER_STATE_KEEP_ENABLE: - enabledAttributeListInContext[i] = SHADER_STATE_PENDING; - break; - // Expired - case SHADER_STATE_PENDING: - _gl.disableVertexAttribArray(i); - enabledAttributeListInContext[i] = 0; - break; - } - } - - return locationList; - }, - - buildProgram: function (_gl, shader, vertexShaderCode, fragmentShaderCode) { - var vertexShader = _gl.createShader(_gl.VERTEX_SHADER); - var program = _gl.createProgram(); - - _gl.shaderSource(vertexShader, vertexShaderCode); - _gl.compileShader(vertexShader); - - var fragmentShader = _gl.createShader(_gl.FRAGMENT_SHADER); - _gl.shaderSource(fragmentShader, fragmentShaderCode); - _gl.compileShader(fragmentShader); - - var msg = checkShaderErrorMsg(_gl, vertexShader, vertexShaderCode); - if (msg) { - return msg; - } - msg = checkShaderErrorMsg(_gl, fragmentShader, fragmentShaderCode); - if (msg) { - return msg; - } - - _gl.attachShader(program, vertexShader); - _gl.attachShader(program, fragmentShader); - // Force the position bind to location 0; - if (shader.attributeSemantics['POSITION']) { - _gl.bindAttribLocation(program, 0, shader.attributeSemantics['POSITION'].symbol); - } - else { - // Else choose an attribute and bind to location 0; - var keys = Object.keys(this.attributes); - _gl.bindAttribLocation(program, 0, keys[0]); - } - - _gl.linkProgram(program); - - if (!_gl.getProgramParameter(program, _gl.LINK_STATUS)) { - return 'Could not link program\n' + 'VALIDATE_STATUS: ' + _gl.getProgramParameter(program, _gl.VALIDATE_STATUS) + ', gl error [' + _gl.getError() + ']'; - } - - // Cache uniform locations - for (var i = 0; i < shader.uniforms.length; i++) { - var uniformSymbol = shader.uniforms[i]; - this._locations[uniformSymbol] = _gl.getUniformLocation(program, uniformSymbol); - } - - _gl.deleteShader(vertexShader); - _gl.deleteShader(fragmentShader); - - this._program = program; - - // Save code. - this.vertexCode = vertexShaderCode; - this.fragmentCode = fragmentShaderCode; - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (GLProgram); - -/***/ }), -/* 77 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("vec3 calcAmbientSHLight(int idx, vec3 N) {\n int offset = 9 * idx;\n return ambientSHLightCoefficients[0]\n + ambientSHLightCoefficients[1] * N.x\n + ambientSHLightCoefficients[2] * N.y\n + ambientSHLightCoefficients[3] * N.z\n + ambientSHLightCoefficients[4] * N.x * N.z\n + ambientSHLightCoefficients[5] * N.z * N.y\n + ambientSHLightCoefficients[6] * N.y * N.x\n + ambientSHLightCoefficients[7] * (3.0 * N.z * N.z - 1.0)\n + ambientSHLightCoefficients[8] * (N.x * N.x - N.y * N.y);\n}"); - - -/***/ }), -/* 78 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__dep_glmatrix__); - -var quat = __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix___default.a.quat; - -/** - * @constructor - * @alias clay.math.Quaternion - * @param {number} x - * @param {number} y - * @param {number} z - * @param {number} w - */ -var Quaternion = function (x, y, z, w) { - - x = x || 0; - y = y || 0; - z = z || 0; - w = w === undefined ? 1 : w; - - /** - * Storage of Quaternion, read and write of x, y, z, w will change the values in array - * All methods also operate on the array instead of x, y, z, w components - * @name array - * @type {Float32Array} - * @memberOf clay.math.Quaternion# - */ - this.array = quat.fromValues(x, y, z, w); - - /** - * Dirty flag is used by the Node to determine - * if the matrix is updated to latest - * @name _dirty - * @type {boolean} - * @memberOf clay.math.Quaternion# - */ - this._dirty = true; -}; - -Quaternion.prototype = { - - constructor: Quaternion, - - /** - * Add b to self - * @param {clay.math.Quaternion} b - * @return {clay.math.Quaternion} - */ - add: function (b) { - quat.add(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Calculate the w component from x, y, z component - * @return {clay.math.Quaternion} - */ - calculateW: function () { - quat.calculateW(this.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Set x, y and z components - * @param {number} x - * @param {number} y - * @param {number} z - * @param {number} w - * @return {clay.math.Quaternion} - */ - set: function (x, y, z, w) { - this.array[0] = x; - this.array[1] = y; - this.array[2] = z; - this.array[3] = w; - this._dirty = true; - return this; - }, - - /** - * Set x, y, z and w components from array - * @param {Float32Array|number[]} arr - * @return {clay.math.Quaternion} - */ - setArray: function (arr) { - this.array[0] = arr[0]; - this.array[1] = arr[1]; - this.array[2] = arr[2]; - this.array[3] = arr[3]; - - this._dirty = true; - return this; - }, - - /** - * Clone a new Quaternion - * @return {clay.math.Quaternion} - */ - clone: function () { - return new Quaternion(this.x, this.y, this.z, this.w); - }, - - /** - * Calculates the conjugate of self If the quaternion is normalized, - * this function is faster than invert and produces the same result. - * - * @return {clay.math.Quaternion} - */ - conjugate: function () { - quat.conjugate(this.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Copy from b - * @param {clay.math.Quaternion} b - * @return {clay.math.Quaternion} - */ - copy: function (b) { - quat.copy(this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Dot product of self and b - * @param {clay.math.Quaternion} b - * @return {number} - */ - dot: function (b) { - return quat.dot(this.array, b.array); - }, - - /** - * Set from the given 3x3 rotation matrix - * @param {clay.math.Matrix3} m - * @return {clay.math.Quaternion} - */ - fromMat3: function (m) { - quat.fromMat3(this.array, m.array); - this._dirty = true; - return this; - }, - - /** - * Set from the given 4x4 rotation matrix - * The 4th column and 4th row will be droped - * @param {clay.math.Matrix4} m - * @return {clay.math.Quaternion} - */ - fromMat4: (function () { - var mat3 = __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix___default.a.mat3; - var m3 = mat3.create(); - return function (m) { - mat3.fromMat4(m3, m.array); - // TODO Not like mat4, mat3 in glmatrix seems to be row-based - mat3.transpose(m3, m3); - quat.fromMat3(this.array, m3); - this._dirty = true; - return this; - }; - })(), - - /** - * Set to identity quaternion - * @return {clay.math.Quaternion} - */ - identity: function () { - quat.identity(this.array); - this._dirty = true; - return this; - }, - /** - * Invert self - * @return {clay.math.Quaternion} - */ - invert: function () { - quat.invert(this.array, this.array); - this._dirty = true; - return this; - }, - /** - * Alias of length - * @return {number} - */ - len: function () { - return quat.len(this.array); - }, - - /** - * Calculate the length - * @return {number} - */ - length: function () { - return quat.length(this.array); - }, - - /** - * Linear interpolation between a and b - * @param {clay.math.Quaternion} a - * @param {clay.math.Quaternion} b - * @param {number} t - * @return {clay.math.Quaternion} - */ - lerp: function (a, b, t) { - quat.lerp(this.array, a.array, b.array, t); - this._dirty = true; - return this; - }, - - /** - * Alias for multiply - * @param {clay.math.Quaternion} b - * @return {clay.math.Quaternion} - */ - mul: function (b) { - quat.mul(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Alias for multiplyLeft - * @param {clay.math.Quaternion} a - * @return {clay.math.Quaternion} - */ - mulLeft: function (a) { - quat.multiply(this.array, a.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Mutiply self and b - * @param {clay.math.Quaternion} b - * @return {clay.math.Quaternion} - */ - multiply: function (b) { - quat.multiply(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Mutiply a and self - * Quaternion mutiply is not commutative, so the result of mutiplyLeft is different with multiply. - * @param {clay.math.Quaternion} a - * @return {clay.math.Quaternion} - */ - multiplyLeft: function (a) { - quat.multiply(this.array, a.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Normalize self - * @return {clay.math.Quaternion} - */ - normalize: function () { - quat.normalize(this.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Rotate self by a given radian about X axis - * @param {number} rad - * @return {clay.math.Quaternion} - */ - rotateX: function (rad) { - quat.rotateX(this.array, this.array, rad); - this._dirty = true; - return this; - }, - - /** - * Rotate self by a given radian about Y axis - * @param {number} rad - * @return {clay.math.Quaternion} - */ - rotateY: function (rad) { - quat.rotateY(this.array, this.array, rad); - this._dirty = true; - return this; - }, - - /** - * Rotate self by a given radian about Z axis - * @param {number} rad - * @return {clay.math.Quaternion} - */ - rotateZ: function (rad) { - quat.rotateZ(this.array, this.array, rad); - this._dirty = true; - return this; - }, - - /** - * Sets self to represent the shortest rotation from Vector3 a to Vector3 b. - * a and b needs to be normalized - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {clay.math.Quaternion} - */ - rotationTo: function (a, b) { - quat.rotationTo(this.array, a.array, b.array); - this._dirty = true; - return this; - }, - /** - * Sets self with values corresponding to the given axes - * @param {clay.math.Vector3} view - * @param {clay.math.Vector3} right - * @param {clay.math.Vector3} up - * @return {clay.math.Quaternion} - */ - setAxes: function (view, right, up) { - quat.setAxes(this.array, view.array, right.array, up.array); - this._dirty = true; - return this; - }, - - /** - * Sets self with a rotation axis and rotation angle - * @param {clay.math.Vector3} axis - * @param {number} rad - * @return {clay.math.Quaternion} - */ - setAxisAngle: function (axis, rad) { - quat.setAxisAngle(this.array, axis.array, rad); - this._dirty = true; - return this; - }, - /** - * Perform spherical linear interpolation between a and b - * @param {clay.math.Quaternion} a - * @param {clay.math.Quaternion} b - * @param {number} t - * @return {clay.math.Quaternion} - */ - slerp: function (a, b, t) { - quat.slerp(this.array, a.array, b.array, t); - this._dirty = true; - return this; - }, - - /** - * Alias for squaredLength - * @return {number} - */ - sqrLen: function () { - return quat.sqrLen(this.array); - }, - - /** - * Squared length of self - * @return {number} - */ - squaredLength: function () { - return quat.squaredLength(this.array); - }, - - /** - * Set from euler - * @param {clay.math.Vector3} v - * @param {String} order - */ - fromEuler: function (v, order) { - return Quaternion.fromEuler(this, v, order); - }, - - toString: function () { - return '[' + Array.prototype.join.call(this.array, ',') + ']'; - }, - - toArray: function () { - return Array.prototype.slice.call(this.array); - } -}; - -var defineProperty = Object.defineProperty; -// Getter and Setter -if (defineProperty) { - - var proto = Quaternion.prototype; - /** - * @name x - * @type {number} - * @memberOf clay.math.Quaternion - * @instance - */ - defineProperty(proto, 'x', { - get: function () { - return this.array[0]; - }, - set: function (value) { - this.array[0] = value; - this._dirty = true; - } - }); - - /** - * @name y - * @type {number} - * @memberOf clay.math.Quaternion - * @instance - */ - defineProperty(proto, 'y', { - get: function () { - return this.array[1]; - }, - set: function (value) { - this.array[1] = value; - this._dirty = true; - } - }); - - /** - * @name z - * @type {number} - * @memberOf clay.math.Quaternion - * @instance - */ - defineProperty(proto, 'z', { - get: function () { - return this.array[2]; - }, - set: function (value) { - this.array[2] = value; - this._dirty = true; - } - }); - - /** - * @name w - * @type {number} - * @memberOf clay.math.Quaternion - * @instance - */ - defineProperty(proto, 'w', { - get: function () { - return this.array[3]; - }, - set: function (value) { - this.array[3] = value; - this._dirty = true; - } - }); -} - -// Supply methods that are not in place - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Quaternion} a - * @param {clay.math.Quaternion} b - * @return {clay.math.Quaternion} - */ -Quaternion.add = function (out, a, b) { - quat.add(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} out - * @param {number} x - * @param {number} y - * @param {number} z - * @param {number} w - * @return {clay.math.Quaternion} - */ -Quaternion.set = function (out, x, y, z, w) { - quat.set(out.array, x, y, z, w); - out._dirty = true; -}; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Quaternion} b - * @return {clay.math.Quaternion} - */ -Quaternion.copy = function (out, b) { - quat.copy(out.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Quaternion} a - * @return {clay.math.Quaternion} - */ -Quaternion.calculateW = function (out, a) { - quat.calculateW(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Quaternion} a - * @return {clay.math.Quaternion} - */ -Quaternion.conjugate = function (out, a) { - quat.conjugate(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} out - * @return {clay.math.Quaternion} - */ -Quaternion.identity = function (out) { - quat.identity(out.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Quaternion} a - * @return {clay.math.Quaternion} - */ -Quaternion.invert = function (out, a) { - quat.invert(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} a - * @param {clay.math.Quaternion} b - * @return {number} - */ -Quaternion.dot = function (a, b) { - return quat.dot(a.array, b.array); -}; - -/** - * @param {clay.math.Quaternion} a - * @return {number} - */ -Quaternion.len = function (a) { - return quat.length(a.array); -}; - -// Quaternion.length = Quaternion.len; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Quaternion} a - * @param {clay.math.Quaternion} b - * @param {number} t - * @return {clay.math.Quaternion} - */ -Quaternion.lerp = function (out, a, b, t) { - quat.lerp(out.array, a.array, b.array, t); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Quaternion} a - * @param {clay.math.Quaternion} b - * @param {number} t - * @return {clay.math.Quaternion} - */ -Quaternion.slerp = function (out, a, b, t) { - quat.slerp(out.array, a.array, b.array, t); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Quaternion} a - * @param {clay.math.Quaternion} b - * @return {clay.math.Quaternion} - */ -Quaternion.mul = function (out, a, b) { - quat.multiply(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @function - * @param {clay.math.Quaternion} out - * @param {clay.math.Quaternion} a - * @param {clay.math.Quaternion} b - * @return {clay.math.Quaternion} - */ -Quaternion.multiply = Quaternion.mul; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Quaternion} a - * @param {number} rad - * @return {clay.math.Quaternion} - */ -Quaternion.rotateX = function (out, a, rad) { - quat.rotateX(out.array, a.array, rad); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Quaternion} a - * @param {number} rad - * @return {clay.math.Quaternion} - */ -Quaternion.rotateY = function (out, a, rad) { - quat.rotateY(out.array, a.array, rad); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Quaternion} a - * @param {number} rad - * @return {clay.math.Quaternion} - */ -Quaternion.rotateZ = function (out, a, rad) { - quat.rotateZ(out.array, a.array, rad); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Vector3} axis - * @param {number} rad - * @return {clay.math.Quaternion} - */ -Quaternion.setAxisAngle = function (out, axis, rad) { - quat.setAxisAngle(out.array, axis.array, rad); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Quaternion} a - * @return {clay.math.Quaternion} - */ -Quaternion.normalize = function (out, a) { - quat.normalize(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} a - * @return {number} - */ -Quaternion.sqrLen = function (a) { - return quat.sqrLen(a.array); -}; - -/** - * @function - * @param {clay.math.Quaternion} a - * @return {number} - */ -Quaternion.squaredLength = Quaternion.sqrLen; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Matrix3} m - * @return {clay.math.Quaternion} - */ -Quaternion.fromMat3 = function (out, m) { - quat.fromMat3(out.array, m.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Vector3} view - * @param {clay.math.Vector3} right - * @param {clay.math.Vector3} up - * @return {clay.math.Quaternion} - */ -Quaternion.setAxes = function (out, view, right, up) { - quat.setAxes(out.array, view.array, right.array, up.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Quaternion} out - * @param {clay.math.Vector3} a - * @param {clay.math.Vector3} b - * @return {clay.math.Quaternion} - */ -Quaternion.rotationTo = function (out, a, b) { - quat.rotationTo(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * Set quaternion from euler - * @param {clay.math.Quaternion} out - * @param {clay.math.Vector3} v - * @param {String} order - */ -Quaternion.fromEuler = function (out, v, order) { - - out._dirty = true; - - v = v.array; - var target = out.array; - var c1 = Math.cos(v[0] / 2); - var c2 = Math.cos(v[1] / 2); - var c3 = Math.cos(v[2] / 2); - var s1 = Math.sin(v[0] / 2); - var s2 = Math.sin(v[1] / 2); - var s3 = Math.sin(v[2] / 2); - - var order = (order || 'XYZ').toUpperCase(); - - // http://www.mathworks.com/matlabcentral/fileexchange/ - // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ - // content/SpinCalc.m - - switch (order) { - case 'XYZ': - target[0] = s1 * c2 * c3 + c1 * s2 * s3; - target[1] = c1 * s2 * c3 - s1 * c2 * s3; - target[2] = c1 * c2 * s3 + s1 * s2 * c3; - target[3] = c1 * c2 * c3 - s1 * s2 * s3; - break; - case 'YXZ': - target[0] = s1 * c2 * c3 + c1 * s2 * s3; - target[1] = c1 * s2 * c3 - s1 * c2 * s3; - target[2] = c1 * c2 * s3 - s1 * s2 * c3; - target[3] = c1 * c2 * c3 + s1 * s2 * s3; - break; - case 'ZXY': - target[0] = s1 * c2 * c3 - c1 * s2 * s3; - target[1] = c1 * s2 * c3 + s1 * c2 * s3; - target[2] = c1 * c2 * s3 + s1 * s2 * c3; - target[3] = c1 * c2 * c3 - s1 * s2 * s3; - break; - case 'ZYX': - target[0] = s1 * c2 * c3 - c1 * s2 * s3; - target[1] = c1 * s2 * c3 + s1 * c2 * s3; - target[2] = c1 * c2 * s3 - s1 * s2 * c3; - target[3] = c1 * c2 * c3 + s1 * s2 * s3; - break; - case 'YZX': - target[0] = s1 * c2 * c3 + c1 * s2 * s3; - target[1] = c1 * s2 * c3 + s1 * c2 * s3; - target[2] = c1 * c2 * s3 - s1 * s2 * c3; - target[3] = c1 * c2 * c3 - s1 * s2 * s3; - break; - case 'XZY': - target[0] = s1 * c2 * c3 - c1 * s2 * s3; - target[1] = c1 * s2 * c3 - s1 * c2 * s3; - target[2] = c1 * c2 * s3 + s1 * s2 * c3; - target[3] = c1 * c2 * c3 + s1 * s2 * s3; - break; - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (Quaternion); - - -/***/ }), -/* 79 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1__dep_glmatrix__); - - -var vec3 = __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default.a.vec3; -var mat4 = __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default.a.mat4; -var vec4 = __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default.a.vec4; - -/** - * @constructor - * @alias clay.math.Plane - * @param {clay.math.Vector3} [normal] - * @param {number} [distance] - */ -var Plane = function(normal, distance) { - /** - * Normal of the plane - * @type {clay.math.Vector3} - */ - this.normal = normal || new __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */](0, 1, 0); - - /** - * Constant of the plane equation, used as distance to the origin - * @type {number} - */ - this.distance = distance || 0; -}; - -Plane.prototype = { - - constructor: Plane, - - /** - * Distance from a given point to the plane - * @param {clay.math.Vector3} point - * @return {number} - */ - distanceToPoint: function(point) { - return vec3.dot(point.array, this.normal.array) - this.distance; - }, - - /** - * Calculate the projection point on the plane - * @param {clay.math.Vector3} point - * @param {clay.math.Vector3} out - * @return {clay.math.Vector3} - */ - projectPoint: function(point, out) { - if (!out) { - out = new __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */](); - } - var d = this.distanceToPoint(point); - vec3.scaleAndAdd(out.array, point.array, this.normal.array, -d); - out._dirty = true; - return out; - }, - - /** - * Normalize the plane's normal and calculate the distance - */ - normalize: function() { - var invLen = 1 / vec3.len(this.normal.array); - vec3.scale(this.normal.array, invLen); - this.distance *= invLen; - }, - - /** - * If the plane intersect a frustum - * @param {clay.math.Frustum} Frustum - * @return {boolean} - */ - intersectFrustum: function(frustum) { - // Check if all coords of frustum is on plane all under plane - var coords = frustum.vertices; - var normal = this.normal.array; - var onPlane = vec3.dot(coords[0].array, normal) > this.distance; - for (var i = 1; i < 8; i++) { - if ((vec3.dot(coords[i].array, normal) > this.distance) != onPlane) { - return true; - } - } - }, - - /** - * Calculate the intersection point between plane and a given line - * @function - * @param {clay.math.Vector3} start start point of line - * @param {clay.math.Vector3} end end point of line - * @param {clay.math.Vector3} [out] - * @return {clay.math.Vector3} - */ - intersectLine: (function() { - var rd = vec3.create(); - return function(start, end, out) { - var d0 = this.distanceToPoint(start); - var d1 = this.distanceToPoint(end); - if ((d0 > 0 && d1 > 0) || (d0 < 0 && d1 < 0)) { - return null; - } - // Ray intersection - var pn = this.normal.array; - var d = this.distance; - var ro = start.array; - // direction - vec3.sub(rd, end.array, start.array); - vec3.normalize(rd, rd); - - var divider = vec3.dot(pn, rd); - // ray is parallel to the plane - if (divider === 0) { - return null; - } - if (!out) { - out = new __WEBPACK_IMPORTED_MODULE_0__Vector3__["a" /* default */](); - } - var t = (vec3.dot(pn, ro) - d) / divider; - vec3.scaleAndAdd(out.array, ro, rd, -t); - out._dirty = true; - return out; - }; - })(), - - /** - * Apply an affine transform matrix to plane - * @function - * @return {clay.math.Matrix4} - */ - applyTransform: (function() { - var inverseTranspose = mat4.create(); - var normalv4 = vec4.create(); - var pointv4 = vec4.create(); - pointv4[3] = 1; - return function(m4) { - m4 = m4.array; - // Transform point on plane - vec3.scale(pointv4, this.normal.array, this.distance); - vec4.transformMat4(pointv4, pointv4, m4); - this.distance = vec3.dot(pointv4, this.normal.array); - // Transform plane normal - mat4.invert(inverseTranspose, m4); - mat4.transpose(inverseTranspose, inverseTranspose); - normalv4[3] = 0; - vec3.copy(normalv4, this.normal.array); - vec4.transformMat4(normalv4, normalv4, inverseTranspose); - vec3.copy(this.normal.array, normalv4); - }; - })(), - - /** - * Copy from another plane - * @param {clay.math.Vector3} plane - */ - copy: function(plane) { - vec3.copy(this.normal.array, plane.normal.array); - this.normal._dirty = true; - this.distance = plane.distance; - }, - - /** - * Clone a new plane - * @return {clay.math.Plane} - */ - clone: function() { - var plane = new Plane(); - plane.copy(this); - return plane; - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (Plane); - - -/***/ }), -/* 80 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Joint__ = __webpack_require__(48); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_2__dep_glmatrix__); - - - - -var quat = __WEBPACK_IMPORTED_MODULE_2__dep_glmatrix___default.a.quat; -var vec3 = __WEBPACK_IMPORTED_MODULE_2__dep_glmatrix___default.a.vec3; -var mat4 = __WEBPACK_IMPORTED_MODULE_2__dep_glmatrix___default.a.mat4; - -/** - * @constructor clay.Skeleton - */ -var Skeleton = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend(function () { - return /** @lends clay.Skeleton# */{ - - /** - * Relative root node that not affect transform of joint. - * @type {clay.Node} - */ - relativeRootNode: null, - /** - * @type {string} - */ - name: '', - - /** - * joints - * @type {Array.} - */ - joints: [], - - _clips: [], - - // Matrix to joint space (relative to root joint) - _invBindPoseMatricesArray: null, - - // Use subarray instead of copy back each time computing matrix - // http://jsperf.com/subarray-vs-copy-for-array-transform/5 - _jointMatricesSubArrays: [], - - // jointMatrix * currentPoseMatrix - // worldTransform is relative to the root bone - // still in model space not world space - _skinMatricesArray: null, - - _skinMatricesSubArrays: [], - - _subSkinMatricesArray: {} - }; -}, -/** @lends clay.Skeleton.prototype */ -{ - - /** - * Add a skinning clip and create a map between clip and skeleton - * @param {clay.animation.SkinningClip} clip - * @param {Object} [mapRule] Map between joint name in skeleton and joint name in clip - */ - addClip: function (clip, mapRule) { - // Clip have been exists in - for (var i = 0; i < this._clips.length; i++) { - if (this._clips[i].clip === clip) { - return; - } - } - // Map the joint index in skeleton to joint pose index in clip - var maps = []; - for (var i = 0; i < this.joints.length; i++) { - maps[i] = -1; - } - // Create avatar - for (var i = 0; i < clip.tracks.length; i++) { - for (var j = 0; j < this.joints.length; j++) { - var joint = this.joints[j]; - var track = clip.tracks[i]; - var jointName = joint.name; - if (mapRule) { - jointName = mapRule[jointName]; - } - if (track.name === jointName) { - maps[j] = i; - break; - } - } - } - - this._clips.push({ - maps: maps, - clip: clip - }); - - return this._clips.length - 1; - }, - - /** - * @param {clay.animation.SkinningClip} clip - */ - removeClip: function (clip) { - var idx = -1; - for (var i = 0; i < this._clips.length; i++) { - if (this._clips[i].clip === clip) { - idx = i; - break; - } - } - if (idx > 0) { - this._clips.splice(idx, 1); - } - }, - /** - * Remove all clips - */ - removeClipsAll: function () { - this._clips = []; - }, - - /** - * Get clip by index - * @param {number} index - */ - getClip: function (index) { - if (this._clips[index]) { - return this._clips[index].clip; - } - }, - - /** - * @return {number} - */ - getClipNumber: function () { - return this._clips.length; - }, - - /** - * Calculate joint matrices from node transform - * @function - */ - updateJointMatrices: (function () { - - var m4 = mat4.create(); - - return function () { - this._invBindPoseMatricesArray = new Float32Array(this.joints.length * 16); - this._skinMatricesArray = new Float32Array(this.joints.length * 16); - - for (var i = 0; i < this.joints.length; i++) { - var joint = this.joints[i]; - // if (this.relativeRootNode) { - // mat4.invert(m4, this.relativeRootNode.worldTransform.array); - // mat4.multiply( - // m4, - // m4, - // joint.node.worldTransform.array - // ); - // mat4.invert(m4, m4); - // } - // else { - mat4.copy(m4, joint.node.worldTransform.array); - mat4.invert(m4, m4); - // } - - var offset = i * 16; - for (var j = 0; j < 16; j++) { - this._invBindPoseMatricesArray[offset + j] = m4[j]; - } - } - - this.updateMatricesSubArrays(); - }; - })(), - - setJointMatricesArray: function (arr) { - this._invBindPoseMatricesArray = arr; - this._skinMatricesArray = new Float32Array(arr.length); - this.updateMatricesSubArrays(); - }, - - updateMatricesSubArrays: function () { - for (var i = 0; i < this.joints.length; i++) { - this._jointMatricesSubArrays[i] = this._invBindPoseMatricesArray.subarray(i * 16, (i+1) * 16); - this._skinMatricesSubArrays[i] = this._skinMatricesArray.subarray(i * 16, (i+1) * 16); - } - }, - - /** - * Update skinning matrices - */ - update: (function () { - // var m4 = mat4.create(); - return function () { - for (var i = 0; i < this.joints.length; i++) { - var joint = this.joints[i]; - mat4.multiply( - this._skinMatricesSubArrays[i], - joint.node.worldTransform.array, - this._jointMatricesSubArrays[i] - ); - - // Joint space is relative to root, if have - // if (this.relativeRootNode) { - // mat4.invert(m4, this.relativeRootNode.worldTransform.array); - // mat4.multiply( - // this._skinMatricesSubArrays[i], - // m4, - // this._skinMatricesSubArrays[i] - // ); - // } - } - }; - })(), - - getSubSkinMatrices: function (meshId, joints) { - var subArray = this._subSkinMatricesArray[meshId]; - if (!subArray) { - subArray - = this._subSkinMatricesArray[meshId] - = new Float32Array(joints.length * 16); - } - var cursor = 0; - for (var i = 0; i < joints.length; i++) { - var idx = joints[i]; - for (var j = 0; j < 16; j++) { - subArray[cursor++] = this._skinMatricesArray[idx * 16 + j]; - } - } - return subArray; - }, - - /** - * Set pose and update skinning matrices - * @param {number} clipIndex - */ - setPose: function (clipIndex) { - if (this._clips[clipIndex]) { - var clip = this._clips[clipIndex].clip; - var maps = this._clips[clipIndex].maps; - - for (var i = 0; i < this.joints.length; i++) { - var joint = this.joints[i]; - if (maps[i] === -1) { - continue; - } - var pose = clip.tracks[maps[i]]; - - // Not update if there is no data. - // PENDING If sync pose.position, pose.rotation, pose.scale - if (pose.channels.position) { - vec3.copy(joint.node.position.array, pose.position); - } - if (pose.channels.rotation) { - quat.copy(joint.node.rotation.array, pose.rotation); - } - if (pose.channels.scale) { - vec3.copy(joint.node.scale.array, pose.scale); - } - - joint.node.position._dirty = true; - joint.node.rotation._dirty = true; - joint.node.scale._dirty = true; - } - } - this.update(); - }, - - clone: function (rootNode, newRootNode) { - var skeleton = new Skeleton(); - skeleton.name = this.name; - - for (var i = 0; i < this.joints.length; i++) { - var newJoint = new __WEBPACK_IMPORTED_MODULE_1__Joint__["a" /* default */](); - newJoint.name = this.joints[i].name; - newJoint.index = this.joints[i].index; - - var path = this.joints[i].node.getPath(rootNode); - var rootNodePath = this.joints[i].rootNode.getPath(rootNode); - - if (path != null && rootNodePath != null) { - newJoint.node = newRootNode.queryNode(path); - } - else { - // PENDING - console.warn('Something wrong in clone, may be the skeleton root nodes is not mounted on the cloned root node.') - } - skeleton.joints.push(newJoint); - } - - if (this._invBindPoseMatricesArray) { - var len = this._invBindPoseMatricesArray.length; - skeleton._invBindPoseMatricesArray = new Float32Array(len); - for (var i = 0; i < len; i++) { - skeleton._invBindPoseMatricesArray[i] = this._invBindPoseMatricesArray[i]; - } - - skeleton._skinMatricesArray = new Float32Array(len); - - skeleton.updateMatricesSubArrays(); - } - - skeleton.update(); - - return skeleton; - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (Skeleton); - - -/***/ }), -/* 81 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Clip__ = __webpack_require__(32); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1__dep_glmatrix__); - - - -var quat = __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default.a.quat; -var vec3 = __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default.a.vec3; - -/** - * - * Animation clip that manage a collection of {@link clay.animation.SamplerTrack} - * @constructor - * @alias clay.animation.TrackClip - * - * @extends clay.animation.Clip - * @param {Object} [opts] - * @param {string} [opts.name] - * @param {Object} [opts.target] - * @param {number} [opts.life] - * @param {number} [opts.delay] - * @param {number} [opts.gap] - * @param {number} [opts.playbackRatio] - * @param {boolean|number} [opts.loop] If loop is a number, it indicate the loop count of animation - * @param {string|Function} [opts.easing] - * @param {Function} [opts.onframe] - * @param {Function} [opts.onfinish] - * @param {Function} [opts.onrestart] - * @param {Array.} [opts.tracks] - */ -var TrackClip = function (opts) { - - opts = opts || {}; - - __WEBPACK_IMPORTED_MODULE_0__Clip__["a" /* default */].call(this, opts); - - /** - * - * @type {clay.animation.SamplerTrack[]} - */ - this.tracks = opts.tracks || []; -}; - -TrackClip.prototype = Object.create(__WEBPACK_IMPORTED_MODULE_0__Clip__["a" /* default */].prototype); - -TrackClip.prototype.constructor = TrackClip; - -TrackClip.prototype.step = function (time, dTime, silent) { - - var ret = __WEBPACK_IMPORTED_MODULE_0__Clip__["a" /* default */].prototype.step.call(this, time, dTime, true); - - if (ret !== 'finish') { - var time = this.getElapsedTime(); - // TODO life may be changed. - if (this._range) { - time = this._range[0] + time; - } - this.setTime(time); - } - - // PENDING Schedule - if (!silent && ret !== 'paused') { - this.fire('frame'); - } - - return ret; -}; - -/** - * @param {Array.} range - */ -TrackClip.prototype.setRange = function (range) { - this.calcLifeFromTracks(); - this._range = range; - if (range) { - range[1] = Math.min(range[1], this.life); - range[0] = Math.min(range[0], this.life); - this.life = (range[1] - range[0]); - } -}; - -TrackClip.prototype.setTime = function (time) { - for (var i = 0; i < this.tracks.length; i++) { - this.tracks[i].setTime(time); - } -}; - -TrackClip.prototype.calcLifeFromTracks = function () { - this.life = 0; - for (var i = 0; i < this.tracks.length; i++) { - this.life = Math.max(this.life, this.tracks[i].getMaxTime()); - } -}; - -/** - * @param {clay.animation.SamplerTrack} jointClip - */ -TrackClip.prototype.addTrack = function (track) { - this.tracks.push(track); -}; - -/** - * @param {clay.animation.SamplerTrack} jointClip - */ -TrackClip.prototype.removeTarck = function (track) { - var idx = this.tracks.indexOf(track); - if (idx >= 0) { - this.tracks.splice(idx, 1); - } -}; - -/** - * @param {number} startTime - * @param {number} endTime - * @param {boolean} isLoop - * @return {clay.animation.TrackClip} - */ -TrackClip.prototype.getSubClip = function (startTime, endTime, isLoop) { - var subClip = new TrackClip({ - name: this.name - }); - - for (var i = 0; i < this.tracks.length; i++) { - var subTrack = this.tracks[i].getSubTrack(startTime, endTime); - subClip.addTrack(subTrack); - } - - if (isLoop !== undefined) { - subClip.setLoop(isLoop); - } - - subClip.life = endTime - startTime; - - return subClip; -}; - -/** - * 1d blending from two skinning clips - * @param {clay.animation.TrackClip} clip1 - * @param {clay.animation.TrackClip} clip2 - * @param {number} w - */ -TrackClip.prototype.blend1D = function (clip1, clip2, w) { - for (var i = 0; i < this.tracks.length; i++) { - var c1 = clip1.tracks[i]; - var c2 = clip2.tracks[i]; - var tClip = this.tracks[i]; - - tClip.blend1D(c1, c2, w); - } -}; - -/** - * Additive blending from two skinning clips - * @param {clay.animation.TrackClip} clip1 - * @param {clay.animation.TrackClip} clip2 - */ -TrackClip.prototype.additiveBlend = function (clip1, clip2) { - for (var i = 0; i < this.tracks.length; i++) { - var c1 = clip1.tracks[i]; - var c2 = clip2.tracks[i]; - var tClip = this.tracks[i]; - - tClip.additiveBlend(c1, c2); - } -}; - -/** - * Subtractive blending from two skinning clips - * @param {clay.animation.TrackClip} clip1 - * @param {clay.animation.TrackClip} clip2 - */ -TrackClip.prototype.subtractiveBlend = function (clip1, clip2) { - for (var i = 0; i < this.tracks.length; i++) { - var c1 = clip1.tracks[i]; - var c2 = clip2.tracks[i]; - var tClip = this.tracks[i]; - - tClip.subtractiveBlend(c1, c2); - } -}; - -/** - * 2D blending from three skinning clips - * @param {clay.animation.TrackClip} clip1 - * @param {clay.animation.TrackClip} clip2 - * @param {clay.animation.TrackClip} clip3 - * @param {number} f - * @param {number} g - */ -TrackClip.prototype.blend2D = function (clip1, clip2, clip3, f, g) { - for (var i = 0; i < this.tracks.length; i++) { - var c1 = clip1.tracks[i]; - var c2 = clip2.tracks[i]; - var c3 = clip3.tracks[i]; - var tClip = this.tracks[i]; - - tClip.blend2D(c1, c2, c3, f, g); - } -}; - -/** - * Copy SRT of all joints clips from another TrackClip - * @param {clay.animation.TrackClip} clip - */ -TrackClip.prototype.copy = function (clip) { - for (var i = 0; i < this.tracks.length; i++) { - var sTrack = clip.tracks[i]; - var tTrack = this.tracks[i]; - - vec3.copy(tTrack.position, sTrack.position); - vec3.copy(tTrack.scale, sTrack.scale); - quat.copy(tTrack.rotation, sTrack.rotation); - } -}; - -TrackClip.prototype.clone = function () { - var clip = __WEBPACK_IMPORTED_MODULE_0__Clip__["a" /* default */].prototype.clone.call(this); - for (var i = 0; i < this.tracks.length; i++) { - clip.addTrack(this.tracks[i].clone()); - } - clip.life = this.life; - return clip; -}; - -/* harmony default export */ __webpack_exports__["a"] = (TrackClip); - - -/***/ }), -/* 82 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__TransformTrack__ = __webpack_require__(83); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1__dep_glmatrix__); -// Sampler clip is especially for the animation sampler in glTF -// Use Typed Array can reduce a lot of heap memory -// -// TODO Sync target transform - - - - -var quat = __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default.a.quat; -var vec3 = __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default.a.vec3; - -// lerp function with offset in large array -function vec3lerp(out, a, b, t, oa, ob) { - var ax = a[oa]; - var ay = a[oa + 1]; - var az = a[oa + 2]; - out[0] = ax + t * (b[ob] - ax); - out[1] = ay + t * (b[ob + 1] - ay); - out[2] = az + t * (b[ob + 2] - az); - - return out; -} - -function quatSlerp(out, a, b, t, oa, ob) { - // benchmarks: - // http://jsperf.com/quaternion-slerp-implementations - - var ax = a[0 + oa], ay = a[1 + oa], az = a[2 + oa], aw = a[3 + oa], - bx = b[0 + ob], by = b[1 + ob], bz = b[2 + ob], bw = b[3 + ob]; - - var omega, cosom, sinom, scale0, scale1; - - // calc cosine - cosom = ax * bx + ay * by + az * bz + aw * bw; - // adjust signs (if necessary) - if (cosom < 0.0) { - cosom = -cosom; - bx = - bx; - by = - by; - bz = - bz; - bw = - bw; - } - // calculate coefficients - if ((1.0 - cosom) > 0.000001) { - // standard case (slerp) - omega = Math.acos(cosom); - sinom = Math.sin(omega); - scale0 = Math.sin((1.0 - t) * omega) / sinom; - scale1 = Math.sin(t * omega) / sinom; - } - else { - // 'from' and 'to' quaternions are very close - // ... so we can do a linear interpolation - scale0 = 1.0 - t; - scale1 = t; - } - // calculate final values - out[0] = scale0 * ax + scale1 * bx; - out[1] = scale0 * ay + scale1 * by; - out[2] = scale0 * az + scale1 * bz; - out[3] = scale0 * aw + scale1 * bw; - - return out; -} - -/** - * SamplerTrack manages `position`, `rotation`, `scale` tracks in animation of single scene node. - * @constructor - * @alias clay.animation.SamplerTrack - * @param {Object} [opts] - * @param {string} [opts.name] Track name - * @param {clay.Node} [opts.target] Target node's transform will updated automatically - */ -var SamplerTrack = function (opts) { - opts = opts || {}; - - this.name = opts.name || ''; - /** - * @param {clay.Node} - */ - this.target = opts.target || null; - /** - * @type {Float32Array} - */ - this.position = vec3.create(); - /** - * Rotation is represented by a quaternion - * @type {Float32Array} - */ - this.rotation = quat.create(); - /** - * @type {Float32Array} - */ - this.scale = vec3.fromValues(1, 1, 1); - - this.channels = { - time: null, - position: null, - rotation: null, - scale: null - }; - - this._cacheKey = 0; - this._cacheTime = 0; -}; - -SamplerTrack.prototype.setTime = function (time) { - if (!this.channels.time) { - return; - } - var channels = this.channels; - var len = channels.time.length; - var key = -1; - // Only one frame - if (len === 1) { - if (channels.rotation) { - quat.copy(this.rotation, channels.rotation); - } - if (channels.position) { - vec3.copy(this.position, channels.position); - } - if (channels.scale) { - vec3.copy(this.scale, channels.scale); - } - return; - } - // Clamp - else if (time <= channels.time[0]) { - time = channels.time[0]; - key = 0; - } - else if (time >= channels.time[len - 1]) { - time = channels.time[len - 1]; - key = len - 2; - } - else { - if (time < this._cacheTime) { - var s = Math.min(len - 1, this._cacheKey + 1); - for (var i = s; i >= 0; i--) { - if (channels.time[i - 1] <= time && channels.time[i] > time) { - key = i - 1; - break; - } - } - } - else { - for (var i = this._cacheKey; i < len - 1; i++) { - if (channels.time[i] <= time && channels.time[i + 1] > time) { - key = i; - break; - } - } - } - } - if (key > -1) { - this._cacheKey = key; - this._cacheTime = time; - var start = key; - var end = key + 1; - var startTime = channels.time[start]; - var endTime = channels.time[end]; - var range = endTime - startTime; - var percent = range === 0 ? 0 : (time - startTime) / range; - - if (channels.rotation) { - quatSlerp(this.rotation, channels.rotation, channels.rotation, percent, start * 4, end * 4); - } - if (channels.position) { - vec3lerp(this.position, channels.position, channels.position, percent, start * 3, end * 3); - } - if (channels.scale) { - vec3lerp(this.scale, channels.scale, channels.scale, percent, start * 3, end * 3); - } - } - // Loop handling - if (key == len - 2) { - this._cacheKey = 0; - this._cacheTime = 0; - } - - this.updateTarget(); -}; - -/** - * Update transform of target node manually - */ -SamplerTrack.prototype.updateTarget = function () { - var channels = this.channels; - if (this.target) { - // Only update target prop if have data. - if (channels.position) { - this.target.position.setArray(this.position); - } - if (channels.rotation) { - this.target.rotation.setArray(this.rotation); - } - if (channels.scale) { - this.target.scale.setArray(this.scale); - } - } -}; - -/** - * @return {number} - */ -SamplerTrack.prototype.getMaxTime = function () { - return this.channels.time[this.channels.time.length - 1]; -}; - -/** - * @param {number} startTime - * @param {number} endTime - * @return {clay.animation.SamplerTrack} - */ -SamplerTrack.prototype.getSubTrack = function (startTime, endTime) { - - var subClip = new SamplerTrack({ - name: this.name - }); - var minTime = this.channels.time[0]; - startTime = Math.min(Math.max(startTime, minTime), this.life); - endTime = Math.min(Math.max(endTime, minTime), this.life); - - var rangeStart = this._findRange(startTime); - var rangeEnd = this._findRange(endTime); - - var count = rangeEnd[0] - rangeStart[0] + 1; - if (rangeStart[1] === 0 && rangeEnd[1] === 0) { - count -= 1; - } - if (this.channels.rotation) { - subClip.channels.rotation = new Float32Array(count * 4); - } - if (this.channels.position) { - subClip.channels.position = new Float32Array(count * 3); - } - if (this.channels.scale) { - subClip.channels.scale = new Float32Array(count * 3); - } - if (this.channels.time) { - subClip.channels.time = new Float32Array(count); - } - // Clip at the start - this.setTime(startTime); - for (var i = 0; i < 3; i++) { - subClip.channels.rotation[i] = this.rotation[i]; - subClip.channels.position[i] = this.position[i]; - subClip.channels.scale[i] = this.scale[i]; - } - subClip.channels.time[0] = 0; - subClip.channels.rotation[3] = this.rotation[3]; - - for (var i = 1; i < count-1; i++) { - var i2; - for (var j = 0; j < 3; j++) { - i2 = rangeStart[0] + i; - subClip.channels.rotation[i * 4 + j] = this.channels.rotation[i2 * 4 + j]; - subClip.channels.position[i * 3 + j] = this.channels.position[i2 * 3 + j]; - subClip.channels.scale[i * 3 + j] = this.channels.scale[i2 * 3 + j]; - } - subClip.channels.time[i] = this.channels.time[i2] - startTime; - subClip.channels.rotation[i * 4 + 3] = this.channels.rotation[i2 * 4 + 3]; - } - // Clip at the end - this.setTime(endTime); - for (var i = 0; i < 3; i++) { - subClip.channels.rotation[(count - 1) * 4 + i] = this.rotation[i]; - subClip.channels.position[(count - 1) * 3 + i] = this.position[i]; - subClip.channels.scale[(count - 1) * 3 + i] = this.scale[i]; - } - subClip.channels.time[(count - 1)] = endTime - startTime; - subClip.channels.rotation[(count - 1) * 4 + 3] = this.rotation[3]; - - // TODO set back ? - subClip.life = endTime - startTime; - return subClip; -}; - -SamplerTrack.prototype._findRange = function (time) { - var channels = this.channels; - var len = channels.time.length; - var start = -1; - for (var i = 0; i < len - 1; i++) { - if (channels.time[i] <= time && channels.time[i+1] > time) { - start = i; - } - } - var percent = 0; - if (start >= 0) { - var startTime = channels.time[start]; - var endTime = channels.time[start+1]; - var percent = (time-startTime) / (endTime-startTime); - } - // Percent [0, 1) - return [start, percent]; -}; - -/** - * 1D blending between two clips - * @function - * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c1 - * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c2 - * @param {number} w - */ -SamplerTrack.prototype.blend1D = __WEBPACK_IMPORTED_MODULE_0__TransformTrack__["a" /* default */].prototype.blend1D; -/** - * 2D blending between three clips - * @function - * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c1 - * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c2 - * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c3 - * @param {number} f - * @param {number} g - */ -SamplerTrack.prototype.blend2D = __WEBPACK_IMPORTED_MODULE_0__TransformTrack__["a" /* default */].prototype.blend2D; -/** - * Additive blending between two clips - * @function - * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c1 - * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c2 - */ -SamplerTrack.prototype.additiveBlend = __WEBPACK_IMPORTED_MODULE_0__TransformTrack__["a" /* default */].prototype.additiveBlend; -/** - * Subtractive blending between two clips - * @function - * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c1 - * @param {clay.animation.SamplerTrack|clay.animation.TransformTrack} c2 - */ -SamplerTrack.prototype.subtractiveBlend = __WEBPACK_IMPORTED_MODULE_0__TransformTrack__["a" /* default */].prototype.subtractiveBlend; - -/** - * Clone a new SamplerTrack - * @return {clay.animation.SamplerTrack} - */ -SamplerTrack.prototype.clone = function () { - var track = SamplerTrack.prototype.clone.call(this); - track.channels = { - time: this.channels.time || null, - position: this.channels.position || null, - rotation: this.channels.rotation || null, - scale: this.channels.scale || null - }; - vec3.copy(track.position, this.position); - quat.copy(track.rotation, this.rotation); - vec3.copy(track.scale, this.scale); - - track.target = this.target; - track.updateTarget(); - - return track; - -}; - -/* harmony default export */ __webpack_exports__["a"] = (SamplerTrack); - - -/***/ }), -/* 83 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Clip__ = __webpack_require__(32); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1__dep_glmatrix__); - - - -var quat = __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default.a.quat; -var vec3 = __WEBPACK_IMPORTED_MODULE_1__dep_glmatrix___default.a.vec3; - -function keyframeSort(a, b) { - return a.time - b.time; -} - -var TransformTrack = function (opts) { - - this.name = opts.name || ''; - //[{ - // time: //ms - // position: // optional - // rotation: // optional - // scale: // optional - //}] - this.keyFrames = []; - if (opts.keyFrames) { - this.addKeyFrames(opts.keyFrames); - } - - this.position = vec3.create(); - - this.rotation = quat.create(); - - this.scale = vec3.fromValues(1, 1, 1); - - this._cacheKey = 0; - this._cacheTime = 0; -}; - -TransformTrack.prototype = Object.create(__WEBPACK_IMPORTED_MODULE_0__Clip__["a" /* default */].prototype); - -TransformTrack.prototype.constructor = TransformTrack; - -TransformTrack.prototype.step = function (time, dTime, silent) { - - var ret = __WEBPACK_IMPORTED_MODULE_0__Clip__["a" /* default */].prototype.step.call(this, time, dTime, true); - - if (ret !== 'finish') { - this.setTime(this.getElapsedTime()); - } - - // PENDING Schedule - if (!silent && ret !== 'paused') { - this.fire('frame'); - } - - return ret; -}; - -TransformTrack.prototype.setTime = function (time) { - this._interpolateField(time, 'position'); - this._interpolateField(time, 'rotation'); - this._interpolateField(time, 'scale'); -}; - -TransformTrack.prototype.getMaxTime = function () { - var kf = this.keyFrames[this.keyFrames.length - 1]; - return kf ? kf.time : 0; -}; - -TransformTrack.prototype.addKeyFrame = function (kf) { - for (var i = 0; i < this.keyFrames.length - 1; i++) { - var prevFrame = this.keyFrames[i]; - var nextFrame = this.keyFrames[i + 1]; - if (prevFrame.time <= kf.time && nextFrame.time >= kf.time) { - this.keyFrames.splice(i, 0, kf); - return i; - } - } - - this.life = kf.time; - this.keyFrames.push(kf); -}; - -TransformTrack.prototype.addKeyFrames = function (kfs) { - for (var i = 0; i < kfs.length; i++) { - this.keyFrames.push(kfs[i]); - } - - this.keyFrames.sort(keyframeSort); - - this.life = this.keyFrames[this.keyFrames.length - 1].time; -}; - -TransformTrack.prototype._interpolateField = function (time, fieldName) { - var kfs = this.keyFrames; - var len = kfs.length; - var start; - var end; - - if (!kfs.length) { - return; - } - if (time < kfs[0].time || time > kfs[kfs.length-1].time) { - return; - } - if (time < this._cacheTime) { - var s = this._cacheKey >= len-1 ? len-1 : this._cacheKey+1; - for (var i = s; i >= 0; i--) { - if (kfs[i].time <= time && kfs[i][fieldName]) { - start = kfs[i]; - this._cacheKey = i; - this._cacheTime = time; - } else if (kfs[i][fieldName]) { - end = kfs[i]; - break; - } - } - } else { - for (var i = this._cacheKey; i < len; i++) { - if (kfs[i].time <= time && kfs[i][fieldName]) { - start = kfs[i]; - this._cacheKey = i; - this._cacheTime = time; - } else if (kfs[i][fieldName]) { - end = kfs[i]; - break; - } - } - } - - if (start && end) { - var percent = (time - start.time) / (end.time - start.time); - percent = Math.max(Math.min(percent, 1), 0); - if (fieldName === 'rotation') { - quat.slerp(this[fieldName], start[fieldName], end[fieldName], percent); - } else { - vec3.lerp(this[fieldName], start[fieldName], end[fieldName], percent); - } - } else { - this._cacheKey = 0; - this._cacheTime = 0; - } -}; - -TransformTrack.prototype.blend1D = function (t1, t2, w) { - vec3.lerp(this.position, t1.position, t2.position, w); - vec3.lerp(this.scale, t1.scale, t2.scale, w); - quat.slerp(this.rotation, t1.rotation, t2.rotation, w); -}; - -TransformTrack.prototype.blend2D = (function () { - var q1 = quat.create(); - var q2 = quat.create(); - return function (t1, t2, t3, f, g) { - var a = 1 - f - g; - - this.position[0] = t1.position[0] * a + t2.position[0] * f + t3.position[0] * g; - this.position[1] = t1.position[1] * a + t2.position[1] * f + t3.position[1] * g; - this.position[2] = t1.position[2] * a + t2.position[2] * f + t3.position[2] * g; - - this.scale[0] = t1.scale[0] * a + t2.scale[0] * f + t3.scale[0] * g; - this.scale[1] = t1.scale[1] * a + t2.scale[1] * f + t3.scale[1] * g; - this.scale[2] = t1.scale[2] * a + t2.scale[2] * f + t3.scale[2] * g; - - // http://msdn.microsoft.com/en-us/library/windows/desktop/bb205403(v=vs.85).aspx - // http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.quaternion.xmquaternionbarycentric(v=vs.85).aspx - var s = f + g; - if (s === 0) { - quat.copy(this.rotation, t1.rotation); - } else { - quat.slerp(q1, t1.rotation, t2.rotation, s); - quat.slerp(q2, t1.rotation, c3.rotation, s); - quat.slerp(this.rotation, q1, q2, g / s); - } - }; -})(); - -TransformTrack.prototype.additiveBlend = function (t1, t2) { - vec3.add(this.position, t1.position, t2.position); - vec3.add(this.scale, t1.scale, t2.scale); - quat.multiply(this.rotation, t2.rotation, t1.rotation); -}; - -TransformTrack.prototype.subtractiveBlend = function (t1, t2) { - vec3.sub(this.position, t1.position, t2.position); - vec3.sub(this.scale, t1.scale, t2.scale); - quat.invert(this.rotation, t2.rotation); - quat.multiply(this.rotation, this.rotation, t1.rotation); -}; - -TransformTrack.prototype.getSubClip = function (startTime, endTime) { - // TODO - console.warn('TODO'); -}; - -TransformTrack.prototype.clone = function () { - var track = TransformTrack.prototype.clone.call(this); - track.keyFrames = this.keyFrames; - - vec3.copy(track.position, this.position); - quat.copy(track.rotation, this.rotation); - vec3.copy(track.scale, this.scale); - - return track; -}; - - -/* harmony default export */ __webpack_exports__["a"] = (TransformTrack); - - -/***/ }), -/* 84 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__source_header_light__ = __webpack_require__(39); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__source_util_glsl_js__ = __webpack_require__(85); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__source_basic_glsl_js__ = __webpack_require__(50); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__source_lambert_glsl_js__ = __webpack_require__(86); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__source_standard_glsl_js__ = __webpack_require__(45); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__source_wireframe_glsl_js__ = __webpack_require__(87); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__source_skybox_glsl_js__ = __webpack_require__(51); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__source_prez_glsl_js__ = __webpack_require__(40); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__library__ = __webpack_require__(31); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__source_compositor_coloradjust_glsl_js__ = __webpack_require__(88); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_11__source_compositor_blur_glsl_js__ = __webpack_require__(52); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_12__source_compositor_lum_glsl_js__ = __webpack_require__(89); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_13__source_compositor_lut_glsl_js__ = __webpack_require__(90); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_14__source_compositor_vignette_glsl_js__ = __webpack_require__(91); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_15__source_compositor_output_glsl_js__ = __webpack_require__(53); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_16__source_compositor_bright_glsl_js__ = __webpack_require__(54); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_17__source_compositor_downsample_glsl_js__ = __webpack_require__(55); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_18__source_compositor_upsample_glsl_js__ = __webpack_require__(56); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_19__source_compositor_hdr_glsl_js__ = __webpack_require__(57); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_20__source_compositor_dof_glsl_js__ = __webpack_require__(92); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_21__source_compositor_lensflare_glsl_js__ = __webpack_require__(93); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_22__source_compositor_blend_glsl_js__ = __webpack_require__(58); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_23__source_compositor_fxaa_glsl_js__ = __webpack_require__(59); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_24__source_compositor_fxaa3_glsl_js__ = __webpack_require__(94); - - - - - - - - - - - - - - -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_0__source_header_light__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_1__source_util_glsl_js__["a" /* default */]); - -// Some build in shaders -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_2__source_basic_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_3__source_lambert_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_4__source_standard_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_5__source_wireframe_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_6__source_skybox_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_7__source_prez_glsl_js__["a" /* default */]); - -__WEBPACK_IMPORTED_MODULE_8__library__["a" /* default */].template('clay.basic', __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.basic.vertex'), __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.basic.fragment')); -__WEBPACK_IMPORTED_MODULE_8__library__["a" /* default */].template('clay.lambert', __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.lambert.vertex'), __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.lambert.fragment')); -__WEBPACK_IMPORTED_MODULE_8__library__["a" /* default */].template('clay.wireframe', __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.wireframe.vertex'), __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.wireframe.fragment')); -__WEBPACK_IMPORTED_MODULE_8__library__["a" /* default */].template('clay.skybox', __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.skybox.vertex'), __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.skybox.fragment')); -__WEBPACK_IMPORTED_MODULE_8__library__["a" /* default */].template('clay.prez', __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.prez.vertex'), __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.prez.fragment')); -__WEBPACK_IMPORTED_MODULE_8__library__["a" /* default */].template('clay.standard', __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.standard.vertex'), __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.standard.fragment')); -__WEBPACK_IMPORTED_MODULE_8__library__["a" /* default */].template('clay.standardMR', __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.standardMR.vertex'), __WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */].source('clay.standardMR.fragment')); - - - - - - - - - - - - - - - - - - - -// Some build in shaders -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_10__source_compositor_coloradjust_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_11__source_compositor_blur_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_12__source_compositor_lum_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_13__source_compositor_lut_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_14__source_compositor_vignette_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_15__source_compositor_output_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_16__source_compositor_bright_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_17__source_compositor_downsample_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_18__source_compositor_upsample_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_19__source_compositor_hdr_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_20__source_compositor_dof_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_21__source_compositor_lensflare_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_22__source_compositor_blend_glsl_js__["a" /* default */]); - -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_23__source_compositor_fxaa_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_9__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_24__source_compositor_fxaa3_glsl_js__["a" /* default */]); - - -/***/ }), -/* 85 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("\n@export clay.util.rand\nhighp float rand(vec2 uv) {\n const highp float a = 12.9898, b = 78.233, c = 43758.5453;\n highp float dt = dot(uv.xy, vec2(a,b)), sn = mod(dt, 3.141592653589793);\n return fract(sin(sn) * c);\n}\n@end\n@export clay.util.calculate_attenuation\nuniform float attenuationFactor : 5.0;\nfloat lightAttenuation(float dist, float range)\n{\n float attenuation = 1.0;\n attenuation = dist*dist/(range*range+1.0);\n float att_s = attenuationFactor;\n attenuation = 1.0/(attenuation*att_s+1.0);\n att_s = 1.0/(att_s+1.0);\n attenuation = attenuation - att_s;\n attenuation /= 1.0 - att_s;\n return clamp(attenuation, 0.0, 1.0);\n}\n@end\n@export clay.util.edge_factor\nfloat edgeFactor(float width)\n{\n vec3 d = fwidth(v_Barycentric);\n vec3 a3 = smoothstep(vec3(0.0), d * width, v_Barycentric);\n return min(min(a3.x, a3.y), a3.z);\n}\n@end\n@export clay.util.encode_float\nvec4 encodeFloat(const in float depth)\n{\n const vec4 bitShifts = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);\n const vec4 bit_mask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);\n vec4 res = fract(depth * bitShifts);\n res -= res.xxyz * bit_mask;\n return res;\n}\n@end\n@export clay.util.decode_float\nfloat decodeFloat(const in vec4 color)\n{\n const vec4 bitShifts = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);\n return dot(color, bitShifts);\n}\n@end\n@export clay.util.float\n@import clay.util.encode_float\n@import clay.util.decode_float\n@end\n@export clay.util.rgbm_decode\nvec3 RGBMDecode(vec4 rgbm, float range) {\n return range * rgbm.rgb * rgbm.a;\n}\n@end\n@export clay.util.rgbm_encode\nvec4 RGBMEncode(vec3 color, float range) {\n if (dot(color, color) == 0.0) {\n return vec4(0.0);\n }\n vec4 rgbm;\n color /= range;\n rgbm.a = clamp(max(max(color.r, color.g), max(color.b, 1e-6)), 0.0, 1.0);\n rgbm.a = ceil(rgbm.a * 255.0) / 255.0;\n rgbm.rgb = color / rgbm.a;\n return rgbm;\n}\n@end\n@export clay.util.rgbm\n@import clay.util.rgbm_decode\n@import clay.util.rgbm_encode\nvec4 decodeHDR(vec4 color)\n{\n#if defined(RGBM_DECODE) || defined(RGBM)\n return vec4(RGBMDecode(color, 51.5), 1.0);\n#else\n return color;\n#endif\n}\nvec4 encodeHDR(vec4 color)\n{\n#if defined(RGBM_ENCODE) || defined(RGBM)\n return RGBMEncode(color.xyz, 51.5);\n#else\n return color;\n#endif\n}\n@end\n@export clay.util.srgb\nvec4 sRGBToLinear(in vec4 value) {\n return vec4(mix(pow(value.rgb * 0.9478672986 + vec3(0.0521327014), vec3(2.4)), value.rgb * 0.0773993808, vec3(lessThanEqual(value.rgb, vec3(0.04045)))), value.w);\n}\nvec4 linearTosRGB(in vec4 value) {\n return vec4(mix(pow(value.rgb, vec3(0.41666)) * 1.055 - vec3(0.055), value.rgb * 12.92, vec3(lessThanEqual(value.rgb, vec3(0.0031308)))), value.w);\n}\n@end\n@export clay.chunk.skinning_header\n#ifdef SKINNING\nattribute vec3 weight : WEIGHT;\nattribute vec4 joint : JOINT;\nuniform mat4 skinMatrix[JOINT_COUNT] : SKIN_MATRIX;\nmat4 getSkinMatrix(float idx) {\n return skinMatrix[int(idx)];\n}\n#endif\n@end\n@export clay.chunk.skin_matrix\nmat4 skinMatrixWS = getSkinMatrix(joint.x) * weight.x;\nif (weight.y > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.y) * weight.y;\n}\nif (weight.z > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.z) * weight.z;\n}\nfloat weightW = 1.0-weight.x-weight.y-weight.z;\nif (weightW > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.w) * weightW;\n}\n@end\n@export clay.util.parallax_correct\nvec3 parallaxCorrect(in vec3 dir, in vec3 pos, in vec3 boxMin, in vec3 boxMax) {\n vec3 first = (boxMax - pos) / dir;\n vec3 second = (boxMin - pos) / dir;\n vec3 further = max(first, second);\n float dist = min(further.x, min(further.y, further.z));\n vec3 fixedPos = pos + dir * dist;\n vec3 boxCenter = (boxMax + boxMin) * 0.5;\n return normalize(fixedPos - boxCenter);\n}\n@end\n@export clay.util.clamp_sample\nvec4 clampSample(const in sampler2D texture, const in vec2 coord)\n{\n#ifdef STEREO\n float eye = step(0.5, coord.x) * 0.5;\n vec2 coordClamped = clamp(coord, vec2(eye, 0.0), vec2(0.5 + eye, 1.0));\n#else\n vec2 coordClamped = clamp(coord, vec2(0.0), vec2(1.0));\n#endif\n return texture2D(texture, coordClamped);\n}\n@end\n@export clay.util.ACES\nvec3 ACESToneMapping(vec3 color)\n{\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\n@end"); - - -/***/ }), -/* 86 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("\n@export clay.lambert.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\nattribute vec3 normal : NORMAL;\nattribute vec3 barycentric;\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n#endif\n@import clay.chunk.skinning_header\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nvarying vec3 v_Barycentric;\nvoid main()\n{\n vec3 skinnedPosition = position;\n vec3 skinnedNormal = normal;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4( skinnedPosition, 1.0 );\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_Normal = normalize( ( worldInverseTranspose * vec4(skinnedNormal, 0.0) ).xyz );\n v_WorldPosition = ( world * vec4( skinnedPosition, 1.0) ).xyz;\n v_Barycentric = barycentric;\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n}\n@end\n@export clay.lambert.fragment\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nuniform sampler2D diffuseMap;\nuniform sampler2D alphaMap;\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\nvarying vec3 v_Barycentric;\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\n#ifdef AMBIENT_LIGHT_COUNT\n@import clay.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import clay.header.ambient_sh_light\n#endif\n#ifdef POINT_LIGHT_COUNT\n@import clay.header.point_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n#ifdef SPOT_LIGHT_COUNT\n@import clay.header.spot_light\n#endif\n@import clay.util.calculate_attenuation\n@import clay.util.edge_factor\n@import clay.util.rgbm\n@import clay.plugin.compute_shadow_map\n@import clay.util.ACES\nvoid main()\n{\n#ifdef RENDER_NORMAL\n gl_FragColor = vec4(v_Normal * 0.5 + 0.5, 1.0);\n return;\n#endif\n#ifdef RENDER_TEXCOORD\n gl_FragColor = vec4(v_Texcoord, 1.0, 1.0);\n return;\n#endif\n gl_FragColor = vec4(color, alpha);\n#ifdef VERTEX_COLOR\n gl_FragColor *= v_Color;\n#endif\n#ifdef DIFFUSEMAP_ENABLED\n vec4 tex = texture2D( diffuseMap, v_Texcoord );\n#ifdef SRGB_DECODE\n tex.rgb = pow(tex.rgb, vec3(2.2));\n#endif\n gl_FragColor.rgb *= tex.rgb;\n#ifdef DIFFUSEMAP_ALPHA_ALPHA\n gl_FragColor.a *= tex.a;\n#endif\n#endif\n vec3 diffuseColor = vec3(0.0, 0.0, 0.0);\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {\n diffuseColor += ambientLightColor[_idx_];\n }\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseColor += calcAmbientSHLight(_idx_, v_Normal) * ambientSHLightColor[_idx_];\n }}\n#endif\n#ifdef POINT_LIGHT_COUNT\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsPoint[POINT_LIGHT_COUNT];\n if( shadowEnabled )\n {\n computeShadowOfPointLights(v_WorldPosition, shadowContribsPoint);\n }\n#endif\n for(int i = 0; i < POINT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = pointLightPosition[i];\n vec3 lightColor = pointLightColor[i];\n float range = pointLightRange[i];\n vec3 lightDirection = lightPosition - v_WorldPosition;\n float dist = length(lightDirection);\n float attenuation = lightAttenuation(dist, range);\n lightDirection /= dist;\n float ndl = dot( v_Normal, lightDirection );\n float shadowContrib = 1.0;\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsPoint[i];\n }\n#endif\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * attenuation * shadowContrib;\n }\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++)\n {\n vec3 lightDirection = -directionalLightDirection[i];\n vec3 lightColor = directionalLightColor[i];\n float ndl = dot(v_Normal, normalize(lightDirection));\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsDir[i];\n }\n#endif\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * shadowContrib;\n }\n#endif\n#ifdef SPOT_LIGHT_COUNT\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsSpot[SPOT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfSpotLights(v_WorldPosition, shadowContribsSpot);\n }\n#endif\n for(int i = 0; i < SPOT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = -spotLightPosition[i];\n vec3 spotLightDirection = -normalize( spotLightDirection[i] );\n vec3 lightColor = spotLightColor[i];\n float range = spotLightRange[i];\n float a = spotLightUmbraAngleCosine[i];\n float b = spotLightPenumbraAngleCosine[i];\n float falloffFactor = spotLightFalloffFactor[i];\n vec3 lightDirection = lightPosition - v_WorldPosition;\n float dist = length(lightDirection);\n float attenuation = lightAttenuation(dist, range);\n lightDirection /= dist;\n float c = dot(spotLightDirection, lightDirection);\n float falloff;\n falloff = clamp((c - a) /( b - a), 0.0, 1.0);\n falloff = pow(falloff, falloffFactor);\n float ndl = dot(v_Normal, lightDirection);\n ndl = clamp(ndl, 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsSpot[i];\n }\n#endif\n diffuseColor += lightColor * ndl * attenuation * (1.0-falloff) * shadowContrib;\n }\n#endif\n gl_FragColor.rgb *= diffuseColor;\n gl_FragColor.rgb += emission;\n if(lineWidth > 0.)\n {\n gl_FragColor.rgb = mix(gl_FragColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (gl_FragColor.a < alphaCutoff) {\n discard;\n }\n#endif\n#ifdef TONEMAPPING\n gl_FragColor.rgb = ACESToneMapping(gl_FragColor.rgb);\n#endif\n#ifdef SRGB_ENCODE\n gl_FragColor = linearTosRGB(gl_FragColor);\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n}\n@end"); - - -/***/ }), -/* 87 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.wireframe.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 world : WORLD;\nattribute vec3 position : POSITION;\nattribute vec3 barycentric;\n@import clay.chunk.skinning_header\nvarying vec3 v_Barycentric;\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0 );\n v_Barycentric = barycentric;\n}\n@end\n@export clay.wireframe.fragment\nuniform vec3 color : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\nuniform float lineWidth : 1.0;\nvarying vec3 v_Barycentric;\n@import clay.util.edge_factor\nvoid main()\n{\n gl_FragColor.rgb = color;\n gl_FragColor.a = (1.0-edgeFactor(lineWidth)) * alpha;\n}\n@end"); - - -/***/ }), -/* 88 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.compositor.coloradjust\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float brightness : 0.0;\nuniform float contrast : 1.0;\nuniform float exposure : 0.0;\nuniform float gamma : 1.0;\nuniform float saturation : 1.0;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = clamp(tex.rgb + vec3(brightness), 0.0, 1.0);\n color = clamp( (color-vec3(0.5))*contrast+vec3(0.5), 0.0, 1.0);\n color = clamp( color * pow(2.0, exposure), 0.0, 1.0);\n color = clamp( pow(color, vec3(gamma)), 0.0, 1.0);\n float luminance = dot( color, w );\n color = mix(vec3(luminance), color, saturation);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.brightness\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float brightness : 0.0;\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = tex.rgb + vec3(brightness);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.contrast\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float contrast : 1.0;\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = (tex.rgb-vec3(0.5))*contrast+vec3(0.5);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.exposure\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float exposure : 0.0;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = tex.rgb * pow(2.0, exposure);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.gamma\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float gamma : 1.0;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = pow(tex.rgb, vec3(gamma));\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.saturation\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float saturation : 1.0;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = tex.rgb;\n float luminance = dot(color, w);\n color = mix(vec3(luminance), color, saturation);\n gl_FragColor = vec4(color, tex.a);\n}\n@end"); - - -/***/ }), -/* 89 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.compositor.hdr.log_lum\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\n@import clay.util.rgbm\nvoid main()\n{\n vec4 tex = decodeHDR(texture2D(texture, v_Texcoord));\n float luminance = dot(tex.rgb, w);\n luminance = log(luminance + 0.001);\n gl_FragColor = encodeHDR(vec4(vec3(luminance), 1.0));\n}\n@end\n@export clay.compositor.hdr.lum_adaption\nvarying vec2 v_Texcoord;\nuniform sampler2D adaptedLum;\nuniform sampler2D currentLum;\nuniform float frameTime : 0.02;\n@import clay.util.rgbm\nvoid main()\n{\n float fAdaptedLum = decodeHDR(texture2D(adaptedLum, vec2(0.5, 0.5))).r;\n float fCurrentLum = exp(encodeHDR(texture2D(currentLum, vec2(0.5, 0.5))).r);\n fAdaptedLum += (fCurrentLum - fAdaptedLum) * (1.0 - pow(0.98, 30.0 * frameTime));\n gl_FragColor = encodeHDR(vec4(vec3(fAdaptedLum), 1.0));\n}\n@end\n@export clay.compositor.lum\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord );\n float luminance = dot(tex.rgb, w);\n gl_FragColor = vec4(vec3(luminance), 1.0);\n}\n@end"); - - -/***/ }), -/* 90 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("\n@export clay.compositor.lut\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform sampler2D lookup;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n float blueColor = tex.b * 63.0;\n vec2 quad1;\n quad1.y = floor(floor(blueColor) / 8.0);\n quad1.x = floor(blueColor) - (quad1.y * 8.0);\n vec2 quad2;\n quad2.y = floor(ceil(blueColor) / 8.0);\n quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n vec2 texPos1;\n texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.r);\n texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.g);\n vec2 texPos2;\n texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.r);\n texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.g);\n vec4 newColor1 = texture2D(lookup, texPos1);\n vec4 newColor2 = texture2D(lookup, texPos2);\n vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n gl_FragColor = vec4(newColor.rgb, tex.w);\n}\n@end"); - - -/***/ }), -/* 91 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.compositor.vignette\n#define OUTPUT_ALPHA\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float darkness: 1;\nuniform float offset: 1;\n@import clay.util.rgbm\nvoid main()\n{\n vec4 texel = decodeHDR(texture2D(texture, v_Texcoord));\n gl_FragColor.rgb = texel.rgb;\n vec2 uv = (v_Texcoord - vec2(0.5)) * vec2(offset);\n gl_FragColor = encodeHDR(vec4(mix(texel.rgb, vec3(1.0 - darkness), dot(uv, uv)), texel.a));\n}\n@end"); - - -/***/ }), -/* 92 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.compositor.dof.coc\nuniform sampler2D depth;\nuniform float zNear: 0.1;\nuniform float zFar: 2000;\nuniform float focalDist: 3;\nuniform float focalRange: 1;\nuniform float focalLength: 30;\nuniform float fstop: 2.8;\nvarying vec2 v_Texcoord;\n@import clay.util.encode_float\nvoid main()\n{\n float z = texture2D(depth, v_Texcoord).r * 2.0 - 1.0;\n float dist = 2.0 * zNear * zFar / (zFar + zNear - z * (zFar - zNear));\n float aperture = focalLength / fstop;\n float coc;\n float uppper = focalDist + focalRange;\n float lower = focalDist - focalRange;\n if (dist <= uppper && dist >= lower) {\n coc = 0.5;\n }\n else {\n float focalAdjusted = dist > uppper ? uppper : lower;\n coc = abs(aperture * (focalLength * (dist - focalAdjusted)) / (dist * (focalAdjusted - focalLength)));\n coc = clamp(coc, 0.0, 0.4) / 0.4000001;\n if (dist < lower) {\n coc = -coc;\n }\n coc = coc * 0.5 + 0.5;\n }\n gl_FragColor = encodeFloat(coc);\n}\n@end\n@export clay.compositor.dof.premultiply\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.decode_float\nvoid main() {\n float fCoc = max(abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0), 0.1);\n gl_FragColor = encodeHDR(\n vec4(decodeHDR(texture2D(texture, v_Texcoord)).rgb * fCoc, 1.0)\n );\n}\n@end\n@export clay.compositor.dof.min_coc\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.float\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zy)));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.xw)));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zw)));\n gl_FragColor = encodeFloat(fCoc);\n}\n@end\n@export clay.compositor.dof.max_coc\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.float\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zy)));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.xw)));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zw)));\n gl_FragColor = encodeFloat(fCoc);\n}\n@end\n@export clay.compositor.dof.coc_upsample\n#define HIGH_QUALITY\nuniform sampler2D coc;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import clay.util.float\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n float s;\n s = decodeFloat(texture2D(coc, v_Texcoord - d.xy));\n s += decodeFloat(texture2D(coc, v_Texcoord - d.wy)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord - d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zw)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord )) * 4.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xw)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.wy)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n gl_FragColor = encodeFloat(s / 16.0);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n float s;\n s = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xw));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zw));\n gl_FragColor = encodeFloat(s / 4.0);\n#endif\n}\n@end\n@export clay.compositor.dof.upsample\n#define HIGH_QUALITY\nuniform sampler2D coc;\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.decode_float\nfloat tap(vec2 uv, inout vec4 color, float baseWeight) {\n float weight = abs(decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0) * baseWeight;\n color += decodeHDR(texture2D(texture, uv)) * weight;\n return weight;\n}\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n vec4 color = vec4(0.0);\n float baseWeight = 1.0 / 16.0;\n float w = tap(v_Texcoord - d.xy, color, baseWeight);\n w += tap(v_Texcoord - d.wy, color, baseWeight * 2.0);\n w += tap(v_Texcoord - d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.zw, color, baseWeight * 2.0);\n w += tap(v_Texcoord , color, baseWeight * 4.0);\n w += tap(v_Texcoord + d.xw, color, baseWeight * 2.0);\n w += tap(v_Texcoord + d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.wy, color, baseWeight * 2.0);\n w += tap(v_Texcoord + d.xy, color, baseWeight);\n gl_FragColor = encodeHDR(color / w);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n vec4 color = vec4(0.0);\n float baseWeight = 1.0 / 4.0;\n float w = tap(v_Texcoord + d.xy, color, baseWeight);\n w += tap(v_Texcoord + d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.xw, color, baseWeight);\n w += tap(v_Texcoord + d.zw, color, baseWeight);\n gl_FragColor = encodeHDR(color / w);\n#endif\n}\n@end\n@export clay.compositor.dof.downsample\nuniform sampler2D texture;\nuniform sampler2D coc;\nuniform vec2 textureSize : [512, 512];\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.decode_float\nfloat tap(vec2 uv, inout vec4 color) {\n float weight = abs(decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0) * 0.25;\n color += decodeHDR(texture2D(texture, uv)) * weight;\n return weight;\n}\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n vec4 color = vec4(0.0);\n float weight = tap(v_Texcoord + d.xy, color);\n weight += tap(v_Texcoord + d.zy, color);\n weight += tap(v_Texcoord + d.xw, color);\n weight += tap(v_Texcoord + d.zw, color);\n color /= weight;\n gl_FragColor = encodeHDR(color);\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_frag\n@import clay.util.float\nvec4 doBlur(sampler2D targetTexture, vec2 offset) {\n#ifdef BLUR_COC\n float cocSum = 0.0;\n#else\n vec4 color = vec4(0.0);\n#endif\n float weightSum = 0.0;\n float kernelWeight = 1.0 / float(KERNEL_SIZE);\n for (int i = 0; i < KERNEL_SIZE; i++) {\n vec2 coord = v_Texcoord + offset * float(i);\n float w = kernelWeight;\n#ifdef BLUR_COC\n float fCoc = decodeFloat(texture2D(targetTexture, coord)) * 2.0 - 1.0;\n cocSum += clamp(fCoc, -1.0, 0.0) * w;\n#else\n float fCoc = decodeFloat(texture2D(coc, coord)) * 2.0 - 1.0;\n vec4 texel = texture2D(targetTexture, coord);\n #if !defined(BLUR_NEARFIELD)\n w *= abs(fCoc);\n #endif\n color += decodeHDR(texel) * w;\n#endif\n weightSum += w;\n }\n#ifdef BLUR_COC\n return encodeFloat(clamp(cocSum / weightSum, -1.0, 0.0) * 0.5 + 0.5);\n#else\n return color / weightSum;\n#endif\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_1\n#define KERNEL_SIZE 5\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.rgbm\n@import clay.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n gl_FragColor = doBlur(texture, vec2(0.0, offset.y));\n#if !defined(BLUR_COC)\n gl_FragColor = encodeHDR(gl_FragColor);\n#endif\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_2\n#define KERNEL_SIZE 5\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.rgbm\n@import clay.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n offset.y /= 2.0;\n gl_FragColor = doBlur(texture, -offset);\n#if !defined(BLUR_COC)\n gl_FragColor = encodeHDR(gl_FragColor);\n#endif\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_3\n#define KERNEL_SIZE 5\nuniform sampler2D texture1;\nuniform sampler2D texture2;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.rgbm\n@import clay.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n offset.y /= 2.0;\n vec2 vDownRight = vec2(offset.x, -offset.y);\n vec4 texel1 = doBlur(texture1, -offset);\n vec4 texel2 = doBlur(texture1, vDownRight);\n vec4 texel3 = doBlur(texture2, vDownRight);\n#ifdef BLUR_COC\n float coc1 = decodeFloat(texel1) * 2.0 - 1.0;\n float coc2 = decodeFloat(texel2) * 2.0 - 1.0;\n float coc3 = decodeFloat(texel3) * 2.0 - 1.0;\n gl_FragColor = encodeFloat(\n ((coc1 + coc2 + coc3) / 3.0) * 0.5 + 0.5\n );\n#else\n vec4 color = (texel1 + texel2 + texel3) / 3.0;\n gl_FragColor = encodeHDR(color);\n#endif\n}\n@end\n@export clay.compositor.dof.composite\n#define DEBUG 0\nuniform sampler2D original;\nuniform sampler2D blurred;\nuniform sampler2D nearfield;\nuniform sampler2D coc;\nuniform sampler2D nearcoc;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.float\nvoid main()\n{\n vec4 blurredColor = decodeHDR(texture2D(blurred, v_Texcoord));\n vec4 originalColor = decodeHDR(texture2D(original, v_Texcoord));\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord));\n fCoc = abs(fCoc * 2.0 - 1.0);\n float weight = smoothstep(0.0, 1.0, fCoc);\n#ifdef NEARFIELD_ENABLED\n vec4 nearfieldColor = decodeHDR(texture2D(nearfield, v_Texcoord));\n float fNearCoc = decodeFloat(texture2D(nearcoc, v_Texcoord));\n fNearCoc = abs(fNearCoc * 2.0 - 1.0);\n gl_FragColor = encodeHDR(\n mix(\n nearfieldColor, mix(originalColor, blurredColor, weight),\n pow(1.0 - fNearCoc, 4.0)\n )\n );\n#else\n gl_FragColor = encodeHDR(mix(originalColor, blurredColor, weight));\n#endif\n#if DEBUG == 1\n gl_FragColor = vec4(vec3(fCoc), 1.0);\n#elif DEBUG == 2\n gl_FragColor = vec4(vec3(fNearCoc), 1.0);\n#elif DEBUG == 3\n gl_FragColor = encodeHDR(blurredColor);\n#elif DEBUG == 4\n gl_FragColor = encodeHDR(nearfieldColor);\n#endif\n}\n@end"); - - -/***/ }), -/* 93 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.compositor.lensflare\n#define SAMPLE_NUMBER 8\nuniform sampler2D texture;\nuniform sampler2D lenscolor;\nuniform vec2 textureSize : [512, 512];\nuniform float dispersal : 0.3;\nuniform float haloWidth : 0.4;\nuniform float distortion : 1.0;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\nvec4 textureDistorted(\n in vec2 texcoord,\n in vec2 direction,\n in vec3 distortion\n) {\n return vec4(\n decodeHDR(texture2D(texture, texcoord + direction * distortion.r)).r,\n decodeHDR(texture2D(texture, texcoord + direction * distortion.g)).g,\n decodeHDR(texture2D(texture, texcoord + direction * distortion.b)).b,\n 1.0\n );\n}\nvoid main()\n{\n vec2 texcoord = -v_Texcoord + vec2(1.0); vec2 textureOffset = 1.0 / textureSize;\n vec2 ghostVec = (vec2(0.5) - texcoord) * dispersal;\n vec2 haloVec = normalize(ghostVec) * haloWidth;\n vec3 distortion = vec3(-textureOffset.x * distortion, 0.0, textureOffset.x * distortion);\n vec4 result = vec4(0.0);\n for (int i = 0; i < SAMPLE_NUMBER; i++)\n {\n vec2 offset = fract(texcoord + ghostVec * float(i));\n float weight = length(vec2(0.5) - offset) / length(vec2(0.5));\n weight = pow(1.0 - weight, 10.0);\n result += textureDistorted(offset, normalize(ghostVec), distortion) * weight;\n }\n result *= texture2D(lenscolor, vec2(length(vec2(0.5) - texcoord)) / length(vec2(0.5)));\n float weight = length(vec2(0.5) - fract(texcoord + haloVec)) / length(vec2(0.5));\n weight = pow(1.0 - weight, 10.0);\n vec2 offset = fract(texcoord + haloVec);\n result += textureDistorted(offset, normalize(ghostVec), distortion) * weight;\n gl_FragColor = result;\n}\n@end"); - - -/***/ }), -/* 94 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.compositor.fxaa3\nuniform sampler2D texture;\nuniform vec4 viewport : VIEWPORT;\nuniform float subpixel: 0.75;\nuniform float edgeThreshold: 0.125;\nuniform float edgeThresholdMin: 0.0625;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\nfloat FxaaLuma(vec4 rgba) { return rgba.y; }\nvec4 FxaaPixelShader(\n vec2 pos\n ,sampler2D tex\n ,vec2 fxaaQualityRcpFrame\n ,float fxaaQualitySubpix\n ,float fxaaQualityEdgeThreshold\n ,float fxaaQualityEdgeThresholdMin\n) {\n vec2 posM;\n posM.x = pos.x;\n posM.y = pos.y;\n vec4 rgbyM = decodeHDR(texture2D(texture, posM, 0.0));\n float lumaS = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 0.0, 1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaE = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 1.0, 0.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaN = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 0.0,-1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaW = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2(-1.0, 0.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float maxSM = max(lumaS, rgbyM.y);\n float minSM = min(lumaS, rgbyM.y);\n float maxESM = max(lumaE, maxSM);\n float minESM = min(lumaE, minSM);\n float maxWN = max(lumaN, lumaW);\n float minWN = min(lumaN, lumaW);\n float rangeMax = max(maxWN, maxESM);\n float rangeMin = min(minWN, minESM);\n float rangeMaxScaled = rangeMax * fxaaQualityEdgeThreshold;\n float range = rangeMax - rangeMin;\n float rangeMaxClamped = max(fxaaQualityEdgeThresholdMin, rangeMaxScaled);\n bool earlyExit = range < rangeMaxClamped;\n if(earlyExit) return rgbyM;\n float lumaNW = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2(-1.0,-1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaSE = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 1.0, 1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaNE = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2( 1.0,-1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaSW = FxaaLuma(decodeHDR(texture2D(texture, posM + (vec2(-1.0, 1.0) * fxaaQualityRcpFrame.xy), 0.0)));\n float lumaNS = lumaN + lumaS;\n float lumaWE = lumaW + lumaE;\n float subpixRcpRange = 1.0/range;\n float subpixNSWE = lumaNS + lumaWE;\n float edgeHorz1 = (-2.0 * rgbyM.y) + lumaNS;\n float edgeVert1 = (-2.0 * rgbyM.y) + lumaWE;\n float lumaNESE = lumaNE + lumaSE;\n float lumaNWNE = lumaNW + lumaNE;\n float edgeHorz2 = (-2.0 * lumaE) + lumaNESE;\n float edgeVert2 = (-2.0 * lumaN) + lumaNWNE;\n float lumaNWSW = lumaNW + lumaSW;\n float lumaSWSE = lumaSW + lumaSE;\n float edgeHorz4 = (abs(edgeHorz1) * 2.0) + abs(edgeHorz2);\n float edgeVert4 = (abs(edgeVert1) * 2.0) + abs(edgeVert2);\n float edgeHorz3 = (-2.0 * lumaW) + lumaNWSW;\n float edgeVert3 = (-2.0 * lumaS) + lumaSWSE;\n float edgeHorz = abs(edgeHorz3) + edgeHorz4;\n float edgeVert = abs(edgeVert3) + edgeVert4;\n float subpixNWSWNESE = lumaNWSW + lumaNESE;\n float lengthSign = fxaaQualityRcpFrame.x;\n bool horzSpan = edgeHorz >= edgeVert;\n float subpixA = subpixNSWE * 2.0 + subpixNWSWNESE;\n if(!horzSpan) lumaN = lumaW;\n if(!horzSpan) lumaS = lumaE;\n if(horzSpan) lengthSign = fxaaQualityRcpFrame.y;\n float subpixB = (subpixA * (1.0/12.0)) - rgbyM.y;\n float gradientN = lumaN - rgbyM.y;\n float gradientS = lumaS - rgbyM.y;\n float lumaNN = lumaN + rgbyM.y;\n float lumaSS = lumaS + rgbyM.y;\n bool pairN = abs(gradientN) >= abs(gradientS);\n float gradient = max(abs(gradientN), abs(gradientS));\n if(pairN) lengthSign = -lengthSign;\n float subpixC = clamp(abs(subpixB) * subpixRcpRange, 0.0, 1.0);\n vec2 posB;\n posB.x = posM.x;\n posB.y = posM.y;\n vec2 offNP;\n offNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;\n offNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;\n if(!horzSpan) posB.x += lengthSign * 0.5;\n if( horzSpan) posB.y += lengthSign * 0.5;\n vec2 posN;\n posN.x = posB.x - offNP.x * 1.0;\n posN.y = posB.y - offNP.y * 1.0;\n vec2 posP;\n posP.x = posB.x + offNP.x * 1.0;\n posP.y = posB.y + offNP.y * 1.0;\n float subpixD = ((-2.0)*subpixC) + 3.0;\n float lumaEndN = FxaaLuma(decodeHDR(texture2D(texture, posN, 0.0)));\n float subpixE = subpixC * subpixC;\n float lumaEndP = FxaaLuma(decodeHDR(texture2D(texture, posP, 0.0)));\n if(!pairN) lumaNN = lumaSS;\n float gradientScaled = gradient * 1.0/4.0;\n float lumaMM = rgbyM.y - lumaNN * 0.5;\n float subpixF = subpixD * subpixE;\n bool lumaMLTZero = lumaMM < 0.0;\n lumaEndN -= lumaNN * 0.5;\n lumaEndP -= lumaNN * 0.5;\n bool doneN = abs(lumaEndN) >= gradientScaled;\n bool doneP = abs(lumaEndP) >= gradientScaled;\n if(!doneN) posN.x -= offNP.x * 1.5;\n if(!doneN) posN.y -= offNP.y * 1.5;\n bool doneNP = (!doneN) || (!doneP);\n if(!doneP) posP.x += offNP.x * 1.5;\n if(!doneP) posP.y += offNP.y * 1.5;\n if(doneNP) {\n if(!doneN) lumaEndN = FxaaLuma(decodeHDR(texture2D(texture, posN.xy, 0.0)));\n if(!doneP) lumaEndP = FxaaLuma(decodeHDR(texture2D(texture, posP.xy, 0.0)));\n if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;\n if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;\n doneN = abs(lumaEndN) >= gradientScaled;\n doneP = abs(lumaEndP) >= gradientScaled;\n if(!doneN) posN.x -= offNP.x * 2.0;\n if(!doneN) posN.y -= offNP.y * 2.0;\n doneNP = (!doneN) || (!doneP);\n if(!doneP) posP.x += offNP.x * 2.0;\n if(!doneP) posP.y += offNP.y * 2.0;\n if(doneNP) {\n if(!doneN) lumaEndN = FxaaLuma(decodeHDR(texture2D(texture, posN.xy, 0.0)));\n if(!doneP) lumaEndP = FxaaLuma(decodeHDR(texture2D(texture, posP.xy, 0.0)));\n if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;\n if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;\n doneN = abs(lumaEndN) >= gradientScaled;\n doneP = abs(lumaEndP) >= gradientScaled;\n if(!doneN) posN.x -= offNP.x * 4.0;\n if(!doneN) posN.y -= offNP.y * 4.0;\n doneNP = (!doneN) || (!doneP);\n if(!doneP) posP.x += offNP.x * 4.0;\n if(!doneP) posP.y += offNP.y * 4.0;\n if(doneNP) {\n if(!doneN) lumaEndN = FxaaLuma(decodeHDR(texture2D(texture, posN.xy, 0.0)));\n if(!doneP) lumaEndP = FxaaLuma(decodeHDR(texture2D(texture, posP.xy, 0.0)));\n if(!doneN) lumaEndN = lumaEndN - lumaNN * 0.5;\n if(!doneP) lumaEndP = lumaEndP - lumaNN * 0.5;\n doneN = abs(lumaEndN) >= gradientScaled;\n doneP = abs(lumaEndP) >= gradientScaled;\n if(!doneN) posN.x -= offNP.x * 12.0;\n if(!doneN) posN.y -= offNP.y * 12.0;\n doneNP = (!doneN) || (!doneP);\n if(!doneP) posP.x += offNP.x * 12.0;\n if(!doneP) posP.y += offNP.y * 12.0;\n }\n }\n }\n float dstN = posM.x - posN.x;\n float dstP = posP.x - posM.x;\n if(!horzSpan) dstN = posM.y - posN.y;\n if(!horzSpan) dstP = posP.y - posM.y;\n bool goodSpanN = (lumaEndN < 0.0) != lumaMLTZero;\n float spanLength = (dstP + dstN);\n bool goodSpanP = (lumaEndP < 0.0) != lumaMLTZero;\n float spanLengthRcp = 1.0/spanLength;\n bool directionN = dstN < dstP;\n float dst = min(dstN, dstP);\n bool goodSpan = directionN ? goodSpanN : goodSpanP;\n float subpixG = subpixF * subpixF;\n float pixelOffset = (dst * (-spanLengthRcp)) + 0.5;\n float subpixH = subpixG * fxaaQualitySubpix;\n float pixelOffsetGood = goodSpan ? pixelOffset : 0.0;\n float pixelOffsetSubpix = max(pixelOffsetGood, subpixH);\n if(!horzSpan) posM.x += pixelOffsetSubpix * lengthSign;\n if( horzSpan) posM.y += pixelOffsetSubpix * lengthSign;\n return vec4(decodeHDR(texture2D(texture, posM, 0.0)).xyz, rgbyM.y);\n}\nvoid main()\n{\n vec4 color = FxaaPixelShader(\n v_Texcoord,\n texture,\n vec2(1.0) / viewport.zw,\n subpixel,\n edgeThreshold,\n edgeThresholdMin\n );\n gl_FragColor = vec4(color.rgb, 1.0);\n}\n@end"); - - -/***/ }), -/* 95 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Animator__ = __webpack_require__(96); - - - -var requestAnimationFrame = window.requestAnimationFrame - || window.msRequestAnimationFrame - || window.mozRequestAnimationFrame - || window.webkitRequestAnimationFrame - || function (func){ setTimeout(func, 16); }; - -/** - * Animation is global timeline that schedule all clips. each frame animation will set the time of clips to current and update the states of clips - * @constructor clay.animation.Animation - * @extends clay.core.Base - * - * @example - * var animation = new clay.animation.Animation(); - * var node = new clay.Node(); - * animation.animate(node.position) - * .when(1000, { - * x: 500, - * y: 500 - * }) - * .when(2000, { - * x: 100, - * y: 100 - * }) - * .when(3000, { - * z: 10 - * }) - * .start('spline'); - */ -var Timeline = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend(function () { - return /** @lends clay.animation.Timeline# */{ - /** - * stage is an object with render method, each frame if there exists any animating clips, stage.render will be called - * @type {Object} - */ - stage: null, - - _clips: [], - - _running: false, - - _time: 0, - - _paused: false, - - _pausedTime: 0 - }; -}, -/** @lends clay.animation.Timeline.prototype */ -{ - - /** - * Add animator - * @param {clay.animate.Animator} animator - */ - addAnimator: function (animator) { - animator.animation = this; - var clips = animator.getClips(); - for (var i = 0; i < clips.length; i++) { - this.addClip(clips[i]); - } - }, - - /** - * @param {clay.animation.Clip} clip - */ - addClip: function (clip) { - if (this._clips.indexOf(clip) < 0) { - this._clips.push(clip); - } - }, - - /** - * @param {clay.animation.Clip} clip - */ - removeClip: function (clip) { - var idx = this._clips.indexOf(clip); - if (idx >= 0) { - this._clips.splice(idx, 1); - } - }, - - /** - * Remove animator - * @param {clay.animate.Animator} animator - */ - removeAnimator: function (animator) { - var clips = animator.getClips(); - for (var i = 0; i < clips.length; i++) { - this.removeClip(clips[i]); - } - animator.animation = null; - }, - - _update: function () { - - var time = Date.now() - this._pausedTime; - var delta = time - this._time; - var clips = this._clips; - var len = clips.length; - - var deferredEvents = []; - var deferredClips = []; - for (var i = 0; i < len; i++) { - var clip = clips[i]; - var e = clip.step(time, delta, false); - // Throw out the events need to be called after - // stage.render, like finish - if (e) { - deferredEvents.push(e); - deferredClips.push(clip); - } - } - - // Remove the finished clip - for (var i = 0; i < len;) { - if (clips[i]._needsRemove) { - clips[i] = clips[len-1]; - clips.pop(); - len--; - } else { - i++; - } - } - - len = deferredEvents.length; - for (var i = 0; i < len; i++) { - deferredClips[i].fire(deferredEvents[i]); - } - - this._time = time; - - this.trigger('frame', delta); - - if (this.stage && this.stage.render) { - this.stage.render(); - } - }, - /** - * Start running animation - */ - start: function () { - var self = this; - - this._running = true; - this._time = Date.now(); - - this._pausedTime = 0; - - function step() { - if (self._running) { - - requestAnimationFrame(step); - - if (!self._paused) { - self._update(); - } - } - } - - requestAnimationFrame(step); - - }, - /** - * Stop running animation - */ - stop: function () { - this._running = false; - }, - - /** - * Pause - */ - pause: function () { - if (!this._paused) { - this._pauseStart = Date.now(); - this._paused = true; - } - }, - - /** - * Resume - */ - resume: function () { - if (this._paused) { - this._pausedTime += Date.now() - this._pauseStart; - this._paused = false; - } - }, - - /** - * Remove all clips - */ - removeClipsAll: function () { - this._clips = []; - }, - /** - * Create a animator - * @param {Object} target - * @param {Object} [options] - * @param {boolean} [options.loop] - * @param {Function} [options.getter] - * @param {Function} [options.setter] - * @param {Function} [options.interpolater] - * @return {clay.animation.Animator} - */ - animate: function (target, options) { - options = options || {}; - var animator = new __WEBPACK_IMPORTED_MODULE_1__Animator__["a" /* default */]( - target, - options.loop, - options.getter, - options.setter, - options.interpolater - ); - animator.animation = this; - return animator; - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (Timeline); - - -/***/ }), -/* 96 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Clip__ = __webpack_require__(32); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__easing__ = __webpack_require__(49); - - - -var arraySlice = Array.prototype.slice; - -function defaultGetter(target, key) { - return target[key]; -} -function defaultSetter(target, key, value) { - target[key] = value; -} - -function interpolateNumber(p0, p1, percent) { - return (p1 - p0) * percent + p0; -} - -function interpolateArray(p0, p1, percent, out, arrDim) { - var len = p0.length; - if (arrDim == 1) { - for (var i = 0; i < len; i++) { - out[i] = interpolateNumber(p0[i], p1[i], percent); - } - } - else { - var len2 = p0[0].length; - for (var i = 0; i < len; i++) { - for (var j = 0; j < len2; j++) { - out[i][j] = interpolateNumber( - p0[i][j], p1[i][j], percent - ); - } - } - } -} - -function isArrayLike(data) { - if (typeof(data) == 'undefined') { - return false; - } else if (typeof(data) == 'string') { - return false; - } else { - return typeof(data.length) == 'number'; - } -} - -function cloneValue(value) { - if (isArrayLike(value)) { - var len = value.length; - if (isArrayLike(value[0])) { - var ret = []; - for (var i = 0; i < len; i++) { - ret.push(arraySlice.call(value[i])); - } - return ret; - } else { - return arraySlice.call(value); - } - } else { - return value; - } -} - -function catmullRomInterpolateArray( - p0, p1, p2, p3, t, t2, t3, out, arrDim -) { - var len = p0.length; - if (arrDim == 1) { - for (var i = 0; i < len; i++) { - out[i] = catmullRomInterpolate( - p0[i], p1[i], p2[i], p3[i], t, t2, t3 - ); - } - } else { - var len2 = p0[0].length; - for (var i = 0; i < len; i++) { - for (var j = 0; j < len2; j++) { - out[i][j] = catmullRomInterpolate( - p0[i][j], p1[i][j], p2[i][j], p3[i][j], - t, t2, t3 - ); - } - } - } -} - -function catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) { - var v0 = (p2 - p0) * 0.5; - var v1 = (p3 - p1) * 0.5; - return (2 * (p1 - p2) + v0 + v1) * t3 - + (- 3 * (p1 - p2) - 2 * v0 - v1) * t2 - + v0 * t + p1; -} - -// arr0 is source array, arr1 is target array. -// Do some preprocess to avoid error happened when interpolating from arr0 to arr1 -function fillArr(arr0, arr1, arrDim) { - var arr0Len = arr0.length; - var arr1Len = arr1.length; - if (arr0Len !== arr1Len) { - // FIXME Not work for TypedArray - var isPreviousLarger = arr0Len > arr1Len; - if (isPreviousLarger) { - // Cut the previous - arr0.length = arr1Len; - } - else { - // Fill the previous - for (var i = arr0Len; i < arr1Len; i++) { - arr0.push( - arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i]) - ); - } - } - } - // Handling NaN value - var len2 = arr0[0] && arr0[0].length; - for (var i = 0; i < arr0.length; i++) { - if (arrDim === 1) { - if (isNaN(arr0[i])) { - arr0[i] = arr1[i]; - } - } - else { - for (var j = 0; j < len2; j++) { - if (isNaN(arr0[i][j])) { - arr0[i][j] = arr1[i][j]; - } - } - } - } -} - -function isArraySame(arr0, arr1, arrDim) { - if (arr0 === arr1) { - return true; - } - var len = arr0.length; - if (len !== arr1.length) { - return false; - } - if (arrDim === 1) { - for (var i = 0; i < len; i++) { - if (arr0[i] !== arr1[i]) { - return false; - } - } - } - else { - var len2 = arr0[0].length; - for (var i = 0; i < len; i++) { - for (var j = 0; j < len2; j++) { - if (arr0[i][j] !== arr1[i][j]) { - return false; - } - } - } - } - return true; -} - -function createTrackClip(animator, globalEasing, oneTrackDone, keyframes, propName, interpolater, maxTime) { - var getter = animator._getter; - var setter = animator._setter; - var useSpline = globalEasing === 'spline'; - - var trackLen = keyframes.length; - if (!trackLen) { - return; - } - // Guess data type - var firstVal = keyframes[0].value; - var isValueArray = isArrayLike(firstVal); - - // For vertices morphing - var arrDim = ( - isValueArray - && isArrayLike(firstVal[0]) - ) - ? 2 : 1; - // Sort keyframe as ascending - keyframes.sort(function(a, b) { - return a.time - b.time; - }); - - // Percents of each keyframe - var kfPercents = []; - // Value of each keyframe - var kfValues = []; - // Easing funcs of each keyframe. - var kfEasings = []; - - var prevValue = keyframes[0].value; - var isAllValueEqual = true; - for (var i = 0; i < trackLen; i++) { - kfPercents.push(keyframes[i].time / maxTime); - - // Assume value is a color when it is a string - var value = keyframes[i].value; - - // Check if value is equal, deep check if value is array - if (!((isValueArray && isArraySame(value, prevValue, arrDim)) - || (!isValueArray && value === prevValue))) { - isAllValueEqual = false; - } - prevValue = value; - - kfValues.push(value); - kfEasings.push(keyframes[i].easing); - } - if (isAllValueEqual) { - return; - } - - var lastValue = kfValues[trackLen - 1]; - // Polyfill array and NaN value - for (var i = 0; i < trackLen - 1; i++) { - if (isValueArray) { - fillArr(kfValues[i], lastValue, arrDim); - } - else { - if (isNaN(kfValues[i]) && !isNaN(lastValue)) { - kfValues[i] = lastValue; - } - } - } - isValueArray && fillArr(getter(animator._target, propName), lastValue, arrDim); - - // Cache the key of last frame to speed up when - // animation playback is sequency - var cacheKey = 0; - var cachePercent = 0; - var start; - var i, w; - var p0, p1, p2, p3; - - var onframe = function(target, percent) { - // Find the range keyframes - // kf1-----kf2---------current--------kf3 - // find kf2(i) and kf3(i + 1) and do interpolation - if (percent < cachePercent) { - // Start from next key - start = Math.min(cacheKey + 1, trackLen - 1); - for (i = start; i >= 0; i--) { - if (kfPercents[i] <= percent) { - break; - } - } - i = Math.min(i, trackLen - 2); - } - else { - for (i = cacheKey; i < trackLen; i++) { - if (kfPercents[i] > percent) { - break; - } - } - i = Math.min(i - 1, trackLen - 2); - } - cacheKey = i; - cachePercent = percent; - - var range = (kfPercents[i + 1] - kfPercents[i]); - if (range === 0) { - return; - } - else { - w = (percent - kfPercents[i]) / range; - // Clamp 0 - 1 - w = Math.max(Math.min(1, w), 0); - } - w = kfEasings[i + 1](w); - - if (useSpline) { - p1 = kfValues[i]; - p0 = kfValues[i === 0 ? i : i - 1]; - p2 = kfValues[i > trackLen - 2 ? trackLen - 1 : i + 1]; - p3 = kfValues[i > trackLen - 3 ? trackLen - 1 : i + 2]; - if (interpolater) { - setter( - target, - propName, - interpolater( - getter(target, propName), - p0, p1, p2, p3, w - ) - ); - } - else if (isValueArray) { - catmullRomInterpolateArray( - p0, p1, p2, p3, w, w*w, w*w*w, - getter(target, propName), - arrDim - ); - } - else { - setter( - target, - propName, - catmullRomInterpolate(p0, p1, p2, p3, w, w*w, w*w*w) - ); - } - } - else { - if (interpolater) { - setter( - target, - propName, - interpolater( - getter(target, propName), - kfValues[i], - kfValues[i + 1], - w - ) - ); - } - - else if (isValueArray) { - interpolateArray( - kfValues[i], kfValues[i+1], w, - getter(target, propName), - arrDim - ); - } - else { - setter( - target, - propName, - interpolateNumber(kfValues[i], kfValues[i+1], w) - ); - } - } - }; - - var clip = new __WEBPACK_IMPORTED_MODULE_0__Clip__["a" /* default */]({ - target: animator._target, - life: maxTime, - loop: animator._loop, - delay: animator._delay, - onframe: onframe, - onfinish: oneTrackDone - }); - - if (globalEasing && globalEasing !== 'spline') { - clip.setEasing(globalEasing); - } - - return clip; -} - -/** - * @description Animator object can only be created by Animation.prototype.animate method. - * After created, we can use {@link clay.animation.Animator#when} to add all keyframes and {@link clay.animation.Animator#start} it. - * Clips will be automatically created and added to the animation instance which created this deferred object. - * - * @constructor clay.animation.Animator - * - * @param {Object} target - * @param {boolean} loop - * @param {Function} getter - * @param {Function} setter - * @param {Function} interpolater - */ -function Animator(target, loop, getter, setter, interpolater) { - this._tracks = {}; - this._target = target; - - this._loop = loop || false; - - this._getter = getter || defaultGetter; - this._setter = setter || defaultSetter; - - this._interpolater = interpolater || null; - - this._delay = 0; - - this._doneList = []; - - this._onframeList = []; - - this._clipList = []; - - this._maxTime = 0; - - this._lastKFTime = 0; -} - -function noopEasing(w) { - return w; -} - -Animator.prototype = { - - constructor: Animator, - - /** - * @param {number} time Keyframe time using millisecond - * @param {Object} props A key-value object. Value can be number, 1d and 2d array - * @param {string|Function} [easing] - * @return {clay.animation.Animator} - * @memberOf clay.animation.Animator.prototype - */ - when: function (time, props, easing) { - - this._maxTime = Math.max(time, this._maxTime); - - easing = (typeof easing === 'function' ? easing : __WEBPACK_IMPORTED_MODULE_1__easing__["a" /* default */][easing]) || noopEasing; - for (var propName in props) { - if (!this._tracks[propName]) { - this._tracks[propName] = []; - // If time is 0 - // Then props is given initialize value - // Else - // Initialize value from current prop value - if (time !== 0) { - this._tracks[propName].push({ - time: 0, - value: cloneValue( - this._getter(this._target, propName) - ), - easing: easing - }); - } - } - this._tracks[propName].push({ - time: parseInt(time), - value: props[propName], - easing: easing - }); - } - return this; - }, - /** - * @param {number} time Keyframe elapsed time since last keyframe - * @param {Object} props A key-value object. Value can be number, 1d and 2d array - * @param {string|Function} [easing] - * @return {clay.animation.Animator} - * @memberOf clay.animation.Animator.prototype - */ - then: function (duringTime, props, easing) { - this.when(duringTime + this._lastKFTime, props, easing); - this._lastKFTime += duringTime; - return this; - }, - /** - * callback when running animation - * @param {Function} callback callback have two args, animating target and current percent - * @return {clay.animation.Animator} - * @memberOf clay.animation.Animator.prototype - */ - during: function (callback) { - this._onframeList.push(callback); - return this; - }, - - _doneCallback: function () { - // Clear all tracks - this._tracks = {}; - // Clear all clips - this._clipList.length = 0; - - var doneList = this._doneList; - var len = doneList.length; - for (var i = 0; i < len; i++) { - doneList[i].call(this); - } - }, - /** - * Start the animation - * @param {string|Function} easing - * @return {clay.animation.Animator} - * @memberOf clay.animation.Animator.prototype - */ - start: function (globalEasing) { - - var self = this; - var clipCount = 0; - - var oneTrackDone = function() { - clipCount--; - if (clipCount === 0) { - self._doneCallback(); - } - }; - - var lastClip; - var clipMaxTime = 0; - for (var propName in this._tracks) { - var clip = createTrackClip( - this, globalEasing, oneTrackDone, - this._tracks[propName], propName, self._interpolater, self._maxTime - ); - if (clip) { - clipMaxTime = Math.max(clipMaxTime, clip.life); - this._clipList.push(clip); - clipCount++; - - // If start after added to animation - if (this.animation) { - this.animation.addClip(clip); - } - - lastClip = clip; - } - } - - // Add during callback on the last clip - if (lastClip) { - var oldOnFrame = lastClip.onframe; - lastClip.onframe = function (target, percent) { - oldOnFrame(target, percent); - - for (var i = 0; i < self._onframeList.length; i++) { - self._onframeList[i](target, percent); - } - }; - } - - if (!clipCount) { - this._doneCallback(); - } - return this; - }, - - /** - * Stop the animation - * @memberOf clay.animation.Animator.prototype - */ - stop: function () { - for (var i = 0; i < this._clipList.length; i++) { - var clip = this._clipList[i]; - this.animation.removeClip(clip); - } - this._clipList = []; - }, - /** - * Delay given milliseconds - * @param {number} time - * @return {clay.animation.Animator} - * @memberOf clay.animation.Animator.prototype - */ - delay: function (time){ - this._delay = time; - return this; - }, - /** - * Callback after animation finished - * @param {Function} func - * @return {clay.animation.Animator} - * @memberOf clay.animation.Animator.prototype - */ - done: function (func) { - if (func) { - this._doneList.push(func); - } - return this; - }, - /** - * Get all clips created in start method. - * @return {clay.animation.Clip[]} - * @memberOf clay.animation.Animator.prototype - */ - getClips: function () { - return this._clipList; - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (Animator); - - -/***/ }), -/* 97 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Geometry__ = __webpack_require__(19); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Mesh__ = __webpack_require__(16); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Node__ = __webpack_require__(15); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__StandardMaterial__ = __webpack_require__(44); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__math_BoundingBox__ = __webpack_require__(8); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_5__dep_glmatrix__); -// TODO test - - - - - - -var mat4 = __WEBPACK_IMPORTED_MODULE_5__dep_glmatrix___default.a.mat4; -var vec3 = __WEBPACK_IMPORTED_MODULE_5__dep_glmatrix___default.a.vec3; - -/** - * @namespace clay.util.mesh - */ -var meshUtil = { - /** - * Merge multiple meshes to one. - * Note that these meshes must have the same material - * - * @param {Array.} meshes - * @param {boolean} applyWorldTransform - * @return clay.Mesh - * @memberOf clay.util.mesh - */ - merge: function (meshes, applyWorldTransform) { - - if (! meshes.length) { - return; - } - - var templateMesh = meshes[0]; - var templateGeo = templateMesh.geometry; - var material = templateMesh.material; - - var geometry = new __WEBPACK_IMPORTED_MODULE_0__Geometry__["a" /* default */]({ - dynamic: false - }); - geometry.boundingBox = new __WEBPACK_IMPORTED_MODULE_4__math_BoundingBox__["a" /* default */](); - - var attributeNames = templateGeo.getEnabledAttributes(); - - for (var i = 0; i < attributeNames.length; i++) { - var name = attributeNames[i]; - var attr = templateGeo.attributes[name]; - // Extend custom attributes - if (!geometry.attributes[name]) { - geometry.attributes[name] = attr.clone(false); - } - } - - var inverseTransposeMatrix = mat4.create(); - // Initialize the array data and merge bounding box - var nVertex = 0; - var nFace = 0; - for (var k = 0; k < meshes.length; k++) { - var currentGeo = meshes[k].geometry; - if (currentGeo.boundingBox) { - currentGeo.boundingBox.applyTransform(applyWorldTransform ? meshes[k].worldTransform : meshes[k].localTransform); - geometry.boundingBox.union(currentGeo.boundingBox); - } - nVertex += currentGeo.vertexCount; - nFace += currentGeo.triangleCount; - } - for (var n = 0; n < attributeNames.length; n++) { - var name = attributeNames[n]; - var attrib = geometry.attributes[name]; - attrib.init(nVertex); - } - if (nVertex >= 0xffff) { - geometry.indices = new Uint32Array(nFace * 3); - } - else { - geometry.indices = new Uint16Array(nFace * 3); - } - - var vertexOffset = 0; - var indicesOffset = 0; - var useIndices = templateGeo.isUseIndices(); - - for (var mm = 0; mm < meshes.length; mm++) { - var mesh = meshes[mm]; - var currentGeo = mesh.geometry; - - var nVertex = currentGeo.vertexCount; - - var matrix = applyWorldTransform ? mesh.worldTransform.array : mesh.localTransform.array; - mat4.invert(inverseTransposeMatrix, matrix); - mat4.transpose(inverseTransposeMatrix, inverseTransposeMatrix); - - for (var nn = 0; nn < attributeNames.length; nn++) { - var name = attributeNames[nn]; - var currentAttr = currentGeo.attributes[name]; - var targetAttr = geometry.attributes[name]; - // Skip the unused attributes; - if (!currentAttr.value.length) { - continue; - } - var len = currentAttr.value.length; - var size = currentAttr.size; - var offset = vertexOffset * size; - var count = len / size; - for (var i = 0; i < len; i++) { - targetAttr.value[offset + i] = currentAttr.value[i]; - } - // Transform position, normal and tangent - if (name === 'position') { - vec3.forEach(targetAttr.value, size, offset, count, vec3.transformMat4, matrix); - } - else if (name === 'normal' || name === 'tangent') { - vec3.forEach(targetAttr.value, size, offset, count, vec3.transformMat4, inverseTransposeMatrix); - } - } - - if (useIndices) { - var len = currentGeo.indices.length; - for (var i = 0; i < len; i++) { - geometry.indices[i + indicesOffset] = currentGeo.indices[i] + vertexOffset; - } - indicesOffset += len; - } - - vertexOffset += nVertex; - } - - return new __WEBPACK_IMPORTED_MODULE_1__Mesh__["a" /* default */]({ - material: material, - geometry: geometry - }); - }, - - /** - * Split mesh into sub meshes, each mesh will have maxJointNumber joints. - * @param {clay.Mesh} mesh - * @param {number} maxJointNumber - * @param {boolean} inPlace - * @return {clay.Node} - * - * @memberOf clay.util.mesh - */ - - // FIXME, Have issues on some models - splitByJoints: function (mesh, maxJointNumber, inPlace) { - var geometry = mesh.geometry; - var skeleton = mesh.skeleton; - var material = mesh.material; - var joints = mesh.joints; - if (!geometry || !skeleton || !joints.length) { - return; - } - if (joints.length < maxJointNumber) { - return mesh; - } - - - var indices = geometry.indices; - - var faceLen = geometry.triangleCount; - var rest = faceLen; - var isFaceAdded = []; - var jointValues = geometry.attributes.joint.value; - for (var i = 0; i < faceLen; i++) { - isFaceAdded[i] = false; - } - var addedJointIdxPerFace = []; - - var buckets = []; - - var getJointByIndex = function (idx) { - return joints[idx]; - }; - while (rest > 0) { - var bucketTriangles = []; - var bucketJointReverseMap = []; - var bucketJoints = []; - var subJointNumber = 0; - for (var i = 0; i < joints.length; i++) { - bucketJointReverseMap[i] = -1; - } - for (var f = 0; f < faceLen; f++) { - if (isFaceAdded[f]) { - continue; - } - var canAddToBucket = true; - var addedNumber = 0; - for (var i = 0; i < 3; i++) { - - var idx = indices[f * 3 + i]; - - for (var j = 0; j < 4; j++) { - var jointIdx = jointValues[idx * 4 + j]; - - if (jointIdx >= 0) { - if (bucketJointReverseMap[jointIdx] === -1) { - if (subJointNumber < maxJointNumber) { - bucketJointReverseMap[jointIdx] = subJointNumber; - bucketJoints[subJointNumber++] = jointIdx; - addedJointIdxPerFace[addedNumber++] = jointIdx; - } - else { - canAddToBucket = false; - } - } - } - } - } - if (!canAddToBucket) { - // Reverse operation - for (var i = 0; i < addedNumber; i++) { - bucketJointReverseMap[addedJointIdxPerFace[i]] = -1; - bucketJoints.pop(); - subJointNumber--; - } - } - else { - bucketTriangles.push(indices.subarray(f * 3, (f + 1) * 3)); - - isFaceAdded[f] = true; - rest--; - } - } - buckets.push({ - triangles: bucketTriangles, - joints: bucketJoints.map(getJointByIndex), - jointReverseMap: bucketJointReverseMap - }); - } - - var root = new __WEBPACK_IMPORTED_MODULE_2__Node__["a" /* default */]({ - name: mesh.name - }); - var attribNames = geometry.getEnabledAttributes(); - - attribNames.splice(attribNames.indexOf('joint'), 1); - // Map from old vertex index to new vertex index - var newIndices = []; - for (var b = 0; b < buckets.length; b++) { - var bucket = buckets[b]; - var jointReverseMap = bucket.jointReverseMap; - var subJointNumber = bucket.joints.length; - - var subMat = material.clone(); - subMat.name = [material.name, b].join('-'); - - var subGeo = new __WEBPACK_IMPORTED_MODULE_0__Geometry__["a" /* default */](); - - var subMesh = new __WEBPACK_IMPORTED_MODULE_1__Mesh__["a" /* default */]({ - name: [mesh.name, i].join('-'), - material: subMat, - geometry: subGeo, - skeleton: skeleton, - joints: bucket.joints.slice() - }); - var nVertex = 0; - var nVertex2 = geometry.vertexCount; - for (var i = 0; i < nVertex2; i++) { - newIndices[i] = -1; - } - // Count sub geo number - for (var f = 0; f < bucket.triangles.length; f++) { - var face = bucket.triangles[f]; - for (var i = 0; i < 3; i++) { - var idx = face[i]; - if (newIndices[idx] === -1) { - newIndices[idx] = nVertex; - nVertex++; - } - } - } - for (var a = 0; a < attribNames.length; a++) { - var attribName = attribNames[a]; - var subAttrib = subGeo.attributes[attribName]; - subAttrib.init(nVertex); - } - subGeo.attributes.joint.value = new Float32Array(nVertex * 4); - - if (nVertex > 0xffff) { - subGeo.indices = new Uint32Array(bucket.triangles.length * 3); - } - else { - subGeo.indices = new Uint16Array(bucket.triangles.length * 3); - } - - var indicesOffset = 0; - nVertex = 0; - for (var i = 0; i < nVertex2; i++) { - newIndices[i] = -1; - } - - for (var f = 0; f < bucket.triangles.length; f++) { - var triangle = bucket.triangles[f]; - for (var i = 0; i < 3; i++) { - - var idx = triangle[i]; - - if (newIndices[idx] === -1) { - newIndices[idx] = nVertex; - for (var a = 0; a < attribNames.length; a++) { - var attribName = attribNames[a]; - var attrib = geometry.attributes[attribName]; - var subAttrib = subGeo.attributes[attribName]; - var size = attrib.size; - - for (var j = 0; j < size; j++) { - subAttrib.value[nVertex * size + j] = attrib.value[idx * size + j]; - } - } - for (var j = 0; j < 4; j++) { - var jointIdx = geometry.attributes.joint.value[idx * 4 + j]; - var offset = nVertex * 4 + j; - if (jointIdx >= 0) { - subGeo.attributes.joint.value[offset] = jointReverseMap[jointIdx]; - } - else { - subGeo.attributes.joint.value[offset] = -1; - } - } - nVertex++; - } - subGeo.indices[indicesOffset++] = newIndices[idx]; - } - } - subGeo.updateBoundingBox(); - - root.add(subMesh); - } - var children = mesh.children(); - for (var i = 0; i < children.length; i++) { - root.add(children[i]); - } - root.position.copy(mesh.position); - root.rotation.copy(mesh.rotation); - root.scale.copy(mesh.scale); - - if (inPlace) { - if (mesh.getParent()) { - var parent = mesh.getParent(); - parent.remove(mesh); - parent.add(root); - } - } - return root; - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (meshUtil); - - -/***/ }), -/* 98 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_util__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Task__ = __webpack_require__(60); - - - -/** - * @constructor - * @alias clay.async.TaskGroup - * @extends clay.async.Task - */ -var TaskGroup = function () { - - __WEBPACK_IMPORTED_MODULE_1__Task__["a" /* default */].apply(this, arguments); - - this._tasks = []; - - this._fulfilledNumber = 0; - - this._rejectedNumber = 0; -}; - -var Ctor = function (){}; -Ctor.prototype = __WEBPACK_IMPORTED_MODULE_1__Task__["a" /* default */].prototype; -TaskGroup.prototype = new Ctor(); - -TaskGroup.prototype.constructor = TaskGroup; - -/** - * Wait for all given tasks successed, task can also be any notifier object which will trigger success and error events. Like {@link clay.Texture2D}, {@link clay.TextureCube}, {@link clay.loader.GLTF}. - * @param {Array.} tasks - * @chainable - * @example - * // Load texture list - * var list = ['a.jpg', 'b.jpg', 'c.jpg'] - * var textures = list.map(function (src) { - * var texture = new clay.Texture2D(); - * texture.load(src); - * return texture; - * }); - * var taskGroup = new clay.async.TaskGroup(); - * taskGroup.all(textures).success(function () { - * // Do some thing after all textures loaded - * }); - */ -TaskGroup.prototype.all = function (tasks) { - var count = 0; - var self = this; - var data = []; - this._tasks = tasks; - this._fulfilledNumber = 0; - this._rejectedNumber = 0; - - __WEBPACK_IMPORTED_MODULE_0__core_util__["a" /* default */].each(tasks, function (task, idx) { - if (!task || !task.once) { - return; - } - count++; - task.once('success', function (res) { - count--; - - self._fulfilledNumber++; - // TODO - // Some tasks like texture, loader are not inherited from task - // We need to set the states here - task._fulfilled = true; - task._rejected = false; - - data[idx] = res; - if (count === 0) { - self.resolve(data); - } - }); - task.once('error', function () { - - self._rejectedNumber ++; - - task._fulfilled = false; - task._rejected = true; - - self.reject(task); - }); - }); - if (count === 0) { - setTimeout(function () { - self.resolve(data); - }); - return this; - } - return this; -}; -/** - * Wait for all given tasks finished, either successed or failed - * @param {Array.} tasks - * @return {clay.async.TaskGroup} - */ -TaskGroup.prototype.allSettled = function (tasks) { - var count = 0; - var self = this; - var data = []; - if (tasks.length === 0) { - setTimeout(function () { - self.trigger('success', data); - }); - return this; - } - this._tasks = tasks; - - __WEBPACK_IMPORTED_MODULE_0__core_util__["a" /* default */].each(tasks, function (task, idx) { - if (!task || !task.once) { - return; - } - count++; - task.once('success', function (res) { - count--; - - self._fulfilledNumber++; - - task._fulfilled = true; - task._rejected = false; - - data[idx] = res; - if (count === 0) { - self.resolve(data); - } - }); - task.once('error', function (err) { - count--; - - self._rejectedNumber++; - - task._fulfilled = false; - task._rejected = true; - - // TODO - data[idx] = null; - if (count === 0) { - self.resolve(data); - } - }); - }); - return this; -}; -/** - * Get successed sub tasks number, recursive can be true if sub task is also a TaskGroup. - * @param {boolean} [recursive] - * @return {number} - */ -TaskGroup.prototype.getFulfilledNumber = function (recursive) { - if (recursive) { - var nFulfilled = 0; - for (var i = 0; i < this._tasks.length; i++) { - var task = this._tasks[i]; - if (task instanceof TaskGroup) { - nFulfilled += task.getFulfilledNumber(recursive); - } else if(task._fulfilled) { - nFulfilled += 1; - } - } - return nFulfilled; - } else { - return this._fulfilledNumber; - } -}; - -/** - * Get failed sub tasks number, recursive can be true if sub task is also a TaskGroup. - * @param {boolean} [recursive] - * @return {number} - */ -TaskGroup.prototype.getRejectedNumber = function (recursive) { - if (recursive) { - var nRejected = 0; - for (var i = 0; i < this._tasks.length; i++) { - var task = this._tasks[i]; - if (task instanceof TaskGroup) { - nRejected += task.getRejectedNumber(recursive); - } else if(task._rejected) { - nRejected += 1; - } - } - return nRejected; - } else { - return this._rejectedNumber; - } -}; - -/** - * Get finished sub tasks number, recursive can be true if sub task is also a TaskGroup. - * @param {boolean} [recursive] - * @return {number} - */ -TaskGroup.prototype.getSettledNumber = function (recursive) { - - if (recursive) { - var nSettled = 0; - for (var i = 0; i < this._tasks.length; i++) { - var task = this._tasks[i]; - if (task instanceof TaskGroup) { - nSettled += task.getSettledNumber(recursive); - } else if(task._rejected || task._fulfilled) { - nSettled += 1; - } - } - return nSettled; - } else { - return this._fulfilledNumber + this._rejectedNumber; - } -}; - -/** - * Get all sub tasks number, recursive can be true if sub task is also a TaskGroup. - * @param {boolean} [recursive] - * @return {number} - */ -TaskGroup.prototype.getTaskNumber = function (recursive) { - if (recursive) { - var nTask = 0; - for (var i = 0; i < this._tasks.length; i++) { - var task = this._tasks[i]; - if (task instanceof TaskGroup) { - nTask += task.getTaskNumber(recursive); - } else { - nTask += 1; - } - } - return nTask; - } else { - return this._tasks.length; - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (TaskGroup); - - -/***/ }), -/* 99 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__math_Ray__ = __webpack_require__(43); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__math_Vector2__ = __webpack_require__(21); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__math_Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__math_Matrix4__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__Renderable__ = __webpack_require__(46); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__core_glenum__ = __webpack_require__(6); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_7__dep_glmatrix__); - - - - - - - - - -var vec3 = __WEBPACK_IMPORTED_MODULE_7__dep_glmatrix___default.a.vec3; - -/** - * @constructor clay.picking.RayPicking - * @extends clay.core.Base - */ -var RayPicking = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend( -/** @lends clay.picking.RayPicking# */ -{ - /** - * Target scene - * @type {clay.Scene} - */ - scene: null, - /** - * Target camera - * @type {clay.Camera} - */ - camera: null, - /** - * Target renderer - * @type {clay.Renderer} - */ - renderer: null -}, function () { - this._ray = new __WEBPACK_IMPORTED_MODULE_1__math_Ray__["a" /* default */](); - this._ndc = new __WEBPACK_IMPORTED_MODULE_2__math_Vector2__["a" /* default */](); -}, -/** @lends clay.picking.RayPicking.prototype */ -{ - - /** - * Pick the nearest intersection object in the scene - * @param {number} x Mouse position x - * @param {number} y Mouse position y - * @param {boolean} [forcePickAll=false] ignore ignorePicking - * @return {clay.picking.RayPicking~Intersection} - */ - pick: function (x, y, forcePickAll) { - var out = this.pickAll(x, y, [], forcePickAll); - return out[0] || null; - }, - - /** - * Pick all intersection objects, wich will be sorted from near to far - * @param {number} x Mouse position x - * @param {number} y Mouse position y - * @param {Array} [output] - * @param {boolean} [forcePickAll=false] ignore ignorePicking - * @return {Array.} - */ - pickAll: function (x, y, output, forcePickAll) { - this.renderer.screenToNDC(x, y, this._ndc); - this.camera.castRay(this._ndc, this._ray); - - output = output || []; - - this._intersectNode(this.scene, output, forcePickAll || false); - - output.sort(this._intersectionCompareFunc); - - return output; - }, - - _intersectNode: function (node, out, forcePickAll) { - if ((node instanceof __WEBPACK_IMPORTED_MODULE_5__Renderable__["a" /* default */]) && node.isRenderable()) { - if ((!node.ignorePicking || forcePickAll) - && ( - // Only triangle mesh support ray picking - (node.mode === __WEBPACK_IMPORTED_MODULE_6__core_glenum__["a" /* default */].TRIANGLES && node.geometry.isUseIndices()) - // Or if geometry has it's own pickByRay, pick, implementation - || node.geometry.pickByRay - || node.geometry.pick - ) - ) { - this._intersectRenderable(node, out); - } - } - for (var i = 0; i < node._children.length; i++) { - this._intersectNode(node._children[i], out, forcePickAll); - } - }, - - _intersectRenderable: (function () { - - var v1 = new __WEBPACK_IMPORTED_MODULE_3__math_Vector3__["a" /* default */](); - var v2 = new __WEBPACK_IMPORTED_MODULE_3__math_Vector3__["a" /* default */](); - var v3 = new __WEBPACK_IMPORTED_MODULE_3__math_Vector3__["a" /* default */](); - var ray = new __WEBPACK_IMPORTED_MODULE_1__math_Ray__["a" /* default */](); - var worldInverse = new __WEBPACK_IMPORTED_MODULE_4__math_Matrix4__["a" /* default */](); - - return function (renderable, out) { - - var isSkinnedMesh = renderable.isSkinnedMesh(); - ray.copy(this._ray); - __WEBPACK_IMPORTED_MODULE_4__math_Matrix4__["a" /* default */].invert(worldInverse, renderable.worldTransform); - - // Skinned mesh will ignore the world transform. - if (!isSkinnedMesh) { - ray.applyTransform(worldInverse); - } - - var geometry = renderable.geometry; - // Ignore bounding box of skinned mesh? - if (!isSkinnedMesh) { - if (geometry.boundingBox) { - if (!ray.intersectBoundingBox(geometry.boundingBox)) { - return; - } - } - } - // Use user defined picking algorithm - if (geometry.pick) { - geometry.pick( - this._ndc.x, this._ndc.y, - this.renderer, - this.camera, - renderable, out - ); - return; - } - // Use user defined ray picking algorithm - else if (geometry.pickByRay) { - geometry.pickByRay(ray, renderable, out); - return; - } - - var cullBack = (renderable.cullFace === __WEBPACK_IMPORTED_MODULE_6__core_glenum__["a" /* default */].BACK && renderable.frontFace === __WEBPACK_IMPORTED_MODULE_6__core_glenum__["a" /* default */].CCW) - || (renderable.cullFace === __WEBPACK_IMPORTED_MODULE_6__core_glenum__["a" /* default */].FRONT && renderable.frontFace === __WEBPACK_IMPORTED_MODULE_6__core_glenum__["a" /* default */].CW); - - var point; - var indices = geometry.indices; - var positionAttr = geometry.attributes.position; - var weightAttr = geometry.attributes.weight; - var jointAttr = geometry.attributes.joint; - var skinMatricesArray; - var skinMatrices = []; - // Check if valid. - if (!positionAttr || !positionAttr.value || !indices) { - return; - } - if (isSkinnedMesh) { - skinMatricesArray = renderable.skeleton.getSubSkinMatrices(renderable.__uid__, renderable.joints); - for (var i = 0; i < renderable.joints.length; i++) { - skinMatrices[i] = skinMatrices[i] || []; - for (var k = 0; k < 16; k++) { - skinMatrices[i][k] = skinMatricesArray[i * 16 + k]; - } - } - var pos = []; - var weight = []; - var joint = []; - var skinnedPos = []; - var tmp = []; - var skinnedPositionAttr = geometry.attributes.skinnedPosition; - if (!skinnedPositionAttr || !skinnedPositionAttr.value) { - geometry.createAttribute('skinnedPosition', 'f', 3); - skinnedPositionAttr = geometry.attributes.skinnedPosition; - skinnedPositionAttr.init(geometry.vertexCount); - } - for (var i = 0; i < geometry.vertexCount; i++) { - positionAttr.get(i, pos); - weightAttr.get(i, weight); - jointAttr.get(i, joint); - weight[3] = 1 - weight[0] - weight[1] - weight[2]; - vec3.set(skinnedPos, 0, 0, 0); - for (var k = 0; k < 4; k++) { - if (joint[k] >= 0 && weight[k] > 1e-4) { - vec3.transformMat4(tmp, pos, skinMatrices[joint[k]]); - vec3.scaleAndAdd(skinnedPos, skinnedPos, tmp, weight[k]); - } - } - skinnedPositionAttr.set(i, skinnedPos); - } - } - - for (var i = 0; i < indices.length; i += 3) { - var i1 = indices[i]; - var i2 = indices[i + 1]; - var i3 = indices[i + 2]; - var finalPosAttr = isSkinnedMesh - ? geometry.attributes.skinnedPosition - : positionAttr; - finalPosAttr.get(i1, v1.array); - finalPosAttr.get(i2, v2.array); - finalPosAttr.get(i3, v3.array); - - if (cullBack) { - point = ray.intersectTriangle(v1, v2, v3, renderable.culling); - } - else { - point = ray.intersectTriangle(v1, v3, v2, renderable.culling); - } - if (point) { - var pointW = new __WEBPACK_IMPORTED_MODULE_3__math_Vector3__["a" /* default */](); - if (!isSkinnedMesh) { - __WEBPACK_IMPORTED_MODULE_3__math_Vector3__["a" /* default */].transformMat4(pointW, point, renderable.worldTransform); - } - else { - // TODO point maybe not right. - __WEBPACK_IMPORTED_MODULE_3__math_Vector3__["a" /* default */].copy(pointW, point); - } - out.push(new RayPicking.Intersection( - point, pointW, renderable, [i1, i2, i3], i / 3, - __WEBPACK_IMPORTED_MODULE_3__math_Vector3__["a" /* default */].dist(pointW, this._ray.origin) - )); - } - } - }; - })(), - - _intersectionCompareFunc: function (a, b) { - return a.distance - b.distance; - } -}); - -/** - * @constructor clay.picking.RayPicking~Intersection - * @param {clay.math.Vector3} point - * @param {clay.math.Vector3} pointWorld - * @param {clay.Node} target - * @param {Array.} triangle - * @param {number} triangleIndex - * @param {number} distance - */ -RayPicking.Intersection = function (point, pointWorld, target, triangle, triangleIndex, distance) { - /** - * Intersection point in local transform coordinates - * @type {clay.math.Vector3} - */ - this.point = point; - /** - * Intersection point in world transform coordinates - * @type {clay.math.Vector3} - */ - this.pointWorld = pointWorld; - /** - * Intersection scene node - * @type {clay.Node} - */ - this.target = target; - /** - * Intersection triangle, which is an array of vertex index - * @type {Array.} - */ - this.triangle = triangle; - /** - * Index of intersection triangle. - */ - this.triangleIndex = triangleIndex; - /** - * Distance from intersection point to ray origin - * @type {number} - */ - this.distance = distance; -}; - -/* harmony default export */ __webpack_exports__["a"] = (RayPicking); - - -/***/ }), -/* 100 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Geometry__ = __webpack_require__(19); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__math_BoundingBox__ = __webpack_require__(8); - - - -/** - * @constructor clay.geometry.Sphere - * @extends clay.Geometry - * @param {Object} [opt] - * @param {number} [widthSegments] - * @param {number} [heightSegments] - * @param {number} [phiStart] - * @param {number} [phiLength] - * @param {number} [thetaStart] - * @param {number} [thetaLength] - * @param {number} [radius] - */ -var Sphere = __WEBPACK_IMPORTED_MODULE_0__Geometry__["a" /* default */].extend( -/** @lends clay.geometry.Sphere# */ -{ - dynamic: false, - /** - * @type {number} - */ - widthSegments: 40, - /** - * @type {number} - */ - heightSegments: 20, - - /** - * @type {number} - */ - phiStart: 0, - /** - * @type {number} - */ - phiLength: Math.PI * 2, - - /** - * @type {number} - */ - thetaStart: 0, - /** - * @type {number} - */ - thetaLength: Math.PI, - - /** - * @type {number} - */ - radius: 1 - -}, function() { - this.build(); -}, -/** @lends clay.geometry.Sphere.prototype */ -{ - /** - * Build sphere geometry - */ - build: function() { - var heightSegments = this.heightSegments; - var widthSegments = this.widthSegments; - - var positionAttr = this.attributes.position; - var texcoordAttr = this.attributes.texcoord0; - var normalAttr = this.attributes.normal; - - var vertexCount = (widthSegments + 1) * (heightSegments + 1); - positionAttr.init(vertexCount); - texcoordAttr.init(vertexCount); - normalAttr.init(vertexCount); - - var IndicesCtor = vertexCount > 0xffff ? Uint32Array : Uint16Array; - var indices = this.indices = new IndicesCtor(widthSegments * heightSegments * 6); - - var x, y, z, - u, v, - i, j; - - var radius = this.radius; - var phiStart = this.phiStart; - var phiLength = this.phiLength; - var thetaStart = this.thetaStart; - var thetaLength = this.thetaLength; - var radius = this.radius; - - var pos = []; - var uv = []; - var offset = 0; - var divider = 1 / radius; - for (j = 0; j <= heightSegments; j ++) { - for (i = 0; i <= widthSegments; i ++) { - u = i / widthSegments; - v = j / heightSegments; - - // X axis is inverted so texture can be mapped from left to right - x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength); - y = radius * Math.cos(thetaStart + v * thetaLength); - z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength); - - pos[0] = x; pos[1] = y; pos[2] = z; - uv[0] = u; uv[1] = v; - positionAttr.set(offset, pos); - texcoordAttr.set(offset, uv); - pos[0] *= divider; - pos[1] *= divider; - pos[2] *= divider; - normalAttr.set(offset, pos); - offset++; - } - } - - var i1, i2, i3, i4; - - var len = widthSegments + 1; - - var n = 0; - for (j = 0; j < heightSegments; j ++) { - for (i = 0; i < widthSegments; i ++) { - i2 = j * len + i; - i1 = (j * len + i + 1); - i4 = (j + 1) * len + i + 1; - i3 = (j + 1) * len + i; - - indices[n++] = i1; - indices[n++] = i2; - indices[n++] = i4; - - indices[n++] = i2; - indices[n++] = i3; - indices[n++] = i4; - } - } - - this.boundingBox = new __WEBPACK_IMPORTED_MODULE_1__math_BoundingBox__["a" /* default */](); - this.boundingBox.max.set(radius, radius, radius); - this.boundingBox.min.set(-radius, -radius, -radius); - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (Sphere); - - -/***/ }), -/* 101 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Texture2D__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__TextureCube__ = __webpack_require__(17); - - - - -// http://msdn.microsoft.com/en-us/library/windows/desktop/bb943991(v=vs.85).aspx -// https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js -var DDS_MAGIC = 0x20534444; - -var DDSD_CAPS = 0x1; -var DDSD_HEIGHT = 0x2; -var DDSD_WIDTH = 0x4; -var DDSD_PITCH = 0x8; -var DDSD_PIXELFORMAT = 0x1000; -var DDSD_MIPMAPCOUNT = 0x20000; -var DDSD_LINEARSIZE = 0x80000; -var DDSD_DEPTH = 0x800000; - -var DDSCAPS_COMPLEX = 0x8; -var DDSCAPS_MIPMAP = 0x400000; -var DDSCAPS_TEXTURE = 0x1000; - -var DDSCAPS2_CUBEMAP = 0x200; -var DDSCAPS2_CUBEMAP_POSITIVEX = 0x400; -var DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800; -var DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000; -var DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000; -var DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000; -var DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000; -var DDSCAPS2_VOLUME = 0x200000; - -var DDPF_ALPHAPIXELS = 0x1; -var DDPF_ALPHA = 0x2; -var DDPF_FOURCC = 0x4; -var DDPF_RGB = 0x40; -var DDPF_YUV = 0x200; -var DDPF_LUMINANCE = 0x20000; - -function fourCCToInt32(value) { - return value.charCodeAt(0) + - (value.charCodeAt(1) << 8) + - (value.charCodeAt(2) << 16) + - (value.charCodeAt(3) << 24); -} - -function int32ToFourCC(value) { - return String.fromCharCode( - value & 0xff, - (value >> 8) & 0xff, - (value >> 16) & 0xff, - (value >> 24) & 0xff - ); -} - -var headerLengthInt = 31; // The header length in 32 bit ints - -var FOURCC_DXT1 = fourCCToInt32('DXT1'); -var FOURCC_DXT3 = fourCCToInt32('DXT3'); -var FOURCC_DXT5 = fourCCToInt32('DXT5'); - // Offsets into the header array -var off_magic = 0; - -var off_size = 1; -var off_flags = 2; -var off_height = 3; -var off_width = 4; - -var off_mipmapCount = 7; - -var off_pfFlags = 20; -var off_pfFourCC = 21; - -var off_caps = 27; -var off_caps2 = 28; -var off_caps3 = 29; -var off_caps4 = 30; - -var ret = { - parse: function(arrayBuffer, out) { - var header = new Int32Array(arrayBuffer, 0, headerLengthInt); - if (header[off_magic] !== DDS_MAGIC) { - return null; - } - if (!header(off_pfFlags) & DDPF_FOURCC) { - return null; - } - - var fourCC = header(off_pfFourCC); - var width = header[off_width]; - var height = header[off_height]; - var isCubeMap = header[off_caps2] & DDSCAPS2_CUBEMAP; - var hasMipmap = header[off_flags] & DDSD_MIPMAPCOUNT; - var blockBytes, internalFormat; - switch(fourCC) { - case FOURCC_DXT1: - blockBytes = 8; - internalFormat = __WEBPACK_IMPORTED_MODULE_0__Texture__["a" /* default */].COMPRESSED_RGB_S3TC_DXT1_EXT; - break; - case FOURCC_DXT3: - blockBytes = 16; - internalFormat = __WEBPACK_IMPORTED_MODULE_0__Texture__["a" /* default */].COMPRESSED_RGBA_S3TC_DXT3_EXT; - break; - case FOURCC_DXT5: - blockBytes = 16; - internalFormat = __WEBPACK_IMPORTED_MODULE_0__Texture__["a" /* default */].COMPRESSED_RGBA_S3TC_DXT5_EXT; - break; - default: - return null; - } - var dataOffset = header[off_size] + 4; - // TODO: Suppose all face are existed - var faceNumber = isCubeMap ? 6 : 1; - var mipmapCount = 1; - if (hasMipmap) { - mipmapCount = Math.max(1, header[off_mipmapCount]); - } - - var textures = []; - for (var f = 0; f < faceNumber; f++) { - var _width = width; - var _height = height; - textures[f] = new __WEBPACK_IMPORTED_MODULE_1__Texture2D__["a" /* default */]({ - width : _width, - height : _height, - format : internalFormat - }); - var mipmaps = []; - for (var i = 0; i < mipmapCount; i++) { - var dataLength = Math.max(4, _width) / 4 * Math.max(4, _height) / 4 * blockBytes; - var byteArray = new Uint8Array(arrayBuffer, dataOffset, dataLength); - - dataOffset += dataLength; - _width *= 0.5; - _height *= 0.5; - mipmaps[i] = byteArray; - } - textures[f].pixels = mipmaps[0]; - if (hasMipmap) { - textures[f].mipmaps = mipmaps; - } - } - // TODO - // return isCubeMap ? textures : textures[0]; - if (out) { - out.width = textures[0].width; - out.height = textures[0].height; - out.format = textures[0].format; - out.pixels = textures[0].pixels; - out.mipmaps = textures[0].mipmaps; - } - else { - return textures[0]; - } - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (ret); - - -/***/ }), -/* 102 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Texture2D__ = __webpack_require__(5); - - -var toChar = String.fromCharCode; - -var MINELEN = 8; -var MAXELEN = 0x7fff; -function rgbe2float(rgbe, buffer, offset, exposure) { - if (rgbe[3] > 0) { - var f = Math.pow(2.0, rgbe[3] - 128 - 8 + exposure); - buffer[offset + 0] = rgbe[0] * f; - buffer[offset + 1] = rgbe[1] * f; - buffer[offset + 2] = rgbe[2] * f; - } - else { - buffer[offset + 0] = 0; - buffer[offset + 1] = 0; - buffer[offset + 2] = 0; - } - buffer[offset + 3] = 1.0; - return buffer; -} - -function uint82string(array, offset, size) { - var str = ''; - for (var i = offset; i < size; i++) { - str += toChar(array[i]); - } - return str; -} - -function copyrgbe(s, t) { - t[0] = s[0]; - t[1] = s[1]; - t[2] = s[2]; - t[3] = s[3]; -} - -// TODO : check -function oldReadColors(scan, buffer, offset, xmax) { - var rshift = 0, x = 0, len = xmax; - while (len > 0) { - scan[x][0] = buffer[offset++]; - scan[x][1] = buffer[offset++]; - scan[x][2] = buffer[offset++]; - scan[x][3] = buffer[offset++]; - if (scan[x][0] === 1 && scan[x][1] === 1 && scan[x][2] === 1) { - // exp is count of repeated pixels - for (var i = (scan[x][3] << rshift) >>> 0; i > 0; i--) { - copyrgbe(scan[x-1], scan[x]); - x++; - len--; - } - rshift += 8; - } else { - x++; - len--; - rshift = 0; - } - } - return offset; -} - -function readColors(scan, buffer, offset, xmax) { - if ((xmax < MINELEN) | (xmax > MAXELEN)) { - return oldReadColors(scan, buffer, offset, xmax); - } - var i = buffer[offset++]; - if (i != 2) { - return oldReadColors(scan, buffer, offset - 1, xmax); - } - scan[0][1] = buffer[offset++]; - scan[0][2] = buffer[offset++]; - - i = buffer[offset++]; - if ((((scan[0][2] << 8) >>> 0) | i) >>> 0 !== xmax) { - return null; - } - for (var i = 0; i < 4; i++) { - for (var x = 0; x < xmax;) { - var code = buffer[offset++]; - if (code > 128) { - code = (code & 127) >>> 0; - var val = buffer[offset++]; - while (code--) { - scan[x++][i] = val; - } - } else { - while (code--) { - scan[x++][i] = buffer[offset++]; - } - } - } - } - return offset; -} - - -var ret = { - // http://www.graphics.cornell.edu/~bjw/rgbe.html - // Blender source - // http://radsite.lbl.gov/radiance/refer/Notes/picture_format.html - parseRGBE: function(arrayBuffer, texture, exposure) { - if (exposure == null) { - exposure = 0; - } - var data = new Uint8Array(arrayBuffer); - var size = data.length; - if (uint82string(data, 0, 2) !== '#?') { - return; - } - // find empty line, next line is resolution info - for (var i = 2; i < size; i++) { - if (toChar(data[i]) === '\n' && toChar(data[i+1]) === '\n') { - break; - } - } - if (i >= size) { // not found - return; - } - // find resolution info line - i += 2; - var str = ''; - for (; i < size; i++) { - var _char = toChar(data[i]); - if (_char === '\n') { - break; - } - str += _char; - } - // -Y M +X N - var tmp = str.split(' '); - var height = parseInt(tmp[1]); - var width = parseInt(tmp[3]); - if (!width || !height) { - return; - } - - // read and decode actual data - var offset = i+1; - var scanline = []; - // memzero - for (var x = 0; x < width; x++) { - scanline[x] = []; - for (var j = 0; j < 4; j++) { - scanline[x][j] = 0; - } - } - var pixels = new Float32Array(width * height * 4); - var offset2 = 0; - for (var y = 0; y < height; y++) { - var offset = readColors(scanline, data, offset, width); - if (!offset) { - return null; - } - for (var x = 0; x < width; x++) { - rgbe2float(scanline[x], pixels, offset2, exposure); - offset2 += 4; - } - } - - if (!texture) { - texture = new __WEBPACK_IMPORTED_MODULE_1__Texture2D__["a" /* default */](); - } - texture.width = width; - texture.height = height; - texture.pixels = pixels; - // HALF_FLOAT can't use Float32Array - texture.type = __WEBPACK_IMPORTED_MODULE_0__Texture__["a" /* default */].FLOAT; - return texture; - }, - - parseRGBEFromPNG: function(png) { - - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (ret); - - -/***/ }), -/* 103 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_claygl_src_Scene__ = __webpack_require__(18); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_claygl_src_prePass_ShadowMap__ = __webpack_require__(104); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_claygl_src_camera_Perspective__ = __webpack_require__(22); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_claygl_src_camera_Orthographic__ = __webpack_require__(23); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4_claygl_src_math_Matrix4__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5_claygl_src_math_Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6_claygl_src_math_Vector2__ = __webpack_require__(21); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7_claygl_src_core_mixin_notifier__ = __webpack_require__(20); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__EffectCompositor__ = __webpack_require__(109); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__TemporalSuperSampling__ = __webpack_require__(134); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__halton__ = __webpack_require__(25); -// TODO Default parameter of postEffect - - - - - - - - - - - - - - - -function RenderMain(renderer, enableShadow, projection) { - - this.renderer = renderer; - - projection = projection || 'perspective'; - - /** - * @type {clay.Scene} - */ - this.scene = new __WEBPACK_IMPORTED_MODULE_0_claygl_src_Scene__["a" /* default */](); - - /** - * @type {clay.Node} - */ - this.rootNode = this.scene; - - this.viewport = { - x: 0, y: 0, width: 0, height: 0 - }; - - this.preZ = false; - - this.setProjection(projection); - - this._compositor = new __WEBPACK_IMPORTED_MODULE_8__EffectCompositor__["a" /* default */](); - - this._temporalSS = new __WEBPACK_IMPORTED_MODULE_9__TemporalSuperSampling__["a" /* default */](); - - if (enableShadow) { - this._shadowMapPass = new __WEBPACK_IMPORTED_MODULE_1_claygl_src_prePass_ShadowMap__["a" /* default */]({ - lightFrustumBias: 20 - }); - } - - var pcfKernels = []; - var off = 0; - for (var i = 0; i < 30; i++) { - var pcfKernel = []; - for (var k = 0; k < 6; k++) { - pcfKernel.push(Object(__WEBPACK_IMPORTED_MODULE_10__halton__["a" /* default */])(off, 2) * 4.0 - 2.0); - pcfKernel.push(Object(__WEBPACK_IMPORTED_MODULE_10__halton__["a" /* default */])(off, 3) * 4.0 - 2.0); - off++; - } - pcfKernels.push(pcfKernel); - } - this._pcfKernels = pcfKernels; - - this._enableTemporalSS = 'auto'; - - this.scene.on('beforerender', function (renderer, scene, camera) { - if (this.needsTemporalSS()) { - this._temporalSS.jitterProjection(renderer, camera); - } - }, this); -} - -/** - * Set camera type of group - * @param {string} cameraType 'perspective' | 'orthographic' - */ -RenderMain.prototype.setProjection = function (projection) { - var oldCamera = this.camera; - oldCamera && oldCamera.update(); - if (projection === 'perspective') { - if (!(this.camera instanceof __WEBPACK_IMPORTED_MODULE_2_claygl_src_camera_Perspective__["a" /* default */])) { - this.camera = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_camera_Perspective__["a" /* default */](); - if (oldCamera) { - this.camera.setLocalTransform(oldCamera.localTransform); - } - } - } - else { - if (!(this.camera instanceof __WEBPACK_IMPORTED_MODULE_3_claygl_src_camera_Orthographic__["a" /* default */])) { - this.camera = new __WEBPACK_IMPORTED_MODULE_3_claygl_src_camera_Orthographic__["a" /* default */](); - if (oldCamera) { - this.camera.setLocalTransform(oldCamera.localTransform); - } - } - } - this.camera.near = 0.1; - this.camera.far = 2000; -}; - -/** - * Set viewport of group - * @param {number} x Viewport left bottom x - * @param {number} y Viewport left bottom y - * @param {number} width Viewport height - * @param {number} height Viewport height - * @param {number} [dpr=1] - */ -RenderMain.prototype.setViewport = function (x, y, width, height, dpr) { - if (this.camera instanceof __WEBPACK_IMPORTED_MODULE_2_claygl_src_camera_Perspective__["a" /* default */]) { - this.camera.aspect = width / height; - } - dpr = dpr || 1; - - this.viewport.x = x; - this.viewport.y = y; - this.viewport.width = width; - this.viewport.height = height; - this.viewport.devicePixelRatio = dpr; - - // Source and output of compositor use high dpr texture. - // But the intermediate texture of bloom, dof effects use fixed 1.0 dpr - this._compositor.resize(width * dpr, height * dpr); - this._temporalSS.resize(width * dpr, height * dpr); -}; - -/** - * If contain screen point x, y - * @param {number} x offsetX - * @param {number} y offsetY - * @return {boolean} - */ -RenderMain.prototype.containPoint = function (x, y) { - var viewport = this.viewport; - var height = this.layer.renderer.getHeight(); - // Flip y; - y = height - y; - return x >= viewport.x && y >= viewport.y - && x <= viewport.x + viewport.width && y <= viewport.y + viewport.height; -}; - -/** - * Cast a ray - * @param {number} x offsetX - * @param {number} y offsetY - * @param {clay.math.Ray} out - * @return {clay.math.Ray} - */ -var ndc = new __WEBPACK_IMPORTED_MODULE_6_claygl_src_math_Vector2__["a" /* default */](); -RenderMain.prototype.castRay = function (x, y, out) { - var renderer = this.layer.renderer; - - var oldViewport = renderer.viewport; - renderer.viewport = this.viewport; - renderer.screenToNDC(x, y, ndc); - this.camera.castRay(ndc, out); - renderer.viewport = oldViewport; - - return out; -}; - -/** - * Prepare and update scene before render - */ -RenderMain.prototype.prepareRender = function () { - this.scene.update(); - this.camera.update(); - - this._frame = 0; - this._temporalSS.resetFrame(); -}; - -RenderMain.prototype.render = function (accumulating) { - this._doRender(accumulating, this._frame); - this._frame++; -}; - -RenderMain.prototype.needsAccumulate = function () { - return this.needsTemporalSS() || this._needsSortProgressively; -}; - -RenderMain.prototype.needsTemporalSS = function () { - var enableTemporalSS = this._enableTemporalSS; - if (enableTemporalSS == 'auto') { - enableTemporalSS = this._enablePostEffect; - } - return enableTemporalSS; -}; - -RenderMain.prototype.hasDOF = function () { - return this._enableDOF; -}; - -RenderMain.prototype.isAccumulateFinished = function () { - var frame = this._frame; - return !(this.needsTemporalSS() && !this._temporalSS.isFinished(frame)) - && !(this._compositor && !this._compositor.isSSAOFinished(frame)) - && !(this._compositor && !this._compositor.isSSRFinished(frame)) - && !(this._compositor && frame < 30); -}; - -RenderMain.prototype._doRender = function (accumulating, accumFrame) { - - var scene = this.scene; - var camera = this.camera; - var renderer = this.renderer; - - accumFrame = accumFrame || 0; - - if (!accumulating && this._shadowMapPass) { - this._shadowMapPass.kernelPCF = this._pcfKernels[0]; - // Not render shadowmap pass in accumulating frame. - this._shadowMapPass.render(renderer, scene, camera, true); - } - - this._updateShadowPCFKernel(accumFrame); - - // Shadowmap will set clearColor. - renderer.gl.clearColor(0.0, 0.0, 0.0, 0.0); - - if (this._enablePostEffect) { - // normal render also needs to be jittered when have edge pass. - if (this.needsTemporalSS()) { - this._temporalSS.jitterProjection(renderer, camera); - } - this._compositor.updateNormal(renderer, scene, camera, this._temporalSS.getFrame()); - } - - // Always update SSAO to make sure have correct ssaoMap status - this._updateSSAO(renderer, scene, camera, this._temporalSS.getFrame()); - - if (this._enablePostEffect) { - - var frameBuffer = this._compositor.getSourceFrameBuffer(); - frameBuffer.bind(renderer); - renderer.gl.clear(renderer.gl.DEPTH_BUFFER_BIT | renderer.gl.COLOR_BUFFER_BIT); - // FIXME Enable pre z will make alpha test failed - renderer.render(scene, camera, true, this.preZ); - this.afterRenderScene(renderer, scene, camera); - frameBuffer.unbind(renderer); - - if (this.needsTemporalSS() && accumulating) { - this._compositor.composite(renderer, camera, this._temporalSS.getSourceFrameBuffer(), this._temporalSS.getFrame()); - renderer.setViewport(this.viewport); - this._temporalSS.render(renderer); - } - else { - renderer.setViewport(this.viewport); - this._compositor.composite(renderer, camera, null, 0); - } - } - else { - if (this.needsTemporalSS() && accumulating) { - var frameBuffer = this._temporalSS.getSourceFrameBuffer(); - frameBuffer.bind(renderer); - renderer.saveClear(); - renderer.clearBit = renderer.gl.DEPTH_BUFFER_BIT | renderer.gl.COLOR_BUFFER_BIT; - renderer.render(scene, camera, true, this.preZ); - this.afterRenderScene(renderer, scene, camera); - renderer.restoreClear(); - frameBuffer.unbind(renderer); - renderer.setViewport(this.viewport); - this._temporalSS.render(renderer); - } - else { - renderer.setViewport(this.viewport); - renderer.render(scene, camera, true, this.preZ); - this.afterRenderScene(renderer, scene, camera); - } - } - - this.afterRenderAll(renderer, scene, camera); - - // this._compositor._gBufferPass.renderDebug(renderer, camera, 'normal'); - // this._shadowMapPass.renderDebug(renderer); -}; - -RenderMain.prototype.afterRenderScene = function (renderer, scene, camera) {}; -RenderMain.prototype.afterRenderAll = function (renderer, scene, camera) {}; - -RenderMain.prototype._updateSSAO = function (renderer, scene, camera, frame) { - var ifEnableSSAO = this._enableSSAO && this._enablePostEffect; - var compositor = this._compositor; - if (ifEnableSSAO) { - this._compositor.updateSSAO(renderer, scene, camera, this._temporalSS.getFrame()); - } - - function updateQueue(queue) { - for (var i = 0; i < queue.length; i++) { - var renderable = queue[i]; - renderable.material[ifEnableSSAO ? 'enableTexture' : 'disableTexture']('ssaoMap'); - if (ifEnableSSAO) { - renderable.material.set('ssaoMap', compositor.getSSAOTexture()); - } - } - } - updateQueue(scene.opaqueList); - updateQueue(scene.transparentList); -}; - -RenderMain.prototype._updateShadowPCFKernel = function (frame) { - var pcfKernel = this._pcfKernels[frame % this._pcfKernels.length]; - function updateQueue(queue) { - for (var i = 0; i < queue.length; i++) { - if (queue[i].receiveShadow) { - queue[i].material.set('pcfKernel', pcfKernel); - if (queue[i].material) { - queue[i].material.define('fragment', 'PCF_KERNEL_SIZE', pcfKernel.length / 2); - } - } - } - } - updateQueue(this.scene.opaqueList); - updateQueue(this.scene.transparentList); -}; - -RenderMain.prototype.dispose = function (renderer) { - this._compositor.dispose(renderer); - this._temporalSS.dispose(renderer); - if (this._shadowMapPass) { - this._shadowMapPass.dispose(renderer); - } -}; - -RenderMain.prototype.setPostEffect = function (opts, api) { - var compositor = this._compositor; - opts = opts || {}; - this._enablePostEffect = !!opts.enable; - var bloomOpts = opts.bloom || {}; - var edgeOpts = opts.edge || {}; - var dofOpts = opts.depthOfField || {}; - var ssaoOpts = opts.screenSpaceAmbientOcclusion || {}; - var ssrOpts = opts.screenSpaceReflection || {}; - var fxaaOpts = opts.FXAA || {}; - var colorCorrOpts = opts.colorCorrection || {}; - bloomOpts.enable ? compositor.enableBloom() : compositor.disableBloom(); - dofOpts.enable ? compositor.enableDOF() : compositor.disableDOF(); - ssrOpts.enable ? compositor.enableSSR() : compositor.disableSSR(); - colorCorrOpts.enable ? compositor.enableColorCorrection() : compositor.disableColorCorrection(); - edgeOpts.enable ? compositor.enableEdge() : compositor.disableEdge(); - fxaaOpts.enable ? compositor.enableFXAA() : compositor.disableFXAA(); - - this._enableDOF = dofOpts.enable; - this._enableSSAO = ssaoOpts.enable; - - this._enableSSAO ? compositor.enableSSAO() : compositor.disableSSAO(); - - compositor.setBloomIntensity(bloomOpts.intensity); - compositor.setEdgeColor(edgeOpts.color); - compositor.setColorLookupTexture(colorCorrOpts.lookupTexture, api); - compositor.setExposure(colorCorrOpts.exposure); - - ['radius', 'quality', 'intensity'].forEach(function (name) { - compositor.setSSAOParameter(name, ssaoOpts[name]); - }); - ['quality', 'maxRoughness'].forEach(function (name) { - compositor.setSSRParameter(name, ssrOpts[name]); - }); - ['quality', 'focalDistance', 'focalRange', 'blurRadius', 'fstop'].forEach(function (name) { - compositor.setDOFParameter(name, dofOpts[name]); - }); - ['brightness', 'contrast', 'saturation'].forEach(function (name) { - compositor.setColorCorrection(name, colorCorrOpts[name]); - }); -}; - -RenderMain.prototype.isDOFEnabled = function () { - return this._enablePostEffect && this._enableDOF; -} - -RenderMain.prototype.setDOFFocusOnPoint = function (depth) { - if (this._enablePostEffect) { - - if (depth > this.camera.far || depth < this.camera.near) { - return; - } - - this._compositor.setDOFParameter('focalDistance', depth); - return true; - } -}; - -RenderMain.prototype.setTemporalSuperSampling = function (temporalSuperSamplingOpt) { - temporalSuperSamplingOpt = temporalSuperSamplingOpt || {}; - this._enableTemporalSS = temporalSuperSamplingOpt.enable; -}; - -RenderMain.prototype.isLinearSpace = function () { - return this._enablePostEffect; -}; - -RenderMain.prototype.setRootNode = function (rootNode) { - if (this.rootNode === rootNode) { - return; - } - var children = this.rootNode.children(); - for (var i = 0; i < children.length; i++) { - rootNode.add(children[i]); - } - if (rootNode !== this.scene) { - this.scene.add(rootNode); - } - - this.rootNode = rootNode; -}; -// Proxies -RenderMain.prototype.add = function (node3D) { - this.rootNode.add(node3D); -}; -RenderMain.prototype.remove = function (node3D) { - this.rootNode.remove(node3D); -}; -RenderMain.prototype.removeAll = function (node3D) { - this.rootNode.removeAll(node3D); -}; - -/* harmony default export */ __webpack_exports__["a"] = (RenderMain); - -/***/ }), -/* 104 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_glenum__ = __webpack_require__(6); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__math_Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__math_BoundingBox__ = __webpack_require__(8); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__math_Frustum__ = __webpack_require__(42); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__math_Matrix4__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__Renderer__ = __webpack_require__(27); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__Light__ = __webpack_require__(14); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__Mesh__ = __webpack_require__(16); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__light_Spot__ = __webpack_require__(105); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_11__light_Directional__ = __webpack_require__(61); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_12__light_Point__ = __webpack_require__(106); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_13__shader_library__ = __webpack_require__(31); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_14__Material__ = __webpack_require__(10); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_15__FrameBuffer__ = __webpack_require__(11); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_16__Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_17__Texture2D__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_18__TextureCube__ = __webpack_require__(17); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_19__camera_Perspective__ = __webpack_require__(22); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_20__camera_Orthographic__ = __webpack_require__(23); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_21__compositor_Pass__ = __webpack_require__(13); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_22__compositor_TexturePool__ = __webpack_require__(62); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_23__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_23__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_23__dep_glmatrix__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_24__shader_source_shadowmap_glsl_js__ = __webpack_require__(108); - - - - - - - - - - - - - - - - - - - - - - - - - - -var mat4 = __WEBPACK_IMPORTED_MODULE_23__dep_glmatrix___default.a.mat4; -var vec3 = __WEBPACK_IMPORTED_MODULE_23__dep_glmatrix___default.a.vec3; - -var targets = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; - - -__WEBPACK_IMPORTED_MODULE_7__Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_24__shader_source_shadowmap_glsl_js__["a" /* default */]); - -/** - * Pass rendering shadow map. - * - * @constructor clay.prePass.ShadowMap - * @extends clay.core.Base - * @example - * var shadowMapPass = new clay.prePass.ShadowMap({ - * softShadow: clay.prePass.ShadowMap.VSM - * }); - * ... - * animation.on('frame', function (frameTime) { - * shadowMapPass.render(renderer, scene, camera); - * renderer.render(scene, camera); - * }); - */ -var ShadowMapPass = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend(function () { - return /** @lends clay.prePass.ShadowMap# */ { - /** - * Soft shadow technique. - * Can be {@link clay.prePass.ShadowMap.PCF} or {@link clay.prePass.ShadowMap.VSM} - * @type {number} - */ - softShadow: ShadowMapPass.PCF, - - /** - * Soft shadow blur size - * @type {number} - */ - shadowBlur: 1.0, - - lightFrustumBias: 'auto', - - kernelPCF: new Float32Array([ - 1, 0, - 1, 1, - -1, 1, - 0, 1, - -1, 0, - -1, -1, - 1, -1, - 0, -1 - ]), - - precision: 'mediump', - - _lastRenderNotCastShadow: false, - - _frameBuffer: new __WEBPACK_IMPORTED_MODULE_15__FrameBuffer__["a" /* default */](), - - _textures: {}, - _shadowMapNumber: { - 'POINT_LIGHT': 0, - 'DIRECTIONAL_LIGHT': 0, - 'SPOT_LIGHT': 0 - }, - - _depthMaterials: {}, - _distanceMaterials: {}, - - _opaqueCasters: [], - _receivers: [], - _lightsCastShadow: [], - - _lightCameras: {}, - _lightMaterials: {}, - - _texturePool: new __WEBPACK_IMPORTED_MODULE_22__compositor_TexturePool__["a" /* default */]() - }; -}, function () { - // Gaussian filter pass for VSM - this._gaussianPassH = new __WEBPACK_IMPORTED_MODULE_21__compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_7__Shader__["a" /* default */].source('clay.compositor.gaussian_blur') - }); - this._gaussianPassV = new __WEBPACK_IMPORTED_MODULE_21__compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_7__Shader__["a" /* default */].source('clay.compositor.gaussian_blur') - }); - this._gaussianPassH.setUniform('blurSize', this.shadowBlur); - this._gaussianPassH.setUniform('blurDir', 0.0); - this._gaussianPassV.setUniform('blurSize', this.shadowBlur); - this._gaussianPassV.setUniform('blurDir', 1.0); - - this._outputDepthPass = new __WEBPACK_IMPORTED_MODULE_21__compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_7__Shader__["a" /* default */].source('clay.sm.debug_depth') - }); -}, { - /** - * Render scene to shadow textures - * @param {clay.Renderer} renderer - * @param {clay.Scene} scene - * @param {clay.Camera} sceneCamera - * @param {boolean} [notUpdateScene=false] - * @memberOf clay.prePass.ShadowMap.prototype - */ - render: function (renderer, scene, sceneCamera, notUpdateScene) { - if (!sceneCamera) { - sceneCamera = scene.getMainCamera(); - } - this.trigger('beforerender', this, renderer, scene, sceneCamera); - this._renderShadowPass(renderer, scene, sceneCamera, notUpdateScene); - this.trigger('afterrender', this, renderer, scene, sceneCamera); - }, - - /** - * Debug rendering of shadow textures - * @param {clay.Renderer} renderer - * @param {number} size - * @memberOf clay.prePass.ShadowMap.prototype - */ - renderDebug: function (renderer, size) { - renderer.saveClear(); - var viewport = renderer.viewport; - var x = 0, y = 0; - var width = size || viewport.width / 4; - var height = width; - if (this.softShadow === ShadowMapPass.VSM) { - this._outputDepthPass.material.define('fragment', 'USE_VSM'); - } - else { - this._outputDepthPass.material.undefine('fragment', 'USE_VSM'); - } - for (var name in this._textures) { - var texture = this._textures[name]; - renderer.setViewport(x, y, width * texture.width / texture.height, height); - this._outputDepthPass.setUniform('depthMap', texture); - this._outputDepthPass.render(renderer); - x += width * texture.width / texture.height; - } - renderer.setViewport(viewport); - renderer.restoreClear(); - }, - - _updateCasterAndReceiver: function (renderer, mesh) { - if (mesh.castShadow) { - this._opaqueCasters.push(mesh); - } - if (mesh.receiveShadow) { - this._receivers.push(mesh); - mesh.material.set('shadowEnabled', 1); - - mesh.material.set('pcfKernel', this.kernelPCF); - } - else { - mesh.material.set('shadowEnabled', 0); - } - - if (!mesh.material.shader && mesh.material.updateShader) { - mesh.material.updateShader(renderer); - } - if (this.softShadow === ShadowMapPass.VSM) { - mesh.material.define('fragment', 'USE_VSM'); - mesh.material.undefine('fragment', 'PCF_KERNEL_SIZE'); - } - else { - mesh.material.undefine('fragment', 'USE_VSM'); - var kernelPCF = this.kernelPCF; - if (kernelPCF && kernelPCF.length) { - mesh.material.define('fragment', 'PCF_KERNEL_SIZE', kernelPCF.length / 2); - } - else { - mesh.material.undefine('fragment', 'PCF_KERNEL_SIZE'); - } - } - }, - - _update: function (renderer, scene) { - for (var i = 0; i < scene.opaqueList.length; i++) { - this._updateCasterAndReceiver(renderer, scene.opaqueList[i]); - } - for (var i = 0; i < scene.transparentList.length; i++) { - // TODO Transparent object receive shadow will be very slow - // in stealth demo, still not find the reason - this._updateCasterAndReceiver(renderer, scene.transparentList[i]); - } - for (var i = 0; i < scene.lights.length; i++) { - var light = scene.lights[i]; - if (light.castShadow) { - this._lightsCastShadow.push(light); - } - } - }, - - _renderShadowPass: function (renderer, scene, sceneCamera, notUpdateScene) { - // reset - for (var name in this._shadowMapNumber) { - this._shadowMapNumber[name] = 0; - } - this._lightsCastShadow.length = 0; - this._opaqueCasters.length = 0; - this._receivers.length = 0; - - var _gl = renderer.gl; - - if (!notUpdateScene) { - scene.update(); - } - if (sceneCamera) { - sceneCamera.update(); - } - - this._update(renderer, scene); - - // Needs to update the receivers again if shadows come from 1 to 0. - if (!this._lightsCastShadow.length && this._lastRenderNotCastShadow) { - return; - } - - this._lastRenderNotCastShadow = this._lightsCastShadow === 0; - - _gl.enable(_gl.DEPTH_TEST); - _gl.depthMask(true); - _gl.disable(_gl.BLEND); - - // Clear with high-z, so the part not rendered will not been shadowed - // TODO - // TODO restore - _gl.clearColor(1.0, 1.0, 1.0, 1.0); - - // Shadow uniforms - var spotLightShadowMaps = []; - var spotLightMatrices = []; - var directionalLightShadowMaps = []; - var directionalLightMatrices = []; - var shadowCascadeClips = []; - var pointLightShadowMaps = []; - - var dirLightHasCascade; - // Create textures for shadow map - for (var i = 0; i < this._lightsCastShadow.length; i++) { - var light = this._lightsCastShadow[i]; - if (light instanceof __WEBPACK_IMPORTED_MODULE_11__light_Directional__["a" /* default */]) { - - if (dirLightHasCascade) { - console.warn('Only one direectional light supported with shadow cascade'); - continue; - } - if (light.shadowCascade > 4) { - console.warn('Support at most 4 cascade'); - continue; - } - if (light.shadowCascade > 1) { - dirLightHasCascade = light.shadowCascade; - } - - this.renderDirectionalLightShadow( - renderer, - scene, - sceneCamera, - light, - this._opaqueCasters, - shadowCascadeClips, - directionalLightMatrices, - directionalLightShadowMaps - ); - } - else if (light instanceof __WEBPACK_IMPORTED_MODULE_10__light_Spot__["a" /* default */]) { - this.renderSpotLightShadow( - renderer, - scene, - light, - this._opaqueCasters, - spotLightMatrices, - spotLightShadowMaps - ); - } - else if (light instanceof __WEBPACK_IMPORTED_MODULE_12__light_Point__["a" /* default */]) { - this.renderPointLightShadow( - renderer, - scene, - light, - this._opaqueCasters, - pointLightShadowMaps - ); - } - - this._shadowMapNumber[light.type]++; - } - - for (var lightType in this._shadowMapNumber) { - var number = this._shadowMapNumber[lightType]; - var key = lightType + '_SHADOWMAP_COUNT'; - for (var i = 0; i < this._receivers.length; i++) { - var mesh = this._receivers[i]; - var material = mesh.material; - if (material.fragmentDefines[key] !== number) { - if (number > 0) { - material.define('fragment', key, number); - } - else if (material.isDefined('fragment', key)) { - material.undefine('fragment', key); - } - } - } - } - for (var i = 0; i < this._receivers.length; i++) { - var mesh = this._receivers[i]; - var material = mesh.material; - if (dirLightHasCascade) { - material.define('fragment', 'SHADOW_CASCADE', dirLightHasCascade.shadowCascade); - } - else { - material.undefine('fragment', 'SHADOW_CASCADE'); - } - } - - var shadowUniforms = scene.shadowUniforms; - - function getSize(texture) { - return texture.height; - } - if (directionalLightShadowMaps.length > 0) { - var directionalLightShadowMapSizes = directionalLightShadowMaps.map(getSize); - shadowUniforms.directionalLightShadowMaps = { value: directionalLightShadowMaps, type: 'tv' }; - shadowUniforms.directionalLightMatrices = { value: directionalLightMatrices, type: 'm4v' }; - shadowUniforms.directionalLightShadowMapSizes = { value: directionalLightShadowMapSizes, type: '1fv' }; - if (dirLightHasCascade) { - var shadowCascadeClipsNear = shadowCascadeClips.slice(); - var shadowCascadeClipsFar = shadowCascadeClips.slice(); - shadowCascadeClipsNear.pop(); - shadowCascadeClipsFar.shift(); - - // Iterate from far to near - shadowCascadeClipsNear.reverse(); - shadowCascadeClipsFar.reverse(); - // directionalLightShadowMaps.reverse(); - directionalLightMatrices.reverse(); - shadowUniforms.shadowCascadeClipsNear = { value: shadowCascadeClipsNear, type: '1fv' }; - shadowUniforms.shadowCascadeClipsFar = { value: shadowCascadeClipsFar, type: '1fv' }; - } - } - - if (spotLightShadowMaps.length > 0) { - var spotLightShadowMapSizes = spotLightShadowMaps.map(getSize); - var shadowUniforms = scene.shadowUniforms; - shadowUniforms.spotLightShadowMaps = { value: spotLightShadowMaps, type: 'tv' }; - shadowUniforms.spotLightMatrices = { value: spotLightMatrices, type: 'm4v' }; - shadowUniforms.spotLightShadowMapSizes = { value: spotLightShadowMapSizes, type: '1fv' }; - } - - if (pointLightShadowMaps.length > 0) { - shadowUniforms.pointLightShadowMaps = { value: pointLightShadowMaps, type: 'tv' }; - } - }, - - renderDirectionalLightShadow: (function () { - - var splitFrustum = new __WEBPACK_IMPORTED_MODULE_4__math_Frustum__["a" /* default */](); - var splitProjMatrix = new __WEBPACK_IMPORTED_MODULE_5__math_Matrix4__["a" /* default */](); - var cropBBox = new __WEBPACK_IMPORTED_MODULE_3__math_BoundingBox__["a" /* default */](); - var cropMatrix = new __WEBPACK_IMPORTED_MODULE_5__math_Matrix4__["a" /* default */](); - var lightViewMatrix = new __WEBPACK_IMPORTED_MODULE_5__math_Matrix4__["a" /* default */](); - var lightViewProjMatrix = new __WEBPACK_IMPORTED_MODULE_5__math_Matrix4__["a" /* default */](); - var lightProjMatrix = new __WEBPACK_IMPORTED_MODULE_5__math_Matrix4__["a" /* default */](); - - return function (renderer, scene, sceneCamera, light, casters, shadowCascadeClips, directionalLightMatrices, directionalLightShadowMaps) { - - var defaultShadowMaterial = this._getDepthMaterial(light); - var passConfig = { - getMaterial: function (renderable) { - return renderable.shadowDepthMaterial || defaultShadowMaterial; - }, - sortCompare: __WEBPACK_IMPORTED_MODULE_6__Renderer__["a" /* default */].opaqueSortCompare - }; - - // First frame - if (!scene.viewBoundingBoxLastFrame.isFinite()) { - var boundingBox = scene.getBoundingBox(); - scene.viewBoundingBoxLastFrame - .copy(boundingBox).applyTransform(sceneCamera.viewMatrix); - } - // Considering moving speed since the bounding box is from last frame - // TODO: add a bias - var clippedFar = Math.min(-scene.viewBoundingBoxLastFrame.min.z, sceneCamera.far); - var clippedNear = Math.max(-scene.viewBoundingBoxLastFrame.max.z, sceneCamera.near); - - var lightCamera = this._getDirectionalLightCamera(light, scene, sceneCamera); - - var lvpMat4Arr = lightViewProjMatrix.array; - lightProjMatrix.copy(lightCamera.projectionMatrix); - mat4.invert(lightViewMatrix.array, lightCamera.worldTransform.array); - mat4.multiply(lightViewMatrix.array, lightViewMatrix.array, sceneCamera.worldTransform.array); - mat4.multiply(lvpMat4Arr, lightProjMatrix.array, lightViewMatrix.array); - - var clipPlanes = []; - var isPerspective = sceneCamera instanceof __WEBPACK_IMPORTED_MODULE_19__camera_Perspective__["a" /* default */]; - - var scaleZ = (sceneCamera.near + sceneCamera.far) / (sceneCamera.near - sceneCamera.far); - var offsetZ = 2 * sceneCamera.near * sceneCamera.far / (sceneCamera.near - sceneCamera.far); - for (var i = 0; i <= light.shadowCascade; i++) { - var clog = clippedNear * Math.pow(clippedFar / clippedNear, i / light.shadowCascade); - var cuni = clippedNear + (clippedFar - clippedNear) * i / light.shadowCascade; - var c = clog * light.cascadeSplitLogFactor + cuni * (1 - light.cascadeSplitLogFactor); - clipPlanes.push(c); - shadowCascadeClips.push(-(-c * scaleZ + offsetZ) / -c); - } - var texture = this._getTexture(light, light.shadowCascade); - directionalLightShadowMaps.push(texture); - - var viewport = renderer.viewport; - - var _gl = renderer.gl; - this._frameBuffer.attach(texture); - this._frameBuffer.bind(renderer); - _gl.clear(_gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT); - - for (var i = 0; i < light.shadowCascade; i++) { - // Get the splitted frustum - var nearPlane = clipPlanes[i]; - var farPlane = clipPlanes[i + 1]; - if (isPerspective) { - mat4.perspective(splitProjMatrix.array, sceneCamera.fov / 180 * Math.PI, sceneCamera.aspect, nearPlane, farPlane); - } - else { - mat4.ortho( - splitProjMatrix.array, - sceneCamera.left, sceneCamera.right, sceneCamera.bottom, sceneCamera.top, - nearPlane, farPlane - ); - } - splitFrustum.setFromProjection(splitProjMatrix); - splitFrustum.getTransformedBoundingBox(cropBBox, lightViewMatrix); - cropBBox.applyProjection(lightProjMatrix); - var _min = cropBBox.min.array; - var _max = cropBBox.max.array; - _min[0] = Math.max(_min[0], -1); - _min[1] = Math.max(_min[1], -1); - _max[0] = Math.min(_max[0], 1); - _max[1] = Math.min(_max[1], 1); - cropMatrix.ortho(_min[0], _max[0], _min[1], _max[1], 1, -1); - lightCamera.projectionMatrix.multiplyLeft(cropMatrix); - - var shadowSize = light.shadowResolution || 512; - - // Reversed, left to right => far to near - renderer.setViewport((light.shadowCascade - i - 1) * shadowSize, 0, shadowSize, shadowSize, 1); - - renderer.renderPass(casters, lightCamera, passConfig); - - // Filter for VSM - if (this.softShadow === ShadowMapPass.VSM) { - this._gaussianFilter(renderer, texture, texture.width); - } - - var matrix = new __WEBPACK_IMPORTED_MODULE_5__math_Matrix4__["a" /* default */](); - matrix.copy(lightCamera.viewMatrix) - .multiplyLeft(lightCamera.projectionMatrix); - - directionalLightMatrices.push(matrix.array); - - lightCamera.projectionMatrix.copy(lightProjMatrix); - } - - this._frameBuffer.unbind(renderer); - - renderer.setViewport(viewport); - }; - })(), - - renderSpotLightShadow: function (renderer, scene, light, casters, spotLightMatrices, spotLightShadowMaps) { - - var texture = this._getTexture(light); - var lightCamera = this._getSpotLightCamera(light); - var _gl = renderer.gl; - - this._frameBuffer.attach(texture); - this._frameBuffer.bind(renderer); - - _gl.clear(_gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT); - - var defaultShadowMaterial = this._getDepthMaterial(light); - var passConfig = { - getMaterial: function (renderable) { - return renderable.shadowDepthMaterial || defaultShadowMaterial; - }, - sortCompare: __WEBPACK_IMPORTED_MODULE_6__Renderer__["a" /* default */].opaqueSortCompare - }; - - renderer.renderPass(renderer.cullRenderList(casters, null, lightCamera), lightCamera, passConfig); - - this._frameBuffer.unbind(renderer); - - // Filter for VSM - if (this.softShadow === ShadowMapPass.VSM) { - this._gaussianFilter(renderer, texture, texture.width); - } - - var matrix = new __WEBPACK_IMPORTED_MODULE_5__math_Matrix4__["a" /* default */](); - matrix.copy(lightCamera.worldTransform) - .invert() - .multiplyLeft(lightCamera.projectionMatrix); - - spotLightShadowMaps.push(texture); - spotLightMatrices.push(matrix.array); - }, - - renderPointLightShadow: function (renderer, scene, light, casters, pointLightShadowMaps) { - var texture = this._getTexture(light); - var _gl = renderer.gl; - pointLightShadowMaps.push(texture); - - var defaultShadowMaterial = this._getDepthMaterial(light); - var passConfig = { - getMaterial: function (renderable) { - return renderable.shadowDepthMaterial || defaultShadowMaterial; - }, - sortCompare: __WEBPACK_IMPORTED_MODULE_6__Renderer__["a" /* default */].opaqueSortCompare - }; - - for (var i = 0; i < 6; i++) { - var target = targets[i]; - var camera = this._getPointLightCamera(light, target); - - this._frameBuffer.attach(texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i); - this._frameBuffer.bind(renderer); - _gl.clear(_gl.COLOR_BUFFER_BIT | _gl.DEPTH_BUFFER_BIT); - - renderer.renderPass(renderer.cullRenderList(casters, null, camera), camera, passConfig); - } - - this._frameBuffer.unbind(renderer); - }, - - _getDepthMaterial: function (light) { - var shadowMaterial = this._lightMaterials[light.__uid__]; - var isPointLight = light instanceof __WEBPACK_IMPORTED_MODULE_12__light_Point__["a" /* default */]; - if (!shadowMaterial) { - var shaderPrefix = isPointLight ? 'clay.sm.distance.' : 'clay.sm.depth.'; - shadowMaterial = new __WEBPACK_IMPORTED_MODULE_14__Material__["a" /* default */]({ - precision: this.precision, - shader: new __WEBPACK_IMPORTED_MODULE_7__Shader__["a" /* default */](__WEBPACK_IMPORTED_MODULE_7__Shader__["a" /* default */].source(shaderPrefix + 'vertex'), __WEBPACK_IMPORTED_MODULE_7__Shader__["a" /* default */].source(shaderPrefix + 'fragment')) - }); - - this._lightMaterials[light.__uid__] = shadowMaterial; - } - if (light.shadowSlopeScale != null) { - shadowMaterial.setUniform('slopeScale', light.shadowSlopeScale); - } - if (light.shadowBias != null) { - shadowMaterial.setUniform('shadowBias', light.shadowBias); - } - if (this.softShadow === ShadowMapPass.VSM) { - shadowMaterial.define('fragment', 'USE_VSM'); - } - else { - shadowMaterial.undefine('fragment', 'USE_VSM'); - } - - if (isPointLight) { - shadowMaterial.set('lightPosition', light.getWorldPosition().array); - shadowMaterial.set('range', light.range); - } - - return shadowMaterial; - }, - - _gaussianFilter: function (renderer, texture, size) { - var parameter = { - width: size, - height: size, - type: __WEBPACK_IMPORTED_MODULE_16__Texture__["a" /* default */].FLOAT - }; - var tmpTexture = this._texturePool.get(parameter); - - this._frameBuffer.attach(tmpTexture); - this._frameBuffer.bind(renderer); - this._gaussianPassH.setUniform('texture', texture); - this._gaussianPassH.setUniform('textureWidth', size); - this._gaussianPassH.render(renderer); - - this._frameBuffer.attach(texture); - this._gaussianPassV.setUniform('texture', tmpTexture); - this._gaussianPassV.setUniform('textureHeight', size); - this._gaussianPassV.render(renderer); - this._frameBuffer.unbind(renderer); - - this._texturePool.put(tmpTexture); - }, - - _getTexture: function (light, cascade) { - var key = light.__uid__; - var texture = this._textures[key]; - var resolution = light.shadowResolution || 512; - cascade = cascade || 1; - if (!texture) { - if (light instanceof __WEBPACK_IMPORTED_MODULE_12__light_Point__["a" /* default */]) { - texture = new __WEBPACK_IMPORTED_MODULE_18__TextureCube__["a" /* default */](); - } - else { - texture = new __WEBPACK_IMPORTED_MODULE_17__Texture2D__["a" /* default */](); - } - // At most 4 cascade - // TODO share with height ? - texture.width = resolution * cascade; - texture.height = resolution; - if (this.softShadow === ShadowMapPass.VSM) { - texture.type = __WEBPACK_IMPORTED_MODULE_16__Texture__["a" /* default */].FLOAT; - texture.anisotropic = 4; - } - else { - texture.minFilter = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].NEAREST; - texture.magFilter = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].NEAREST; - texture.useMipmap = false; - } - this._textures[key] = texture; - } - - return texture; - }, - - _getPointLightCamera: function (light, target) { - if (!this._lightCameras.point) { - this._lightCameras.point = { - px: new __WEBPACK_IMPORTED_MODULE_19__camera_Perspective__["a" /* default */](), - nx: new __WEBPACK_IMPORTED_MODULE_19__camera_Perspective__["a" /* default */](), - py: new __WEBPACK_IMPORTED_MODULE_19__camera_Perspective__["a" /* default */](), - ny: new __WEBPACK_IMPORTED_MODULE_19__camera_Perspective__["a" /* default */](), - pz: new __WEBPACK_IMPORTED_MODULE_19__camera_Perspective__["a" /* default */](), - nz: new __WEBPACK_IMPORTED_MODULE_19__camera_Perspective__["a" /* default */]() - }; - } - var camera = this._lightCameras.point[target]; - - camera.far = light.range; - camera.fov = 90; - camera.position.set(0, 0, 0); - switch (target) { - case 'px': - camera.lookAt(__WEBPACK_IMPORTED_MODULE_2__math_Vector3__["a" /* default */].POSITIVE_X, __WEBPACK_IMPORTED_MODULE_2__math_Vector3__["a" /* default */].NEGATIVE_Y); - break; - case 'nx': - camera.lookAt(__WEBPACK_IMPORTED_MODULE_2__math_Vector3__["a" /* default */].NEGATIVE_X, __WEBPACK_IMPORTED_MODULE_2__math_Vector3__["a" /* default */].NEGATIVE_Y); - break; - case 'py': - camera.lookAt(__WEBPACK_IMPORTED_MODULE_2__math_Vector3__["a" /* default */].POSITIVE_Y, __WEBPACK_IMPORTED_MODULE_2__math_Vector3__["a" /* default */].POSITIVE_Z); - break; - case 'ny': - camera.lookAt(__WEBPACK_IMPORTED_MODULE_2__math_Vector3__["a" /* default */].NEGATIVE_Y, __WEBPACK_IMPORTED_MODULE_2__math_Vector3__["a" /* default */].NEGATIVE_Z); - break; - case 'pz': - camera.lookAt(__WEBPACK_IMPORTED_MODULE_2__math_Vector3__["a" /* default */].POSITIVE_Z, __WEBPACK_IMPORTED_MODULE_2__math_Vector3__["a" /* default */].NEGATIVE_Y); - break; - case 'nz': - camera.lookAt(__WEBPACK_IMPORTED_MODULE_2__math_Vector3__["a" /* default */].NEGATIVE_Z, __WEBPACK_IMPORTED_MODULE_2__math_Vector3__["a" /* default */].NEGATIVE_Y); - break; - } - light.getWorldPosition(camera.position); - camera.update(); - - return camera; - }, - - _getDirectionalLightCamera: (function () { - var lightViewMatrix = new __WEBPACK_IMPORTED_MODULE_5__math_Matrix4__["a" /* default */](); - var sceneViewBoundingBox = new __WEBPACK_IMPORTED_MODULE_3__math_BoundingBox__["a" /* default */](); - var lightViewBBox = new __WEBPACK_IMPORTED_MODULE_3__math_BoundingBox__["a" /* default */](); - // Camera of directional light will be adjusted - // to contain the view frustum and scene bounding box as tightly as possible - return function (light, scene, sceneCamera) { - if (!this._lightCameras.directional) { - this._lightCameras.directional = new __WEBPACK_IMPORTED_MODULE_20__camera_Orthographic__["a" /* default */](); - } - var camera = this._lightCameras.directional; - - sceneViewBoundingBox.copy(scene.viewBoundingBoxLastFrame); - sceneViewBoundingBox.intersection(sceneCamera.frustum.boundingBox); - // Move to the center of frustum(in world space) - camera.position - .copy(sceneViewBoundingBox.min) - .add(sceneViewBoundingBox.max) - .scale(0.5) - .transformMat4(sceneCamera.worldTransform); - camera.rotation.copy(light.rotation); - camera.scale.copy(light.scale); - camera.updateWorldTransform(); - - // Transform to light view space - __WEBPACK_IMPORTED_MODULE_5__math_Matrix4__["a" /* default */].invert(lightViewMatrix, camera.worldTransform); - __WEBPACK_IMPORTED_MODULE_5__math_Matrix4__["a" /* default */].multiply(lightViewMatrix, lightViewMatrix, sceneCamera.worldTransform); - - lightViewBBox.copy(sceneViewBoundingBox).applyTransform(lightViewMatrix); - - var min = lightViewBBox.min.array; - var max = lightViewBBox.max.array; - - // Move camera to adjust the near to 0 - camera.position.set((min[0] + max[0]) / 2, (min[1] + max[1]) / 2, max[2]) - .transformMat4(camera.worldTransform); - camera.near = 0; - camera.far = -min[2] + max[2]; - // Make sure receivers not in the frustum will stil receive the shadow. - if (isNaN(this.lightFrustumBias)) { - camera.far *= 4; - } - else { - camera.far += this.lightFrustumBias; - } - camera.left = min[0]; - camera.right = max[0]; - camera.top = max[1]; - camera.bottom = min[1]; - camera.update(true); - - return camera; - }; - })(), - - _getSpotLightCamera: function (light) { - if (!this._lightCameras.spot) { - this._lightCameras.spot = new __WEBPACK_IMPORTED_MODULE_19__camera_Perspective__["a" /* default */](); - } - var camera = this._lightCameras.spot; - // Update properties - camera.fov = light.penumbraAngle * 2; - camera.far = light.range; - camera.worldTransform.copy(light.worldTransform); - camera.updateProjectionMatrix(); - mat4.invert(camera.viewMatrix.array, camera.worldTransform.array); - - return camera; - }, - - /** - * @param {clay.Renderer|WebGLRenderingContext} [renderer] - * @memberOf clay.prePass.ShadowMap.prototype - */ - // PENDING Renderer or WebGLRenderingContext - dispose: function (renderer) { - var _gl = renderer.gl || renderer; - - if (this._frameBuffer) { - this._frameBuffer.dispose(_gl); - } - - for (var name in this._textures) { - this._textures[name].dispose(_gl); - } - - this._texturePool.clear(renderer.gl); - - this._depthMaterials = {}; - this._distanceMaterials = {}; - this._textures = {}; - this._lightCameras = {}; - this._shadowMapNumber = { - 'POINT_LIGHT': 0, - 'DIRECTIONAL_LIGHT': 0, - 'SPOT_LIGHT': 0 - }; - this._meshMaterials = {}; - - for (var i = 0; i < this._receivers.length; i++) { - var mesh = this._receivers[i]; - // Mesh may be disposed - if (mesh.material && mesh.material.shader) { - var material = mesh.material; - var shader = material.shader; - shader.undefine('fragment', 'POINT_LIGHT_SHADOW_COUNT'); - shader.undefine('fragment', 'DIRECTIONAL_LIGHT_SHADOW_COUNT'); - shader.undefine('fragment', 'AMBIENT_LIGHT_SHADOW_COUNT'); - material.set('shadowEnabled', 0); - } - } - - this._opaqueCasters = []; - this._receivers = []; - this._lightsCastShadow = []; - } -}); - -/** - * @name clay.prePass.ShadowMap.VSM - * @type {number} - */ -ShadowMapPass.VSM = 1; - -/** - * @name clay.prePass.ShadowMap.PCF - * @type {number} - */ -ShadowMapPass.PCF = 2; - -/* harmony default export */ __webpack_exports__["a"] = (ShadowMapPass); - - -/***/ }), -/* 105 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Light__ = __webpack_require__(14); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__math_Vector3__ = __webpack_require__(2); - - - -/** - * @constructor clay.light.Spot - * @extends clay.Light - */ -var SpotLight = __WEBPACK_IMPORTED_MODULE_0__Light__["a" /* default */].extend( -/**@lends clay.light.Spot */ -{ - /** - * @type {number} - */ - range: 20, - /** - * @type {number} - */ - umbraAngle: 30, - /** - * @type {number} - */ - penumbraAngle: 45, - /** - * @type {number} - */ - falloffFactor: 2.0, - /** - * @type {number} - */ - shadowBias: 0.0002, - /** - * @type {number} - */ - shadowSlopeScale: 2.0 -},{ - - type: 'SPOT_LIGHT', - - uniformTemplates: { - spotLightPosition: { - type: '3f', - value: function (instance) { - return instance.getWorldPosition().array; - } - }, - spotLightRange: { - type: '1f', - value: function (instance) { - return instance.range; - } - }, - spotLightUmbraAngleCosine: { - type: '1f', - value: function (instance) { - return Math.cos(instance.umbraAngle * Math.PI / 180); - } - }, - spotLightPenumbraAngleCosine: { - type: '1f', - value: function (instance) { - return Math.cos(instance.penumbraAngle * Math.PI / 180); - } - }, - spotLightFalloffFactor: { - type: '1f', - value: function (instance) { - return instance.falloffFactor; - } - }, - spotLightDirection: { - type: '3f', - value: function (instance) { - instance.__dir = instance.__dir || new __WEBPACK_IMPORTED_MODULE_1__math_Vector3__["a" /* default */](); - // Direction is target to eye - return instance.__dir.copy(instance.worldTransform.z).negate().array; - } - }, - spotLightColor: { - type: '3f', - value: function (instance) { - var color = instance.color; - var intensity = instance.intensity; - return [color[0] * intensity, color[1] * intensity, color[2] * intensity]; - } - } - }, - /** - * @return {clay.light.Spot} - * @memberOf clay.light.Spot.prototype - */ - clone: function () { - var light = __WEBPACK_IMPORTED_MODULE_0__Light__["a" /* default */].prototype.clone.call(this); - light.range = this.range; - light.umbraAngle = this.umbraAngle; - light.penumbraAngle = this.penumbraAngle; - light.falloffFactor = this.falloffFactor; - light.shadowBias = this.shadowBias; - light.shadowSlopeScale = this.shadowSlopeScale; - return light; - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (SpotLight); - - -/***/ }), -/* 106 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Light__ = __webpack_require__(14); - - -/** - * @constructor clay.light.Point - * @extends clay.Light - */ -var PointLight = __WEBPACK_IMPORTED_MODULE_0__Light__["a" /* default */].extend( -/** @lends clay.light.Point# */ -{ - /** - * @type {number} - */ - range: 100, - - /** - * @type {number} - */ - castShadow: false -}, { - - type: 'POINT_LIGHT', - - uniformTemplates: { - pointLightPosition: { - type: '3f', - value: function(instance) { - return instance.getWorldPosition().array; - } - }, - pointLightRange: { - type: '1f', - value: function(instance) { - return instance.range; - } - }, - pointLightColor: { - type: '3f', - value: function(instance) { - var color = instance.color, - intensity = instance.intensity; - return [ color[0]*intensity, color[1]*intensity, color[2]*intensity ]; - } - } - }, - /** - * @return {clay.light.Point} - * @memberOf clay.light.Point.prototype - */ - clone: function() { - var light = __WEBPACK_IMPORTED_MODULE_0__Light__["a" /* default */].prototype.clone.call(this); - light.range = this.range; - return light; - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (PointLight); - - -/***/ }), -/* 107 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("\n@export clay.compositor.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\nvarying vec2 v_Texcoord;\nvoid main()\n{\n v_Texcoord = texcoord;\n gl_Position = worldViewProjection * vec4(position, 1.0);\n}\n@end"); - - -/***/ }), -/* 108 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.sm.depth.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\n#ifdef SHADOW_TRANSPARENT\nattribute vec2 texcoord : TEXCOORD_0;\n#endif\n@import clay.chunk.skinning_header\nvarying vec4 v_ViewPosition;\n#ifdef SHADOW_TRANSPARENT\nvarying vec2 v_Texcoord;\n#endif\nvoid main(){\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n v_ViewPosition = worldViewProjection * vec4(skinnedPosition, 1.0);\n gl_Position = v_ViewPosition;\n#ifdef SHADOW_TRANSPARENT\n v_Texcoord = texcoord;\n#endif\n}\n@end\n@export clay.sm.depth.fragment\nvarying vec4 v_ViewPosition;\n#ifdef SHADOW_TRANSPARENT\nvarying vec2 v_Texcoord;\n#endif\nuniform float bias : 0.001;\nuniform float slopeScale : 1.0;\n#ifdef SHADOW_TRANSPARENT\nuniform sampler2D transparentMap;\n#endif\n@import clay.util.encode_float\nvoid main(){\n float depth = v_ViewPosition.z / v_ViewPosition.w;\n#ifdef USE_VSM\n depth = depth * 0.5 + 0.5;\n float moment1 = depth;\n float moment2 = depth * depth;\n float dx = dFdx(depth);\n float dy = dFdy(depth);\n moment2 += 0.25*(dx*dx+dy*dy);\n gl_FragColor = vec4(moment1, moment2, 0.0, 1.0);\n#else\n float dx = dFdx(depth);\n float dy = dFdy(depth);\n depth += sqrt(dx*dx + dy*dy) * slopeScale + bias;\n#ifdef SHADOW_TRANSPARENT\n if (texture2D(transparentMap, v_Texcoord).a <= 0.1) {\n gl_FragColor = encodeFloat(0.9999);\n return;\n }\n#endif\n gl_FragColor = encodeFloat(depth * 0.5 + 0.5);\n#endif\n}\n@end\n@export clay.sm.debug_depth\nuniform sampler2D depthMap;\nvarying vec2 v_Texcoord;\n@import clay.util.decode_float\nvoid main() {\n vec4 tex = texture2D(depthMap, v_Texcoord);\n#ifdef USE_VSM\n gl_FragColor = vec4(tex.rgb, 1.0);\n#else\n float depth = decodeFloat(tex);\n gl_FragColor = vec4(depth, depth, depth, 1.0);\n#endif\n}\n@end\n@export clay.sm.distance.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 world : WORLD;\nattribute vec3 position : POSITION;\n@import clay.chunk.skinning_header\nvarying vec3 v_WorldPosition;\nvoid main (){\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition , 1.0);\n v_WorldPosition = (world * vec4(skinnedPosition, 1.0)).xyz;\n}\n@end\n@export clay.sm.distance.fragment\nuniform vec3 lightPosition;\nuniform float range : 100;\nvarying vec3 v_WorldPosition;\n@import clay.util.encode_float\nvoid main(){\n float dist = distance(lightPosition, v_WorldPosition);\n#ifdef USE_VSM\n gl_FragColor = vec4(dist, dist * dist, 0.0, 0.0);\n#else\n dist = dist / range;\n gl_FragColor = encodeFloat(dist);\n#endif\n}\n@end\n@export clay.plugin.shadow_map_common\n@import clay.util.decode_float\nfloat tapShadowMap(sampler2D map, vec2 uv, float z){\n vec4 tex = texture2D(map, uv);\n return step(z, decodeFloat(tex) * 2.0 - 1.0);\n}\nfloat pcf(sampler2D map, vec2 uv, float z, float textureSize, vec2 scale) {\n float shadowContrib = tapShadowMap(map, uv, z);\n vec2 offset = vec2(1.0 / textureSize) * scale;\n#ifdef PCF_KERNEL_SIZE\n for (int _idx_ = 0; _idx_ < PCF_KERNEL_SIZE; _idx_++) {{\n shadowContrib += tapShadowMap(map, uv + offset * pcfKernel[_idx_], z);\n }}\n return shadowContrib / float(PCF_KERNEL_SIZE + 1);\n#else\n shadowContrib += tapShadowMap(map, uv+vec2(offset.x, 0.0), z);\n shadowContrib += tapShadowMap(map, uv+vec2(offset.x, offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(-offset.x, offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(0.0, offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(-offset.x, 0.0), z);\n shadowContrib += tapShadowMap(map, uv+vec2(-offset.x, -offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(offset.x, -offset.y), z);\n shadowContrib += tapShadowMap(map, uv+vec2(0.0, -offset.y), z);\n return shadowContrib / 9.0;\n#endif\n}\nfloat pcf(sampler2D map, vec2 uv, float z, float textureSize) {\n return pcf(map, uv, z, textureSize, vec2(1.0));\n}\nfloat chebyshevUpperBound(vec2 moments, float z){\n float p = 0.0;\n z = z * 0.5 + 0.5;\n if (z <= moments.x) {\n p = 1.0;\n }\n float variance = moments.y - moments.x * moments.x;\n variance = max(variance, 0.0000001);\n float mD = moments.x - z;\n float pMax = variance / (variance + mD * mD);\n pMax = clamp((pMax-0.4)/(1.0-0.4), 0.0, 1.0);\n return max(p, pMax);\n}\nfloat computeShadowContrib(\n sampler2D map, mat4 lightVPM, vec3 position, float textureSize, vec2 scale, vec2 offset\n) {\n vec4 posInLightSpace = lightVPM * vec4(position, 1.0);\n posInLightSpace.xyz /= posInLightSpace.w;\n float z = posInLightSpace.z;\n if(all(greaterThan(posInLightSpace.xyz, vec3(-0.99, -0.99, -1.0))) &&\n all(lessThan(posInLightSpace.xyz, vec3(0.99, 0.99, 1.0)))){\n vec2 uv = (posInLightSpace.xy+1.0) / 2.0;\n #ifdef USE_VSM\n vec2 moments = texture2D(map, uv * scale + offset).xy;\n return chebyshevUpperBound(moments, z);\n #else\n return pcf(map, uv * scale + offset, z, textureSize, scale);\n #endif\n }\n return 1.0;\n}\nfloat computeShadowContrib(sampler2D map, mat4 lightVPM, vec3 position, float textureSize) {\n return computeShadowContrib(map, lightVPM, position, textureSize, vec2(1.0), vec2(0.0));\n}\nfloat computeShadowContribOmni(samplerCube map, vec3 direction, float range)\n{\n float dist = length(direction);\n vec4 shadowTex = textureCube(map, direction);\n#ifdef USE_VSM\n vec2 moments = shadowTex.xy;\n float variance = moments.y - moments.x * moments.x;\n float mD = moments.x - dist;\n float p = variance / (variance + mD * mD);\n if(moments.x + 0.001 < dist){\n return clamp(p, 0.0, 1.0);\n }else{\n return 1.0;\n }\n#else\n return step(dist, (decodeFloat(shadowTex) + 0.0002) * range);\n#endif\n}\n@end\n@export clay.plugin.compute_shadow_map\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT) || defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT) || defined(POINT_LIGHT_SHADOWMAP_COUNT)\n#ifdef SPOT_LIGHT_SHADOWMAP_COUNT\nuniform sampler2D spotLightShadowMaps[SPOT_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\nuniform mat4 spotLightMatrices[SPOT_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\nuniform float spotLightShadowMapSizes[SPOT_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\n#endif\n#ifdef DIRECTIONAL_LIGHT_SHADOWMAP_COUNT\n#if defined(SHADOW_CASCADE)\nuniform sampler2D directionalLightShadowMaps[1]:unconfigurable;\nuniform mat4 directionalLightMatrices[SHADOW_CASCADE]:unconfigurable;\nuniform float directionalLightShadowMapSizes[1]:unconfigurable;\nuniform float shadowCascadeClipsNear[SHADOW_CASCADE]:unconfigurable;\nuniform float shadowCascadeClipsFar[SHADOW_CASCADE]:unconfigurable;\n#else\nuniform sampler2D directionalLightShadowMaps[DIRECTIONAL_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\nuniform mat4 directionalLightMatrices[DIRECTIONAL_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\nuniform float directionalLightShadowMapSizes[DIRECTIONAL_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\n#endif\n#endif\n#ifdef POINT_LIGHT_SHADOWMAP_COUNT\nuniform samplerCube pointLightShadowMaps[POINT_LIGHT_SHADOWMAP_COUNT]:unconfigurable;\n#endif\nuniform bool shadowEnabled : true;\n#ifdef PCF_KERNEL_SIZE\nuniform vec2 pcfKernel[PCF_KERNEL_SIZE];\n#endif\n@import clay.plugin.shadow_map_common\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\nvoid computeShadowOfSpotLights(vec3 position, inout float shadowContribs[SPOT_LIGHT_COUNT] ) {\n float shadowContrib;\n for(int _idx_ = 0; _idx_ < SPOT_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n shadowContrib = computeShadowContrib(\n spotLightShadowMaps[_idx_], spotLightMatrices[_idx_], position,\n spotLightShadowMapSizes[_idx_]\n );\n shadowContribs[_idx_] = shadowContrib;\n }}\n for(int _idx_ = SPOT_LIGHT_SHADOWMAP_COUNT; _idx_ < SPOT_LIGHT_COUNT; _idx_++){{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n#ifdef SHADOW_CASCADE\nvoid computeShadowOfDirectionalLights(vec3 position, inout float shadowContribs[DIRECTIONAL_LIGHT_COUNT]){\n float depth = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far)\n / (gl_DepthRange.far - gl_DepthRange.near);\n float shadowContrib;\n shadowContribs[0] = 1.0;\n for (int _idx_ = 0; _idx_ < SHADOW_CASCADE; _idx_++) {{\n if (\n depth >= shadowCascadeClipsNear[_idx_] &&\n depth <= shadowCascadeClipsFar[_idx_]\n ) {\n shadowContrib = computeShadowContrib(\n directionalLightShadowMaps[0], directionalLightMatrices[_idx_], position,\n directionalLightShadowMapSizes[0],\n vec2(1.0 / float(SHADOW_CASCADE), 1.0),\n vec2(float(_idx_) / float(SHADOW_CASCADE), 0.0)\n );\n shadowContribs[0] = shadowContrib;\n }\n }}\n for(int _idx_ = DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#else\nvoid computeShadowOfDirectionalLights(vec3 position, inout float shadowContribs[DIRECTIONAL_LIGHT_COUNT]){\n float shadowContrib;\n for(int _idx_ = 0; _idx_ < DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n shadowContrib = computeShadowContrib(\n directionalLightShadowMaps[_idx_], directionalLightMatrices[_idx_], position,\n directionalLightShadowMapSizes[_idx_]\n );\n shadowContribs[_idx_] = shadowContrib;\n }}\n for(int _idx_ = DIRECTIONAL_LIGHT_SHADOWMAP_COUNT; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#endif\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\nvoid computeShadowOfPointLights(vec3 position, inout float shadowContribs[POINT_LIGHT_COUNT] ){\n vec3 lightPosition;\n vec3 direction;\n for(int _idx_ = 0; _idx_ < POINT_LIGHT_SHADOWMAP_COUNT; _idx_++) {{\n lightPosition = pointLightPosition[_idx_];\n direction = position - lightPosition;\n shadowContribs[_idx_] = computeShadowContribOmni(pointLightShadowMaps[_idx_], direction, pointLightRange[_idx_]);\n }}\n for(int _idx_ = POINT_LIGHT_SHADOWMAP_COUNT; _idx_ < POINT_LIGHT_COUNT; _idx_++) {{\n shadowContribs[_idx_] = 1.0;\n }}\n}\n#endif\n#endif\n@end"); - - -/***/ }), -/* 109 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_claygl_src_Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_claygl_src_Texture2D__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_claygl_src_FrameBuffer__ = __webpack_require__(11); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4_claygl_src_compositor_createCompositor__ = __webpack_require__(110); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__SSAOPass__ = __webpack_require__(116); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__SSRPass__ = __webpack_require__(118); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__poissonKernel__ = __webpack_require__(123); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8_claygl_src_deferred_GBuffer__ = __webpack_require__(124); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9_claygl_src_math_Matrix4__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__helper__ = __webpack_require__(26); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_11__composite_js__ = __webpack_require__(131); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_12_claygl_src_shader_source_compositor_blur_glsl_js__ = __webpack_require__(52); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_13_claygl_src_shader_source_compositor_output_glsl_js__ = __webpack_require__(53); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_14_claygl_src_shader_source_compositor_bright_glsl_js__ = __webpack_require__(54); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_15_claygl_src_shader_source_compositor_downsample_glsl_js__ = __webpack_require__(55); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_16_claygl_src_shader_source_compositor_upsample_glsl_js__ = __webpack_require__(56); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_17_claygl_src_shader_source_compositor_hdr_glsl_js__ = __webpack_require__(57); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_18_claygl_src_shader_source_compositor_blend_glsl_js__ = __webpack_require__(58); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_19_claygl_src_shader_source_compositor_fxaa_glsl_js__ = __webpack_require__(59); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_20_claygl_src_shader_source_deferred_gbuffer_glsl_js__ = __webpack_require__(64); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_21__DOF_glsl_js__ = __webpack_require__(132); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_22__edge_glsl_js__ = __webpack_require__(133); - - - - - - - - - -// import EdgePass from './EdgePass'; - - - - - - - - - - - - - - - - - - -__WEBPACK_IMPORTED_MODULE_0_claygl_src_Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_12_claygl_src_shader_source_compositor_blur_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_0_claygl_src_Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_13_claygl_src_shader_source_compositor_output_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_0_claygl_src_Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_14_claygl_src_shader_source_compositor_bright_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_0_claygl_src_Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_15_claygl_src_shader_source_compositor_downsample_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_0_claygl_src_Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_16_claygl_src_shader_source_compositor_upsample_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_0_claygl_src_Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_17_claygl_src_shader_source_compositor_hdr_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_0_claygl_src_Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_18_claygl_src_shader_source_compositor_blend_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_0_claygl_src_Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_19_claygl_src_shader_source_compositor_fxaa_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_0_claygl_src_Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_20_claygl_src_shader_source_deferred_gbuffer_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_0_claygl_src_Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_21__DOF_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_0_claygl_src_Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_22__edge_glsl_js__["a" /* default */]); - - -var commonOutputs = { - color : { - parameters : { - width : function (renderer) { - return renderer.getWidth(); - }, - height : function (renderer) { - return renderer.getHeight(); - } - } - } -} - -var FINAL_NODES_CHAIN = ['composite', 'FXAA']; - -function EffectCompositor() { - this._sourceTexture = new __WEBPACK_IMPORTED_MODULE_1_claygl_src_Texture2D__["a" /* default */]({ - type: __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture__["a" /* default */].HALF_FLOAT - }); - this._depthTexture = new __WEBPACK_IMPORTED_MODULE_1_claygl_src_Texture2D__["a" /* default */]({ - format: __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture__["a" /* default */].DEPTH_COMPONENT, - type: __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture__["a" /* default */].UNSIGNED_INT - }); - - this._framebuffer = new __WEBPACK_IMPORTED_MODULE_3_claygl_src_FrameBuffer__["a" /* default */](); - this._framebuffer.attach(this._sourceTexture); - this._framebuffer.attach(this._depthTexture, __WEBPACK_IMPORTED_MODULE_3_claygl_src_FrameBuffer__["a" /* default */].DEPTH_ATTACHMENT); - - this._gBufferPass = new __WEBPACK_IMPORTED_MODULE_8_claygl_src_deferred_GBuffer__["a" /* default */]({ - // enableTargetTexture3: false - }); - - this._compositor = Object(__WEBPACK_IMPORTED_MODULE_4_claygl_src_compositor_createCompositor__["a" /* default */])(__WEBPACK_IMPORTED_MODULE_11__composite_js__["a" /* default */]); - - var sourceNode = this._compositor.getNodeByName('source'); - sourceNode.texture = this._sourceTexture; - var cocNode = this._compositor.getNodeByName('coc'); - - this._sourceNode = sourceNode; - this._cocNode = cocNode; - this._compositeNode = this._compositor.getNodeByName('composite'); - this._fxaaNode = this._compositor.getNodeByName('FXAA'); - - this._dofBlurNodes = ['dof_far_blur', 'dof_near_blur', 'dof_coc_blur'].map(function (name) { - return this._compositor.getNodeByName(name); - }, this); - - this._dofBlurKernel = null; - this._dofBlurKernelSize = new Float32Array(0); - - this._finalNodesChain = FINAL_NODES_CHAIN.map(function (name) { - return this._compositor.getNodeByName(name); - }, this); - - var gBufferObj = { - normalTexture: this._gBufferPass.getTargetTexture1(), - depthTexture: this._gBufferPass.getTargetTexture2(), - albedoTexture: this._gBufferPass.getTargetTexture3() - }; - this._ssaoPass = new __WEBPACK_IMPORTED_MODULE_5__SSAOPass__["a" /* default */](gBufferObj); - this._ssrPass = new __WEBPACK_IMPORTED_MODULE_6__SSRPass__["a" /* default */](gBufferObj); - this._ssrPass.setPhysicallyCorrect(true); - // this._edgePass = new EdgePass(gBufferObj); -} - -EffectCompositor.prototype.resize = function (width, height, dpr) { - dpr = dpr || 1; - width = width * dpr; - height = height * dpr; - var sourceTexture = this._sourceTexture; - var depthTexture = this._depthTexture; - - sourceTexture.width = width; - sourceTexture.height = height; - depthTexture.width = width; - depthTexture.height = height; - - this._gBufferPass.resize(width, height); -}; - -EffectCompositor.prototype._ifRenderNormalPass = function () { - return this._enableSSAO || this._enableEdge || this._enableSSR; -}; - -EffectCompositor.prototype._getPrevNode = function (node) { - var idx = FINAL_NODES_CHAIN.indexOf(node.name) - 1; - var prevNode = this._finalNodesChain[idx]; - while (prevNode && !this._compositor.getNodeByName(prevNode.name)) { - idx -= 1; - prevNode = this._finalNodesChain[idx]; - } - return prevNode; -}; -EffectCompositor.prototype._getNextNode = function (node) { - var idx = FINAL_NODES_CHAIN.indexOf(node.name) + 1; - var nextNode = this._finalNodesChain[idx]; - while (nextNode && !this._compositor.getNodeByName(nextNode.name)) { - idx += 1; - nextNode = this._finalNodesChain[idx]; - } - return nextNode; -}; -EffectCompositor.prototype._addChainNode = function (node) { - var prevNode = this._getPrevNode(node); - var nextNode = this._getNextNode(node); - if (!prevNode) { - return; - } - - prevNode.outputs = commonOutputs; - node.inputs.texture = prevNode.name; - if (nextNode) { - node.outputs = commonOutputs; - nextNode.inputs.texture = node.name; - } - else { - node.outputs = null; - } - this._compositor.addNode(node); -}; -EffectCompositor.prototype._removeChainNode = function (node) { - var prevNode = this._getPrevNode(node); - var nextNode = this._getNextNode(node); - if (!prevNode) { - return; - } - - if (nextNode) { - prevNode.outputs = commonOutputs; - nextNode.inputs.texture = prevNode.name; - } - else { - prevNode.outputs = null; - } - this._compositor.removeNode(node); -}; -/** - * Update normal - */ -EffectCompositor.prototype.updateNormal = function (renderer, scene, camera, frame) { - if (this._ifRenderNormalPass()) { - this._gBufferPass.update(renderer, scene, camera); - } -}; - -/** - * Render SSAO after render the scene, before compositing - */ -EffectCompositor.prototype.updateSSAO = function (renderer, scene, camera, frame) { - this._ssaoPass.update(renderer, camera, frame); -}; - -/** - * Enable SSAO effect - */ -EffectCompositor.prototype.enableSSAO = function () { - this._enableSSAO = true; -}; - -/** - * Disable SSAO effect - */ -EffectCompositor.prototype.disableSSAO = function () { - this._enableSSAO = false; -}; - -/** - * Enable SSR effect - */ -EffectCompositor.prototype.enableSSR = function () { - this._enableSSR = true; -}; -/** - * Disable SSR effect - */ -EffectCompositor.prototype.disableSSR = function () { - this._enableSSR = false; -}; - -/** - * Render SSAO after render the scene, before compositing - */ -EffectCompositor.prototype.getSSAOTexture = function (renderer, scene, camera, frame) { - return this._ssaoPass.getTargetTexture(); -}; - -/** - * @return {clay.FrameBuffer} - */ -EffectCompositor.prototype.getSourceFrameBuffer = function () { - return this._framebuffer; -}; - -/** - * @return {clay.Texture2D} - */ -EffectCompositor.prototype.getSourceTexture = function () { - return this._sourceTexture; -}; - -/** - * Disable fxaa effect - */ -EffectCompositor.prototype.disableFXAA = function () { - this._removeChainNode(this._fxaaNode); -}; - -/** - * Enable fxaa effect - */ -EffectCompositor.prototype.enableFXAA = function () { - this._addChainNode(this._fxaaNode); -}; - -/** - * Enable bloom effect - */ -EffectCompositor.prototype.enableBloom = function () { - this._compositeNode.inputs.bloom = 'bloom_composite'; - this._compositor.dirty(); -}; - -/** - * Disable bloom effect - */ -EffectCompositor.prototype.disableBloom = function () { - this._compositeNode.inputs.bloom = null; - this._compositor.dirty(); -}; - -/** - * Enable depth of field effect - */ -EffectCompositor.prototype.enableDOF = function () { - this._compositeNode.inputs.texture = 'dof_composite'; - this._compositor.dirty(); -}; -/** - * Disable depth of field effect - */ -EffectCompositor.prototype.disableDOF = function () { - this._compositeNode.inputs.texture = 'source'; - this._compositor.dirty(); -}; - -/** - * Enable color correction - */ -EffectCompositor.prototype.enableColorCorrection = function () { - this._compositeNode.define('COLOR_CORRECTION'); - this._enableColorCorrection = true; -}; -/** - * Disable color correction - */ -EffectCompositor.prototype.disableColorCorrection = function () { - this._compositeNode.undefine('COLOR_CORRECTION'); - this._enableColorCorrection = false; -}; - -/** - * Enable edge detection - */ -EffectCompositor.prototype.enableEdge = function () { - this._enableEdge = true; -}; - -/** - * Disable edge detection - */ -EffectCompositor.prototype.disableEdge = function () { - this._enableEdge = false; -}; - -/** - * Set bloom intensity - * @param {number} value - */ -EffectCompositor.prototype.setBloomIntensity = function (value) { - if (value == null) { - return; - } - this._compositeNode.setParameter('bloomIntensity', value); -}; - -EffectCompositor.prototype.setSSAOParameter = function (name, value) { - if (value == null) { - return; - } - switch (name) { - case 'quality': - // PENDING - var kernelSize = ({ - low: 6, - medium: 12, - high: 32, - ultra: 62 - })[value] || 12; - this._ssaoPass.setParameter('kernelSize', kernelSize); - break; - case 'radius': - this._ssaoPass.setParameter(name, value); - this._ssaoPass.setParameter('bias', value / 50); - break; - case 'intensity': - this._ssaoPass.setParameter(name, value); - break; - } -}; - -EffectCompositor.prototype.setDOFParameter = function (name, value) { - if (value == null) { - return; - } - switch (name) { - case 'focalDistance': - case 'focalRange': - case 'fstop': - this._cocNode.setParameter(name, value); - break; - case 'blurRadius': - for (var i = 0; i < this._dofBlurNodes.length; i++) { - this._dofBlurNodes[i].setParameter('blurRadius', value); - } - break; - case 'quality': - var kernelSize = ({ - low: 4, medium: 8, high: 16, ultra: 32 - })[value] || 8; - this._dofBlurKernelSize = kernelSize; - for (var i = 0; i < this._dofBlurNodes.length; i++) { - this._dofBlurNodes[i].define('POISSON_KERNEL_SIZE', kernelSize); - } - this._dofBlurKernel = new Float32Array(kernelSize * 2); - break; - } -}; - -EffectCompositor.prototype.setSSRParameter = function (name, value) { - if (value == null) { - return; - } - switch (name) { - case 'quality': - // PENDING - var maxIteration = ({ - low: 10, - medium: 20, - high: 40, - ultra: 80 - })[value] || 20; - var pixelStride = ({ - low: 32, - medium: 16, - high: 8, - ultra: 4 - })[value] || 16; - this._ssrPass.setParameter('maxIteration', maxIteration); - this._ssrPass.setParameter('pixelStride', pixelStride); - break; - case 'maxRoughness': - this._ssrPass.setParameter('minGlossiness', Math.max(Math.min(1.0 - value, 1.0), 0.0)); - break; - default: - if (__DEV__) { - console.warn('Unkown SSR parameter ' + name); - } - } -} -; -/** - * Set color of edge - */ -EffectCompositor.prototype.setEdgeColor = function (value) { - // if (value == null) { - // return; - // } - // this._edgePass.setParameter('edgeColor', value); -}; - -EffectCompositor.prototype.setExposure = function (value) { - if (value == null) { - return; - } - this._compositeNode.setParameter('exposure', Math.pow(2, value)); -}; - -EffectCompositor.prototype.setColorLookupTexture = function (image, api) { - this._compositeNode.pass.material.setTextureImage('lut', this._enableColorCorrection ? image : 'none', api, { - minFilter: __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture__["a" /* default */].NEAREST, - magFilter: __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture__["a" /* default */].NEAREST, - flipY: false - }); -}; -EffectCompositor.prototype.setColorCorrection = function (type, value) { - this._compositeNode.setParameter(type, value); -}; - -EffectCompositor.prototype.composite = function (renderer, camera, framebuffer, frame) { - - var sourceTexture = this._sourceTexture; - var targetTexture = sourceTexture; - // if (this._enableEdge) { - // this._edgePass.update(renderer, camera, sourceTexture, frame); - // sourceTexture = targetTexture = this._edgePass.getTargetTexture(); - // } - if (this._enableSSR) { - this._ssrPass.update(renderer, camera, sourceTexture, frame); - targetTexture = this._ssrPass.getTargetTexture(); - - this._ssrPass.setSSAOTexture( - this._enableSSAO ? this._ssaoPass.getTargetTexture() : null - ); - } - this._sourceNode.texture = targetTexture; - - this._cocNode.setParameter('depth', this._depthTexture); - - var blurKernel = this._dofBlurKernel; - var blurKernelSize = this._dofBlurKernelSize; - var frameAll = Math.floor(__WEBPACK_IMPORTED_MODULE_7__poissonKernel__["a" /* default */].length / 2 / blurKernelSize); - var kernelOffset = frame % frameAll; - - for (var i = 0; i < blurKernelSize * 2; i++) { - blurKernel[i] = __WEBPACK_IMPORTED_MODULE_7__poissonKernel__["a" /* default */][i + kernelOffset * blurKernelSize * 2]; - } - - for (var i = 0; i < this._dofBlurNodes.length; i++) { - this._dofBlurNodes[i].setParameter('percent', frame / 30.0); - this._dofBlurNodes[i].setParameter('poissonKernel', blurKernel); - } - - this._cocNode.setParameter('zNear', camera.near); - this._cocNode.setParameter('zFar', camera.far); - - this._compositor.render(renderer, framebuffer); -}; - -EffectCompositor.prototype.isSSRFinished = function (frame) { - return this._ssrPass ? this._ssrPass.isFinished(frame) : true; -}; - -EffectCompositor.prototype.isSSAOFinished = function (frame) { - return this._ssaoPass ? this._ssaoPass.isFinished(frame) : true; -}; - -EffectCompositor.prototype.dispose = function (renderer) { - this._sourceTexture.dispose(renderer); - this._depthTexture.dispose(renderer); - this._framebuffer.dispose(renderer); - this._compositor.dispose(renderer); - - this._gBufferPass.dispose(renderer); - this._ssaoPass.dispose(renderer); -}; - -/* harmony default export */ __webpack_exports__["a"] = (EffectCompositor); - -/***/ }), -/* 110 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_util__ = __webpack_require__(7); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Compositor__ = __webpack_require__(111); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__SceneNode__ = __webpack_require__(113); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__TextureNode__ = __webpack_require__(114); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__FilterNode__ = __webpack_require__(115); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__Texture2D__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__TextureCube__ = __webpack_require__(17); - - - - - - - - - - -var shaderSourceReg = /^#source\((.*?)\)/; - -/** - * @name clay.compositor.createCompositor - * @function - * @param {Object} json - * @param {Object} [opts] - * @return {clay.compositor.Compositor} - */ -function createCompositor(json, opts) { - var compositor = new __WEBPACK_IMPORTED_MODULE_1__Compositor__["a" /* default */](); - opts = opts || {}; - - var lib = { - textures: {}, - parameters: {} - }; - var afterLoad = function(shaderLib, textureLib) { - for (var i = 0; i < json.nodes.length; i++) { - var nodeInfo = json.nodes[i]; - var node = createNode(nodeInfo, lib, opts); - if (node) { - compositor.addNode(node); - } - } - }; - - for (var name in json.parameters) { - var paramInfo = json.parameters[name]; - lib.parameters[name] = convertParameter(paramInfo); - } - // TODO load texture asynchronous - loadTextures(json, lib, opts, function(textureLib) { - lib.textures = textureLib; - afterLoad(); - }); - - return compositor; -} - -function createNode(nodeInfo, lib, opts) { - var type = nodeInfo.type || 'filter'; - var shaderSource; - var inputs; - var outputs; - - if (type === 'filter') { - var shaderExp = nodeInfo.shader.trim(); - var res = shaderSourceReg.exec(shaderExp); - if (res) { - shaderSource = __WEBPACK_IMPORTED_MODULE_5__Shader__["a" /* default */].source(res[1].trim()); - } - else if (shaderExp.charAt(0) === '#') { - shaderSource = lib.shaders[shaderExp.substr(1)]; - } - if (!shaderSource) { - shaderSource = shaderExp; - } - if (!shaderSource) { - return; - } - } - - if (nodeInfo.inputs) { - inputs = {}; - for (var name in nodeInfo.inputs) { - if (typeof nodeInfo.inputs[name] === 'string') { - inputs[name] = nodeInfo.inputs[name]; - } - else { - inputs[name] = { - node: nodeInfo.inputs[name].node, - pin: nodeInfo.inputs[name].pin - }; - } - } - } - if (nodeInfo.outputs) { - outputs = {}; - for (var name in nodeInfo.outputs) { - var outputInfo = nodeInfo.outputs[name]; - outputs[name] = {}; - if (outputInfo.attachment != null) { - outputs[name].attachment = outputInfo.attachment; - } - if (outputInfo.keepLastFrame != null) { - outputs[name].keepLastFrame = outputInfo.keepLastFrame; - } - if (outputInfo.outputLastFrame != null) { - outputs[name].outputLastFrame = outputInfo.outputLastFrame; - } - if (outputInfo.parameters) { - outputs[name].parameters = convertParameter(outputInfo.parameters); - } - } - } - var node; - if (type === 'scene') { - node = new __WEBPACK_IMPORTED_MODULE_2__SceneNode__["a" /* default */]({ - name: nodeInfo.name, - scene: opts.scene, - camera: opts.camera, - outputs: outputs - }); - } - else if (type === 'texture') { - node = new __WEBPACK_IMPORTED_MODULE_3__TextureNode__["a" /* default */]({ - name: nodeInfo.name, - outputs: outputs - }); - } - // Default is filter - else { - node = new __WEBPACK_IMPORTED_MODULE_4__FilterNode__["a" /* default */]({ - name: nodeInfo.name, - shader: shaderSource, - inputs: inputs, - outputs: outputs - }); - } - if (node) { - if (nodeInfo.parameters) { - for (var name in nodeInfo.parameters) { - var val = nodeInfo.parameters[name]; - if (typeof(val) === 'string') { - val = val.trim(); - if (val.charAt(0) === '#') { - val = lib.textures[val.substr(1)]; - } - else { - node.on( - 'beforerender', createSizeSetHandler( - name, tryConvertExpr(val) - ) - ); - } - } - node.setParameter(name, val); - } - } - if (nodeInfo.defines && node.pass) { - for (var name in nodeInfo.defines) { - var val = nodeInfo.defines[name]; - node.pass.material.define('fragment', name, val); - } - } - } - return node; -} - -function convertParameter(paramInfo) { - var param = {}; - if (!paramInfo) { - return param; - } - ['type', 'minFilter', 'magFilter', 'wrapS', 'wrapT', 'flipY', 'useMipmap'] - .forEach(function(name) { - var val = paramInfo[name]; - if (val != null) { - // Convert string to enum - if (typeof val === 'string') { - val = __WEBPACK_IMPORTED_MODULE_6__Texture__["a" /* default */][val]; - } - param[name] = val; - } - }); - ['width', 'height'] - .forEach(function(name) { - if (paramInfo[name] != null) { - var val = paramInfo[name]; - if (typeof val === 'string') { - val = val.trim(); - param[name] = createSizeParser( - name, tryConvertExpr(val) - ); - } - else { - param[name] = val; - } - } - }); - if (paramInfo.useMipmap != null) { - param.useMipmap = paramInfo.useMipmap; - } - return param; -} - -function loadTextures(json, lib, opts, callback) { - if (!json.textures) { - callback({}); - return; - } - var textures = {}; - var loading = 0; - - var cbd = false; - var textureRootPath = opts.textureRootPath; - __WEBPACK_IMPORTED_MODULE_0__core_util__["a" /* default */].each(json.textures, function(textureInfo, name) { - var texture; - var path = textureInfo.path; - var parameters = convertParameter(textureInfo.parameters); - if (Array.isArray(path) && path.length === 6) { - if (textureRootPath) { - path = path.map(function(item) { - return __WEBPACK_IMPORTED_MODULE_0__core_util__["a" /* default */].relative2absolute(item, textureRootPath); - }); - } - texture = new __WEBPACK_IMPORTED_MODULE_8__TextureCube__["a" /* default */](parameters); - } - else if(typeof path === 'string') { - if (textureRootPath) { - path = __WEBPACK_IMPORTED_MODULE_0__core_util__["a" /* default */].relative2absolute(path, textureRootPath); - } - texture = new __WEBPACK_IMPORTED_MODULE_7__Texture2D__["a" /* default */](parameters); - } - else { - return; - } - - texture.load(path); - loading++; - texture.once('success', function() { - textures[name] = texture; - loading--; - if (loading === 0) { - callback(textures); - cbd = true; - } - }); - }); - - if (loading === 0 && !cbd) { - callback(textures); - } -} - -function createSizeSetHandler(name, exprFunc) { - return function (renderer) { - // PENDING viewport size or window size - var dpr = renderer.getDevicePixelRatio(); - // PENDING If multiply dpr ? - var width = renderer.getWidth(); - var height = renderer.getHeight(); - var result = exprFunc(width, height, dpr); - this.setParameter(name, result); - }; -} - -function createSizeParser(name, exprFunc) { - return function (renderer) { - var dpr = renderer.getDevicePixelRatio(); - var width = renderer.getWidth(); - var height = renderer.getHeight(); - return exprFunc(width, height, dpr); - }; -} - -function tryConvertExpr(string) { - // PENDING - var exprRes = /^expr\((.*)\)$/.exec(string); - if (exprRes) { - try { - var func = new Function('width', 'height', 'dpr', 'return ' + exprRes[1]); - // Try run t - func(1, 1); - - return func; - } - catch (e) { - throw new Error('Invalid expression.'); - } - } -} - -/* harmony default export */ __webpack_exports__["a"] = (createCompositor); - - -/***/ }), -/* 111 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Graph__ = __webpack_require__(112); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__TexturePool__ = __webpack_require__(62); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__FrameBuffer__ = __webpack_require__(11); - - - - -/** - * Compositor provide graph based post processing - * - * @constructor clay.compositor.Compositor - * @extends clay.compositor.Graph - * - */ -var Compositor = __WEBPACK_IMPORTED_MODULE_0__Graph__["a" /* default */].extend(function() { - return { - // Output node - _outputs: [], - - _texturePool: new __WEBPACK_IMPORTED_MODULE_1__TexturePool__["a" /* default */](), - - _frameBuffer: new __WEBPACK_IMPORTED_MODULE_2__FrameBuffer__["a" /* default */]({ - depthBuffer: false - }) - }; -}, -/** @lends clay.compositor.Compositor.prototype */ -{ - addNode: function(node) { - __WEBPACK_IMPORTED_MODULE_0__Graph__["a" /* default */].prototype.addNode.call(this, node); - node._compositor = this; - }, - /** - * @param {clay.Renderer} renderer - */ - render: function(renderer, frameBuffer) { - if (this._dirty) { - this.update(); - this._dirty = false; - - this._outputs.length = 0; - for (var i = 0; i < this.nodes.length; i++) { - if (!this.nodes[i].outputs) { - this._outputs.push(this.nodes[i]); - } - } - } - - for (var i = 0; i < this.nodes.length; i++) { - // Update the reference number of each output texture - this.nodes[i].beforeFrame(); - } - - for (var i = 0; i < this._outputs.length; i++) { - this._outputs[i].updateReference(); - } - - for (var i = 0; i < this._outputs.length; i++) { - this._outputs[i].render(renderer, frameBuffer); - } - - for (var i = 0; i < this.nodes.length; i++) { - // Clear up - this.nodes[i].afterFrame(); - } - }, - - allocateTexture: function (parameters) { - return this._texturePool.get(parameters); - }, - - releaseTexture: function (parameters) { - this._texturePool.put(parameters); - }, - - getFrameBuffer: function () { - return this._frameBuffer; - }, - - /** - * Dispose compositor - * @param {clay.Renderer} renderer - */ - dispose: function (renderer) { - this._texturePool.clear(renderer); - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (Compositor); - - -/***/ }), -/* 112 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Node__ = __webpack_require__(24); - - - -/** - * @constructor clay.compositor.Graph - * @extends clay.core.Base - */ -var Graph = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend(function () { - return /** @lends clay.compositor.Graph# */ { - /** - * @type {Array.} - */ - nodes: [] - }; -}, -/** @lends clay.compositor.Graph.prototype */ -{ - - /** - * Mark to update - */ - dirty: function () { - this._dirty = true; - }, - /** - * @param {clay.compositor.Node} node - */ - addNode: function (node) { - - if (this.nodes.indexOf(node) >= 0) { - return; - } - - this.nodes.push(node); - - this._dirty = true; - }, - /** - * @param {clay.compositor.Node|string} node - */ - removeNode: function (node) { - if (typeof node === 'string') { - node = this.getNodeByName(node); - } - var idx = this.nodes.indexOf(node); - if (idx >= 0) { - this.nodes.splice(idx, 1); - this._dirty = true; - } - }, - /** - * @param {string} name - * @return {clay.compositor.Node} - */ - getNodeByName: function (name) { - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].name === name) { - return this.nodes[i]; - } - } - }, - /** - * Update links of graph - */ - update: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - // Traverse all the nodes and build the graph - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (!node.inputs) { - continue; - } - for (var inputName in node.inputs) { - if (!node.inputs[inputName]) { - continue; - } - if (node.pass && !node.pass.material.isUniformEnabled(inputName)) { - console.warn('Pin ' + node.name + '.' + inputName + ' not used.'); - continue; - } - var fromPinInfo = node.inputs[inputName]; - - var fromPin = this.findPin(fromPinInfo); - if (fromPin) { - node.link(inputName, fromPin.node, fromPin.pin); - } - else { - if (typeof fromPinInfo === 'string') { - console.warn('Node ' + fromPinInfo + ' not exist'); - } - else { - console.warn('Pin of ' + fromPinInfo.node + '.' + fromPinInfo.pin + ' not exist'); - } - } - } - } - }, - - findPin: function (input) { - var node; - // Try to take input as a directly a node - if (typeof input === 'string' || input instanceof __WEBPACK_IMPORTED_MODULE_1__Node__["a" /* default */]) { - input = { - node: input - }; - } - - if (typeof input.node === 'string') { - for (var i = 0; i < this.nodes.length; i++) { - var tmp = this.nodes[i]; - if (tmp.name === input.node) { - node = tmp; - } - } - } - else { - node = input.node; - } - if (node) { - var inputPin = input.pin; - if (!inputPin) { - // Use first pin defaultly - if (node.outputs) { - inputPin = Object.keys(node.outputs)[0]; - } - } - if (node.outputs[inputPin]) { - return { - node: node, - pin: inputPin - }; - } - } - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (Graph); - - -/***/ }), -/* 113 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Node__ = __webpack_require__(24); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_glenum__ = __webpack_require__(6); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__FrameBuffer__ = __webpack_require__(11); - - - - -/** - * @constructor clay.compositor.SceneNode - * @extends clay.compositor.Node - */ -var SceneNode = __WEBPACK_IMPORTED_MODULE_0__Node__["a" /* default */].extend( -/** @lends clay.compositor.SceneNode# */ -{ - name: 'scene', - /** - * @type {clay.Scene} - */ - scene: null, - /** - * @type {clay.Camera} - */ - camera: null, - /** - * @type {boolean} - */ - autoUpdateScene: true, - /** - * @type {boolean} - */ - preZ: false - -}, function() { - this.frameBuffer = new __WEBPACK_IMPORTED_MODULE_2__FrameBuffer__["a" /* default */](); -}, { - render: function(renderer) { - - this._rendering = true; - var _gl = renderer.gl; - - this.trigger('beforerender'); - - var renderInfo; - - if (!this.outputs) { - - renderInfo = renderer.render(this.scene, this.camera, !this.autoUpdateScene, this.preZ); - - } - else { - - var frameBuffer = this.frameBuffer; - for (var name in this.outputs) { - var parameters = this.updateParameter(name, renderer); - var outputInfo = this.outputs[name]; - var texture = this._compositor.allocateTexture(parameters); - this._outputTextures[name] = texture; - - var attachment = outputInfo.attachment || _gl.COLOR_ATTACHMENT0; - if (typeof(attachment) == 'string') { - attachment = _gl[attachment]; - } - frameBuffer.attach(texture, attachment); - } - frameBuffer.bind(renderer); - - // MRT Support in chrome - // https://www.khronos.org/registry/webgl/sdk/tests/conformance/extensions/ext-draw-buffers.html - var ext = renderer.getGLExtension('EXT_draw_buffers'); - if (ext) { - var bufs = []; - for (var attachment in this.outputs) { - attachment = parseInt(attachment); - if (attachment >= _gl.COLOR_ATTACHMENT0 && attachment <= _gl.COLOR_ATTACHMENT0 + 8) { - bufs.push(attachment); - } - } - ext.drawBuffersEXT(bufs); - } - - // Always clear - // PENDING - renderer.saveClear(); - renderer.clearBit = __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].DEPTH_BUFFER_BIT | __WEBPACK_IMPORTED_MODULE_1__core_glenum__["a" /* default */].COLOR_BUFFER_BIT; - renderInfo = renderer.render(this.scene, this.camera, !this.autoUpdateScene, this.preZ); - renderer.restoreClear(); - - frameBuffer.unbind(renderer); - } - - this.trigger('afterrender', renderInfo); - - this._rendering = false; - this._rendered = true; - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (SceneNode); - - -/***/ }), -/* 114 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Node__ = __webpack_require__(24); - - -/** - * @constructor clay.compositor.TextureNode - * @extends clay.compositor.Node - */ -var TextureNode = __WEBPACK_IMPORTED_MODULE_0__Node__["a" /* default */].extend(function() { - return /** @lends clay.compositor.TextureNode# */ { - /** - * @type {clay.Texture2D} - */ - texture: null, - - // Texture node must have output without parameters - outputs: { - color: {} - } - }; -}, function () { -}, { - - getOutput: function (renderer, name) { - return this.texture; - }, - - // Do nothing - beforeFrame: function () {}, - afterFrame: function () {} -}); - -/* harmony default export */ __webpack_exports__["a"] = (TextureNode); - - -/***/ }), -/* 115 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Pass__ = __webpack_require__(13); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Node__ = __webpack_require__(24); -// TODO Shader library - - - -// TODO curlnoise demo wrong - -// PENDING -// Use topological sort ? - -/** - * Filter node - * - * @constructor clay.compositor.FilterNode - * @extends clay.compositor.Node - * - * @example - var node = new clay.compositor.Node({ - name: 'fxaa', - shader: clay.Shader.source('clay.compositor.fxaa'), - inputs: { - texture: { - node: 'scene', - pin: 'color' - } - }, - // Multiple outputs is preserved for MRT support in WebGL2.0 - outputs: { - color: { - attachment: clay.FrameBuffer.COLOR_ATTACHMENT0 - parameters: { - format: clay.Texture.RGBA, - width: 512, - height: 512 - }, - // Node will keep the RTT rendered in last frame - keepLastFrame: true, - // Force the node output the RTT rendered in last frame - outputLastFrame: true - } - } - }); - * - */ -var FilterNode = __WEBPACK_IMPORTED_MODULE_1__Node__["a" /* default */].extend(function () { - return /** @lends clay.compositor.Node# */ { - /** - * @type {string} - */ - name: '', - - /** - * @type {Object} - */ - inputs: {}, - - /** - * @type {Object} - */ - outputs: null, - - /** - * @type {string} - */ - shader: '', - - /** - * Input links, will be updated by the graph - * @example: - * inputName: { - * node: someNode, - * pin: 'xxxx' - * } - * @type {Object} - */ - inputLinks: {}, - - /** - * Output links, will be updated by the graph - * @example: - * outputName: { - * node: someNode, - * pin: 'xxxx' - * } - * @type {Object} - */ - outputLinks: {}, - - /** - * @type {clay.compositor.Pass} - */ - pass: null, - - // Save the output texture of previous frame - // Will be used when there exist a circular reference - _prevOutputTextures: {}, - _outputTextures: {}, - - // Example: { name: 2 } - _outputReferences: {}, - - _rendering: false, - // If rendered in this frame - _rendered: false, - - _compositor: null - }; -}, function () { - - var pass = new __WEBPACK_IMPORTED_MODULE_0__Pass__["a" /* default */]({ - fragment: this.shader - }); - this.pass = pass; -}, -/** @lends clay.compositor.Node.prototype */ -{ - /** - * @param {clay.Renderer} renderer - */ - render: function (renderer, frameBuffer) { - this.trigger('beforerender', renderer); - - this._rendering = true; - - var _gl = renderer.gl; - - for (var inputName in this.inputLinks) { - var link = this.inputLinks[inputName]; - var inputTexture = link.node.getOutput(renderer, link.pin); - this.pass.setUniform(inputName, inputTexture); - } - // Output - if (!this.outputs) { - this.pass.outputs = null; - - this._compositor.getFrameBuffer().unbind(renderer); - - this.pass.render(renderer, frameBuffer); - } - else { - this.pass.outputs = {}; - - var attachedTextures = {}; - for (var name in this.outputs) { - var parameters = this.updateParameter(name, renderer); - if (isNaN(parameters.width)) { - this.updateParameter(name, renderer); - } - var outputInfo = this.outputs[name]; - var texture = this._compositor.allocateTexture(parameters); - this._outputTextures[name] = texture; - var attachment = outputInfo.attachment || _gl.COLOR_ATTACHMENT0; - if (typeof(attachment) == 'string') { - attachment = _gl[attachment]; - } - attachedTextures[attachment] = texture; - } - this._compositor.getFrameBuffer().bind(renderer); - - for (var attachment in attachedTextures) { - // FIXME attachment changes in different nodes - this._compositor.getFrameBuffer().attach( - attachedTextures[attachment], attachment - ); - } - - this.pass.render(renderer); - - // Because the data of texture is changed over time, - // Here update the mipmaps of texture each time after rendered; - this._compositor.getFrameBuffer().updateMipmap(renderer.gl); - } - - for (var inputName in this.inputLinks) { - var link = this.inputLinks[inputName]; - link.node.removeReference(link.pin); - } - - this._rendering = false; - this._rendered = true; - - this.trigger('afterrender', renderer); - }, - - // TODO Remove parameter function callback - updateParameter: function (outputName, renderer) { - var outputInfo = this.outputs[outputName]; - var parameters = outputInfo.parameters; - var parametersCopy = outputInfo._parametersCopy; - if (!parametersCopy) { - parametersCopy = outputInfo._parametersCopy = {}; - } - if (parameters) { - for (var key in parameters) { - if (key !== 'width' && key !== 'height') { - parametersCopy[key] = parameters[key]; - } - } - } - var width, height; - if (parameters.width instanceof Function) { - width = parameters.width.call(this, renderer); - } - else { - width = parameters.width; - } - if (parameters.height instanceof Function) { - height = parameters.height.call(this, renderer); - } - else { - height = parameters.height; - } - if ( - parametersCopy.width !== width - || parametersCopy.height !== height - ) { - if (this._outputTextures[outputName]) { - this._outputTextures[outputName].dispose(renderer); - } - } - parametersCopy.width = width; - parametersCopy.height = height; - - return parametersCopy; - }, - - /** - * Set parameter - * @param {string} name - * @param {} value - */ - setParameter: function (name, value) { - this.pass.setUniform(name, value); - }, - /** - * Get parameter value - * @param {string} name - * @return {} - */ - getParameter: function (name) { - return this.pass.getUniform(name); - }, - /** - * Set parameters - * @param {Object} obj - */ - setParameters: function (obj) { - for (var name in obj) { - this.setParameter(name, obj[name]); - } - }, - // /** - // * Set shader code - // * @param {string} shaderStr - // */ - // setShader: function (shaderStr) { - // var material = this.pass.material; - // material.shader.setFragment(shaderStr); - // material.attachShader(material.shader, true); - // }, - /** - * Proxy of pass.material.define('fragment', xxx); - * @param {string} symbol - * @param {number} [val] - */ - define: function (symbol, val) { - this.pass.material.define('fragment', symbol, val); - }, - - /** - * Proxy of pass.material.undefine('fragment', xxx) - * @param {string} symbol - */ - undefine: function (symbol) { - this.pass.material.undefine('fragment', symbol); - }, - - removeReference: function (outputName) { - this._outputReferences[outputName]--; - if (this._outputReferences[outputName] === 0) { - var outputInfo = this.outputs[outputName]; - if (outputInfo.keepLastFrame) { - if (this._prevOutputTextures[outputName]) { - this._compositor.releaseTexture(this._prevOutputTextures[outputName]); - } - this._prevOutputTextures[outputName] = this._outputTextures[outputName]; - } - else { - // Output of this node have alreay been used by all other nodes - // Put the texture back to the pool. - this._compositor.releaseTexture(this._outputTextures[outputName]); - } - } - }, - - clear: function () { - __WEBPACK_IMPORTED_MODULE_1__Node__["a" /* default */].prototype.clear.call(this); - - // Default disable all texture - this.pass.material.disableTexturesAll(); - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (FilterNode); - - -/***/ }), -/* 116 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_claygl_src_math_Matrix4__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_claygl_src_math_Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture2D__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_claygl_src_Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4_claygl_src_compositor_Pass__ = __webpack_require__(13); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5_claygl_src_Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6_claygl_src_FrameBuffer__ = __webpack_require__(11); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__halton__ = __webpack_require__(25); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__SSAO_glsl_js__ = __webpack_require__(117); - - - - - - - - - - - -__WEBPACK_IMPORTED_MODULE_5_claygl_src_Shader__["a" /* default */].import(__WEBPACK_IMPORTED_MODULE_8__SSAO_glsl_js__["a" /* default */]); - -function generateNoiseData(size) { - var data = new Uint8Array(size * size * 4); - var n = 0; - var v3 = new __WEBPACK_IMPORTED_MODULE_1_claygl_src_math_Vector3__["a" /* default */](); - - for (var i = 0; i < size; i++) { - for (var j = 0; j < size; j++) { - v3.set(Math.random() * 2 - 1, Math.random() * 2 - 1, 0).normalize(); - data[n++] = (v3.x * 0.5 + 0.5) * 255; - data[n++] = (v3.y * 0.5 + 0.5) * 255; - data[n++] = 0; - data[n++] = 255; - } - } - return data; -} - -function generateNoiseTexture(size) { - return new __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture2D__["a" /* default */]({ - pixels: generateNoiseData(size), - wrapS: __WEBPACK_IMPORTED_MODULE_3_claygl_src_Texture__["a" /* default */].REPEAT, - wrapT: __WEBPACK_IMPORTED_MODULE_3_claygl_src_Texture__["a" /* default */].REPEAT, - width: size, - height: size - }); -} - -function generateKernel(size, offset, hemisphere) { - var kernel = new Float32Array(size * 3); - offset = offset || 0; - for (var i = 0; i < size; i++) { - var phi = Object(__WEBPACK_IMPORTED_MODULE_7__halton__["a" /* default */])(i + offset, 2) * (hemisphere ? 1 : 2) * Math.PI; - var theta = Object(__WEBPACK_IMPORTED_MODULE_7__halton__["a" /* default */])(i + offset, 3) * Math.PI; - var r = Math.random(); - var x = Math.cos(phi) * Math.sin(theta) * r; - var y = Math.cos(theta) * r; - var z = Math.sin(phi) * Math.sin(theta) * r; - - kernel[i * 3] = x; - kernel[i * 3 + 1] = y; - kernel[i * 3 + 2] = z; - } - return kernel; -} - -function SSAOPass(opt) { - opt = opt || {}; - - this._ssaoPass = new __WEBPACK_IMPORTED_MODULE_4_claygl_src_compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_5_claygl_src_Shader__["a" /* default */].source('ecgl.ssao.estimate') - }); - this._blurPass = new __WEBPACK_IMPORTED_MODULE_4_claygl_src_compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_5_claygl_src_Shader__["a" /* default */].source('ecgl.ssao.blur') - }); - this._framebuffer = new __WEBPACK_IMPORTED_MODULE_6_claygl_src_FrameBuffer__["a" /* default */](); - - this._ssaoTexture = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture2D__["a" /* default */](); - this._blurTexture = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture2D__["a" /* default */](); - - this._depthTex = opt.depthTexture; - this._normalTex = opt.normalTexture; - - this.setNoiseSize(4); - this.setKernelSize(opt.kernelSize || 12); - if (opt.radius != null) { - this.setParameter('radius', opt.radius); - } - if (opt.power != null) { - this.setParameter('power', opt.power); - } - - if (!this._normalTex) { - this._ssaoPass.material.disableTexture('normalTex'); - this._blurPass.material.disableTexture('normalTex'); - } - if (!this._depthTex) { - this._blurPass.material.disableTexture('depthTex'); - } - - this._blurPass.material.setUniform('normalTex', this._normalTex); - this._blurPass.material.setUniform('depthTex', this._depthTex); -} - -SSAOPass.prototype.setDepthTexture = function (depthTex) { - this._depthTex = depthTex; -}; - -SSAOPass.prototype.setNormalTexture = function (normalTex) { - this._normalTex = normalTex; - this._ssaoPass.material[normalTex ? 'enableTexture' : 'disableTexture']('normalTex'); - // Switch between hemisphere and shere kernel. - this.setKernelSize(this._kernelSize); -}; - -SSAOPass.prototype.update = function (renderer, camera, frame) { - var width = renderer.getWidth(); - var height = renderer.getHeight(); - - var ssaoPass = this._ssaoPass; - var blurPass = this._blurPass; - - ssaoPass.setUniform('kernel', this._kernels[frame % this._kernels.length]); - ssaoPass.setUniform('depthTex', this._depthTex); - if (this._normalTex != null) { - ssaoPass.setUniform('normalTex', this._normalTex); - } - ssaoPass.setUniform('depthTexSize', [this._depthTex.width, this._depthTex.height]); - - var viewInverseTranspose = new __WEBPACK_IMPORTED_MODULE_0_claygl_src_math_Matrix4__["a" /* default */](); - __WEBPACK_IMPORTED_MODULE_0_claygl_src_math_Matrix4__["a" /* default */].transpose(viewInverseTranspose, camera.worldTransform); - - ssaoPass.setUniform('projection', camera.projectionMatrix.array); - ssaoPass.setUniform('projectionInv', camera.invProjectionMatrix.array); - ssaoPass.setUniform('viewInverseTranspose', viewInverseTranspose.array); - - var ssaoTexture = this._ssaoTexture; - var blurTexture = this._blurTexture; - - ssaoTexture.width = width; - ssaoTexture.height = height; - blurTexture.width = width; - blurTexture.height = height; - - this._framebuffer.attach(ssaoTexture); - this._framebuffer.bind(renderer); - renderer.gl.clearColor(1, 1, 1, 1); - renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT); - ssaoPass.render(renderer); - - blurPass.setUniform('textureSize', [width, height]); - blurPass.setUniform('projection', camera.projectionMatrix.array); - this._framebuffer.attach(blurTexture); - blurPass.setUniform('direction', 0); - blurPass.setUniform('ssaoTexture', ssaoTexture); - blurPass.render(renderer); - - this._framebuffer.attach(ssaoTexture); - blurPass.setUniform('direction', 1); - blurPass.setUniform('ssaoTexture', blurTexture); - blurPass.render(renderer); - - this._framebuffer.unbind(renderer); - - // Restore clear - var clearColor = renderer.clearColor; - renderer.gl.clearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); -}; - -SSAOPass.prototype.getTargetTexture = function () { - return this._ssaoTexture; -}; - -SSAOPass.prototype.setParameter = function (name, val) { - if (name === 'noiseTexSize') { - this.setNoiseSize(val); - } - else if (name === 'kernelSize') { - this.setKernelSize(val); - } - else if (name === 'intensity') { - this._ssaoPass.material.set('intensity', val); - } - else { - this._ssaoPass.setUniform(name, val); - } -}; - -SSAOPass.prototype.setKernelSize = function (size) { - this._kernelSize = size; - this._ssaoPass.material.define('fragment', 'KERNEL_SIZE', size); - this._kernels = this._kernels || []; - for (var i = 0; i < 30; i++) { - this._kernels[i] = generateKernel(size, i * size, !!this._normalTex); - } -}; - -SSAOPass.prototype.setNoiseSize = function (size) { - var texture = this._ssaoPass.getUniform('noiseTex'); - if (!texture) { - texture = generateNoiseTexture(size); - this._ssaoPass.setUniform('noiseTex', generateNoiseTexture(size)); - } - else { - texture.data = generateNoiseData(size); - texture.width = texture.height = size; - texture.dirty(); - } - - this._ssaoPass.setUniform('noiseTexSize', [size, size]); -}; - -SSAOPass.prototype.dispose = function (renderer) { - this._blurTexture.dispose(renderer); - this._ssaoTexture.dispose(renderer); -}; - -SSAOPass.prototype.isFinished = function (frame) { - return frame > 30; -}; - -/* harmony default export */ __webpack_exports__["a"] = (SSAOPass); - -/***/ }), -/* 117 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export ecgl.ssao.estimate\n\n#define SHADER_NAME SSAO\n\nuniform sampler2D depthTex;\n\nuniform sampler2D normalTex;\n\nuniform sampler2D noiseTex;\n\nuniform vec2 depthTexSize;\n\nuniform vec2 noiseTexSize;\n\nuniform mat4 projection;\n\nuniform mat4 projectionInv;\n\nuniform mat4 viewInverseTranspose;\n\nuniform vec3 kernel[KERNEL_SIZE];\n\nuniform float radius : 1;\n\nuniform float power : 1;\n\nuniform float bias: 0.01;\n\nuniform float intensity: 1.0;\n\nvarying vec2 v_Texcoord;\n\nfloat ssaoEstimator(in vec3 originPos, in vec3 N, in mat3 kernelBasis) {\n float occlusion = 0.0;\n\n for (int i = 0; i < KERNEL_SIZE; i++) {\n vec3 samplePos = kernel[i];\n#ifdef NORMALTEX_ENABLED\n samplePos = kernelBasis * samplePos;\n#endif\n samplePos = samplePos * radius + originPos;\n\n vec4 texCoord = projection * vec4(samplePos, 1.0);\n texCoord.xy /= texCoord.w;\n texCoord.xy = texCoord.xy * 0.5 + 0.5;\n\n vec4 depthTexel = texture2D(depthTex, texCoord.xy);\n float z = depthTexel.r * 2.0 - 1.0;\n#ifdef ALCHEMY\n vec4 projectedPos = vec4(texCoord.xy * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * projectedPos;\n p4.xyz /= p4.w;\n vec3 cDir = p4.xyz - originPos;\n\n float vv = dot(cDir, cDir);\n float vn = dot(cDir, N);\n\n float radius2 = radius * radius;\n\n vn = max(vn + p4.z * bias, 0.0);\n float f = max(radius2 - vv, 0.0) / radius2;\n occlusion += f * f * f * max(vn / (0.01 + vv), 0.0);\n#else\n if (projection[3][3] == 0.0) {\n z = projection[3][2] / (z * projection[2][3] - projection[2][2]);\n }\n else {\n z = (z - projection[3][2]) / projection[2][2];\n }\n float factor = step(samplePos.z, z - bias);\n float rangeCheck = smoothstep(0.0, 1.0, radius / abs(originPos.z - z));\n occlusion += rangeCheck * factor;\n#endif\n }\n#ifdef NORMALTEX_ENABLED\n occlusion = 1.0 - occlusion / float(KERNEL_SIZE);\n#else\n occlusion = 1.0 - clamp((occlusion / float(KERNEL_SIZE) - 0.6) * 2.5, 0.0, 1.0);\n#endif\n return pow(occlusion, power);\n}\n\nvoid main()\n{\n\n vec4 depthTexel = texture2D(depthTex, v_Texcoord);\n\n#ifdef NORMALTEX_ENABLED\n vec4 tex = texture2D(normalTex, v_Texcoord);\n if (dot(tex.rgb, tex.rgb) == 0.0) {\n gl_FragColor = vec4(1.0);\n return;\n }\n vec3 N = tex.rgb * 2.0 - 1.0;\n N = (viewInverseTranspose * vec4(N, 0.0)).xyz;\n\n vec2 noiseTexCoord = depthTexSize / vec2(noiseTexSize) * v_Texcoord;\n vec3 rvec = texture2D(noiseTex, noiseTexCoord).rgb * 2.0 - 1.0;\n vec3 T = normalize(rvec - N * dot(rvec, N));\n vec3 BT = normalize(cross(N, T));\n mat3 kernelBasis = mat3(T, BT, N);\n#else\n if (depthTexel.r > 0.99999) {\n gl_FragColor = vec4(1.0);\n return;\n }\n mat3 kernelBasis;\n#endif\n\n float z = depthTexel.r * 2.0 - 1.0;\n\n vec4 projectedPos = vec4(v_Texcoord * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * projectedPos;\n\n vec3 position = p4.xyz / p4.w;\n\n float ao = ssaoEstimator(position, N, kernelBasis);\n ao = clamp(1.0 - (1.0 - ao) * intensity, 0.0, 1.0);\n gl_FragColor = vec4(vec3(ao), 1.0);\n}\n\n@end\n\n\n@export ecgl.ssao.blur\n#define SHADER_NAME SSAO_BLUR\n\nuniform sampler2D ssaoTexture;\n\n#ifdef NORMALTEX_ENABLED\nuniform sampler2D normalTex;\n#endif\n\nvarying vec2 v_Texcoord;\n\nuniform vec2 textureSize;\nuniform float blurSize : 1.0;\n\nuniform int direction: 0.0;\n\n#ifdef DEPTHTEX_ENABLED\nuniform sampler2D depthTex;\nuniform mat4 projection;\nuniform float depthRange : 0.05;\n\nfloat getLinearDepth(vec2 coord)\n{\n float depth = texture2D(depthTex, coord).r * 2.0 - 1.0;\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n}\n#endif\n\nvoid main()\n{\n @import clay.compositor.kernel.gaussian_9\n\n vec2 off = vec2(0.0);\n if (direction == 0) {\n off[0] = blurSize / textureSize.x;\n }\n else {\n off[1] = blurSize / textureSize.y;\n }\n\n vec2 coord = v_Texcoord;\n\n float sum = 0.0;\n float weightAll = 0.0;\n\n#ifdef NORMALTEX_ENABLED\n vec3 centerNormal = texture2D(normalTex, v_Texcoord).rgb * 2.0 - 1.0;\n#endif\n#if defined(DEPTHTEX_ENABLED)\n float centerDepth = getLinearDepth(v_Texcoord);\n#endif\n\n for (int i = 0; i < 9; i++) {\n vec2 coord = clamp(v_Texcoord + vec2(float(i) - 4.0) * off, vec2(0.0), vec2(1.0));\n\n float w = gaussianKernel[i];\n#ifdef NORMALTEX_ENABLED\n vec3 normal = texture2D(normalTex, coord).rgb * 2.0 - 1.0;\n w *= clamp(dot(normal, centerNormal), 0.0, 1.0);\n#endif\n#ifdef DEPTHTEX_ENABLED\n float d = getLinearDepth(coord);\n w *= (1.0 - smoothstep(abs(centerDepth - d) / depthRange, 0.0, 1.0));\n#endif\n\n weightAll += w;\n sum += texture2D(ssaoTexture, coord).r * w;\n }\n\n gl_FragColor = vec4(vec3(sum / weightAll), 1.0);\n}\n\n@end\n"); - - -/***/ }), -/* 118 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_claygl_src_math_Matrix4__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_claygl_src_math_Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture2D__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_claygl_src_Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4_claygl_src_compositor_Pass__ = __webpack_require__(13); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5_claygl_src_Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6_claygl_src_FrameBuffer__ = __webpack_require__(11); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__halton__ = __webpack_require__(25); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8_claygl_src_util_cubemap__ = __webpack_require__(63); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__SSR_glsl_js__ = __webpack_require__(122); - - - - - - - - - - - - -__WEBPACK_IMPORTED_MODULE_5_claygl_src_Shader__["a" /* default */].import(__WEBPACK_IMPORTED_MODULE_9__SSR_glsl_js__["a" /* default */]); - -function generateNormals(size, offset, hemisphere) { - var kernel = new Float32Array(size * 3); - offset = offset || 0; - for (var i = 0; i < size; i++) { - var phi = Object(__WEBPACK_IMPORTED_MODULE_7__halton__["a" /* default */])(i + offset, 2) * (hemisphere ? 1 : 2) * Math.PI / 2; - var theta = Object(__WEBPACK_IMPORTED_MODULE_7__halton__["a" /* default */])(i + offset, 3) * 2 * Math.PI; - var x = Math.cos(theta) * Math.sin(phi); - var y = Math.sin(theta) * Math.sin(phi); - var z = Math.cos(phi); - kernel[i * 3] = x; - kernel[i * 3 + 1] = y; - kernel[i * 3 + 2] = z; - } - return kernel; -} - -function SSRPass(opt) { - opt = opt || {}; - - this._ssrPass = new __WEBPACK_IMPORTED_MODULE_4_claygl_src_compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_5_claygl_src_Shader__["a" /* default */].source('ecgl.ssr.main'), - clearColor: [0, 0, 0, 0] - }); - this._blurPass1 = new __WEBPACK_IMPORTED_MODULE_4_claygl_src_compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_5_claygl_src_Shader__["a" /* default */].source('ecgl.ssr.blur'), - clearColor: [0, 0, 0, 0] - }); - this._blurPass2 = new __WEBPACK_IMPORTED_MODULE_4_claygl_src_compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_5_claygl_src_Shader__["a" /* default */].source('ecgl.ssr.blur'), - clearColor: [0, 0, 0, 0] - }); - this._blendPass = new __WEBPACK_IMPORTED_MODULE_4_claygl_src_compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_5_claygl_src_Shader__["a" /* default */].source('clay.compositor.blend') - }); - this._blendPass.material.disableTexturesAll(); - this._blendPass.material.enableTexture(['texture1', 'texture2']); - - this._ssrPass.setUniform('gBufferTexture1', opt.normalTexture); - this._ssrPass.setUniform('gBufferTexture2', opt.depthTexture); - this._ssrPass.setUniform('gBufferTexture3', opt.albedoTexture); - - this._blurPass1.setUniform('gBufferTexture1', opt.normalTexture); - this._blurPass1.setUniform('gBufferTexture2', opt.depthTexture); - - this._blurPass2.setUniform('gBufferTexture1', opt.normalTexture); - this._blurPass2.setUniform('gBufferTexture2', opt.depthTexture); - - this._blurPass2.material.define('fragment', 'VERTICAL'); - this._blurPass2.material.define('fragment', 'BLEND'); - - this._ssrTexture = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture2D__["a" /* default */]({ - type: __WEBPACK_IMPORTED_MODULE_3_claygl_src_Texture__["a" /* default */].HALF_FLOAT - }); - this._texture2 = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture2D__["a" /* default */]({ - type: __WEBPACK_IMPORTED_MODULE_3_claygl_src_Texture__["a" /* default */].HALF_FLOAT - }); - this._texture3 = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture2D__["a" /* default */]({ - type: __WEBPACK_IMPORTED_MODULE_3_claygl_src_Texture__["a" /* default */].HALF_FLOAT - }); - this._prevTexture = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture2D__["a" /* default */]({ - type: __WEBPACK_IMPORTED_MODULE_3_claygl_src_Texture__["a" /* default */].HALF_FLOAT - }); - this._currentTexture = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture2D__["a" /* default */]({ - type: __WEBPACK_IMPORTED_MODULE_3_claygl_src_Texture__["a" /* default */].HALF_FLOAT - }); - - this._frameBuffer = new __WEBPACK_IMPORTED_MODULE_6_claygl_src_FrameBuffer__["a" /* default */]({ - depthBuffer: false - }); - - this._normalDistribution = null; - - this._totalSamples = 512; - this._samplePerFrame = 5; - - this._ssrPass.material.define('fragment', 'SAMPLE_PER_FRAME', this._samplePerFrame); - - this._downScale = 2; - - // this._diffuseSampleNormals = []; - // for (var i = 0; i < this._totalSamples; i++) { - // this._diffuseSampleNormals.push(generateNormals(this._samplePerFrame, i * this._samplePerFrame, true)); - // } -} - -SSRPass.prototype.update = function (renderer, camera, sourceTexture, frame) { - var width = renderer.getWidth(); - var height = renderer.getHeight(); - var ssrTexture = this._ssrTexture; - var texture2 = this._texture2; - var texture3 = this._texture3; - ssrTexture.width = this._prevTexture.width = this._currentTexture.width = width / this._downScale; - ssrTexture.height = this._prevTexture.height = this._currentTexture.height = height / this._downScale; - - texture2.width = texture3.width = width; - texture2.height = texture3.height = height; - - var frameBuffer = this._frameBuffer; - - var ssrPass = this._ssrPass; - var blurPass1 = this._blurPass1; - var blurPass2 = this._blurPass2; - var blendPass = this._blendPass; - - var viewInverseTranspose = new __WEBPACK_IMPORTED_MODULE_0_claygl_src_math_Matrix4__["a" /* default */](); - __WEBPACK_IMPORTED_MODULE_0_claygl_src_math_Matrix4__["a" /* default */].transpose(viewInverseTranspose, camera.worldTransform); - - ssrPass.setUniform('sourceTexture', sourceTexture); - ssrPass.setUniform('projection', camera.projectionMatrix.array); - ssrPass.setUniform('projectionInv', camera.invProjectionMatrix.array); - ssrPass.setUniform('viewInverseTranspose', viewInverseTranspose.array); - ssrPass.setUniform('nearZ', camera.near); - - var percent = frame / this._totalSamples * this._samplePerFrame; - ssrPass.setUniform('jitterOffset', percent); - ssrPass.setUniform('normalJitter', frame / this._totalSamples); - // ssrPass.setUniform('lambertNormals', this._diffuseSampleNormals[frame % this._totalSamples]); - - blurPass1.setUniform('textureSize', [ssrTexture.width, ssrTexture.height]); - blurPass2.setUniform('textureSize', [width, height]); - blurPass2.setUniform('sourceTexture', sourceTexture); - - blurPass1.setUniform('projection', camera.projectionMatrix.array); - blurPass2.setUniform('projection', camera.projectionMatrix.array); - - frameBuffer.attach(ssrTexture); - frameBuffer.bind(renderer); - ssrPass.render(renderer); - - frameBuffer.attach(this._currentTexture); - blendPass.setUniform('texture1', ssrTexture); - blendPass.setUniform('texture2', this._prevTexture); - blendPass.material.set({ - 'weight1': 1, - 'weight2': frame >= 1 ? 1 : 0 - }); - blendPass.render(renderer); - - frameBuffer.attach(texture2); - blurPass1.setUniform('texture', this._currentTexture); - blurPass1.render(renderer); - - frameBuffer.attach(texture3); - blurPass2.setUniform('texture', texture2); - blurPass2.render(renderer); - frameBuffer.unbind(renderer); - - var tmp = this._prevTexture; - this._prevTexture = this._currentTexture; - this._currentTexture = tmp; -}; - -SSRPass.prototype.getTargetTexture = function () { - return this._texture3; -}; - -SSRPass.prototype.setParameter = function (name, val) { - if (name === 'maxIteration') { - this._ssrPass.material.define('fragment', 'MAX_ITERATION', val); - } - else { - this._ssrPass.setUniform(name, val); - } -}; - -SSRPass.prototype.setPhysicallyCorrect = function (isPhysicallyCorrect) { - if (isPhysicallyCorrect) { - if (!this._normalDistribution) { - this._normalDistribution = __WEBPACK_IMPORTED_MODULE_8_claygl_src_util_cubemap__["a" /* default */].generateNormalDistribution(128, this._totalSamples); - } - this._ssrPass.material.define('fragment', 'PHYSICALLY_CORRECT'); - this._ssrPass.material.set('normalDistribution', this._normalDistribution); - } - else { - this._ssrPass.material.undefine('fragment', 'PHYSICALLY_CORRECT'); - } -}; - -SSRPass.prototype.setSSAOTexture = function (texture) { - var blendPass = this._blurPass2; - if (texture) { - blendPass.material.enableTexture('ssaoTex'); - blendPass.material.set('ssaoTex', texture); - } - else { - blendPass.material.disableTexture('ssaoTex'); - } -}; - -SSRPass.prototype.isFinished = function (frame) { - return frame > (this._totalSamples / this._samplePerFrame); -}; - -SSRPass.prototype.dispose = function (renderer) { - this._ssrTexture.dispose(renderer); - this._texture2.dispose(renderer); - this._texture3.dispose(renderer); - this._prevTexture.dispose(renderer); - this._currentTexture.dispose(renderer); - this._frameBuffer.dispose(renderer); -}; - -/* harmony default export */ __webpack_exports__["a"] = (SSRPass); - -/***/ }), -/* 119 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Geometry__ = __webpack_require__(19); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Plane__ = __webpack_require__(33); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__math_Matrix4__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__math_Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__math_BoundingBox__ = __webpack_require__(8); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__core_vendor__ = __webpack_require__(12); - - - - - - - -var planeMatrix = new __WEBPACK_IMPORTED_MODULE_2__math_Matrix4__["a" /* default */](); - -/** - * @constructor clay.geometry.Cube - * @extends clay.Geometry - * @param {Object} [opt] - * @param {number} [opt.widthSegments] - * @param {number} [opt.heightSegments] - * @param {number} [opt.depthSegments] - * @param {boolean} [opt.inside] - */ -var Cube = __WEBPACK_IMPORTED_MODULE_0__Geometry__["a" /* default */].extend( -/**@lends clay.geometry.Cube# */ -{ - dynamic: false, - /** - * @type {number} - */ - widthSegments: 1, - /** - * @type {number} - */ - heightSegments: 1, - /** - * @type {number} - */ - depthSegments: 1, - /** - * @type {boolean} - */ - inside: false -}, function() { - this.build(); -}, -/** @lends clay.geometry.Cube.prototype */ -{ - /** - * Build cube geometry - */ - build: function() { - - var planes = { - 'px': createPlane('px', this.depthSegments, this.heightSegments), - 'nx': createPlane('nx', this.depthSegments, this.heightSegments), - 'py': createPlane('py', this.widthSegments, this.depthSegments), - 'ny': createPlane('ny', this.widthSegments, this.depthSegments), - 'pz': createPlane('pz', this.widthSegments, this.heightSegments), - 'nz': createPlane('nz', this.widthSegments, this.heightSegments), - }; - - var attrList = ['position', 'texcoord0', 'normal']; - var vertexNumber = 0; - var faceNumber = 0; - for (var pos in planes) { - vertexNumber += planes[pos].vertexCount; - faceNumber += planes[pos].indices.length; - } - for (var k = 0; k < attrList.length; k++) { - this.attributes[attrList[k]].init(vertexNumber); - } - this.indices = new __WEBPACK_IMPORTED_MODULE_5__core_vendor__["a" /* default */].Uint16Array(faceNumber); - var faceOffset = 0; - var vertexOffset = 0; - for (var pos in planes) { - var plane = planes[pos]; - for (var k = 0; k < attrList.length; k++) { - var attrName = attrList[k]; - var attrArray = plane.attributes[attrName].value; - var attrSize = plane.attributes[attrName].size; - var isNormal = attrName === 'normal'; - for (var i = 0; i < attrArray.length; i++) { - var value = attrArray[i]; - if (this.inside && isNormal) { - value = -value; - } - this.attributes[attrName].value[i + attrSize * vertexOffset] = value; - } - } - var len = plane.indices.length; - for (var i = 0; i < plane.indices.length; i++) { - this.indices[i + faceOffset] = vertexOffset + plane.indices[this.inside ? (len - i - 1) : i]; - } - faceOffset += plane.indices.length; - vertexOffset += plane.vertexCount; - } - - this.boundingBox = new __WEBPACK_IMPORTED_MODULE_4__math_BoundingBox__["a" /* default */](); - this.boundingBox.max.set(1, 1, 1); - this.boundingBox.min.set(-1, -1, -1); - } -}); - -function createPlane(pos, widthSegments, heightSegments) { - - planeMatrix.identity(); - - var plane = new __WEBPACK_IMPORTED_MODULE_1__Plane__["a" /* default */]({ - widthSegments: widthSegments, - heightSegments: heightSegments - }); - - switch(pos) { - case 'px': - __WEBPACK_IMPORTED_MODULE_2__math_Matrix4__["a" /* default */].translate(planeMatrix, planeMatrix, __WEBPACK_IMPORTED_MODULE_3__math_Vector3__["a" /* default */].POSITIVE_X); - __WEBPACK_IMPORTED_MODULE_2__math_Matrix4__["a" /* default */].rotateY(planeMatrix, planeMatrix, Math.PI / 2); - break; - case 'nx': - __WEBPACK_IMPORTED_MODULE_2__math_Matrix4__["a" /* default */].translate(planeMatrix, planeMatrix, __WEBPACK_IMPORTED_MODULE_3__math_Vector3__["a" /* default */].NEGATIVE_X); - __WEBPACK_IMPORTED_MODULE_2__math_Matrix4__["a" /* default */].rotateY(planeMatrix, planeMatrix, -Math.PI / 2); - break; - case 'py': - __WEBPACK_IMPORTED_MODULE_2__math_Matrix4__["a" /* default */].translate(planeMatrix, planeMatrix, __WEBPACK_IMPORTED_MODULE_3__math_Vector3__["a" /* default */].POSITIVE_Y); - __WEBPACK_IMPORTED_MODULE_2__math_Matrix4__["a" /* default */].rotateX(planeMatrix, planeMatrix, -Math.PI / 2); - break; - case 'ny': - __WEBPACK_IMPORTED_MODULE_2__math_Matrix4__["a" /* default */].translate(planeMatrix, planeMatrix, __WEBPACK_IMPORTED_MODULE_3__math_Vector3__["a" /* default */].NEGATIVE_Y); - __WEBPACK_IMPORTED_MODULE_2__math_Matrix4__["a" /* default */].rotateX(planeMatrix, planeMatrix, Math.PI / 2); - break; - case 'pz': - __WEBPACK_IMPORTED_MODULE_2__math_Matrix4__["a" /* default */].translate(planeMatrix, planeMatrix, __WEBPACK_IMPORTED_MODULE_3__math_Vector3__["a" /* default */].POSITIVE_Z); - break; - case 'nz': - __WEBPACK_IMPORTED_MODULE_2__math_Matrix4__["a" /* default */].translate(planeMatrix, planeMatrix, __WEBPACK_IMPORTED_MODULE_3__math_Vector3__["a" /* default */].NEGATIVE_Z); - __WEBPACK_IMPORTED_MODULE_2__math_Matrix4__["a" /* default */].rotateY(planeMatrix, planeMatrix, Math.PI); - break; - } - plane.applyTransform(planeMatrix); - return plane; -} - -/* harmony default export */ __webpack_exports__["a"] = (Cube); - - -/***/ }), -/* 120 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("#define SAMPLE_NUMBER 1024\n#define PI 3.14159265358979\nuniform sampler2D normalDistribution;\nuniform vec2 viewportSize : [512, 256];\nconst vec3 N = vec3(0.0, 0.0, 1.0);\nconst float fSampleNumber = float(SAMPLE_NUMBER);\nvec3 importanceSampleNormal(float i, float roughness, vec3 N) {\n vec3 H = texture2D(normalDistribution, vec2(roughness, i)).rgb;\n vec3 upVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);\n vec3 tangentX = normalize(cross(upVector, N));\n vec3 tangentY = cross(N, tangentX);\n return tangentX * H.x + tangentY * H.y + N * H.z;\n}\nfloat G_Smith(float roughness, float NoV, float NoL) {\n float k = roughness * roughness / 2.0;\n float G1V = NoV / (NoV * (1.0 - k) + k);\n float G1L = NoL / (NoL * (1.0 - k) + k);\n return G1L * G1V;\n}\nvoid main() {\n vec2 uv = gl_FragCoord.xy / viewportSize;\n float NoV = uv.x;\n float roughness = uv.y;\n vec3 V;\n V.x = sqrt(1.0 - NoV * NoV);\n V.y = 0.0;\n V.z = NoV;\n float A = 0.0;\n float B = 0.0;\n for (int i = 0; i < SAMPLE_NUMBER; i++) {\n vec3 H = importanceSampleNormal(float(i) / fSampleNumber, roughness, N);\n vec3 L = reflect(-V, H);\n float NoL = clamp(L.z, 0.0, 1.0);\n float NoH = clamp(H.z, 0.0, 1.0);\n float VoH = clamp(dot(V, H), 0.0, 1.0);\n if (NoL > 0.0) {\n float G = G_Smith(roughness, NoV, NoL);\n float G_Vis = G * VoH / (NoH * NoV);\n float Fc = pow(1.0 - VoH, 5.0);\n A += (1.0 - Fc) * G_Vis;\n B += Fc * G_Vis;\n }\n }\n gl_FragColor = vec4(vec2(A, B) / fSampleNumber, 0.0, 1.0);\n}\n"); - - -/***/ }), -/* 121 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("#define SAMPLE_NUMBER 1024\n#define PI 3.14159265358979\nuniform mat4 viewInverse : VIEWINVERSE;\nuniform samplerCube environmentMap;\nuniform sampler2D normalDistribution;\nuniform float roughness : 0.5;\nvarying vec2 v_Texcoord;\nvarying vec3 v_WorldPosition;\nconst float fSampleNumber = float(SAMPLE_NUMBER);\n@import clay.util.rgbm\nvec3 importanceSampleNormal(float i, float roughness, vec3 N) {\n vec3 H = texture2D(normalDistribution, vec2(roughness, i)).rgb;\n vec3 upVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);\n vec3 tangentX = normalize(cross(upVector, N));\n vec3 tangentY = cross(N, tangentX);\n return tangentX * H.x + tangentY * H.y + N * H.z;\n}\nvoid main() {\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = normalize(v_WorldPosition - eyePos);\n vec3 N = V;\n vec3 R = V;\n vec3 prefilteredColor = vec3(0.0);\n float totalWeight = 0.0;\n for (int i = 0; i < SAMPLE_NUMBER; i++) {\n vec3 H = importanceSampleNormal(float(i) / fSampleNumber, roughness, N);\n vec3 L = reflect(-V, H);\n float NoL = clamp(dot(N, L), 0.0, 1.0);\n if (NoL > 0.0) {\n prefilteredColor += decodeHDR(textureCube(environmentMap, L)).rgb * NoL;\n totalWeight += NoL;\n }\n }\n gl_FragColor = encodeHDR(vec4(prefilteredColor / totalWeight, 1.0));\n}\n"); - - -/***/ }), -/* 122 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export ecgl.ssr.main\n\n#define MAX_ITERATION 20;\n#define SAMPLE_PER_FRAME 5;\n\nuniform sampler2D sourceTexture;\nuniform sampler2D gBufferTexture1;\nuniform sampler2D gBufferTexture2;\nuniform sampler2D gBufferTexture3;\n\nuniform mat4 projection;\nuniform mat4 projectionInv;\nuniform mat4 viewInverseTranspose;\n\nuniform float maxRayDistance: 200;\n\nuniform float pixelStride: 16;\nuniform float pixelStrideZCutoff: 50; \nuniform float screenEdgeFadeStart: 0.9; \nuniform float eyeFadeStart : 0.2; uniform float eyeFadeEnd: 0.8; \nuniform float minGlossiness: 0.2; uniform float zThicknessThreshold: 1;\n\nuniform float nearZ;\nuniform vec2 viewportSize : VIEWPORT_SIZE;\n\nuniform float jitterOffset: 0;\n\nvarying vec2 v_Texcoord;\n\n#ifdef DEPTH_DECODE\n@import clay.util.decode_float\n#endif\n\n#ifdef PHYSICALLY_CORRECT\nuniform vec3 lambertNormals[SAMPLE_PER_FRAME];\nuniform sampler2D normalDistribution;\nuniform float normalJitter: 0;\nvec3 transformNormal(vec3 H, vec3 N) {\n vec3 upVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);\n vec3 tangentX = normalize(cross(upVector, N));\n vec3 tangentY = cross(N, tangentX);\n return normalize(tangentX * H.x + tangentY * H.y + N * H.z);\n}\nvec3 importanceSampleNormalGGX(float i, float roughness, vec3 N) {\n vec3 H = texture2D(normalDistribution, vec2(roughness, i + normalJitter)).rgb;\n return transformNormal(H, N);\n}\nfloat G_Smith(float g, float ndv, float ndl) {\n float roughness = 1.0 - g;\n float k = roughness * roughness / 2.0;\n float G1V = ndv / (ndv * (1.0 - k) + k);\n float G1L = ndl / (ndl * (1.0 - k) + k);\n return G1L * G1V;\n}\nvec3 F_Schlick(float ndv, vec3 spec) {\n return spec + (1.0 - spec) * pow(1.0 - ndv, 5.0);\n}\n#endif\n\nfloat fetchDepth(sampler2D depthTexture, vec2 uv)\n{\n vec4 depthTexel = texture2D(depthTexture, uv);\n return depthTexel.r * 2.0 - 1.0;\n}\n\nfloat linearDepth(float depth)\n{\n if (projection[3][3] == 0.0) {\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n }\n else {\n return (depth - projection[3][2]) / projection[2][2];\n }\n}\n\nbool rayIntersectDepth(float rayZNear, float rayZFar, vec2 hitPixel)\n{\n if (rayZFar > rayZNear)\n {\n float t = rayZFar; rayZFar = rayZNear; rayZNear = t;\n }\n float cameraZ = linearDepth(fetchDepth(gBufferTexture2, hitPixel));\n return rayZFar <= cameraZ && rayZNear >= cameraZ - zThicknessThreshold;\n}\n\n\nbool traceScreenSpaceRay(\n vec3 rayOrigin, vec3 rayDir, float jitter,\n out vec2 hitPixel, out vec3 hitPoint, out float iterationCount\n)\n{\n float rayLength = ((rayOrigin.z + rayDir.z * maxRayDistance) > -nearZ)\n ? (-nearZ - rayOrigin.z) / rayDir.z : maxRayDistance;\n\n vec3 rayEnd = rayOrigin + rayDir * rayLength;\n\n vec4 H0 = projection * vec4(rayOrigin, 1.0);\n vec4 H1 = projection * vec4(rayEnd, 1.0);\n\n float k0 = 1.0 / H0.w, k1 = 1.0 / H1.w;\n\n vec3 Q0 = rayOrigin * k0, Q1 = rayEnd * k1;\n\n vec2 P0 = (H0.xy * k0 * 0.5 + 0.5) * viewportSize;\n vec2 P1 = (H1.xy * k1 * 0.5 + 0.5) * viewportSize;\n\n P1 += dot(P1 - P0, P1 - P0) < 0.0001 ? 0.01 : 0.0;\n vec2 delta = P1 - P0;\n\n bool permute = false;\n if (abs(delta.x) < abs(delta.y)) {\n permute = true;\n delta = delta.yx;\n P0 = P0.yx;\n P1 = P1.yx;\n }\n float stepDir = sign(delta.x);\n float invdx = stepDir / delta.x;\n\n vec3 dQ = (Q1 - Q0) * invdx;\n float dk = (k1 - k0) * invdx;\n\n vec2 dP = vec2(stepDir, delta.y * invdx);\n\n float strideScaler = 1.0 - min(1.0, -rayOrigin.z / pixelStrideZCutoff);\n float pixStride = 1.0 + strideScaler * pixelStride;\n\n dP *= pixStride; dQ *= pixStride; dk *= pixStride;\n\n vec4 pqk = vec4(P0, Q0.z, k0);\n vec4 dPQK = vec4(dP, dQ.z, dk);\n\n pqk += dPQK * jitter;\n float rayZFar = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);\n float rayZNear;\n\n bool intersect = false;\n\n vec2 texelSize = 1.0 / viewportSize;\n\n iterationCount = 0.0;\n\n for (int i = 0; i < MAX_ITERATION; i++)\n {\n pqk += dPQK;\n\n rayZNear = rayZFar;\n rayZFar = (dPQK.z * 0.5 + pqk.z) / (dPQK.w * 0.5 + pqk.w);\n\n hitPixel = permute ? pqk.yx : pqk.xy;\n hitPixel *= texelSize;\n\n intersect = rayIntersectDepth(rayZNear, rayZFar, hitPixel);\n\n iterationCount += 1.0;\n\n if (intersect && iterationCount > 1.0) {\n break;\n }\n }\n\n Q0.xy += dQ.xy * iterationCount;\n Q0.z = pqk.z;\n hitPoint = Q0 / pqk.w;\n\n return intersect;\n}\n\nfloat calculateAlpha(\n float iterationCount, float reflectivity,\n vec2 hitPixel, vec3 hitPoint, float dist, vec3 rayDir\n)\n{\n float alpha = clamp(reflectivity, 0.0, 1.0);\n alpha *= 1.0 - (iterationCount / float(MAX_ITERATION));\n vec2 hitPixelNDC = hitPixel * 2.0 - 1.0;\n float maxDimension = min(1.0, max(abs(hitPixelNDC.x), abs(hitPixelNDC.y)));\n alpha *= 1.0 - max(0.0, maxDimension - screenEdgeFadeStart) / (1.0 - screenEdgeFadeStart);\n\n float _eyeFadeStart = eyeFadeStart;\n float _eyeFadeEnd = eyeFadeEnd;\n if (_eyeFadeStart > _eyeFadeEnd) {\n float tmp = _eyeFadeEnd;\n _eyeFadeEnd = _eyeFadeStart;\n _eyeFadeStart = tmp;\n }\n\n float eyeDir = clamp(rayDir.z, _eyeFadeStart, _eyeFadeEnd);\n alpha *= 1.0 - (eyeDir - _eyeFadeStart) / (_eyeFadeEnd - _eyeFadeStart);\n\n alpha *= 1.0 - clamp(dist / maxRayDistance, 0.0, 1.0);\n\n return alpha;\n}\n\n@import clay.util.rand\n\n@import clay.util.rgbm\n\nvoid main()\n{\n vec4 normalAndGloss = texture2D(gBufferTexture1, v_Texcoord);\n\n if (dot(normalAndGloss.rgb, vec3(1.0)) == 0.0) {\n discard;\n }\n\n float g = normalAndGloss.a;\n#if !defined(PHYSICALLY_CORRECT)\n if (g <= minGlossiness) {\n discard;\n }\n#endif\n\n float reflectivity = (g - minGlossiness) / (1.0 - minGlossiness);\n\n vec3 N = normalAndGloss.rgb * 2.0 - 1.0;\n N = normalize((viewInverseTranspose * vec4(N, 0.0)).xyz);\n\n vec4 projectedPos = vec4(v_Texcoord * 2.0 - 1.0, fetchDepth(gBufferTexture2, v_Texcoord), 1.0);\n vec4 pos = projectionInv * projectedPos;\n vec3 rayOrigin = pos.xyz / pos.w;\n vec3 V = -normalize(rayOrigin);\n\n float ndv = clamp(dot(N, V), 0.0, 1.0);\n float iterationCount;\n#ifdef PHYSICALLY_CORRECT\n vec4 color = vec4(vec3(0.0), 1.0);\n vec4 albedoMetalness = texture2D(gBufferTexture3, v_Texcoord);\n vec3 albedo = albedoMetalness.rgb;\n float m = albedoMetalness.a;\n vec3 diffuseColor = albedo * (1.0 - m);\n vec3 spec = mix(vec3(0.04), albedo, m);\n for (int i = 0; i < SAMPLE_PER_FRAME; i++) {\n vec3 H = importanceSampleNormalGGX(float(i) / float(SAMPLE_PER_FRAME), 1.0 - g, N);\n vec3 rayDir = normalize(reflect(-V, H));\n#else\n vec3 rayDir = normalize(reflect(-V, N));\n#endif\n vec2 hitPixel;\n vec3 hitPoint;\n\n vec2 uv2 = v_Texcoord * viewportSize;\n float jitter = rand(fract(v_Texcoord + jitterOffset));\n\n bool intersect = traceScreenSpaceRay(rayOrigin, rayDir, jitter, hitPixel, hitPoint, iterationCount);\n\n float dist = distance(rayOrigin, hitPoint);\n\n vec3 hitNormal = texture2D(gBufferTexture1, hitPixel).rgb * 2.0 - 1.0;\n hitNormal = normalize((viewInverseTranspose * vec4(hitNormal, 0.0)).xyz);\n#ifdef PHYSICALLY_CORRECT\n if (dot(hitNormal, rayDir) < 0.0 && intersect) {\n float ndl = clamp(dot(N, rayDir), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float vdh = clamp(dot(V, H), 0.0, 1.0);\n vec3 litTexel = decodeHDR(texture2D(sourceTexture, hitPixel)).rgb;\n float fade = pow(clamp(1.0 - dist / 200.0, 0.0, 1.0), 4.0);\n color.rgb += ndl * litTexel * fade * (\n F_Schlick(ndl, spec) * G_Smith(g, ndv, ndl) * vdh / (ndh * ndv + 0.001)\n );\n }\n }\n color.rgb /= 512.0;\n#else\n if (dot(hitNormal, rayDir) >= 0.0) {\n discard;\n }\n if (!intersect) {\n discard;\n }\n float alpha = calculateAlpha(iterationCount, reflectivity, hitPixel, hitPoint, dist, rayDir) * float(intersect);\n vec4 color = decodeHDR(texture2D(sourceTexture, hitPixel));\n color.rgb *= alpha;\n#endif\n\n gl_FragColor = encodeHDR(color);\n}\n@end\n\n@export ecgl.ssr.blur\n\nuniform sampler2D texture;\nuniform sampler2D gBufferTexture1;\nuniform sampler2D gBufferTexture2;\nuniform mat4 projection;\nuniform float depthRange : 0.05;\n\nvarying vec2 v_Texcoord;\n\nuniform vec2 textureSize;\nuniform float blurSize : 1.0;\n\n#ifdef BLEND\n #ifdef SSAOTEX_ENABLED\nuniform sampler2D ssaoTex;\n #endif\nuniform sampler2D sourceTexture;\n#endif\n\nfloat getLinearDepth(vec2 coord)\n{\n float depth = texture2D(gBufferTexture2, coord).r * 2.0 - 1.0;\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n}\n\n@import clay.util.rgbm\n\n\nvoid main()\n{\n @import clay.compositor.kernel.gaussian_9\n\n vec4 centerNTexel = texture2D(gBufferTexture1, v_Texcoord);\n float g = centerNTexel.a;\n float maxBlurSize = clamp(1.0 - g + 0.1, 0.0, 1.0) * blurSize;\n#ifdef VERTICAL\n vec2 off = vec2(0.0, blurSize / textureSize.y);\n#else\n vec2 off = vec2(blurSize / textureSize.x, 0.0);\n#endif\n\n vec2 coord = v_Texcoord;\n\n vec4 sum = vec4(0.0);\n float weightAll = 0.0;\n\n vec3 cN = centerNTexel.rgb * 2.0 - 1.0;\n float cD = getLinearDepth(v_Texcoord);\n for (int i = 0; i < 9; i++) {\n vec2 coord = clamp((float(i) - 4.0) * off + v_Texcoord, vec2(0.0), vec2(1.0));\n float w = gaussianKernel[i]\n * clamp(dot(cN, texture2D(gBufferTexture1, coord).rgb * 2.0 - 1.0), 0.0, 1.0);\n float d = getLinearDepth(coord);\n w *= (1.0 - smoothstep(abs(cD - d) / depthRange, 0.0, 1.0));\n\n weightAll += w;\n sum += decodeHDR(texture2D(texture, coord)) * w;\n }\n\n#ifdef BLEND\n float aoFactor = 1.0;\n #ifdef SSAOTEX_ENABLED\n aoFactor = texture2D(ssaoTex, v_Texcoord).r;\n #endif\n gl_FragColor = encodeHDR(\n sum / weightAll * aoFactor + decodeHDR(texture2D(sourceTexture, v_Texcoord))\n );\n#else\n gl_FragColor = encodeHDR(sum / weightAll);\n#endif\n}\n\n@end"); - - -/***/ }), -/* 123 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -// Based on https://bl.ocks.org/mbostock/19168c663618b707158 - -/* harmony default export */ __webpack_exports__["a"] = ([ -0.0, 0.0, --0.321585265978, -0.154972575841, -0.458126042375, 0.188473391593, -0.842080129861, 0.527766490688, -0.147304551086, -0.659453822776, --0.331943915203, -0.940619700594, -0.0479226680259, 0.54812163202, -0.701581552186, -0.709825561388, --0.295436780218, 0.940589268233, --0.901489676764, 0.237713156085, -0.973570876096, -0.109899459384, --0.866792314779, -0.451805525005, -0.330975007087, 0.800048655954, --0.344275183665, 0.381779221166, --0.386139432542, -0.437418421534, --0.576478634965, -0.0148463392551, -0.385798197415, -0.262426961053, --0.666302061145, 0.682427250835, --0.628010632582, -0.732836215494, -0.10163141741, -0.987658134403, -0.711995289051, -0.320024291314, -0.0296005138058, 0.950296523438, -0.0130612307608, -0.351024443122, --0.879596633704, -0.10478487883, -0.435712737232, 0.504254490347, -0.779203817497, 0.206477676721, -0.388264289969, -0.896736162545, --0.153106280781, -0.629203242522, --0.245517550697, 0.657969239148, -0.126830499058, 0.26862328493, --0.634888119007, -0.302301223431, -0.617074219636, 0.779817204925 -]); - -/***/ }), -/* 124 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__Texture2D__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__Material__ = __webpack_require__(10); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__FrameBuffer__ = __webpack_require__(11); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__Renderer__ = __webpack_require__(27); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__compositor_Pass__ = __webpack_require__(13); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__math_Matrix4__ = __webpack_require__(9); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__shader_source_deferred_gbuffer_glsl_js__ = __webpack_require__(64); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__shader_source_deferred_chunk_glsl_js__ = __webpack_require__(125); - - - - - - - - - - - - - -__WEBPACK_IMPORTED_MODULE_5__Shader__["a" /* default */].import(__WEBPACK_IMPORTED_MODULE_9__shader_source_deferred_gbuffer_glsl_js__["a" /* default */]); -__WEBPACK_IMPORTED_MODULE_5__Shader__["a" /* default */].import(__WEBPACK_IMPORTED_MODULE_10__shader_source_deferred_chunk_glsl_js__["a" /* default */]); - -function createFillCanvas(color) { - var canvas = document.createElement('canvas'); - canvas.width = canvas.height = 1; - var ctx = canvas.getContext('2d'); - ctx.fillStyle = color || '#000'; - ctx.fillRect(0, 0, 1, 1); - - return canvas; -} - -function attachTextureToSlot(renderer, program, symbol, texture, slot) { - var gl = renderer.gl; - program.setUniform(gl, '1i', symbol, slot); - - gl.activeTexture(gl.TEXTURE0 + slot); - // Maybe texture is not loaded yet; - if (texture.isRenderable()) { - texture.bind(renderer); - } - else { - // Bind texture to null - texture.unbind(renderer); - } -} - -// TODO Use globalShader insteadof globalMaterial? -function getBeforeRenderHook1 (gl, defaultNormalMap, defaultRoughnessMap) { - - var previousNormalMap; - var previousRougGlossMap; - var previousRenderable; - - return function (renderable, gBufferMat, prevMaterial) { - // Material not change - if (previousRenderable && previousRenderable.material === renderable.material) { - return; - } - - var standardMaterial = renderable.material; - var program = renderable.__program; - - var glossiness; - var roughGlossMap; - var useRoughnessWorkflow = standardMaterial.isDefined('fragment', 'USE_ROUGHNESS'); - var doubleSided = standardMaterial.isDefined('fragment', 'DOUBLE_SIDED'); - var roughGlossChannel; - if (useRoughnessWorkflow) { - glossiness = 1.0 - standardMaterial.get('roughness'); - roughGlossMap = standardMaterial.get('roughnessMap'); - roughGlossChannel = standardMaterial.getDefine('fragment', 'ROUGHNESS_CHANNEL'); - } - else { - glossiness = standardMaterial.get('glossiness'); - roughGlossMap = standardMaterial.get('glossinessMap'); - roughGlossChannel = standardMaterial.getDefine('fragment', 'GLOSSINESS_CHANNEL'); - } - var useRoughGlossMap = !!roughGlossMap; - - var normalMap = standardMaterial.get('normalMap') || defaultNormalMap; - var uvRepeat = standardMaterial.get('uvRepeat'); - var uvOffset = standardMaterial.get('uvOffset'); - - roughGlossMap = roughGlossMap || defaultRoughnessMap; - - if (prevMaterial !== gBufferMat) { - gBufferMat.set('glossiness', glossiness); - gBufferMat.set('normalMap', normalMap); - gBufferMat.set('roughGlossMap', roughGlossMap); - gBufferMat.set('useRoughGlossMap', +useRoughGlossMap); - gBufferMat.set('useRoughness', +useRoughnessWorkflow); - gBufferMat.set('doubleSided', +doubleSided); - gBufferMat.set('roughGlossChannel', +roughGlossChannel || 0); - gBufferMat.set('uvRepeat', uvRepeat); - gBufferMat.set('uvOffset', uvOffset); - } - else { - program.setUniform( - gl, '1f', 'glossiness', glossiness - ); - - if (previousNormalMap !== normalMap) { - attachTextureToSlot(this, program, 'normalMap', normalMap, 0); - } - if (previousRougGlossMap !== roughGlossMap) { - attachTextureToSlot(this, program, 'roughGlossMap', roughGlossMap, 1); - } - program.setUniform(gl, '1i', 'useRoughGlossMap', +useRoughGlossMap); - program.setUniform(gl, '1i', 'useRoughness', +useRoughnessWorkflow); - program.setUniform(gl, '1i', 'doubleSided', +doubleSided); - program.setUniform(gl, '1i', 'roughGlossChannel', +roughGlossChannel || 0); - if (uvRepeat != null) { - program.setUniform(gl, '2f', 'uvRepeat', uvRepeat); - } - if (uvOffset != null) { - program.setUniform(gl, '2f', 'uvOffset', uvOffset); - } - } - - previousNormalMap = normalMap; - previousRougGlossMap = roughGlossMap; - - previousRenderable = renderable; - }; -} - -function getBeforeRenderHook2(gl, defaultDiffuseMap, defaultMetalnessMap) { - var previousDiffuseMap; - var previousRenderable; - var previousMetalnessMap; - - return function (renderable, gBufferMat, prevMaterial) { - // Material not change - if (previousRenderable && previousRenderable.material === renderable.material) { - return; - } - - var program = renderable.__program; - var standardMaterial = renderable.material; - - var color = standardMaterial.get('color'); - var metalness = standardMaterial.get('metalness'); - - var diffuseMap = standardMaterial.get('diffuseMap'); - var metalnessMap = standardMaterial.get('metalnessMap'); - - var uvRepeat = standardMaterial.get('uvRepeat'); - var uvOffset = standardMaterial.get('uvOffset'); - - var useMetalnessMap = !!metalnessMap; - - diffuseMap = diffuseMap || defaultDiffuseMap; - metalnessMap = metalnessMap || defaultMetalnessMap; - - if (prevMaterial !== gBufferMat) { - gBufferMat.set('color', color); - gBufferMat.set('metalness', metalness); - gBufferMat.set('diffuseMap', diffuseMap); - gBufferMat.set('metalnessMap', metalnessMap); - gBufferMat.set('useMetalnessMap', +useMetalnessMap); - gBufferMat.set('uvRepeat', uvRepeat); - gBufferMat.set('uvOffset', uvOffset); - - gBufferMat.set('linear', +standardMaterial.linear); - } - else { - program.setUniform(gl, '1f', 'metalness', metalness); - - program.setUniform(gl, '3f', 'color', color); - if (previousDiffuseMap !== diffuseMap) { - attachTextureToSlot(this, program, 'diffuseMap', diffuseMap, 0); - } - if (previousMetalnessMap !== metalnessMap) { - attachTextureToSlot(this, program, 'metalnessMap', metalnessMap, 1); - } - program.setUniform(gl, '1i', 'useMetalnessMap', +useMetalnessMap); - program.setUniform(gl, '2f', 'uvRepeat', uvRepeat); - program.setUniform(gl, '2f', 'uvOffset', uvOffset); - - program.setUniform(gl, '1i', 'linear', +standardMaterial.linear); - } - - previousDiffuseMap = diffuseMap; - previousMetalnessMap = metalnessMap; - - previousRenderable = renderable; - }; -} - -/** - * GBuffer is provided for deferred rendering and SSAO, SSR pass. - * It will do two passes rendering to three target textures. See - * + {@link clay.deferred.GBuffer#getTargetTexture1} - * + {@link clay.deferred.GBuffer#getTargetTexture2} - * + {@link clay.deferred.GBuffer#getTargetTexture3} - * @constructor - * @alias clay.deferred.GBuffer - * @extends clay.core.Base - */ -var GBuffer = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend(function () { - - return { - - enableTargetTexture1: true, - - enableTargetTexture2: true, - - enableTargetTexture3: true, - - renderTransparent: false, - - _renderList: [], - // - R: normal.x - // - G: normal.y - // - B: normal.z - // - A: glossiness - _gBufferTex1: new __WEBPACK_IMPORTED_MODULE_1__Texture2D__["a" /* default */]({ - minFilter: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].NEAREST, - magFilter: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].NEAREST, - // PENDING - type: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].HALF_FLOAT - }), - - // - R: depth - _gBufferTex2: new __WEBPACK_IMPORTED_MODULE_1__Texture2D__["a" /* default */]({ - minFilter: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].NEAREST, - magFilter: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].NEAREST, - // format: Texture.DEPTH_COMPONENT, - // type: Texture.UNSIGNED_INT - - format: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].DEPTH_STENCIL, - type: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].UNSIGNED_INT_24_8_WEBGL - }), - - // - R: albedo.r - // - G: albedo.g - // - B: albedo.b - // - A: metalness - _gBufferTex3: new __WEBPACK_IMPORTED_MODULE_1__Texture2D__["a" /* default */]({ - minFilter: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].NEAREST, - magFilter: __WEBPACK_IMPORTED_MODULE_2__Texture__["a" /* default */].NEAREST - }), - - _defaultNormalMap: new __WEBPACK_IMPORTED_MODULE_1__Texture2D__["a" /* default */]({ - image: createFillCanvas('#000') - }), - _defaultRoughnessMap: new __WEBPACK_IMPORTED_MODULE_1__Texture2D__["a" /* default */]({ - image: createFillCanvas('#fff') - }), - _defaultMetalnessMap: new __WEBPACK_IMPORTED_MODULE_1__Texture2D__["a" /* default */]({ - image: createFillCanvas('#fff') - }), - _defaultDiffuseMap: new __WEBPACK_IMPORTED_MODULE_1__Texture2D__["a" /* default */]({ - image: createFillCanvas('#fff') - }), - - _frameBuffer: new __WEBPACK_IMPORTED_MODULE_4__FrameBuffer__["a" /* default */](), - - _gBufferMaterial1: new __WEBPACK_IMPORTED_MODULE_3__Material__["a" /* default */]({ - shader: new __WEBPACK_IMPORTED_MODULE_5__Shader__["a" /* default */]( - __WEBPACK_IMPORTED_MODULE_5__Shader__["a" /* default */].source('clay.deferred.gbuffer.vertex'), - __WEBPACK_IMPORTED_MODULE_5__Shader__["a" /* default */].source('clay.deferred.gbuffer1.fragment') - ), - vertexDefines: { - FIRST_PASS: null - }, - fragmentDefines: { - FIRST_PASS: null - } - }), - _gBufferMaterial2: new __WEBPACK_IMPORTED_MODULE_3__Material__["a" /* default */]({ - shader: new __WEBPACK_IMPORTED_MODULE_5__Shader__["a" /* default */]( - __WEBPACK_IMPORTED_MODULE_5__Shader__["a" /* default */].source('clay.deferred.gbuffer.vertex'), - __WEBPACK_IMPORTED_MODULE_5__Shader__["a" /* default */].source('clay.deferred.gbuffer2.fragment') - ) - }), - - _debugPass: new __WEBPACK_IMPORTED_MODULE_7__compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_5__Shader__["a" /* default */].source('clay.deferred.gbuffer.debug') - }) - }; -}, /** @lends clay.deferred.GBuffer# */{ - - /** - * Set G Buffer size. - * @param {number} width - * @param {number} height - */ - resize: function (width, height) { - if (this._gBufferTex1.width === width - && this._gBufferTex1.height === height - ) { - return; - } - this._gBufferTex1.width = width; - this._gBufferTex1.height = height; - - this._gBufferTex2.width = width; - this._gBufferTex2.height = height; - - this._gBufferTex3.width = width; - this._gBufferTex3.height = height; - }, - - // TODO is dpr needed? - setViewport: function (x, y, width, height, dpr) { - var viewport; - if (typeof x === 'object') { - viewport = x; - } - else { - viewport = { - x: x, y: y, - width: width, height: height, - devicePixelRatio: dpr || 1 - }; - } - this._frameBuffer.viewport = viewport; - }, - - getViewport: function () { - if (this._frameBuffer.viewport) { - return this._frameBuffer.viewport; - } - else { - return { - x: 0, y: 0, - width: this._gBufferTex1.width, - height: this._gBufferTex1.height, - devicePixelRatio: 1 - }; - } - }, - - /** - * Update G Buffer - * @param {clay.Renderer} renderer - * @param {clay.Scene} scene - * @param {clay.camera.Perspective} camera - */ - update: function (renderer, scene, camera) { - - var gl = renderer.gl; - - var frameBuffer = this._frameBuffer; - var viewport = frameBuffer.viewport; - var opaqueList = scene.opaqueList; - var transparentList = scene.transparentList; - - var offset = 0; - var renderList = this._renderList; - for (var i = 0; i < opaqueList.length; i++) { - if (!opaqueList[i].ignoreGBuffer) { - renderList[offset++] = opaqueList[i]; - } - } - if (this.renderTransparent) { - for (var i = 0; i < transparentList.length; i++) { - if (!transparentList[i].ignoreGBuffer) { - renderList[offset++] = transparentList[i]; - } - } - } - renderList.length = offset; - - gl.clearColor(0, 0, 0, 0); - gl.depthMask(true); - gl.colorMask(true, true, true, true); - gl.disable(gl.BLEND); - - var enableTargetTexture1 = this.enableTargetTexture1; - var enableTargetTexture2 = this.enableTargetTexture2; - var enableTargetTexture3 = this.enableTargetTexture3; - if (!enableTargetTexture1 && !enableTargetTexture3) { - console.warn('Can\'t disable targetTexture1 targetTexture3 both'); - enableTargetTexture1 = true; - } - - if (enableTargetTexture2) { - frameBuffer.attach(this._gBufferTex2, renderer.gl.DEPTH_STENCIL_ATTACHMENT); - } - - // PENDING, scene.boundingBoxLastFrame needs be updated if have shadow - renderer.bindSceneRendering(scene); - if (enableTargetTexture1) { - // Pass 1 - frameBuffer.attach(this._gBufferTex1); - frameBuffer.bind(renderer); - - if (viewport) { - var dpr = viewport.devicePixelRatio; - // use scissor to make sure only clear the viewport - gl.enable(gl.SCISSOR_TEST); - gl.scissor(viewport.x * dpr, viewport.y * dpr, viewport.width * dpr, viewport.height * dpr); - } - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - if (viewport) { - gl.disable(gl.SCISSOR_TEST); - } - var gBufferMaterial1 = this._gBufferMaterial1; - var passConfig = { - getMaterial: function () { - return gBufferMaterial1; - }, - beforeRender: getBeforeRenderHook1(gl, this._defaultNormalMap, this._defaultRoughnessMap), - sortCompare: renderer.opaqueSortCompare - }; - // FIXME Use MRT if possible - renderer.renderPass(renderList, camera, passConfig); - - } - if (enableTargetTexture3) { - - // Pass 2 - frameBuffer.attach(this._gBufferTex3); - frameBuffer.bind(renderer); - - if (viewport) { - var dpr = viewport.devicePixelRatio; - // use scissor to make sure only clear the viewport - gl.enable(gl.SCISSOR_TEST); - gl.scissor(viewport.x * dpr, viewport.y * dpr, viewport.width * dpr, viewport.height * dpr); - } - gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); - if (viewport) { - gl.disable(gl.SCISSOR_TEST); - } - - var gBufferMaterial2 = this._gBufferMaterial2; - var passConfig = { - getMaterial: function () { - return gBufferMaterial2; - }, - beforeRender: getBeforeRenderHook2(gl, this._defaultDiffuseMap, this._defaultMetalnessMap), - sortCompare: renderer.opaqueSortCompare - }; - renderer.renderPass(renderList, camera, passConfig); - } - - renderer.bindSceneRendering(null); - frameBuffer.unbind(renderer); - }, - - renderDebug: function (renderer, camera, type, viewport) { - var debugTypes = { - normal: 0, - depth: 1, - position: 2, - glossiness: 3, - metalness: 4, - albedo: 5 - }; - if (debugTypes[type] == null) { - console.warn('Unkown type "' + type + '"'); - // Default use normal - type = 'normal'; - } - - renderer.saveClear(); - renderer.saveViewport(); - renderer.clearBit = renderer.gl.DEPTH_BUFFER_BIT; - - if (viewport) { - renderer.setViewport(viewport); - } - var viewProjectionInv = new __WEBPACK_IMPORTED_MODULE_8__math_Matrix4__["a" /* default */](); - __WEBPACK_IMPORTED_MODULE_8__math_Matrix4__["a" /* default */].multiply(viewProjectionInv, camera.worldTransform, camera.invProjectionMatrix); - - var debugPass = this._debugPass; - debugPass.setUniform('viewportSize', [renderer.getWidth(), renderer.getHeight()]); - debugPass.setUniform('gBufferTexture1', this._gBufferTex1); - debugPass.setUniform('gBufferTexture2', this._gBufferTex2); - debugPass.setUniform('gBufferTexture3', this._gBufferTex3); - debugPass.setUniform('debug', debugTypes[type]); - debugPass.setUniform('viewProjectionInv', viewProjectionInv.array); - debugPass.render(renderer); - - renderer.restoreViewport(); - renderer.restoreClear(); - }, - - /** - * Get first target texture. - * Channel storage: - * + R: normal.x * 0.5 + 0.5 - * + G: normal.y * 0.5 + 0.5 - * + B: normal.z * 0.5 + 0.5 - * + A: glossiness - * @return {clay.Texture2D} - */ - getTargetTexture1: function () { - return this._gBufferTex1; - }, - - /** - * Get second target texture. - * Channel storage: - * + R: depth - * @return {clay.Texture2D} - */ - getTargetTexture2: function () { - return this._gBufferTex2; - }, - - /** - * Get third target texture. - * Channel storage: - * + R: albedo.r - * + G: albedo.g - * + B: albedo.b - * + A: metalness - * @return {clay.Texture2D} - */ - getTargetTexture3: function () { - return this._gBufferTex3; - }, - - - /** - * @param {clay.Renderer} renderer - */ - dispose: function (renderer) { - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (GBuffer); - -/***/ }), -/* 125 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export clay.deferred.chunk.light_head\nuniform sampler2D gBufferTexture1;\nuniform sampler2D gBufferTexture2;\nuniform sampler2D gBufferTexture3;\nuniform vec2 windowSize: WINDOW_SIZE;\nuniform vec4 viewport: VIEWPORT;\nuniform mat4 viewProjectionInv;\n#ifdef DEPTH_ENCODED\n@import clay.util.decode_float\n#endif\n@end\n@export clay.deferred.chunk.gbuffer_read\n vec2 uv = gl_FragCoord.xy / windowSize;\n vec2 uv2 = (gl_FragCoord.xy - viewport.xy) / viewport.zw;\n vec4 texel1 = texture2D(gBufferTexture1, uv);\n vec4 texel3 = texture2D(gBufferTexture3, uv);\n if (dot(texel1.rgb, vec3(1.0)) == 0.0) {\n discard;\n }\n float glossiness = texel1.a;\n float metalness = texel3.a;\n vec3 N = texel1.rgb * 2.0 - 1.0;\n float z = texture2D(gBufferTexture2, uv).r * 2.0 - 1.0;\n vec2 xy = uv2 * 2.0 - 1.0;\n vec4 projectedPos = vec4(xy, z, 1.0);\n vec4 p4 = viewProjectionInv * projectedPos;\n vec3 position = p4.xyz / p4.w;\n vec3 albedo = texel3.rgb;\n vec3 diffuseColor = albedo * (1.0 - metalness);\n vec3 specularColor = mix(vec3(0.04), albedo, metalness);\n@end\n@export clay.deferred.chunk.light_equation\nfloat D_Phong(in float g, in float ndh) {\n float a = pow(8192.0, g);\n return (a + 2.0) / 8.0 * pow(ndh, a);\n}\nfloat D_GGX(in float g, in float ndh) {\n float r = 1.0 - g;\n float a = r * r;\n float tmp = ndh * ndh * (a - 1.0) + 1.0;\n return a / (3.1415926 * tmp * tmp);\n}\nvec3 F_Schlick(in float ndv, vec3 spec) {\n return spec + (1.0 - spec) * pow(1.0 - ndv, 5.0);\n}\nvec3 lightEquation(\n in vec3 lightColor, in vec3 diffuseColor, in vec3 specularColor,\n in float ndl, in float ndh, in float ndv, in float g\n)\n{\n return ndl * lightColor\n * (diffuseColor + D_Phong(g, ndh) * F_Schlick(ndv, specularColor));\n}\n@end"); - - -/***/ }), -/* 126 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Light__ = __webpack_require__(14); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__util_cubemap__ = __webpack_require__(63); -// https://docs.unrealengine.com/latest/INT/Engine/Rendering/LightingAndShadows/AmbientCubemap/ - - - -/** - * Ambient cubemap light provides specular parts of Image Based Lighting. - * Which is a basic requirement for Physically Based Rendering - * @constructor clay.light.AmbientCubemap - * @extends clay.Light - */ -var AmbientCubemapLight = __WEBPACK_IMPORTED_MODULE_0__Light__["a" /* default */].extend({ - - /** - * @type {clay.TextureCube} - * @memberOf clay.light.AmbientCubemap# - */ - cubemap: null, - - // TODO - // range: 100, - - castShadow: false, - - _normalDistribution: null, - _brdfLookup: null - -}, /** @lends clay.light.AmbientCubemap# */ { - - type: 'AMBIENT_CUBEMAP_LIGHT', - - /** - * Do prefitering the cubemap - * @param {clay.Renderer} renderer - * @param {number} [size=32] - */ - prefilter: function (renderer, size) { - if (!this._brdfLookup) { - this._normalDistribution = __WEBPACK_IMPORTED_MODULE_1__util_cubemap__["a" /* default */].generateNormalDistribution(); - this._brdfLookup = __WEBPACK_IMPORTED_MODULE_1__util_cubemap__["a" /* default */].integrateBRDF(renderer, this._normalDistribution); - } - var cubemap = this.cubemap; - if (cubemap.__prefiltered) { - return; - } - - var result = __WEBPACK_IMPORTED_MODULE_1__util_cubemap__["a" /* default */].prefilterEnvironmentMap( - renderer, cubemap, { - encodeRGBM: true, - width: size, - height: size - }, this._normalDistribution, this._brdfLookup - ); - this.cubemap = result.environmentMap; - this.cubemap.__prefiltered = true; - - cubemap.dispose(renderer); - }, - - uniformTemplates: { - ambientCubemapLightColor: { - type: '3f', - value: function (instance) { - var color = instance.color; - var intensity = instance.intensity; - return [color[0]*intensity, color[1]*intensity, color[2]*intensity]; - } - }, - - ambientCubemapLightCubemap: { - type: 't', - value: function (instance) { - return instance.cubemap; - } - }, - - ambientCubemapLightBRDFLookup: { - type: 't', - value: function (instance) { - return instance._brdfLookup; - } - } - } - /** - * @function - * @name clone - * @return {clay.light.AmbientCubemap} - * @memberOf clay.light.AmbientCubemap.prototype - */ -}); - -/* harmony default export */ __webpack_exports__["a"] = (AmbientCubemapLight); - - -/***/ }), -/* 127 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Light__ = __webpack_require__(14); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__core_vendor__ = __webpack_require__(12); - - - -/** - * Spherical Harmonic Ambient Light - * @constructor clay.light.AmbientSH - * @extends clay.Light - */ -var AmbientSHLight = __WEBPACK_IMPORTED_MODULE_0__Light__["a" /* default */].extend({ - - castShadow: false, - - /** - * Spherical Harmonic Coefficients - * @type {Array.} - * @memberOf clay.light.AmbientSH# - */ - coefficients: [], - -}, function () { - this._coefficientsTmpArr = new __WEBPACK_IMPORTED_MODULE_1__core_vendor__["a" /* default */].Float32Array(9 * 3); -}, { - - type: 'AMBIENT_SH_LIGHT', - - uniformTemplates: { - ambientSHLightColor: { - type: '3f', - value: function (instance) { - var color = instance.color; - var intensity = instance.intensity; - return [color[0] * intensity, color[1] * intensity, color[2] * intensity]; - } - }, - - ambientSHLightCoefficients: { - type: '3f', - value: function (instance) { - var coefficientsTmpArr = instance._coefficientsTmpArr; - for (var i = 0; i < instance.coefficients.length; i++) { - coefficientsTmpArr[i] = instance.coefficients[i]; - } - return coefficientsTmpArr; - } - } - } - /** - * @function - * @name clone - * @return {clay.light.Ambient} - * @memberOf clay.light.Ambient.prototype - */ -}); - -/* harmony default export */ __webpack_exports__["a"] = (AmbientSHLight); - - -/***/ }), -/* 128 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__FrameBuffer__ = __webpack_require__(11); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__Texture2D__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__compositor_Pass__ = __webpack_require__(13); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__core_vendor__ = __webpack_require__(12); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__plugin_Skybox__ = __webpack_require__(37); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__plugin_Skydome__ = __webpack_require__(36); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__prePass_EnvironmentMap__ = __webpack_require__(35); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__Scene__ = __webpack_require__(18); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_9__dep_glmatrix__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_10__shader_projectEnvMap_glsl_js__ = __webpack_require__(129); -// Spherical Harmonic Helpers - - - - - - - - - - -var vec3 = __WEBPACK_IMPORTED_MODULE_9__dep_glmatrix___default.a.vec3; -var sh = {}; - - - -var targets = ['px', 'nx', 'py', 'ny', 'pz', 'nz']; - -// Project on gpu, but needs browser to support readPixels as Float32Array. -function projectEnvironmentMapGPU(renderer, envMap) { - var shTexture = new __WEBPACK_IMPORTED_MODULE_2__Texture2D__["a" /* default */]({ - width: 9, - height: 1, - type: __WEBPACK_IMPORTED_MODULE_0__Texture__["a" /* default */].FLOAT - }); - var pass = new __WEBPACK_IMPORTED_MODULE_3__compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_10__shader_projectEnvMap_glsl_js__["a" /* default */] - }); - pass.material.define('fragment', 'TEXTURE_SIZE', envMap.width); - pass.setUniform('environmentMap', envMap); - - var framebuffer = new __WEBPACK_IMPORTED_MODULE_1__FrameBuffer__["a" /* default */](); - framebuffer.attach(shTexture); - pass.render(renderer, framebuffer); - - framebuffer.bind(renderer); - // TODO Only chrome and firefox support Float32Array - var pixels = new __WEBPACK_IMPORTED_MODULE_4__core_vendor__["a" /* default */].Float32Array(9 * 4); - renderer.gl.readPixels(0, 0, 9, 1, __WEBPACK_IMPORTED_MODULE_0__Texture__["a" /* default */].RGBA, __WEBPACK_IMPORTED_MODULE_0__Texture__["a" /* default */].FLOAT, pixels); - - var coeff = new __WEBPACK_IMPORTED_MODULE_4__core_vendor__["a" /* default */].Float32Array(9 * 3); - for (var i = 0; i < 9; i++) { - coeff[i * 3] = pixels[i * 4]; - coeff[i * 3 + 1] = pixels[i * 4 + 1]; - coeff[i * 3 + 2] = pixels[i * 4 + 2]; - } - framebuffer.unbind(renderer); - - framebuffer.dispose(renderer); - pass.dispose(renderer); - return coeff; -} - -function harmonics(normal, index){ - var x = normal[0]; - var y = normal[1]; - var z = normal[2]; - - if (index === 0) { - return 1.0; - } - else if (index === 1) { - return x; - } - else if (index === 2) { - return y; - } - else if (index === 3) { - return z; - } - else if (index === 4) { - return x * z; - } - else if (index === 5) { - return y * z; - } - else if (index === 6) { - return x * y; - } - else if (index === 7) { - return 3.0 * z * z - 1.0; - } - else { - return x * x - y * y; - } -} - -var normalTransform = { - px: [2, 1, 0, -1, -1, 1], - nx: [2, 1, 0, 1, -1, -1], - py: [0, 2, 1, 1, -1, -1], - ny: [0, 2, 1, 1, 1, 1], - pz: [0, 1, 2, -1, -1, -1], - nz: [0, 1, 2, 1, -1, 1] -}; - -// Project on cpu. -function projectEnvironmentMapCPU(renderer, cubePixels, width, height) { - var coeff = new __WEBPACK_IMPORTED_MODULE_4__core_vendor__["a" /* default */].Float32Array(9 * 3); - var normal = vec3.create(); - var texel = vec3.create(); - var fetchNormal = vec3.create(); - for (var m = 0; m < 9; m++) { - var result = vec3.create(); - for (var k = 0; k < targets.length; k++) { - var pixels = cubePixels[targets[k]]; - - var sideResult = vec3.create(); - var divider = 0; - var i = 0; - var transform = normalTransform[targets[k]]; - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - - normal[0] = x / (width - 1.0) * 2.0 - 1.0; - // TODO Flip y? - normal[1] = y / (height - 1.0) * 2.0 - 1.0; - normal[2] = -1.0; - vec3.normalize(normal, normal); - - fetchNormal[0] = normal[transform[0]] * transform[3]; - fetchNormal[1] = normal[transform[1]] * transform[4]; - fetchNormal[2] = normal[transform[2]] * transform[5]; - - texel[0] = pixels[i++] / 255; - texel[1] = pixels[i++] / 255; - texel[2] = pixels[i++] / 255; - // RGBM Decode - var scale = pixels[i++] / 255 * 51.5; - texel[0] *= scale; - texel[1] *= scale; - texel[2] *= scale; - - vec3.scaleAndAdd(sideResult, sideResult, texel, harmonics(fetchNormal, m) * -normal[2]); - // -normal.z equals cos(theta) of Lambertian - divider += -normal[2]; - } - } - vec3.scaleAndAdd(result, result, sideResult, 1 / divider); - } - - coeff[m * 3] = result[0] / 6.0; - coeff[m * 3 + 1] = result[1] / 6.0; - coeff[m * 3 + 2] = result[2] / 6.0; - } - return coeff; -} - -/** - * @param {clay.Renderer} renderer - * @param {clay.Texture} envMap - * @param {Object} [textureOpts] - * @param {Object} [textureOpts.lod] - * @param {boolean} [textureOpts.decodeRGBM] - */ -sh.projectEnvironmentMap = function (renderer, envMap, opts) { - - // TODO sRGB - - opts = opts || {}; - opts.lod = opts.lod || 0; - - var skybox; - var dummyScene = new __WEBPACK_IMPORTED_MODULE_8__Scene__["a" /* default */](); - var size = 64; - if (envMap instanceof __WEBPACK_IMPORTED_MODULE_2__Texture2D__["a" /* default */]) { - skybox = new __WEBPACK_IMPORTED_MODULE_6__plugin_Skydome__["a" /* default */]({ - scene: dummyScene, - environmentMap: envMap - }); - } - else { - size = (envMap.image && envMap.image.px) ? envMap.image.px.width : envMap.width; - skybox = new __WEBPACK_IMPORTED_MODULE_5__plugin_Skybox__["a" /* default */]({ - scene: dummyScene, - environmentMap: envMap - }); - } - // Convert to rgbm - var width = Math.ceil(size / Math.pow(2, opts.lod)); - var height = Math.ceil(size / Math.pow(2, opts.lod)); - var rgbmTexture = new __WEBPACK_IMPORTED_MODULE_2__Texture2D__["a" /* default */]({ - width: width, - height: height - }); - var framebuffer = new __WEBPACK_IMPORTED_MODULE_1__FrameBuffer__["a" /* default */](); - skybox.material.define('fragment', 'RGBM_ENCODE'); - if (opts.decodeRGBM) { - skybox.material.define('fragment', 'RGBM_DECODE'); - } - skybox.material.set('lod', opts.lod); - var envMapPass = new __WEBPACK_IMPORTED_MODULE_7__prePass_EnvironmentMap__["a" /* default */]({ - texture: rgbmTexture - }); - var cubePixels = {}; - for (var i = 0; i < targets.length; i++) { - cubePixels[targets[i]] = new Uint8Array(width * height * 4); - var camera = envMapPass.getCamera(targets[i]); - camera.fov = 90; - framebuffer.attach(rgbmTexture); - framebuffer.bind(renderer); - renderer.render(dummyScene, camera); - renderer.gl.readPixels( - 0, 0, width, height, - __WEBPACK_IMPORTED_MODULE_0__Texture__["a" /* default */].RGBA, __WEBPACK_IMPORTED_MODULE_0__Texture__["a" /* default */].UNSIGNED_BYTE, cubePixels[targets[i]] - ); - framebuffer.unbind(renderer); - } - - skybox.dispose(renderer); - framebuffer.dispose(renderer); - rgbmTexture.dispose(renderer); - - return projectEnvironmentMapCPU(renderer, cubePixels, width, height); -}; - -/* harmony default export */ __webpack_exports__["a"] = (sh); - - -/***/ }), -/* 129 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("uniform samplerCube environmentMap;\nvarying vec2 v_Texcoord;\n#define TEXTURE_SIZE 16\nmat3 front = mat3(\n 1.0, 0.0, 0.0,\n 0.0, 1.0, 0.0,\n 0.0, 0.0, 1.0\n);\nmat3 back = mat3(\n -1.0, 0.0, 0.0,\n 0.0, 1.0, 0.0,\n 0.0, 0.0, -1.0\n);\nmat3 left = mat3(\n 0.0, 0.0, -1.0,\n 0.0, 1.0, 0.0,\n 1.0, 0.0, 0.0\n);\nmat3 right = mat3(\n 0.0, 0.0, 1.0,\n 0.0, 1.0, 0.0,\n -1.0, 0.0, 0.0\n);\nmat3 up = mat3(\n 1.0, 0.0, 0.0,\n 0.0, 0.0, 1.0,\n 0.0, -1.0, 0.0\n);\nmat3 down = mat3(\n 1.0, 0.0, 0.0,\n 0.0, 0.0, -1.0,\n 0.0, 1.0, 0.0\n);\nfloat harmonics(vec3 normal){\n int index = int(gl_FragCoord.x);\n float x = normal.x;\n float y = normal.y;\n float z = normal.z;\n if(index==0){\n return 1.0;\n }\n else if(index==1){\n return x;\n }\n else if(index==2){\n return y;\n }\n else if(index==3){\n return z;\n }\n else if(index==4){\n return x*z;\n }\n else if(index==5){\n return y*z;\n }\n else if(index==6){\n return x*y;\n }\n else if(index==7){\n return 3.0*z*z - 1.0;\n }\n else{\n return x*x - y*y;\n }\n}\nvec3 sampleSide(mat3 rot)\n{\n vec3 result = vec3(0.0);\n float divider = 0.0;\n for (int i = 0; i < TEXTURE_SIZE * TEXTURE_SIZE; i++) {\n float x = mod(float(i), float(TEXTURE_SIZE));\n float y = float(i / TEXTURE_SIZE);\n vec2 sidecoord = ((vec2(x, y) + vec2(0.5, 0.5)) / vec2(TEXTURE_SIZE)) * 2.0 - 1.0;\n vec3 normal = normalize(vec3(sidecoord, -1.0));\n vec3 fetchNormal = rot * normal;\n vec3 texel = textureCube(environmentMap, fetchNormal).rgb;\n result += harmonics(fetchNormal) * texel * -normal.z;\n divider += -normal.z;\n }\n return result / divider;\n}\nvoid main()\n{\n vec3 result = (\n sampleSide(front) +\n sampleSide(back) +\n sampleSide(left) +\n sampleSide(right) +\n sampleSide(up) +\n sampleSide(down)\n ) / 6.0;\n gl_FragColor = vec4(result, 1.0);\n}"); - - -/***/ }), -/* 130 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["a"] = parse; -/* unused harmony export lift */ -/* unused harmony export toHex */ -/* unused harmony export fastLerp */ -/* unused harmony export fastMapToColor */ -/* unused harmony export lerp */ -/* unused harmony export mapToColor */ -/* unused harmony export modifyHSL */ -/* unused harmony export modifyAlpha */ -/* harmony export (immutable) */ __webpack_exports__["b"] = stringify; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_LRU__ = __webpack_require__(65); - - -var kCSSColorTable = { - 'transparent': [0,0,0,0], 'aliceblue': [240,248,255,1], - 'antiquewhite': [250,235,215,1], 'aqua': [0,255,255,1], - 'aquamarine': [127,255,212,1], 'azure': [240,255,255,1], - 'beige': [245,245,220,1], 'bisque': [255,228,196,1], - 'black': [0,0,0,1], 'blanchedalmond': [255,235,205,1], - 'blue': [0,0,255,1], 'blueviolet': [138,43,226,1], - 'brown': [165,42,42,1], 'burlywood': [222,184,135,1], - 'cadetblue': [95,158,160,1], 'chartreuse': [127,255,0,1], - 'chocolate': [210,105,30,1], 'coral': [255,127,80,1], - 'cornflowerblue': [100,149,237,1], 'cornsilk': [255,248,220,1], - 'crimson': [220,20,60,1], 'cyan': [0,255,255,1], - 'darkblue': [0,0,139,1], 'darkcyan': [0,139,139,1], - 'darkgoldenrod': [184,134,11,1], 'darkgray': [169,169,169,1], - 'darkgreen': [0,100,0,1], 'darkgrey': [169,169,169,1], - 'darkkhaki': [189,183,107,1], 'darkmagenta': [139,0,139,1], - 'darkolivegreen': [85,107,47,1], 'darkorange': [255,140,0,1], - 'darkorchid': [153,50,204,1], 'darkred': [139,0,0,1], - 'darksalmon': [233,150,122,1], 'darkseagreen': [143,188,143,1], - 'darkslateblue': [72,61,139,1], 'darkslategray': [47,79,79,1], - 'darkslategrey': [47,79,79,1], 'darkturquoise': [0,206,209,1], - 'darkviolet': [148,0,211,1], 'deeppink': [255,20,147,1], - 'deepskyblue': [0,191,255,1], 'dimgray': [105,105,105,1], - 'dimgrey': [105,105,105,1], 'dodgerblue': [30,144,255,1], - 'firebrick': [178,34,34,1], 'floralwhite': [255,250,240,1], - 'forestgreen': [34,139,34,1], 'fuchsia': [255,0,255,1], - 'gainsboro': [220,220,220,1], 'ghostwhite': [248,248,255,1], - 'gold': [255,215,0,1], 'goldenrod': [218,165,32,1], - 'gray': [128,128,128,1], 'green': [0,128,0,1], - 'greenyellow': [173,255,47,1], 'grey': [128,128,128,1], - 'honeydew': [240,255,240,1], 'hotpink': [255,105,180,1], - 'indianred': [205,92,92,1], 'indigo': [75,0,130,1], - 'ivory': [255,255,240,1], 'khaki': [240,230,140,1], - 'lavender': [230,230,250,1], 'lavenderblush': [255,240,245,1], - 'lawngreen': [124,252,0,1], 'lemonchiffon': [255,250,205,1], - 'lightblue': [173,216,230,1], 'lightcoral': [240,128,128,1], - 'lightcyan': [224,255,255,1], 'lightgoldenrodyellow': [250,250,210,1], - 'lightgray': [211,211,211,1], 'lightgreen': [144,238,144,1], - 'lightgrey': [211,211,211,1], 'lightpink': [255,182,193,1], - 'lightsalmon': [255,160,122,1], 'lightseagreen': [32,178,170,1], - 'lightskyblue': [135,206,250,1], 'lightslategray': [119,136,153,1], - 'lightslategrey': [119,136,153,1], 'lightsteelblue': [176,196,222,1], - 'lightyellow': [255,255,224,1], 'lime': [0,255,0,1], - 'limegreen': [50,205,50,1], 'linen': [250,240,230,1], - 'magenta': [255,0,255,1], 'maroon': [128,0,0,1], - 'mediumaquamarine': [102,205,170,1], 'mediumblue': [0,0,205,1], - 'mediumorchid': [186,85,211,1], 'mediumpurple': [147,112,219,1], - 'mediumseagreen': [60,179,113,1], 'mediumslateblue': [123,104,238,1], - 'mediumspringgreen': [0,250,154,1], 'mediumturquoise': [72,209,204,1], - 'mediumvioletred': [199,21,133,1], 'midnightblue': [25,25,112,1], - 'mintcream': [245,255,250,1], 'mistyrose': [255,228,225,1], - 'moccasin': [255,228,181,1], 'navajowhite': [255,222,173,1], - 'navy': [0,0,128,1], 'oldlace': [253,245,230,1], - 'olive': [128,128,0,1], 'olivedrab': [107,142,35,1], - 'orange': [255,165,0,1], 'orangered': [255,69,0,1], - 'orchid': [218,112,214,1], 'palegoldenrod': [238,232,170,1], - 'palegreen': [152,251,152,1], 'paleturquoise': [175,238,238,1], - 'palevioletred': [219,112,147,1], 'papayawhip': [255,239,213,1], - 'peachpuff': [255,218,185,1], 'peru': [205,133,63,1], - 'pink': [255,192,203,1], 'plum': [221,160,221,1], - 'powderblue': [176,224,230,1], 'purple': [128,0,128,1], - 'red': [255,0,0,1], 'rosybrown': [188,143,143,1], - 'royalblue': [65,105,225,1], 'saddlebrown': [139,69,19,1], - 'salmon': [250,128,114,1], 'sandybrown': [244,164,96,1], - 'seagreen': [46,139,87,1], 'seashell': [255,245,238,1], - 'sienna': [160,82,45,1], 'silver': [192,192,192,1], - 'skyblue': [135,206,235,1], 'slateblue': [106,90,205,1], - 'slategray': [112,128,144,1], 'slategrey': [112,128,144,1], - 'snow': [255,250,250,1], 'springgreen': [0,255,127,1], - 'steelblue': [70,130,180,1], 'tan': [210,180,140,1], - 'teal': [0,128,128,1], 'thistle': [216,191,216,1], - 'tomato': [255,99,71,1], 'turquoise': [64,224,208,1], - 'violet': [238,130,238,1], 'wheat': [245,222,179,1], - 'white': [255,255,255,1], 'whitesmoke': [245,245,245,1], - 'yellow': [255,255,0,1], 'yellowgreen': [154,205,50,1] -}; - -function clampCssByte(i) { // Clamp to integer 0 .. 255. - i = Math.round(i); // Seems to be what Chrome does (vs truncation). - return i < 0 ? 0 : i > 255 ? 255 : i; -} - -function clampCssAngle(i) { // Clamp to integer 0 .. 360. - i = Math.round(i); // Seems to be what Chrome does (vs truncation). - return i < 0 ? 0 : i > 360 ? 360 : i; -} - -function clampCssFloat(f) { // Clamp to float 0.0 .. 1.0. - return f < 0 ? 0 : f > 1 ? 1 : f; -} - -function parseCssInt(str) { // int or percentage. - if (str.length && str.charAt(str.length - 1) === '%') { - return clampCssByte(parseFloat(str) / 100 * 255); - } - return clampCssByte(parseInt(str, 10)); -} - -function parseCssFloat(str) { // float or percentage. - if (str.length && str.charAt(str.length - 1) === '%') { - return clampCssFloat(parseFloat(str) / 100); - } - return clampCssFloat(parseFloat(str)); -} - -function cssHueToRgb(m1, m2, h) { - if (h < 0) { - h += 1; - } - else if (h > 1) { - h -= 1; - } - - if (h * 6 < 1) { - return m1 + (m2 - m1) * h * 6; - } - if (h * 2 < 1) { - return m2; - } - if (h * 3 < 2) { - return m1 + (m2 - m1) * (2/3 - h) * 6; - } - return m1; -} - -function lerpNumber(a, b, p) { - return a + (b - a) * p; -} - -function setRgba(out, r, g, b, a) { - out[0] = r; out[1] = g; out[2] = b; out[3] = a; - return out; -} -function copyRgba(out, a) { - out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; - return out; -} - -var colorCache = new __WEBPACK_IMPORTED_MODULE_0__core_LRU__["a" /* default */](20); -var lastRemovedArr = null; - -function putToCache(colorStr, rgbaArr) { - // Reuse removed array - if (lastRemovedArr) { - copyRgba(lastRemovedArr, rgbaArr); - } - lastRemovedArr = colorCache.put(colorStr, lastRemovedArr || (rgbaArr.slice())); -} - -/** - * @param {string} colorStr - * @param {Array.} out - * @return {Array.} - * @memberOf module:zrender/util/color - */ -function parse(colorStr, rgbaArr) { - if (!colorStr) { - return; - } - rgbaArr = rgbaArr || []; - - var cached = colorCache.get(colorStr); - if (cached) { - return copyRgba(rgbaArr, cached); - } - - // colorStr may be not string - colorStr = colorStr + ''; - // Remove all whitespace, not compliant, but should just be more accepting. - var str = colorStr.replace(/ /g, '').toLowerCase(); - - // Color keywords (and transparent) lookup. - if (str in kCSSColorTable) { - copyRgba(rgbaArr, kCSSColorTable[str]); - putToCache(colorStr, rgbaArr); - return rgbaArr; - } - - // #abc and #abc123 syntax. - if (str.charAt(0) === '#') { - if (str.length === 4) { - var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. - if (!(iv >= 0 && iv <= 0xfff)) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; // Covers NaN. - } - setRgba(rgbaArr, - ((iv & 0xf00) >> 4) | ((iv & 0xf00) >> 8), - (iv & 0xf0) | ((iv & 0xf0) >> 4), - (iv & 0xf) | ((iv & 0xf) << 4), - 1 - ); - putToCache(colorStr, rgbaArr); - return rgbaArr; - } - else if (str.length === 7) { - var iv = parseInt(str.substr(1), 16); // TODO(deanm): Stricter parsing. - if (!(iv >= 0 && iv <= 0xffffff)) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; // Covers NaN. - } - setRgba(rgbaArr, - (iv & 0xff0000) >> 16, - (iv & 0xff00) >> 8, - iv & 0xff, - 1 - ); - putToCache(colorStr, rgbaArr); - return rgbaArr; - } - - return; - } - var op = str.indexOf('('), ep = str.indexOf(')'); - if (op !== -1 && ep + 1 === str.length) { - var fname = str.substr(0, op); - var params = str.substr(op + 1, ep - (op + 1)).split(','); - var alpha = 1; // To allow case fallthrough. - switch (fname) { - case 'rgba': - if (params.length !== 4) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; - } - alpha = parseCssFloat(params.pop()); // jshint ignore:line - // Fall through. - case 'rgb': - if (params.length !== 3) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; - } - setRgba(rgbaArr, - parseCssInt(params[0]), - parseCssInt(params[1]), - parseCssInt(params[2]), - alpha - ); - putToCache(colorStr, rgbaArr); - return rgbaArr; - case 'hsla': - if (params.length !== 4) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; - } - params[3] = parseCssFloat(params[3]); - hsla2rgba(params, rgbaArr); - putToCache(colorStr, rgbaArr); - return rgbaArr; - case 'hsl': - if (params.length !== 3) { - setRgba(rgbaArr, 0, 0, 0, 1); - return; - } - hsla2rgba(params, rgbaArr); - putToCache(colorStr, rgbaArr); - return rgbaArr; - default: - return; - } - } - - setRgba(rgbaArr, 0, 0, 0, 1); - return; -} - -/** - * @param {Array.} hsla - * @param {Array.} rgba - * @return {Array.} rgba - */ -function hsla2rgba(hsla, rgba) { - var h = (((parseFloat(hsla[0]) % 360) + 360) % 360) / 360; // 0 .. 1 - // NOTE(deanm): According to the CSS spec s/l should only be - // percentages, but we don't bother and let float or percentage. - var s = parseCssFloat(hsla[1]); - var l = parseCssFloat(hsla[2]); - var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s; - var m1 = l * 2 - m2; - - rgba = rgba || []; - setRgba(rgba, - clampCssByte(cssHueToRgb(m1, m2, h + 1 / 3) * 255), - clampCssByte(cssHueToRgb(m1, m2, h) * 255), - clampCssByte(cssHueToRgb(m1, m2, h - 1 / 3) * 255), - 1 - ); - - if (hsla.length === 4) { - rgba[3] = hsla[3]; - } - - return rgba; -} - -/** - * @param {Array.} rgba - * @return {Array.} hsla - */ -function rgba2hsla(rgba) { - if (!rgba) { - return; - } - - // RGB from 0 to 255 - var R = rgba[0] / 255; - var G = rgba[1] / 255; - var B = rgba[2] / 255; - - var vMin = Math.min(R, G, B); // Min. value of RGB - var vMax = Math.max(R, G, B); // Max. value of RGB - var delta = vMax - vMin; // Delta RGB value - - var L = (vMax + vMin) / 2; - var H; - var S; - // HSL results from 0 to 1 - if (delta === 0) { - H = 0; - S = 0; - } - else { - if (L < 0.5) { - S = delta / (vMax + vMin); - } - else { - S = delta / (2 - vMax - vMin); - } - - var deltaR = (((vMax - R) / 6) + (delta / 2)) / delta; - var deltaG = (((vMax - G) / 6) + (delta / 2)) / delta; - var deltaB = (((vMax - B) / 6) + (delta / 2)) / delta; - - if (R === vMax) { - H = deltaB - deltaG; - } - else if (G === vMax) { - H = (1 / 3) + deltaR - deltaB; - } - else if (B === vMax) { - H = (2 / 3) + deltaG - deltaR; - } - - if (H < 0) { - H += 1; - } - - if (H > 1) { - H -= 1; - } - } - - var hsla = [H * 360, S, L]; - - if (rgba[3] != null) { - hsla.push(rgba[3]); - } - - return hsla; -} - -/** - * @param {string} color - * @param {number} level - * @return {string} - * @memberOf module:zrender/util/color - */ -function lift(color, level) { - var colorArr = parse(color); - if (colorArr) { - for (var i = 0; i < 3; i++) { - if (level < 0) { - colorArr[i] = colorArr[i] * (1 - level) | 0; - } - else { - colorArr[i] = ((255 - colorArr[i]) * level + colorArr[i]) | 0; - } - } - return stringify(colorArr, colorArr.length === 4 ? 'rgba' : 'rgb'); - } -} - -/** - * @param {string} color - * @return {string} - * @memberOf module:zrender/util/color - */ -function toHex(color) { - var colorArr = parse(color); - if (colorArr) { - return ((1 << 24) + (colorArr[0] << 16) + (colorArr[1] << 8) + (+colorArr[2])).toString(16).slice(1); - } -} - -/** - * Map value to color. Faster than lerp methods because color is represented by rgba array. - * @param {number} normalizedValue A float between 0 and 1. - * @param {Array.>} colors List of rgba color array - * @param {Array.} [out] Mapped gba color array - * @return {Array.} will be null/undefined if input illegal. - */ -function fastLerp(normalizedValue, colors, out) { - if (!(colors && colors.length) - || !(normalizedValue >= 0 && normalizedValue <= 1) - ) { - return; - } - - out = out || []; - - var value = normalizedValue * (colors.length - 1); - var leftIndex = Math.floor(value); - var rightIndex = Math.ceil(value); - var leftColor = colors[leftIndex]; - var rightColor = colors[rightIndex]; - var dv = value - leftIndex; - out[0] = clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)); - out[1] = clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)); - out[2] = clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)); - out[3] = clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv)); - - return out; -} - -/** - * @deprecated - */ -var fastMapToColor = fastLerp; - -/** - * @param {number} normalizedValue A float between 0 and 1. - * @param {Array.} colors Color list. - * @param {boolean=} fullOutput Default false. - * @return {(string|Object)} Result color. If fullOutput, - * return {color: ..., leftIndex: ..., rightIndex: ..., value: ...}, - * @memberOf module:zrender/util/color - */ -function lerp(normalizedValue, colors, fullOutput) { - if (!(colors && colors.length) - || !(normalizedValue >= 0 && normalizedValue <= 1) - ) { - return; - } - - var value = normalizedValue * (colors.length - 1); - var leftIndex = Math.floor(value); - var rightIndex = Math.ceil(value); - var leftColor = parse(colors[leftIndex]); - var rightColor = parse(colors[rightIndex]); - var dv = value - leftIndex; - - var color = stringify( - [ - clampCssByte(lerpNumber(leftColor[0], rightColor[0], dv)), - clampCssByte(lerpNumber(leftColor[1], rightColor[1], dv)), - clampCssByte(lerpNumber(leftColor[2], rightColor[2], dv)), - clampCssFloat(lerpNumber(leftColor[3], rightColor[3], dv)) - ], - 'rgba' - ); - - return fullOutput - ? { - color: color, - leftIndex: leftIndex, - rightIndex: rightIndex, - value: value - } - : color; -} - -/** - * @deprecated - */ -var mapToColor = lerp; - -/** - * @param {string} color - * @param {number=} h 0 ~ 360, ignore when null. - * @param {number=} s 0 ~ 1, ignore when null. - * @param {number=} l 0 ~ 1, ignore when null. - * @return {string} Color string in rgba format. - * @memberOf module:zrender/util/color - */ -function modifyHSL(color, h, s, l) { - color = parse(color); - - if (color) { - color = rgba2hsla(color); - h != null && (color[0] = clampCssAngle(h)); - s != null && (color[1] = parseCssFloat(s)); - l != null && (color[2] = parseCssFloat(l)); - - return stringify(hsla2rgba(color), 'rgba'); - } -} - -/** - * @param {string} color - * @param {number=} alpha 0 ~ 1 - * @return {string} Color string in rgba format. - * @memberOf module:zrender/util/color - */ -function modifyAlpha(color, alpha) { - color = parse(color); - - if (color && alpha != null) { - color[3] = clampCssFloat(alpha); - return stringify(color, 'rgba'); - } -} - -/** - * @param {Array.} arrColor like [12,33,44,0.4] - * @param {string} type 'rgba', 'hsva', ... - * @return {string} Result color. (If input illegal, return undefined). - */ -function stringify(arrColor, type) { - if (!arrColor || !arrColor.length) { - return; - } - var colorStr = arrColor[0] + ',' + arrColor[1] + ',' + arrColor[2]; - if (type === 'rgba' || type === 'hsva' || type === 'hsla') { - colorStr += ',' + arrColor[3]; - } - return type + '(' + colorStr + ')'; -} - - -/***/ }), -/* 131 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ({ - 'type' : 'compositor', - 'nodes' : [ - { - 'name': 'source', - 'type': 'texture', - 'outputs': { - 'color': {} - } - }, - { - 'name': 'source_half', - 'shader': '#source(clay.compositor.downsample)', - 'inputs': { - 'texture': 'source' - }, - 'outputs': { - 'color': { - 'parameters': { - 'width': 'expr(width * 1.0 / 2)', - 'height': 'expr(height * 1.0 / 2)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'textureSize': 'expr( [width * 1.0, height * 1.0] )' - } - }, - - - { - 'name' : 'bright', - 'shader' : '#source(clay.compositor.bright)', - 'inputs' : { - 'texture' : 'source_half' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 2)', - 'height' : 'expr(height * 1.0 / 2)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'threshold' : 2, - 'scale': 4, - 'textureSize': 'expr([width * 1.0 / 2, height / 2])' - } - }, - - { - 'name': 'bright_downsample_4', - 'shader' : '#source(clay.compositor.downsample)', - 'inputs' : { - 'texture' : 'bright' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 4)', - 'height' : 'expr(height * 1.0 / 4)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'textureSize': 'expr( [width * 1.0 / 2, height / 2] )' - } - }, - { - 'name': 'bright_downsample_8', - 'shader' : '#source(clay.compositor.downsample)', - 'inputs' : { - 'texture' : 'bright_downsample_4' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 8)', - 'height' : 'expr(height * 1.0 / 8)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'textureSize': 'expr( [width * 1.0 / 4, height / 4] )' - } - }, - { - 'name': 'bright_downsample_16', - 'shader' : '#source(clay.compositor.downsample)', - 'inputs' : { - 'texture' : 'bright_downsample_8' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 16)', - 'height' : 'expr(height * 1.0 / 16)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'textureSize': 'expr( [width * 1.0 / 8, height / 8] )' - } - }, - { - 'name': 'bright_downsample_32', - 'shader' : '#source(clay.compositor.downsample)', - 'inputs' : { - 'texture' : 'bright_downsample_16' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 32)', - 'height' : 'expr(height * 1.0 / 32)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'textureSize': 'expr( [width * 1.0 / 16, height / 16] )' - } - }, - - - { - 'name' : 'bright_upsample_16_blur_h', - 'shader' : '#source(clay.compositor.gaussian_blur)', - 'inputs' : { - 'texture' : 'bright_downsample_32' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 16)', - 'height' : 'expr(height * 1.0 / 16)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'blurSize' : 1, - 'blurDir': 0.0, - 'textureSize': 'expr( [width * 1.0 / 32, height / 32] )' - } - }, - { - 'name' : 'bright_upsample_16_blur_v', - 'shader' : '#source(clay.compositor.gaussian_blur)', - 'inputs' : { - 'texture' : 'bright_upsample_16_blur_h' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 16)', - 'height' : 'expr(height * 1.0 / 16)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'blurSize' : 1, - 'blurDir': 1.0, - 'textureSize': 'expr( [width * 1.0 / 32, height * 1.0 / 32] )' - } - }, - - - - { - 'name' : 'bright_upsample_8_blur_h', - 'shader' : '#source(clay.compositor.gaussian_blur)', - 'inputs' : { - 'texture' : 'bright_downsample_16' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 8)', - 'height' : 'expr(height * 1.0 / 8)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'blurSize' : 1, - 'blurDir': 0.0, - 'textureSize': 'expr( [width * 1.0 / 16, height * 1.0 / 16] )' - } - }, - { - 'name' : 'bright_upsample_8_blur_v', - 'shader' : '#source(clay.compositor.gaussian_blur)', - 'inputs' : { - 'texture' : 'bright_upsample_8_blur_h' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 8)', - 'height' : 'expr(height * 1.0 / 8)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'blurSize' : 1, - 'blurDir': 1.0, - 'textureSize': 'expr( [width * 1.0 / 16, height * 1.0 / 16] )' - } - }, - { - 'name' : 'bright_upsample_8_blend', - 'shader' : '#source(clay.compositor.blend)', - 'inputs' : { - 'texture1' : 'bright_upsample_8_blur_v', - 'texture2' : 'bright_upsample_16_blur_v' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 8)', - 'height' : 'expr(height * 1.0 / 8)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'weight1' : 0.3, - 'weight2' : 0.7 - } - }, - - - { - 'name' : 'bright_upsample_4_blur_h', - 'shader' : '#source(clay.compositor.gaussian_blur)', - 'inputs' : { - 'texture' : 'bright_downsample_8' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 4)', - 'height' : 'expr(height * 1.0 / 4)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'blurSize' : 1, - 'blurDir': 0.0, - 'textureSize': 'expr( [width * 1.0 / 8, height * 1.0 / 8] )' - } - }, - { - 'name' : 'bright_upsample_4_blur_v', - 'shader' : '#source(clay.compositor.gaussian_blur)', - 'inputs' : { - 'texture' : 'bright_upsample_4_blur_h' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 4)', - 'height' : 'expr(height * 1.0 / 4)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'blurSize' : 1, - 'blurDir': 1.0, - 'textureSize': 'expr( [width * 1.0 / 8, height * 1.0 / 8] )' - } - }, - { - 'name' : 'bright_upsample_4_blend', - 'shader' : '#source(clay.compositor.blend)', - 'inputs' : { - 'texture1' : 'bright_upsample_4_blur_v', - 'texture2' : 'bright_upsample_8_blend' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 4)', - 'height' : 'expr(height * 1.0 / 4)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'weight1' : 0.3, - 'weight2' : 0.7 - } - }, - - - - - - { - 'name' : 'bright_upsample_2_blur_h', - 'shader' : '#source(clay.compositor.gaussian_blur)', - 'inputs' : { - 'texture' : 'bright_downsample_4' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 2)', - 'height' : 'expr(height * 1.0 / 2)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'blurSize' : 1, - 'blurDir': 0.0, - 'textureSize': 'expr( [width * 1.0 / 4, height * 1.0 / 4] )' - } - }, - { - 'name' : 'bright_upsample_2_blur_v', - 'shader' : '#source(clay.compositor.gaussian_blur)', - 'inputs' : { - 'texture' : 'bright_upsample_2_blur_h' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 2)', - 'height' : 'expr(height * 1.0 / 2)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'blurSize' : 1, - 'blurDir': 1.0, - 'textureSize': 'expr( [width * 1.0 / 4, height * 1.0 / 4] )' - } - }, - { - 'name' : 'bright_upsample_2_blend', - 'shader' : '#source(clay.compositor.blend)', - 'inputs' : { - 'texture1' : 'bright_upsample_2_blur_v', - 'texture2' : 'bright_upsample_4_blend' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0 / 2)', - 'height' : 'expr(height * 1.0 / 2)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'weight1' : 0.3, - 'weight2' : 0.7 - } - }, - - - - { - 'name' : 'bright_upsample_full_blur_h', - 'shader' : '#source(clay.compositor.gaussian_blur)', - 'inputs' : { - 'texture' : 'bright' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0)', - 'height' : 'expr(height * 1.0)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'blurSize' : 1, - 'blurDir': 0.0, - 'textureSize': 'expr( [width * 1.0 / 2, height * 1.0 / 2] )' - } - }, - { - 'name' : 'bright_upsample_full_blur_v', - 'shader' : '#source(clay.compositor.gaussian_blur)', - 'inputs' : { - 'texture' : 'bright_upsample_full_blur_h' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0)', - 'height' : 'expr(height * 1.0)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'blurSize' : 1, - 'blurDir': 1.0, - 'textureSize': 'expr( [width * 1.0 / 2, height * 1.0 / 2] )' - } - }, - { - 'name' : 'bloom_composite', - 'shader' : '#source(clay.compositor.blend)', - 'inputs' : { - 'texture1' : 'bright_upsample_full_blur_v', - 'texture2' : 'bright_upsample_2_blend' - }, - 'outputs' : { - 'color' : { - 'parameters' : { - 'width' : 'expr(width * 1.0)', - 'height' : 'expr(height * 1.0)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters' : { - 'weight1' : 0.3, - 'weight2' : 0.7 - } - }, - - - { - 'name': 'coc', - 'shader': '#source(ecgl.dof.coc)', - 'outputs': { - 'color': { - 'parameters': { - 'minFilter': 'NEAREST', - 'magFilter': 'NEAREST', - 'width': 'expr(width * 1.0)', - 'height': 'expr(height * 1.0)' - } - } - }, - 'parameters': { - 'focalDist': 50, - 'focalRange': 30 - } - }, - - { - 'name': 'dof_far_blur', - 'shader': '#source(ecgl.dof.diskBlur)', - 'inputs': { - 'texture': 'source', - 'coc': 'coc' - }, - 'outputs': { - 'color': { - 'parameters': { - 'width': 'expr(width * 1.0)', - 'height': 'expr(height * 1.0)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters': { - 'textureSize': 'expr( [width * 1.0, height * 1.0] )' - } - }, - { - 'name': 'dof_near_blur', - 'shader': '#source(ecgl.dof.diskBlur)', - 'inputs': { - 'texture': 'source', - 'coc': 'coc' - }, - 'outputs': { - 'color': { - 'parameters': { - 'width': 'expr(width * 1.0)', - 'height': 'expr(height * 1.0)', - 'type': 'HALF_FLOAT' - } - } - }, - 'parameters': { - 'textureSize': 'expr( [width * 1.0, height * 1.0] )' - }, - 'defines': { - 'BLUR_NEARFIELD': null - } - }, - - - { - 'name': 'dof_coc_blur', - 'shader': '#source(ecgl.dof.diskBlur)', - 'inputs': { - 'texture': 'coc' - }, - 'outputs': { - 'color': { - 'parameters': { - 'minFilter': 'NEAREST', - 'magFilter': 'NEAREST', - 'width': 'expr(width * 1.0)', - 'height': 'expr(height * 1.0)' - } - } - }, - 'parameters': { - 'textureSize': 'expr( [width * 1.0, height * 1.0] )' - }, - 'defines': { - 'BLUR_COC': null - } - }, - - { - 'name': 'dof_composite', - 'shader': '#source(ecgl.dof.composite)', - 'inputs': { - 'original': 'source', - 'blurred': 'dof_far_blur', - 'nearfield': 'dof_near_blur', - 'coc': 'coc', - 'nearcoc': 'dof_coc_blur' - }, - 'outputs': { - 'color': { - 'parameters': { - 'width': 'expr(width * 1.0)', - 'height': 'expr(height * 1.0)', - 'type': 'HALF_FLOAT' - } - } - } - }, - { - 'name' : 'composite', - 'shader' : '#source(clay.compositor.hdr.composite)', - 'inputs' : { - 'texture': 'source', - 'bloom' : 'bloom_composite' - }, - 'defines': { - // Images are all premultiplied alpha before composite because of blending. - // 'PREMULTIPLY_ALPHA': null, - // 'DEBUG': 1 - } - }, - { - 'name' : 'FXAA', - 'shader' : '#source(clay.compositor.fxaa)', - 'inputs' : { - 'texture' : 'composite' - } - } - ] -}); - -/***/ }), -/* 132 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export ecgl.dof.coc\n\nuniform sampler2D depth;\n\nuniform float zNear: 0.1;\nuniform float zFar: 2000;\n\nuniform float focalDistance: 3;\nuniform float focalRange: 1;\nuniform float focalLength: 30;\nuniform float fstop: 2.8;\n\nvarying vec2 v_Texcoord;\n\n@import clay.util.encode_float\n\nvoid main()\n{\n float z = texture2D(depth, v_Texcoord).r * 2.0 - 1.0;\n\n float dist = 2.0 * zNear * zFar / (zFar + zNear - z * (zFar - zNear));\n\n float aperture = focalLength / fstop;\n\n float coc;\n\n float uppper = focalDistance + focalRange;\n float lower = focalDistance - focalRange;\n if (dist <= uppper && dist >= lower) {\n coc = 0.5;\n }\n else {\n float focalAdjusted = dist > uppper ? uppper : lower;\n\n coc = abs(aperture * (focalLength * (dist - focalAdjusted)) / (dist * (focalAdjusted - focalLength)));\n coc = clamp(coc, 0.0, 2.0) / 2.00001;\n\n if (dist < lower) {\n coc = -coc;\n }\n coc = coc * 0.5 + 0.5;\n }\n\n gl_FragColor = encodeFloat(coc);\n}\n@end\n\n\n@export ecgl.dof.composite\n\n#define DEBUG 0\n\nuniform sampler2D original;\nuniform sampler2D blurred;\nuniform sampler2D nearfield;\nuniform sampler2D coc;\nuniform sampler2D nearcoc;\nvarying vec2 v_Texcoord;\n\n@import clay.util.rgbm\n@import clay.util.float\n\nvoid main()\n{\n vec4 blurredColor = decodeHDR(texture2D(blurred, v_Texcoord));\n vec4 originalColor = decodeHDR(texture2D(original, v_Texcoord));\n\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord));\n\n fCoc = abs(fCoc * 2.0 - 1.0);\n\n float weight = smoothstep(0.0, 1.0, fCoc);\n \n#ifdef NEARFIELD_ENABLED\n vec4 nearfieldColor = decodeHDR(texture2D(nearfield, v_Texcoord));\n float fNearCoc = decodeFloat(texture2D(nearcoc, v_Texcoord));\n fNearCoc = abs(fNearCoc * 2.0 - 1.0);\n\n gl_FragColor = encodeHDR(\n mix(\n nearfieldColor, mix(originalColor, blurredColor, weight),\n pow(1.0 - fNearCoc, 4.0)\n )\n );\n#else\n gl_FragColor = encodeHDR(mix(originalColor, blurredColor, weight));\n#endif\n\n}\n\n@end\n\n\n\n@export ecgl.dof.diskBlur\n\n#define POISSON_KERNEL_SIZE 16;\n\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\n\nuniform float blurRadius : 10.0;\nuniform vec2 textureSize : [512.0, 512.0];\n\nuniform vec2 poissonKernel[POISSON_KERNEL_SIZE];\n\nuniform float percent;\n\nfloat nrand(const in vec2 n) {\n return fract(sin(dot(n.xy ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\n@import clay.util.rgbm\n@import clay.util.float\n\n\nvoid main()\n{\n vec2 offset = blurRadius / textureSize;\n\n float rnd = 6.28318 * nrand(v_Texcoord + 0.07 * percent );\n float cosa = cos(rnd);\n float sina = sin(rnd);\n vec4 basis = vec4(cosa, -sina, sina, cosa);\n\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n\n#ifdef BLUR_COC\n float cocSum = 0.0;\n#else\n vec4 color = vec4(0.0);\n#endif\n\n\n float weightSum = 0.0;\n\n for (int i = 0; i < POISSON_KERNEL_SIZE; i++) {\n vec2 ofs = poissonKernel[i];\n\n ofs = vec2(dot(ofs, basis.xy), dot(ofs, basis.zw));\n\n vec2 uv = v_Texcoord + ofs * offset;\n vec4 texel = texture2D(texture, uv);\n\n float w = 1.0;\n#ifdef BLUR_COC\n float fCoc = decodeFloat(texel) * 2.0 - 1.0;\n cocSum += clamp(fCoc, -1.0, 0.0) * w;\n#else\n texel = decodeHDR(texel);\n #if !defined(BLUR_NEARFIELD)\n float fCoc = decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0;\n w *= abs(fCoc);\n #endif\n color += texel * w;\n#endif\n\n weightSum += w;\n }\n\n#ifdef BLUR_COC\n gl_FragColor = encodeFloat(clamp(cocSum / weightSum, -1.0, 0.0) * 0.5 + 0.5);\n#else\n color /= weightSum;\n gl_FragColor = encodeHDR(color);\n#endif\n}\n\n@end"); - - -/***/ }), -/* 133 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export ecgl.edge\n\nuniform sampler2D texture;\n\nuniform sampler2D normalTexture;\nuniform sampler2D depthTexture;\n\nuniform mat4 projectionInv;\n\nuniform vec2 textureSize;\n\nuniform vec4 edgeColor: [0,0,0,0.8];\n\nvarying vec2 v_Texcoord;\n\nvec3 packColor(vec2 coord) {\n float z = texture2D(depthTexture, coord).r * 2.0 - 1.0;\n vec4 p = vec4(v_Texcoord * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * p;\n\n return vec3(\n texture2D(normalTexture, coord).rg,\n -p4.z / p4.w / 5.0\n );\n}\n\nvoid main() {\n vec2 cc = v_Texcoord;\n vec3 center = packColor(cc);\n\n float size = clamp(1.0 - (center.z - 10.0) / 100.0, 0.0, 1.0) * 0.5;\n float dx = size / textureSize.x;\n float dy = size / textureSize.y;\n\n vec2 coord;\n vec3 topLeft = packColor(cc+vec2(-dx, -dy));\n vec3 top = packColor(cc+vec2(0.0, -dy));\n vec3 topRight = packColor(cc+vec2(dx, -dy));\n vec3 left = packColor(cc+vec2(-dx, 0.0));\n vec3 right = packColor(cc+vec2(dx, 0.0));\n vec3 bottomLeft = packColor(cc+vec2(-dx, dy));\n vec3 bottom = packColor(cc+vec2(0.0, dy));\n vec3 bottomRight = packColor(cc+vec2(dx, dy));\n\n vec3 v = -topLeft-2.0*top-topRight+bottomLeft+2.0*bottom+bottomRight;\n vec3 h = -bottomLeft-2.0*left-topLeft+bottomRight+2.0*right+topRight;\n\n float edge = sqrt(dot(h, h) + dot(v, v));\n\n edge = smoothstep(0.8, 1.0, edge);\n\n gl_FragColor = mix(texture2D(texture, v_Texcoord), vec4(edgeColor.rgb, 1.0), edgeColor.a * edge);\n}\n@end"); - - -/***/ }), -/* 134 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__halton__ = __webpack_require__(25); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_claygl_src_compositor_Pass__ = __webpack_require__(13); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_claygl_src_FrameBuffer__ = __webpack_require__(11); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_claygl_src_Texture2D__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4_claygl_src_Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5_claygl_src_math_Matrix4__ = __webpack_require__(9); -// Temporal Super Sample for static Scene - - - - - - - -function TemporalSuperSampling () { - var haltonSequence = []; - - for (var i = 0; i < 30; i++) { - haltonSequence.push([ - Object(__WEBPACK_IMPORTED_MODULE_0__halton__["a" /* default */])(i, 2), Object(__WEBPACK_IMPORTED_MODULE_0__halton__["a" /* default */])(i, 3) - ]); - } - - this._haltonSequence = haltonSequence; - - this._frame = 0; - - this._sourceTex = new __WEBPACK_IMPORTED_MODULE_3_claygl_src_Texture2D__["a" /* default */](); - this._sourceFb = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_FrameBuffer__["a" /* default */](); - this._sourceFb.attach(this._sourceTex); - - // Frame texture before temporal supersampling - this._prevFrameTex = new __WEBPACK_IMPORTED_MODULE_3_claygl_src_Texture2D__["a" /* default */](); - this._outputTex = new __WEBPACK_IMPORTED_MODULE_3_claygl_src_Texture2D__["a" /* default */](); - - var blendPass = this._blendPass = new __WEBPACK_IMPORTED_MODULE_1_claygl_src_compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_4_claygl_src_Shader__["a" /* default */].source('clay.compositor.blend') - }); - blendPass.material.disableTexturesAll(); - blendPass.material.enableTexture(['texture1', 'texture2']); - - this._blendFb = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_FrameBuffer__["a" /* default */]({ - depthBuffer: false - }); - - this._outputPass = new __WEBPACK_IMPORTED_MODULE_1_claygl_src_compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_4_claygl_src_Shader__["a" /* default */].source('clay.compositor.output'), - // TODO, alpha is premultiplied? - blendWithPrevious: true - }); - this._outputPass.material.define('fragment', 'OUTPUT_ALPHA'); - this._outputPass.material.blend = function (_gl) { - // FIXME. - // Output is premultiplied alpha when BLEND is enabled ? - // http://stackoverflow.com/questions/2171085/opengl-blending-with-previous-contents-of-framebuffer - _gl.blendEquationSeparate(_gl.FUNC_ADD, _gl.FUNC_ADD); - _gl.blendFuncSeparate(_gl.ONE, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA); - } -} - -TemporalSuperSampling.prototype = { - - constructor: TemporalSuperSampling, - - /** - * Jitter camera projectionMatrix - * @parma {clay.Renderer} renderer - * @param {clay.Camera} camera - */ - jitterProjection: function (renderer, camera) { - var viewport = renderer.viewport; - var dpr = viewport.devicePixelRatio || renderer.getDevicePixelRatio(); - var width = viewport.width * dpr; - var height = viewport.height * dpr; - - var offset = this._haltonSequence[this._frame % this._haltonSequence.length]; - - var translationMat = new __WEBPACK_IMPORTED_MODULE_5_claygl_src_math_Matrix4__["a" /* default */](); - translationMat.array[12] = (offset[0] * 2.0 - 1.0) / width; - translationMat.array[13] = (offset[1] * 2.0 - 1.0) / height; - - __WEBPACK_IMPORTED_MODULE_5_claygl_src_math_Matrix4__["a" /* default */].mul(camera.projectionMatrix, translationMat, camera.projectionMatrix); - - __WEBPACK_IMPORTED_MODULE_5_claygl_src_math_Matrix4__["a" /* default */].invert(camera.invProjectionMatrix, camera.projectionMatrix); - }, - - /** - * Reset accumulating frame - */ - resetFrame: function () { - this._frame = 0; - }, - - /** - * Return current frame - */ - getFrame: function () { - return this._frame; - }, - - /** - * Get source framebuffer for usage - */ - getSourceFrameBuffer: function () { - return this._sourceFb; - }, - - resize: function (width, height) { - if (this._sourceTex.width !== width || this._sourceTex.height !== height) { - - this._prevFrameTex.width = width; - this._prevFrameTex.height = height; - - this._outputTex.width = width; - this._outputTex.height = height; - - this._sourceTex.width = width; - this._sourceTex.height = height; - - this._prevFrameTex.dirty(); - this._outputTex.dirty(); - this._sourceTex.dirty(); - } - }, - - isFinished: function () { - return this._frame >= this._haltonSequence.length; - }, - - render: function (renderer) { - var blendPass = this._blendPass; - if (this._frame === 0) { - // Direct output - blendPass.setUniform('weight1', 0); - blendPass.setUniform('weight2', 1); - } - else { - blendPass.setUniform('weight1', 0.9); - blendPass.setUniform('weight2', 0.1); - } - blendPass.setUniform('texture1', this._prevFrameTex); - blendPass.setUniform('texture2', this._sourceTex); - - this._blendFb.attach(this._outputTex); - this._blendFb.bind(renderer); - blendPass.render(renderer); - this._blendFb.unbind(renderer); - - this._outputPass.setUniform('texture', this._outputTex); - this._outputPass.render(renderer); - - // Swap texture - var tmp = this._prevFrameTex; - this._prevFrameTex = this._outputTex; - this._outputTex = tmp; - - this._frame++; - }, - - dispose: function (renderer) { - this._sourceFb.dispose(renderer); - this._blendFb.dispose(renderer); - this._prevFrameTex.dispose(renderer); - this._outputTex.dispose(renderer); - this._sourceTex.dispose(renderer); - this._outputPass.dispose(renderer); - this._blendPass.dispose(renderer); - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (TemporalSuperSampling); - -/***/ }), -/* 135 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__helper__ = __webpack_require__(26); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_claygl_src_plugin_Skybox__ = __webpack_require__(37); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_claygl_src_plugin_Skydome__ = __webpack_require__(36); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_claygl_src_math_Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4_claygl_src_light_Directional__ = __webpack_require__(61); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5_claygl_src_light_Ambient__ = __webpack_require__(136); - - - - - - - -function SceneHelper(scene) { - this.setScene(scene); -} - -SceneHelper.prototype = { - constructor: SceneHelper, - - setScene: function (scene) { - this._scene = scene; - - if (this._skybox) { - this._skybox.attachScene(this._scene); - } - - }, - - initLight: function (rootNode) { - this._lightRoot = rootNode; - /** - * @type {clay.light.Directional} - */ - this.mainLight = new __WEBPACK_IMPORTED_MODULE_4_claygl_src_light_Directional__["a" /* default */]({ - shadowBias: 0.005 - }); - /** - * @type {clay.light.Directional} - */ - this.secondaryLight = new __WEBPACK_IMPORTED_MODULE_4_claygl_src_light_Directional__["a" /* default */]({ - shadowBias: 0.005 - }); - /** - * @type {clay.light.Directional} - */ - this.tertiaryLight = new __WEBPACK_IMPORTED_MODULE_4_claygl_src_light_Directional__["a" /* default */]({ - shadowBias: 0.005 - }); - - /** - * @type {clay.light.Ambient} - */ - this.ambientLight = new __WEBPACK_IMPORTED_MODULE_5_claygl_src_light_Ambient__["a" /* default */](); - }, - - dispose: function (renderer) { - if (this._lightRoot) { - this._lightRoot.remove(this.mainLight); - this._lightRoot.remove(this.ambientLight); - } - if (this._currentCubemapLights) { - this._lightRoot.remove(this._currentCubemapLights.diffuse); - if (this._currentCubemapLights.specular) { - this._lightRoot.remove(this._currentCubemapLights.specular); - this._currentCubemapLights.specular.cubemap.dispose(renderer); - } - } - }, - - updateMainLight: function (opts, app) { - this._updateDirectionalLight(this.mainLight, opts, app); - }, - - updateSecondaryLight: function (opts, app) { - this._updateDirectionalLight(this.secondaryLight, opts, app); - }, - - updateTertiaryLight: function (opts, app) { - this._updateDirectionalLight(this.tertiaryLight, opts, app); - }, - - _updateDirectionalLight: function (light, opts, app) { - opts = opts || {}; - if (opts.intensity != null) { - light.intensity = opts.intensity; - this._lightRoot[opts.intensity ? 'add' : 'remove'](light); - } - if (opts.color != null) { - light.color = __WEBPACK_IMPORTED_MODULE_0__helper__["a" /* default */].parseColor(opts.color).slice(0, 3); - } - var alpha = __WEBPACK_IMPORTED_MODULE_0__helper__["a" /* default */].firstNotNull(opts.alpha, 45); - var beta = __WEBPACK_IMPORTED_MODULE_0__helper__["a" /* default */].firstNotNull(opts.beta, 45); - - light.position.setArray(__WEBPACK_IMPORTED_MODULE_0__helper__["a" /* default */].directionFromAlphaBeta(alpha, beta)); - light.lookAt(__WEBPACK_IMPORTED_MODULE_3_claygl_src_math_Vector3__["a" /* default */].ZERO); - - var shadowResolution = ({ - 'low': 512, - 'medium': 1024, - 'high': 2048, - 'ultra': 4096 - })[opts.quality] || 1024; - - light.castShadow = __WEBPACK_IMPORTED_MODULE_0__helper__["a" /* default */].firstNotNull(opts.shadow, true); - light.shadowResolution = shadowResolution; - }, - - updateAmbientLight: function (opts, app) { - opts = opts || {}; - if (opts.intensity != null) { - this.ambientLight.intensity = opts.intensity; - this._lightRoot[opts.intensity ? 'add' : 'remove'](this.ambientLight); - } - if (opts.color != null) { - this.ambientLight.color = __WEBPACK_IMPORTED_MODULE_0__helper__["a" /* default */].parseColor(opts.color).slice(0, 3); - } - }, - - updateAmbientCubemapLight: function (opts, app) { - opts = opts || {}; - var renderer = app.getRenderer(); - var textureUrl = opts.texture; - var self = this; - - // TODO Change exposure - if ('texture' in opts) { - if (!this._currentCubemapLights || textureUrl !== this._currentCubemapLights.textureUrl) { - if (this._currentCubemapLights) { - this._lightRoot.remove(this._currentCubemapLights.diffuse); - if (this._currentCubemapLights.specular) { - this._lightRoot.remove(this._currentCubemapLights.specular); - this._currentCubemapLights.specular.cubemap.dispose(renderer.gl); - } - } - if (textureUrl) { - var lights = __WEBPACK_IMPORTED_MODULE_0__helper__["a" /* default */].createAmbientCubemap(opts, app, function () { - // Use prefitered cubemap - if (lights.specular && (self._skybox instanceof __WEBPACK_IMPORTED_MODULE_1_claygl_src_plugin_Skybox__["a" /* default */])) { - self._skybox.setEnvironmentMap(lights.specular.cubemap); - } - app.refresh(); - }); - if (lights.diffuse) { - this._lightRoot.add(lights.diffuse); - } - if (lights.specular) { - this._lightRoot.add(lights.specular); - } - - this._currentCubemapLights = lights; - this._currentCubemapLights.textureUrl = textureUrl; - } - else if (this._currentCubemapLights) { - this._lightRoot.remove(this._currentCubemapLights.diffuse); - this._lightRoot.remove(this._currentCubemapLights.specular); - this._currentCubemapLights = null; - } - } - } - - if (this._currentCubemapLights) { - if (opts.specularIntensity != null && this._currentCubemapLights.specular) { - this._currentCubemapLights.specular.intensity = opts.specularIntensity; - } - if (opts.diffuseIntensity != null && this._currentCubemapLights.diffuse) { - this._currentCubemapLights.diffuse.intensity = opts.diffuseIntensity; - } - } - - }, - - updateSkybox: function (environmentUrl, isLinearSpace, app) { - var renderer = app.getRenderer(); - var self = this; - function getSkybox() { - if (!(self._skybox instanceof __WEBPACK_IMPORTED_MODULE_1_claygl_src_plugin_Skybox__["a" /* default */])) { - if (self._skybox) { - self._skybox.dispose(renderer); - } - self._skybox = new __WEBPACK_IMPORTED_MODULE_1_claygl_src_plugin_Skybox__["a" /* default */](); - } - return self._skybox; - } - function getSkydome() { - if (!(self._skybox instanceof __WEBPACK_IMPORTED_MODULE_2_claygl_src_plugin_Skydome__["a" /* default */])) { - if (self._skybox) { - self._skybox.dispose(renderer); - } - self._skybox = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_plugin_Skydome__["a" /* default */](); - } - return self._skybox; - } - - if (environmentUrl && environmentUrl !== 'none') { - if (environmentUrl === 'auto') { - // Use environment in ambient cubemap - if (this._currentCubemapLights) { - var skybox = getSkybox(); - if (this._currentCubemapLights.specular) { - var cubemap = this._currentCubemapLights.specular.cubemap; - skybox.setEnvironmentMap(cubemap); - } - if (this._scene) { - skybox.attachScene(this._scene); - } - skybox.material.set('lod', 2); - } - else if (this._skybox) { - this._skybox.detachScene(); - } - } - else { - // Panorama - var skydome = getSkydome(); - var texture = __WEBPACK_IMPORTED_MODULE_0__helper__["a" /* default */].loadTexture(environmentUrl, app, { - flipY: false - }, function () { - app.refresh(); - }); - skydome.setEnvironmentMap(texture); - - skydome.attachScene(this._scene); - } - } - else { - if (this._skybox) { - this._skybox.detachScene(this._scene); - } - this._skybox = null; - } - - if (this._skybox) { - if (environmentUrl !== 'auto' - && !(environmentUrl.match && environmentUrl.match(/.hdr$/)) - ) { - var srgbDefineMethod = isLinearSpace ? 'define' : 'undefine'; - this._skybox.material[srgbDefineMethod]('fragment', 'SRGB_DECODE'); - } - else { - this._skybox.material.undefine('fragment', 'SRGB_DECODE'); - } - } - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (SceneHelper); - -/***/ }), -/* 136 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__Light__ = __webpack_require__(14); - - -/** - * @constructor clay.light.Ambient - * @extends clay.Light - */ -var AmbientLight = __WEBPACK_IMPORTED_MODULE_0__Light__["a" /* default */].extend({ - - castShadow: false - -}, { - - type: 'AMBIENT_LIGHT', - - uniformTemplates: { - ambientLightColor: { - type: '3f', - value: function(instance) { - var color = instance.color; - var intensity = instance.intensity; - return [color[0]*intensity, color[1]*intensity, color[2]*intensity]; - } - } - } - /** - * @function - * @name clone - * @return {clay.light.Ambient} - * @memberOf clay.light.Ambient.prototype - */ -}); - -/* harmony default export */ __webpack_exports__["a"] = (AmbientLight); - - -/***/ }), -/* 137 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ({ - devicePixelRatio: null, - - // If enable preZ - preZ: false, - // If enable picking - picking: false, - - // If enable shadow - shadow: true, - // Environment panorama texture url. - environment: '', - - // Configuration abount ground - ground: { - show: false - }, - - // QMV provide three directional lights and two ambient lights. - - // Configuration of main light - mainLight: { - // If enable shadow of main light. - shadow: true, - // Quality of main light shadow. 'low'|'medium'|'high'|'ultra' - shadowQuality: 'medium', - // Intensity of main light - intensity: 0.8, - // Color of main light - color: '#fff', - // Alpha is rotation from bottom to up. - alpha: 45, - // Beta is rotation from left to right. - beta: 45 - }, - // Configuration of secondary light - secondaryLight: { - // If enable shadow of secondary light. - shadow: false, - shadowQuality: 'medium', - // Intensity of secondary light. Defaultly not enable secondary light. - intensity: 0, - // Color of secondary light. - color: '#fff', - alpha: 60, - beta: -50 - }, - // Configuration of tertiary light - tertiaryLight: { - // If enable shadow of tertiary light. - shadow: false, - shadowQuality: 'medium', - // Intensity of secondary light. Defaultly not enable secondary light. - intensity: 0, - // Color of tertiary light. - color: '#fff', - alpha: 89, - beta: 0 - }, - // Configuration of constant ambient light. - // Which will add a constant color on any surface. - ambientLight: { - // ambient light intensity. - intensity: 0.3, - // ambient light color. - color: '#fff' - }, - ambientCubemapLight: { - // Environment panorama texture url for cubemap lighting - texture: '', - // Exposure factor when parsing hdr format. - exposure: 3, - // Intensity of diffuse radiance. - diffuseIntensity: 0.5, - // Intensity of specular radiance. - specularIntensity: 0.5 - }, - // Configuration about post effects. - postEffect: { - // If enable post effects. - enable: false, - // Configuration about bloom post effect - bloom: { - // If enable bloom - enable: false, - // Intensity of bloom - intensity: 0.1 - }, - // Configuration about depth of field - depthOfField: { - enable: false, - // Focal distance of camera in word space. - focalDistance: 5, - // Focal range of camera in word space. in this range image will be absolutely sharp. - focalRange: 1, - // Max out of focus blur radius. - blurRadius: 5, - // fstop of camera. Smaller fstop will have shallow depth of field - fstop: 2.8, - // Blur quality. 'low'|'medium'|'high'|'ultra' - quality: 'medium' - }, - // Configuration about screen space ambient occulusion - screenSpaceAmbientOcculusion: { - // If enable SSAO - enable: false, - // Sampling radius in work space. - // Larger will produce more soft concat shadow. - // But also needs higher quality or it will have more obvious artifacts - radius: 0.5, - // Quality of SSAO. 'low'|'medium'|'high'|'ultra' - quality: 'medium', - // Intensity of SSAO - intensity: 1 - }, - // Configuration about screen space reflection - screenSpaceReflection: { - enable: false, - // Quality of SSR. 'low'|'medium'|'high'|'ultra' - quality: 'medium', - // Surface with less roughness will have reflection. - maxRoughness: 0.8 - }, - // Configuration about color correction - colorCorrection: { - // If enable color correction - enable: true, - exposure: 0, - brightness: 0, - contrast: 1, - saturation: 1, - // Lookup texture for color correction. - // See https://ecomfe.github.io/echarts-doc/public/cn/option-gl.html#globe.postEffect.colorCorrection.lookupTexture - lookupTexture: '' - }, - FXAA: { - // If enable FXAA - enable: false - } - } -}); - -/***/ }), -/* 138 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (immutable) */ __webpack_exports__["a"] = clone; -/* harmony export (immutable) */ __webpack_exports__["b"] = merge; -/* unused harmony export mergeAll */ -/* unused harmony export extend */ -/* unused harmony export defaults */ -/* unused harmony export createCanvas */ -/* unused harmony export getContext */ -/* unused harmony export indexOf */ -/* unused harmony export inherits */ -/* unused harmony export mixin */ -/* unused harmony export isArrayLike */ -/* unused harmony export each */ -/* unused harmony export map */ -/* unused harmony export reduce */ -/* unused harmony export filter */ -/* unused harmony export find */ -/* unused harmony export bind */ -/* unused harmony export curry */ -/* unused harmony export isArray */ -/* unused harmony export isFunction */ -/* unused harmony export isString */ -/* unused harmony export isObject */ -/* unused harmony export isBuiltInObject */ -/* unused harmony export isDom */ -/* unused harmony export eqNaN */ -/* unused harmony export retrieve */ -/* unused harmony export retrieve2 */ -/* unused harmony export retrieve3 */ -/* unused harmony export slice */ -/* unused harmony export normalizeCssArray */ -/* unused harmony export assert */ -/* unused harmony export setAsPrimitive */ -/* unused harmony export isPrimitive */ -/* unused harmony export createHashMap */ -/* unused harmony export noop */ -/* unused harmony export $inject */ -/** - * @module zrender/core/util - */ - -// 用于处理merge时无法遍历Date等对象的问题 -var BUILTIN_OBJECT = { - '[object Function]': 1, - '[object RegExp]': 1, - '[object Date]': 1, - '[object Error]': 1, - '[object CanvasGradient]': 1, - '[object CanvasPattern]': 1, - // For node-canvas - '[object Image]': 1, - '[object Canvas]': 1 -}; - -var TYPED_ARRAY = { - '[object Int8Array]': 1, - '[object Uint8Array]': 1, - '[object Uint8ClampedArray]': 1, - '[object Int16Array]': 1, - '[object Uint16Array]': 1, - '[object Int32Array]': 1, - '[object Uint32Array]': 1, - '[object Float32Array]': 1, - '[object Float64Array]': 1 -}; - -var objToString = Object.prototype.toString; - -var arrayProto = Array.prototype; -var nativeForEach = arrayProto.forEach; -var nativeFilter = arrayProto.filter; -var nativeSlice = arrayProto.slice; -var nativeMap = arrayProto.map; -var nativeReduce = arrayProto.reduce; - -/** - * Those data types can be cloned: - * Plain object, Array, TypedArray, number, string, null, undefined. - * Those data types will be assgined using the orginal data: - * BUILTIN_OBJECT - * Instance of user defined class will be cloned to a plain object, without - * properties in prototype. - * Other data types is not supported (not sure what will happen). - * - * Caution: do not support clone Date, for performance consideration. - * (There might be a large number of date in `series.data`). - * So date should not be modified in and out of echarts. - * - * @param {*} source - * @return {*} new - */ -function clone(source) { - if (source == null || typeof source != 'object') { - return source; - } - - var result = source; - var typeStr = objToString.call(source); - - if (typeStr === '[object Array]') { - result = []; - for (var i = 0, len = source.length; i < len; i++) { - result[i] = clone(source[i]); - } - } - else if (TYPED_ARRAY[typeStr]) { - var Ctor = source.constructor; - if (source.constructor.from) { - result = Ctor.from(source); - } - else { - result = new Ctor(source.length); - for (var i = 0, len = source.length; i < len; i++) { - result[i] = clone(source[i]); - } - } - } - else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) { - result = {}; - for (var key in source) { - if (source.hasOwnProperty(key)) { - result[key] = clone(source[key]); - } - } - } - - return result; -} - -/** - * @memberOf module:zrender/core/util - * @param {*} target - * @param {*} source - * @param {boolean} [overwrite=false] - */ -function merge(target, source, overwrite) { - // We should escapse that source is string - // and enter for ... in ... - if (!isObject(source) || !isObject(target)) { - return overwrite ? clone(source) : target; - } - - for (var key in source) { - if (source.hasOwnProperty(key)) { - var targetProp = target[key]; - var sourceProp = source[key]; - - if (isObject(sourceProp) - && isObject(targetProp) - && !isArray(sourceProp) - && !isArray(targetProp) - && !isDom(sourceProp) - && !isDom(targetProp) - && !isBuiltInObject(sourceProp) - && !isBuiltInObject(targetProp) - && !isPrimitive(sourceProp) - && !isPrimitive(targetProp) - ) { - // 如果需要递归覆盖,就递归调用merge - merge(targetProp, sourceProp, overwrite); - } - else if (overwrite || !(key in target)) { - // 否则只处理overwrite为true,或者在目标对象中没有此属性的情况 - // NOTE,在 target[key] 不存在的时候也是直接覆盖 - target[key] = clone(source[key], true); - } - } - } - - return target; -} - -/** - * @param {Array} targetAndSources The first item is target, and the rests are source. - * @param {boolean} [overwrite=false] - * @return {*} target - */ -function mergeAll(targetAndSources, overwrite) { - var result = targetAndSources[0]; - for (var i = 1, len = targetAndSources.length; i < len; i++) { - result = merge(result, targetAndSources[i], overwrite); - } - return result; -} - -/** - * @param {*} target - * @param {*} source - * @memberOf module:zrender/core/util - */ -function extend(target, source) { - for (var key in source) { - if (source.hasOwnProperty(key)) { - target[key] = source[key]; - } - } - return target; -} - -/** - * @param {*} target - * @param {*} source - * @param {boolean} [overlay=false] - * @memberOf module:zrender/core/util - */ -function defaults(target, source, overlay) { - for (var key in source) { - if (source.hasOwnProperty(key) - && (overlay ? source[key] != null : target[key] == null) - ) { - target[key] = source[key]; - } - } - return target; -} - -var createCanvas = function () { - return document.createElement('canvas'); -}; - -// FIXME -var _ctx; - -function getContext() { - if (!_ctx) { - // Use util.createCanvas instead of createCanvas - // because createCanvas may be overwritten in different environment - _ctx = createCanvas().getContext('2d'); - } - return _ctx; -} - -/** - * 查询数组中元素的index - * @memberOf module:zrender/core/util - */ -function indexOf(array, value) { - if (array) { - if (array.indexOf) { - return array.indexOf(value); - } - for (var i = 0, len = array.length; i < len; i++) { - if (array[i] === value) { - return i; - } - } - } - return -1; -} - -/** - * 构造类继承关系 - * - * @memberOf module:zrender/core/util - * @param {Function} clazz 源类 - * @param {Function} baseClazz 基类 - */ -function inherits(clazz, baseClazz) { - var clazzPrototype = clazz.prototype; - function F() {} - F.prototype = baseClazz.prototype; - clazz.prototype = new F(); - - for (var prop in clazzPrototype) { - clazz.prototype[prop] = clazzPrototype[prop]; - } - clazz.prototype.constructor = clazz; - clazz.superClass = baseClazz; -} - -/** - * @memberOf module:zrender/core/util - * @param {Object|Function} target - * @param {Object|Function} sorce - * @param {boolean} overlay - */ -function mixin(target, source, overlay) { - target = 'prototype' in target ? target.prototype : target; - source = 'prototype' in source ? source.prototype : source; - - defaults(target, source, overlay); -} - -/** - * Consider typed array. - * @param {Array|TypedArray} data - */ -function isArrayLike(data) { - if (! data) { - return; - } - if (typeof data == 'string') { - return false; - } - return typeof data.length == 'number'; -} - -/** - * 数组或对象遍历 - * @memberOf module:zrender/core/util - * @param {Object|Array} obj - * @param {Function} cb - * @param {*} [context] - */ -function each(obj, cb, context) { - if (!(obj && cb)) { - return; - } - if (obj.forEach && obj.forEach === nativeForEach) { - obj.forEach(cb, context); - } - else if (obj.length === +obj.length) { - for (var i = 0, len = obj.length; i < len; i++) { - cb.call(context, obj[i], i, obj); - } - } - else { - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - cb.call(context, obj[key], key, obj); - } - } - } -} - -/** - * 数组映射 - * @memberOf module:zrender/core/util - * @param {Array} obj - * @param {Function} cb - * @param {*} [context] - * @return {Array} - */ -function map(obj, cb, context) { - if (!(obj && cb)) { - return; - } - if (obj.map && obj.map === nativeMap) { - return obj.map(cb, context); - } - else { - var result = []; - for (var i = 0, len = obj.length; i < len; i++) { - result.push(cb.call(context, obj[i], i, obj)); - } - return result; - } -} - -/** - * @memberOf module:zrender/core/util - * @param {Array} obj - * @param {Function} cb - * @param {Object} [memo] - * @param {*} [context] - * @return {Array} - */ -function reduce(obj, cb, memo, context) { - if (!(obj && cb)) { - return; - } - if (obj.reduce && obj.reduce === nativeReduce) { - return obj.reduce(cb, memo, context); - } - else { - for (var i = 0, len = obj.length; i < len; i++) { - memo = cb.call(context, memo, obj[i], i, obj); - } - return memo; - } -} - -/** - * 数组过滤 - * @memberOf module:zrender/core/util - * @param {Array} obj - * @param {Function} cb - * @param {*} [context] - * @return {Array} - */ -function filter(obj, cb, context) { - if (!(obj && cb)) { - return; - } - if (obj.filter && obj.filter === nativeFilter) { - return obj.filter(cb, context); - } - else { - var result = []; - for (var i = 0, len = obj.length; i < len; i++) { - if (cb.call(context, obj[i], i, obj)) { - result.push(obj[i]); - } - } - return result; - } -} - -/** - * 数组项查找 - * @memberOf module:zrender/core/util - * @param {Array} obj - * @param {Function} cb - * @param {*} [context] - * @return {*} - */ -function find(obj, cb, context) { - if (!(obj && cb)) { - return; - } - for (var i = 0, len = obj.length; i < len; i++) { - if (cb.call(context, obj[i], i, obj)) { - return obj[i]; - } - } -} - -/** - * @memberOf module:zrender/core/util - * @param {Function} func - * @param {*} context - * @return {Function} - */ -function bind(func, context) { - var args = nativeSlice.call(arguments, 2); - return function () { - return func.apply(context, args.concat(nativeSlice.call(arguments))); - }; -} - -/** - * @memberOf module:zrender/core/util - * @param {Function} func - * @return {Function} - */ -function curry(func) { - var args = nativeSlice.call(arguments, 1); - return function () { - return func.apply(this, args.concat(nativeSlice.call(arguments))); - }; -} - -/** - * @memberOf module:zrender/core/util - * @param {*} value - * @return {boolean} - */ -function isArray(value) { - return objToString.call(value) === '[object Array]'; -} - -/** - * @memberOf module:zrender/core/util - * @param {*} value - * @return {boolean} - */ -function isFunction(value) { - return typeof value === 'function'; -} - -/** - * @memberOf module:zrender/core/util - * @param {*} value - * @return {boolean} - */ -function isString(value) { - return objToString.call(value) === '[object String]'; -} - -/** - * @memberOf module:zrender/core/util - * @param {*} value - * @return {boolean} - */ -function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return type === 'function' || (!!value && type == 'object'); -} - -/** - * @memberOf module:zrender/core/util - * @param {*} value - * @return {boolean} - */ -function isBuiltInObject(value) { - return !!BUILTIN_OBJECT[objToString.call(value)]; -} - -/** - * @memberOf module:zrender/core/util - * @param {*} value - * @return {boolean} - */ -function isDom(value) { - return typeof value === 'object' - && typeof value.nodeType === 'number' - && typeof value.ownerDocument === 'object'; -} - -/** - * Whether is exactly NaN. Notice isNaN('a') returns true. - * @param {*} value - * @return {boolean} - */ -function eqNaN(value) { - return value !== value; -} - -/** - * If value1 is not null, then return value1, otherwise judget rest of values. - * Low performance. - * @memberOf module:zrender/core/util - * @return {*} Final value - */ -function retrieve(values) { - for (var i = 0, len = arguments.length; i < len; i++) { - if (arguments[i] != null) { - return arguments[i]; - } - } -} - -function retrieve2(value0, value1) { - return value0 != null - ? value0 - : value1; -} - -function retrieve3(value0, value1, value2) { - return value0 != null - ? value0 - : value1 != null - ? value1 - : value2; -} - -/** - * @memberOf module:zrender/core/util - * @param {Array} arr - * @param {number} startIndex - * @param {number} endIndex - * @return {Array} - */ -function slice() { - return Function.call.apply(nativeSlice, arguments); -} - -/** - * Normalize css liked array configuration - * e.g. - * 3 => [3, 3, 3, 3] - * [4, 2] => [4, 2, 4, 2] - * [4, 3, 2] => [4, 3, 2, 3] - * @param {number|Array.} val - * @return {Array.} - */ -function normalizeCssArray(val) { - if (typeof (val) === 'number') { - return [val, val, val, val]; - } - var len = val.length; - if (len === 2) { - // vertical | horizontal - return [val[0], val[1], val[0], val[1]]; - } - else if (len === 3) { - // top | horizontal | bottom - return [val[0], val[1], val[2], val[1]]; - } - return val; -} - -/** - * @memberOf module:zrender/core/util - * @param {boolean} condition - * @param {string} message - */ -function assert(condition, message) { - if (!condition) { - throw new Error(message); - } -} - -var primitiveKey = '__ec_primitive__'; -/** - * Set an object as primitive to be ignored traversing children in clone or merge - */ -function setAsPrimitive(obj) { - obj[primitiveKey] = true; -} - -function isPrimitive(obj) { - return obj[primitiveKey]; -} - -/** - * @constructor - * @param {Object} obj Only apply `ownProperty`. - */ -function HashMap(obj) { - obj && each(obj, function (value, key) { - this.set(key, value); - }, this); -} - -// Add prefix to avoid conflict with Object.prototype. -var HASH_MAP_PREFIX = '_ec_'; -var HASH_MAP_PREFIX_LENGTH = 4; - -HashMap.prototype = { - constructor: HashMap, - // Do not provide `has` method to avoid defining what is `has`. - // (We usually treat `null` and `undefined` as the same, different - // from ES6 Map). - get: function (key) { - return this[HASH_MAP_PREFIX + key]; - }, - set: function (key, value) { - this[HASH_MAP_PREFIX + key] = value; - // Comparing with invocation chaining, `return value` is more commonly - // used in this case: `var someVal = map.set('a', genVal());` - return value; - }, - // Although util.each can be performed on this hashMap directly, user - // should not use the exposed keys, who are prefixed. - each: function (cb, context) { - context !== void 0 && (cb = bind(cb, context)); - for (var prefixedKey in this) { - this.hasOwnProperty(prefixedKey) - && cb(this[prefixedKey], prefixedKey.slice(HASH_MAP_PREFIX_LENGTH)); - } - }, - // Do not use this method if performance sensitive. - removeKey: function (key) { - delete this[HASH_MAP_PREFIX + key]; - } -}; - -function createHashMap(obj) { - return new HashMap(obj); -} - -function noop() {} - -var $inject = { - createCanvas: function (f) { - createCanvas = f; /* ESM2CJS_REPLACE exports.createCanvas = f; */ - } -}; - - -/***/ }), -/* 139 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_claygl_src_math_BoundingBox__ = __webpack_require__(8); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_claygl_src_dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_claygl_src_dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1_claygl_src_dep_glmatrix__); - - -var vec3 = __WEBPACK_IMPORTED_MODULE_1_claygl_src_dep_glmatrix___default.a.vec3; - -function getBoundingBoxOfSkinningMesh(mesh, out) { - var pos = []; - var joint = []; - var weight = []; - var skinMatrices = []; - var skinnedPos = []; - var tmp = []; - - var geometry = mesh.geometry; - var skinMatricesArray = mesh.skeleton.getSubSkinMatrices(mesh.__GUID__, mesh.joints); - for (var i = 0; i < mesh.joints.length; i++) { - skinMatrices[i] = skinMatrices[i] || []; - for (var k = 0; k < 16; k++) { - skinMatrices[i][k] = skinMatricesArray[i * 16 + k]; - } - } - - var positionAttr = geometry.attributes.position; - var weightAttr = geometry.attributes.weight; - var jointAttr = geometry.attributes.joint; - - var min = [Infinity, Infinity, Infinity]; - var max = [-Infinity, -Infinity, -Infinity]; - - for (var i = 0; i < geometry.vertexCount; i++) { - positionAttr.get(i, pos); - weightAttr.get(i, weight); - jointAttr.get(i, joint); - weight[3] = 1 - weight[0] - weight[1] - weight[2]; - - vec3.set(skinnedPos, 0, 0, 0); - for (var k = 0; k < 4; k++) { - if (joint[k] >= 0 && weight[k] > 1e-6) { - vec3.transformMat4(tmp, pos, skinMatrices[joint[k]]); - vec3.scaleAndAdd(skinnedPos, skinnedPos, tmp, weight[k]); - } - } - - vec3.min(min, min, skinnedPos); - vec3.max(max, max, skinnedPos); - } - out.min.setArray(min); - out.max.setArray(max); -} - -function getBoundingBoxWithSkinning(node, out) { - - out = out || new __WEBPACK_IMPORTED_MODULE_0_claygl_src_math_BoundingBox__["a" /* default */](); - - var tmpBBox = new __WEBPACK_IMPORTED_MODULE_0_claygl_src_math_BoundingBox__["a" /* default */](); - node.traverse(function (mesh) { - if (mesh.geometry) { - if (mesh.isSkinnedMesh()) { - getBoundingBoxOfSkinningMesh(mesh, tmpBBox); - mesh.geometry.boundingBox.copy(tmpBBox); - } - else { - tmpBBox.copy(mesh.geometry.boundingBox); - tmpBBox.applyTransform(mesh.worldTransform); - } - out.union(tmpBBox); - } - }); - return out; -} - -/* harmony default export */ __webpack_exports__["a"] = (getBoundingBoxWithSkinning); - -/***/ }), -/* 140 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__math_Vector2__ = __webpack_require__(21); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__math_Vector3__ = __webpack_require__(2); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__GestureMgr__ = __webpack_require__(141); - - - - - -function firstNotNull() { - for (var i = 0, len = arguments.length; i < len; i++) { - if (arguments[i] != null) { - return arguments[i]; - } - } -} - -function convertToArray(val) { - if (!Array.isArray(val)) { - val = [val, val]; - } - return val; -} - -/** - * @constructor - * @alias clay.plugin.OrbitControl - */ -var OrbitControl = __WEBPACK_IMPORTED_MODULE_0__core_Base__["a" /* default */].extend(function () { - - return /** @lends clay.plugin.OrbitControl# */ { - - timeline: null, - - /** - * @type {HTMLDomElement} - */ - domElement: null, - - /** - * @type {clay.Node} - */ - target: null, - /** - * @type {clay.math.Vector3} - */ - _center: new __WEBPACK_IMPORTED_MODULE_2__math_Vector3__["a" /* default */](), - - /** - * Minimum distance to the center - * @type {number} - * @default 0.5 - */ - minDistance: 0.1, - - /** - * Maximum distance to the center - * @type {number} - * @default 2 - */ - maxDistance: 1000, - - /** - * Minimum alpha rotation - */ - minAlpha: -90, - - /** - * Maximum alpha rotation - */ - maxAlpha: 90, - - /** - * Minimum beta rotation - */ - minBeta: -Infinity, - /** - * Maximum beta rotation - */ - maxBeta: Infinity, - - /** - * Start auto rotating after still for the given time - */ - autoRotateAfterStill: 0, - - /** - * Direction of autoRotate. cw or ccw when looking top down. - */ - autoRotateDirection: 'cw', - - /** - * Degree per second - */ - autoRotateSpeed: 60, - - /** - * Pan or rotate - * @type {String} - */ - _mode: 'rotate', - - /** - * @param {number} - */ - damping: 0.8, - - /** - * @param {number} - */ - rotateSensitivity: 1, - - /** - * @param {number} - */ - zoomSensitivity: 1, - - /** - * @param {number} - */ - panSensitivity: 1, - - _needsUpdate: false, - - _rotating: false, - - // Rotation around yAxis - _phi: 0, - // Rotation around xAxis - _theta: 0, - - _mouseX: 0, - _mouseY: 0, - - _rotateVelocity: new __WEBPACK_IMPORTED_MODULE_1__math_Vector2__["a" /* default */](), - - _panVelocity: new __WEBPACK_IMPORTED_MODULE_1__math_Vector2__["a" /* default */](), - - _distance: 20, - - _zoomSpeed: 0, - - _stillTimeout: 0, - - _animators: [], - - _gestureMgr: new __WEBPACK_IMPORTED_MODULE_3__GestureMgr__["a" /* default */]() - }; -}, function () { - // Each OrbitControl has it's own handler - this._mouseDownHandler = this._mouseDownHandler.bind(this); - this._mouseWheelHandler = this._mouseWheelHandler.bind(this); - this._mouseMoveHandler = this._mouseMoveHandler.bind(this); - this._mouseUpHandler = this._mouseUpHandler.bind(this); - this._pinchHandler = this._pinchHandler.bind(this); - - this.update = this.update.bind(this); - - this.init(); -}, /** @lends clay.plugin.OrbitControl# */ { - /** - * Initialize. - * Mouse event binding - */ - init: function () { - var dom = this.domElement; - - dom.addEventListener('touchstart', this._mouseDownHandler); - - dom.addEventListener('mousedown', this._mouseDownHandler); - dom.addEventListener('mousewheel', this._mouseWheelHandler); - - if (this.timeline) { - this.timeline.on('frame', this.update); - } - }, - - /** - * Dispose. - * Mouse event unbinding - */ - dispose: function () { - var dom = this.domElement; - - dom.removeEventListener('touchstart', this._mouseDownHandler); - dom.removeEventListener('touchmove', this._mouseMoveHandler); - dom.removeEventListener('touchend', this._mouseUpHandler); - - dom.removeEventListener('mousedown', this._mouseDownHandler); - dom.removeEventListener('mousemove', this._mouseMoveHandler); - dom.removeEventListener('mouseup', this._mouseUpHandler); - dom.removeEventListener('mousewheel', this._mouseWheelHandler); - - if (this.timeline) { - this.timeline.off('frame', this.update); - } - this.stopAllAnimation(); - }, - - /** - * Get distance - * @return {number} - */ - getDistance: function () { - return this._distance; - }, - - /** - * Set distance - * @param {number} distance - */ - setDistance: function (distance) { - this._distance = distance; - this._needsUpdate = true; - }, - - /** - * Get alpha rotation - * Alpha angle for top-down rotation. Positive to rotate to top. - * - * Which means camera rotation around x axis. - */ - getAlpha: function () { - return this._theta / Math.PI * 180; - }, - - /** - * Get beta rotation - * Beta angle for left-right rotation. Positive to rotate to right. - * - * Which means camera rotation around y axis. - */ - getBeta: function () { - return -this._phi / Math.PI * 180; - }, - - /** - * Get control center - * @return {Array.} - */ - getCenter: function () { - return this._center.toArray(); - }, - - /** - * Set alpha rotation angle - * @param {number} alpha - */ - setAlpha: function (alpha) { - alpha = Math.max(Math.min(this.maxAlpha, alpha), this.minAlpha); - - this._theta = alpha / 180 * Math.PI; - this._needsUpdate = true; - }, - - /** - * Set beta rotation angle - * @param {number} beta - */ - setBeta: function (beta) { - beta = Math.max(Math.min(this.maxBeta, beta), this.minBeta); - - this._phi = -beta / 180 * Math.PI; - this._needsUpdate = true; - }, - - /** - * Set control center - * @param {Array.} center - */ - setCenter: function (centerArr) { - this._center.setArray(centerArr); - }, - - setOption: function (opts) { - opts = opts || {}; - - ['autoRotate', 'autoRotateAfterStill', - 'autoRotateDirection', 'autoRotateSpeed', - 'damping', - 'minDistance', 'maxDistance', - 'minAlpha', 'maxAlpha', 'minBeta', 'maxBeta', - 'rotateSensitivity', 'zoomSensitivity', 'panSensitivity' - ].forEach(function (key) { - if (opts[key] != null) { - this[key] = opts[key]; - } - }, this); - - if (opts.distance != null) { - this.setDistance(opts.distance); - } - - if (opts.alpha != null) { - this.setAlpha(opts.alpha); - } - if (opts.beta != null) { - this.setBeta(opts.beta); - } - - if (opts.center) { - this.setCenter(opts.center); - } - }, - - /** - * @param {Object} opts - * @param {number} opts.distance - * @param {number} opts.alpha - * @param {number} opts.beta - * @param {number} [opts.duration=1000] - * @param {number} [opts.easing='linear'] - * @param {number} [opts.done] - */ - animateTo: function (opts) { - var self = this; - - var obj = {}; - var target = {}; - var timeline = this.timeline; - if (!timeline) { - return; - } - if (opts.distance != null) { - obj.distance = this.getDistance(); - target.distance = opts.distance; - } - if (opts.alpha != null) { - obj.alpha = this.getAlpha(); - target.alpha = opts.alpha; - } - if (opts.beta != null) { - obj.beta = this.getBeta(); - target.beta = opts.beta; - } - if (opts.center != null) { - obj.center = this.getCenter(); - target.center = opts.center; - } - - return this._addAnimator( - timeline.animate(obj) - .when(opts.duration || 1000, target) - .during(function () { - if (obj.alpha != null) { - self.setAlpha(obj.alpha); - } - if (obj.beta != null) { - self.setBeta(obj.beta); - } - if (obj.distance != null) { - self.setDistance(obj.distance); - } - if (obj.center != null) { - self.setCenter(obj.center); - } - self._needsUpdate = true; - }) - .done(opts.done) - ).start(opts.easing || 'linear'); - }, - - /** - * Stop all animations - */ - stopAllAnimation: function () { - for (var i = 0; i < this._animators.length; i++) { - this._animators[i].stop(); - } - this._animators.length = 0; - }, - - _isAnimating: function () { - return this._animators.length > 0; - }, - /** - * Call update each frame - * @param {number} deltaTime Frame time - */ - update: function (deltaTime) { - - deltaTime = deltaTime || 16; - - if (this._rotating) { - var radian = (this.autoRotateDirection === 'cw' ? 1 : -1) - * this.autoRotateSpeed / 180 * Math.PI; - this._phi -= radian * deltaTime / 1000; - this._needsUpdate = true; - } - else if (this._rotateVelocity.len() > 0) { - this._needsUpdate = true; - } - - if (Math.abs(this._zoomSpeed) > 0.01 || this._panVelocity.len() > 0) { - this._needsUpdate = true; - } - - if (!this._needsUpdate) { - return; - } - - // Fixed deltaTime - this._updateDistance(Math.min(deltaTime, 50)); - this._updatePan(Math.min(deltaTime, 50)); - - this._updateRotate(Math.min(deltaTime, 50)); - - this._updateTransform(); - - this.target.update(); - - this.trigger('update'); - - this._needsUpdate = false; - }, - - _updateRotate: function (deltaTime) { - var velocity = this._rotateVelocity; - this._phi = velocity.y * deltaTime / 20 + this._phi; - this._theta = velocity.x * deltaTime / 20 + this._theta; - - this.setAlpha(this.getAlpha()); - this.setBeta(this.getBeta()); - - this._vectorDamping(velocity, this.damping); - }, - - _updateDistance: function (deltaTime) { - this._setDistance(this._distance + this._zoomSpeed * deltaTime / 20); - this._zoomSpeed *= this.damping; - }, - - _setDistance: function (distance) { - this._distance = Math.max(Math.min(distance, this.maxDistance), this.minDistance); - }, - - _updatePan: function (deltaTime) { - var velocity = this._panVelocity; - var len = this._distance; - - var target = this.target; - var yAxis = target.worldTransform.y; - var xAxis = target.worldTransform.x; - - // PENDING - this._center - .scaleAndAdd(xAxis, -velocity.x * len / 200) - .scaleAndAdd(yAxis, -velocity.y * len / 200); - - this._vectorDamping(velocity, 0); - }, - - _updateTransform: function () { - var camera = this.target; - - var dir = new __WEBPACK_IMPORTED_MODULE_2__math_Vector3__["a" /* default */](); - var theta = this._theta + Math.PI / 2; - var phi = this._phi + Math.PI / 2; - var r = Math.sin(theta); - - dir.x = r * Math.cos(phi); - dir.y = -Math.cos(theta); - dir.z = r * Math.sin(phi); - - camera.position.copy(this._center).scaleAndAdd(dir, this._distance); - camera.rotation.identity() - // First around y, then around x - .rotateY(-this._phi) - .rotateX(-this._theta); - }, - - _startCountingStill: function () { - clearTimeout(this._stillTimeout); - - var time = this.autoRotateAfterStill; - var self = this; - if (!isNaN(time) && time > 0) { - this._stillTimeout = setTimeout(function () { - self._rotating = true; - }, time * 1000); - } - }, - - _vectorDamping: function (v, damping) { - var speed = v.len(); - speed = speed * damping; - if (speed < 1e-4) { - speed = 0; - } - v.normalize().scale(speed); - }, - - decomposeTransform: function () { - if (!this.target) { - return; - } - - // FIXME euler order...... - // FIXME alpha is not certain when beta is 90 or -90 - // var euler = new Vector3(); - // euler.eulerFromMat3( - // new Matrix3().fromQuat(this.target.rotation), 'ZYX' - // ); - // euler.eulerFromQuat( - // this.target.rotation.normalize(), 'ZYX' - // ); - this.target.updateWorldTransform(); - - var forward = this.target.worldTransform.z; - var alpha = Math.asin(forward.y); - var beta = Math.atan2(forward.x, forward.z); - - this._theta = alpha; - this._phi = -beta; - - this.setBeta(this.getBeta()); - this.setAlpha(this.getAlpha()); - - this._setDistance(this.target.position.dist(this._center)); - }, - - _mouseDownHandler: function (e) { - if (this._isAnimating()) { - return; - } - var x = e.clientX; - var y = e.clientY; - // Touch - if (e.targetTouches) { - var touch = e.targetTouches[0]; - x = touch.clientX; - y = touch.clientY; - - this._mode = 'rotate'; - - this._processGesture(e, 'start'); - } - - var dom = this.domElement; - dom.addEventListener('touchmove', this._mouseMoveHandler); - dom.addEventListener('touchend', this._mouseUpHandler); - - dom.addEventListener('mousemove', this._mouseMoveHandler); - dom.addEventListener('mouseup', this._mouseUpHandler); - - if (e.button === 0) { - this._mode = 'rotate'; - } - else if (e.button === 1) { - this._mode = 'pan'; - } - - // Reset rotate velocity - this._rotateVelocity.set(0, 0); - this._rotating = false; - if (this.autoRotate) { - this._startCountingStill(); - } - - this._mouseX = x; - this._mouseY = y; - }, - - _mouseMoveHandler: function (e) { - if (this._isAnimating()) { - return; - } - var x = e.clientX; - var y = e.clientY; - - var haveGesture; - // Touch - if (e.targetTouches) { - var touch = e.targetTouches[0]; - x = touch.clientX; - y = touch.clientY; - - haveGesture = this._processGesture(e, 'change'); - } - - var panSensitivity = convertToArray(this.panSensitivity); - var rotateSensitivity = convertToArray(this.rotateSensitivity); - - if (!haveGesture) { - if (this._mode === 'rotate') { - this._rotateVelocity.y = (x - this._mouseX) / this.domElement.clientHeight * 2 * rotateSensitivity[0]; - this._rotateVelocity.x = (y - this._mouseY) / this.domElement.clientWidth * 2 * rotateSensitivity[1]; - } - else if (this._mode === 'pan') { - this._panVelocity.x = (x - this._mouseX) / this.domElement.clientWidth * panSensitivity[0] * 400; - this._panVelocity.y = (-y + this._mouseY) / this.domElement.clientHeight * panSensitivity[1] * 400; - } - } - - this._mouseX = x; - this._mouseY = y; - - e.preventDefault(); - }, - - _mouseWheelHandler: function (e) { - if (this._isAnimating()) { - return; - } - var delta = e.wheelDelta // Webkit - || -e.detail; // Firefox - if (delta === 0) { - return; - } - this._zoomHandler(e, delta > 0 ? -1 : 1); - }, - - _pinchHandler: function (e) { - if (this._isAnimating()) { - return; - } - this._zoomHandler(e, e.pinchScale > 1 ? -0.4 : 0.4); - }, - - _zoomHandler: function (e, delta) { - - var distance = Math.max(Math.min( - this._distance - this.minDistance, - this.maxDistance - this._distance - )); - this._zoomSpeed = delta * Math.max(distance / 40 * this.zoomSensitivity, 0.2); - - this._rotating = false; - - if (this.autoRotate && this._mode === 'rotate') { - this._startCountingStill(); - } - - e.preventDefault(); - }, - - _mouseUpHandler: function (event) { - var dom = this.domElement; - dom.removeEventListener('touchmove', this._mouseMoveHandler); - dom.removeEventListener('touchend', this._mouseUpHandler); - dom.removeEventListener('mousemove', this._mouseMoveHandler); - dom.removeEventListener('mouseup', this._mouseUpHandler); - - this._processGesture(event, 'end'); - }, - - _addAnimator: function (animator) { - var animators = this._animators; - animators.push(animator); - animator.done(function () { - var idx = animators.indexOf(animator); - if (idx >= 0) { - animators.splice(idx, 1); - } - }); - return animator; - }, - - - _processGesture: function (event, stage) { - var gestureMgr = this._gestureMgr; - - stage === 'start' && gestureMgr.clear(); - - var gestureInfo = gestureMgr.recognize( - event, - null, - this.domElement - ); - - stage === 'end' && gestureMgr.clear(); - - // Do not do any preventDefault here. Upper application do that if necessary. - if (gestureInfo) { - var type = gestureInfo.type; - event.gestureEvent = type; - - this._pinchHandler(gestureInfo.event); - } - - return gestureInfo; - } -}); - -/** - * If auto rotate the target - * @type {boolean} - * @default false - */ -Object.defineProperty(OrbitControl.prototype, 'autoRotate', { - get: function () { - return this._autoRotate; - }, - set: function (val) { - this._autoRotate = val; - this._rotating = val; - } -}); - -Object.defineProperty(OrbitControl.prototype, 'target', { - get: function () { - return this._target; - }, - set: function (val) { - if (val && val.target) { - this.setCenter(val.target.toArray()); - } - this._target = val; - this.decomposeTransform(); - } -}); - - -/* harmony default export */ __webpack_exports__["a"] = (OrbitControl); - - -/***/ }), -/* 141 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -var GestureMgr = function () { - - this._track = []; -}; - -GestureMgr.prototype = { - - constructor: GestureMgr, - - recognize: function (event, target, root) { - this._doTrack(event, target, root); - return this._recognize(event); - }, - - clear: function () { - this._track.length = 0; - return this; - }, - - _doTrack: function (event, target, root) { - var touches = event.targetTouches; - - if (!touches) { - return; - } - - var trackItem = { - points: [], - touches: [], - target: target, - event: event - }; - - for (var i = 0, len = touches.length; i < len; i++) { - var touch = touches[i]; - trackItem.points.push([touch.clientX, touch.clientY]); - trackItem.touches.push(touch); - } - - this._track.push(trackItem); - }, - - _recognize: function (event) { - for (var eventName in recognizers) { - if (recognizers.hasOwnProperty(eventName)) { - var gestureInfo = recognizers[eventName](this._track, event); - if (gestureInfo) { - return gestureInfo; - } - } - } - } -}; - -function dist(pointPair) { - var dx = pointPair[1][0] - pointPair[0][0]; - var dy = pointPair[1][1] - pointPair[0][1]; - - return Math.sqrt(dx * dx + dy * dy); -} - -function center(pointPair) { - return [ - (pointPair[0][0] + pointPair[1][0]) / 2, - (pointPair[0][1] + pointPair[1][1]) / 2 - ]; -} - -var recognizers = { - - pinch: function (track, event) { - var trackLen = track.length; - - if (!trackLen) { - return; - } - - var pinchEnd = (track[trackLen - 1] || {}).points; - var pinchPre = (track[trackLen - 2] || {}).points || pinchEnd; - - if (pinchPre - && pinchPre.length > 1 - && pinchEnd - && pinchEnd.length > 1 - ) { - var pinchScale = dist(pinchEnd) / dist(pinchPre); - !isFinite(pinchScale) && (pinchScale = 1); - - event.pinchScale = pinchScale; - - var pinchCenter = center(pinchEnd); - event.pinchX = pinchCenter[0]; - event.pinchY = pinchCenter[1]; - - return { - type: 'pinch', - target: track[0].target, - event: event - }; - } - } -}; - -/* harmony default export */ __webpack_exports__["a"] = (GestureMgr); - - -/***/ }), -/* 142 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_claygl_src_core_Base__ = __webpack_require__(1); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_claygl_src_math_Vector4__ = __webpack_require__(143); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_claygl_src_math_BoundingBox__ = __webpack_require__(8); - - - - -var DEFAULT_FAR_ALPHA = 0.1; -var DEFAULT_NEAR_ALPHA = 1.0; - -var HotspotManger = __WEBPACK_IMPORTED_MODULE_0_claygl_src_core_Base__["a" /* default */].extend(function () { - - return { - - /** - * @type {HTMLDomElement} - */ - dom: null, - - /** - * @type {clay.Renderer} - */ - renderer: null, - - /** - * @type {clay.camera.Perspective} - */ - camera: null, - - _boundingBox: new __WEBPACK_IMPORTED_MODULE_2_claygl_src_math_BoundingBox__["a" /* default */](), - - /** - * @type {HTMLDomElement} - * @private - */ - _hotspotRoot: null, - - _hotspots: [] - }; -}, function () { - if (!this.dom || !this.renderer || !this.camera) { - throw new Error('Tip manager needs `root`, `camera`, `renderer`'); - } - - var tipRoot = this._hotspotRoot = document.createElement('div'); - tipRoot.style.cssText = 'position:absolute;top:0;left:0;right:0;bottom:0;overflow:hidden;'; - this.dom.appendChild(tipRoot); -}, { - - setBoundingBox: function (min, max) { - this._boundingBox.min.setArray(min); - this._boundingBox.max.setArray(max); - }, - - add: function (position, tipDom) { - - if (typeof tipDom === 'string') { - var tipDom2 = document.createElement('div'); - tipDom2.innerHTML = tipDom; - tipDom = tipDom2; - } - - tipDom.classList.add('qmv-annotation'); - tipDom.style.position = 'absolute'; - - this._hotspotRoot.appendChild(tipDom); - - this._hotspots.push({ - position: position, - dom: tipDom - }); - - return tipDom; - }, - - remove: function (tipDom) { - var idx = -1; - for (var i = 0; i < this._hotspots.length; i++) { - if (this._hotspots[i].dom === tipDom) { - idx = i; - break; - } - } - if (idx >= 0) { - this._hotspots.splice(idx, 1); - this._hotspotRoot.removeChild(tipDom); - } - }, - - update: function () { - var pos = new __WEBPACK_IMPORTED_MODULE_1_claygl_src_math_Vector4__["a" /* default */](); - var tmpBBox = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_math_BoundingBox__["a" /* default */](); - this._hotspots.forEach(function (hotspot) { - - // Update position - var p = hotspot.position; - pos.set(p[0], p[1], p[2], 1); - pos.transformMat4(this.camera.viewMatrix); - var linearDepth = pos.z; - - pos.transformMat4(this.camera.projectionMatrix); - pos.scale(1 / pos.w); - - var x = (pos.x + 1.0) * 0.5 * this.renderer.getWidth(); - var y = (pos.y + 1.0) * 0.5 * this.renderer.getHeight(); - - hotspot.dom.style.left = x + 'px'; - hotspot.dom.style.top = this.renderer.getHeight() - y + 'px'; - - // Upadte alpha - var farAlpha = hotspot.farAlpha == null ? DEFAULT_FAR_ALPHA : hotspot.farAlpha; - var nearAlpha = hotspot.nearAlpha == null ? DEFAULT_NEAR_ALPHA : hotspot.nearAlpha; - - tmpBBox.copy(this._boundingBox); - tmpBBox.applyTransform(this.camera.viewMatrix); - var percent = (linearDepth - tmpBBox.max.z) / (tmpBBox.min.z - tmpBBox.max.z); - var alpha = Math.max(Math.min(percent, 1.0), 0.0) * (farAlpha - nearAlpha) + nearAlpha; - - hotspot.dom.style.opacity = 1; - - hotspot.onupdate && hotspot.onupdate(x, y); - }, this); - } -}); - -/* harmony default export */ __webpack_exports__["a"] = (HotspotManger); - -/***/ }), -/* 143 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix__ = __webpack_require__(0); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0__dep_glmatrix__); - -var vec4 = __WEBPACK_IMPORTED_MODULE_0__dep_glmatrix___default.a.vec4; - -/** - * @constructor - * @alias clay.math.Vector4 - * @param {number} x - * @param {number} y - * @param {number} z - * @param {number} w - */ -var Vector4 = function(x, y, z, w) { - - x = x || 0; - y = y || 0; - z = z || 0; - w = w || 0; - - /** - * Storage of Vector4, read and write of x, y, z, w will change the values in array - * All methods also operate on the array instead of x, y, z, w components - * @name array - * @type {Float32Array} - * @memberOf clay.math.Vector4# - */ - this.array = vec4.fromValues(x, y, z, w); - - /** - * Dirty flag is used by the Node to determine - * if the matrix is updated to latest - * @name _dirty - * @type {boolean} - * @memberOf clay.math.Vector4# - */ - this._dirty = true; -}; - -Vector4.prototype = { - - constructor: Vector4, - - /** - * Add b to self - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ - add: function(b) { - vec4.add(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Set x, y and z components - * @param {number} x - * @param {number} y - * @param {number} z - * @param {number} w - * @return {clay.math.Vector4} - */ - set: function(x, y, z, w) { - this.array[0] = x; - this.array[1] = y; - this.array[2] = z; - this.array[3] = w; - this._dirty = true; - return this; - }, - - /** - * Set x, y, z and w components from array - * @param {Float32Array|number[]} arr - * @return {clay.math.Vector4} - */ - setArray: function(arr) { - this.array[0] = arr[0]; - this.array[1] = arr[1]; - this.array[2] = arr[2]; - this.array[3] = arr[3]; - - this._dirty = true; - return this; - }, - - /** - * Clone a new Vector4 - * @return {clay.math.Vector4} - */ - clone: function() { - return new Vector4(this.x, this.y, this.z, this.w); - }, - - /** - * Copy from b - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ - copy: function(b) { - vec4.copy(this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Alias for distance - * @param {clay.math.Vector4} b - * @return {number} - */ - dist: function(b) { - return vec4.dist(this.array, b.array); - }, - - /** - * Distance between self and b - * @param {clay.math.Vector4} b - * @return {number} - */ - distance: function(b) { - return vec4.distance(this.array, b.array); - }, - - /** - * Alias for divide - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ - div: function(b) { - vec4.div(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Divide self by b - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ - divide: function(b) { - vec4.divide(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Dot product of self and b - * @param {clay.math.Vector4} b - * @return {number} - */ - dot: function(b) { - return vec4.dot(this.array, b.array); - }, - - /** - * Alias of length - * @return {number} - */ - len: function() { - return vec4.len(this.array); - }, - - /** - * Calculate the length - * @return {number} - */ - length: function() { - return vec4.length(this.array); - }, - /** - * Linear interpolation between a and b - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @param {number} t - * @return {clay.math.Vector4} - */ - lerp: function(a, b, t) { - vec4.lerp(this.array, a.array, b.array, t); - this._dirty = true; - return this; - }, - - /** - * Minimum of self and b - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ - min: function(b) { - vec4.min(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Maximum of self and b - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ - max: function(b) { - vec4.max(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Alias for multiply - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ - mul: function(b) { - vec4.mul(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Mutiply self and b - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ - multiply: function(b) { - vec4.multiply(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Negate self - * @return {clay.math.Vector4} - */ - negate: function() { - vec4.negate(this.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Normalize self - * @return {clay.math.Vector4} - */ - normalize: function() { - vec4.normalize(this.array, this.array); - this._dirty = true; - return this; - }, - - /** - * Generate random x, y, z, w components with a given scale - * @param {number} scale - * @return {clay.math.Vector4} - */ - random: function(scale) { - vec4.random(this.array, scale); - this._dirty = true; - return this; - }, - - /** - * Scale self - * @param {number} scale - * @return {clay.math.Vector4} - */ - scale: function(s) { - vec4.scale(this.array, this.array, s); - this._dirty = true; - return this; - }, - /** - * Scale b and add to self - * @param {clay.math.Vector4} b - * @param {number} scale - * @return {clay.math.Vector4} - */ - scaleAndAdd: function(b, s) { - vec4.scaleAndAdd(this.array, this.array, b.array, s); - this._dirty = true; - return this; - }, - - /** - * Alias for squaredDistance - * @param {clay.math.Vector4} b - * @return {number} - */ - sqrDist: function(b) { - return vec4.sqrDist(this.array, b.array); - }, - - /** - * Squared distance between self and b - * @param {clay.math.Vector4} b - * @return {number} - */ - squaredDistance: function(b) { - return vec4.squaredDistance(this.array, b.array); - }, - - /** - * Alias for squaredLength - * @return {number} - */ - sqrLen: function() { - return vec4.sqrLen(this.array); - }, - - /** - * Squared length of self - * @return {number} - */ - squaredLength: function() { - return vec4.squaredLength(this.array); - }, - - /** - * Alias for subtract - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ - sub: function(b) { - vec4.sub(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Subtract b from self - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ - subtract: function(b) { - vec4.subtract(this.array, this.array, b.array); - this._dirty = true; - return this; - }, - - /** - * Transform self with a Matrix4 m - * @param {clay.math.Matrix4} m - * @return {clay.math.Vector4} - */ - transformMat4: function(m) { - vec4.transformMat4(this.array, this.array, m.array); - this._dirty = true; - return this; - }, - - /** - * Transform self with a Quaternion q - * @param {clay.math.Quaternion} q - * @return {clay.math.Vector4} - */ - transformQuat: function(q) { - vec4.transformQuat(this.array, this.array, q.array); - this._dirty = true; - return this; - }, - - toString: function() { - return '[' + Array.prototype.join.call(this.array, ',') + ']'; - }, - - toArray: function () { - return Array.prototype.slice.call(this.array); - } -}; - -var defineProperty = Object.defineProperty; -// Getter and Setter -if (defineProperty) { - - var proto = Vector4.prototype; - /** - * @name x - * @type {number} - * @memberOf clay.math.Vector4 - * @instance - */ - defineProperty(proto, 'x', { - get: function () { - return this.array[0]; - }, - set: function (value) { - this.array[0] = value; - this._dirty = true; - } - }); - - /** - * @name y - * @type {number} - * @memberOf clay.math.Vector4 - * @instance - */ - defineProperty(proto, 'y', { - get: function () { - return this.array[1]; - }, - set: function (value) { - this.array[1] = value; - this._dirty = true; - } - }); - - /** - * @name z - * @type {number} - * @memberOf clay.math.Vector4 - * @instance - */ - defineProperty(proto, 'z', { - get: function () { - return this.array[2]; - }, - set: function (value) { - this.array[2] = value; - this._dirty = true; - } - }); - - /** - * @name w - * @type {number} - * @memberOf clay.math.Vector4 - * @instance - */ - defineProperty(proto, 'w', { - get: function () { - return this.array[3]; - }, - set: function (value) { - this.array[3] = value; - this._dirty = true; - } - }); -} - -// Supply methods that are not in place - -/** - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ -Vector4.add = function(out, a, b) { - vec4.add(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector4} out - * @param {number} x - * @param {number} y - * @param {number} z - * @return {clay.math.Vector4} - */ -Vector4.set = function(out, x, y, z, w) { - vec4.set(out.array, x, y, z, w); - out._dirty = true; -}; - -/** - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ -Vector4.copy = function(out, b) { - vec4.copy(out.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @return {number} - */ -Vector4.dist = function(a, b) { - return vec4.distance(a.array, b.array); -}; - -/** - * @function - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @return {number} - */ -Vector4.distance = Vector4.dist; - -/** - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ -Vector4.div = function(out, a, b) { - vec4.divide(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @function - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ -Vector4.divide = Vector4.div; - -/** - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @return {number} - */ -Vector4.dot = function(a, b) { - return vec4.dot(a.array, b.array); -}; - -/** - * @param {clay.math.Vector4} a - * @return {number} - */ -Vector4.len = function(b) { - return vec4.length(b.array); -}; - -// Vector4.length = Vector4.len; - -/** - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @param {number} t - * @return {clay.math.Vector4} - */ -Vector4.lerp = function(out, a, b, t) { - vec4.lerp(out.array, a.array, b.array, t); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ -Vector4.min = function(out, a, b) { - vec4.min(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ -Vector4.max = function(out, a, b) { - vec4.max(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ -Vector4.mul = function(out, a, b) { - vec4.multiply(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @function - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ -Vector4.multiply = Vector4.mul; - -/** - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @return {clay.math.Vector4} - */ -Vector4.negate = function(out, a) { - vec4.negate(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @return {clay.math.Vector4} - */ -Vector4.normalize = function(out, a) { - vec4.normalize(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector4} out - * @param {number} scale - * @return {clay.math.Vector4} - */ -Vector4.random = function(out, scale) { - vec4.random(out.array, scale); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @param {number} scale - * @return {clay.math.Vector4} - */ -Vector4.scale = function(out, a, scale) { - vec4.scale(out.array, a.array, scale); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @param {number} scale - * @return {clay.math.Vector4} - */ -Vector4.scaleAndAdd = function(out, a, b, scale) { - vec4.scaleAndAdd(out.array, a.array, b.array, scale); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @return {number} - */ -Vector4.sqrDist = function(a, b) { - return vec4.sqrDist(a.array, b.array); -}; - -/** - * @function - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @return {number} - */ -Vector4.squaredDistance = Vector4.sqrDist; - -/** - * @param {clay.math.Vector4} a - * @return {number} - */ -Vector4.sqrLen = function(a) { - return vec4.sqrLen(a.array); -}; -/** - * @function - * @param {clay.math.Vector4} a - * @return {number} - */ -Vector4.squaredLength = Vector4.sqrLen; - -/** - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ -Vector4.sub = function(out, a, b) { - vec4.subtract(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @function - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @param {clay.math.Vector4} b - * @return {clay.math.Vector4} - */ -Vector4.subtract = Vector4.sub; - -/** - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @param {clay.math.Matrix4} m - * @return {clay.math.Vector4} - */ -Vector4.transformMat4 = function(out, a, m) { - vec4.transformMat4(out.array, a.array, m.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.math.Vector4} out - * @param {clay.math.Vector4} a - * @param {clay.math.Quaternion} q - * @return {clay.math.Vector4} - */ -Vector4.transformQuat = function(out, a, q) { - vec4.transformQuat(out.array, a.array, q.array); - out._dirty = true; - return out; -}; - -/* harmony default export */ __webpack_exports__["a"] = (Vector4); - - -/***/ }), -/* 144 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export qmv.ground.vertex\n@import clay.lambert.vertex\n@end\n\n\n@export qmv.ground.fragment\n\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\nuniform float gridSize: 5;\nuniform float gridSize2: 1;\nuniform vec4 gridColor: [0, 0, 0, 1];\nuniform vec4 gridColor2: [0.3, 0.3, 0.3, 1];\n\nuniform float glossiness: 0.7;\n\n#ifdef SSAOMAP_ENABLED\nuniform sampler2D ssaoMap;\nuniform vec4 viewport : VIEWPORT;\n#endif\n\n#ifdef AMBIENT_LIGHT_COUNT\n@import clay.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import clay.header.ambient_sh_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n\n@import clay.plugin.compute_shadow_map\n\nvoid main()\n{\n gl_FragColor = color;\n\n float wx = v_WorldPosition.x;\n float wz = v_WorldPosition.z;\n float x0 = abs(fract(wx / gridSize - 0.5) - 0.5) / fwidth(wx) * gridSize / 2.0;\n float z0 = abs(fract(wz / gridSize - 0.5) - 0.5) / fwidth(wz) * gridSize / 2.0;\n\n float x1 = abs(fract(wx / gridSize2 - 0.5) - 0.5) / fwidth(wx) * gridSize2;\n float z1 = abs(fract(wz / gridSize2 - 0.5) - 0.5) / fwidth(wz) * gridSize2;\n\n float v0 = 1.0 - clamp(min(x0, z0), 0.0, 1.0);\n float v1 = 1.0 - clamp(min(x1, z1), 0.0, 1.0);\n if (v0 > 0.1) {\n gl_FragColor = mix(gl_FragColor, gridColor, v0);\n }\n else {\n gl_FragColor = mix(gl_FragColor, gridColor2, v1);\n }\n\n vec3 diffuseColor = vec3(0.0, 0.0, 0.0);\n\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {\n diffuseColor += ambientLightColor[_idx_];\n }\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseColor += calcAmbientSHLight(_idx_, v_Normal) * ambientSHLightColor[_idx_];\n }}\n#endif\n\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++)\n {\n vec3 lightDirection = -directionalLightDirection[i];\n vec3 lightColor = directionalLightColor[i];\n\n float ndl = dot(v_Normal, normalize(lightDirection));\n\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsDir[i];\n }\n#endif\n\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * shadowContrib;\n }\n#endif\n\n#ifdef SSAOMAP_ENABLED\n diffuseColor *= texture2D(ssaoMap, (gl_FragCoord.xy - viewport.xy) / viewport.zw).r;\n#endif\n\n gl_FragColor.rgb *= diffuseColor;\n\n gl_FragColor.a *= 1.0 - clamp(length(v_WorldPosition.xz) / 30.0, 0.0, 1.0);\n\n}\n\n@end"); - - -/***/ }), -/* 145 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__env__ = __webpack_require__(38); - - -/* harmony default export */ __webpack_exports__["a"] = (function () { - return { - - preZ: true, - - materials: [], - - takes: [], - - textureFlipY: false, - - zUpToYUp: false, - - shadow: true, - - environment: 'auto', - - viewControl: { - alpha: 20, - beta: 30, - distance: 18 - }, - - ground: { - show: true - }, - - mainLight: { - // If enable shadow of main light. - shadow: true, - // Quality of main light shadow. 'low'|'medium'|'high'|'ultra' - shadowQuality: 'medium', - // Intensity of main light - intensity: 0.8, - // Color of main light - color: '#fff', - // Alpha is rotation from bottom to up. - alpha: 45, - // Beta is rotation from left to right. - beta: 45, - - $padAngle: [0.25, 0.5] - }, - // Configuration of secondary light - secondaryLight: { - // If enable shadow of secondary light. - shadow: false, - shadowQuality: 'medium', - // Intensity of secondary light. Defaultly not enable secondary light. - intensity: 0, - // Color of secondary light. - color: '#fff', - alpha: 60, - beta: -50, - - $padAngle: [-50 / 180, 60 / 90] - }, - // Configuration of tertiary light - tertiaryLight: { - // If enable shadow of tertiary light. - shadow: false, - shadowQuality: 'medium', - // Intensity of secondary light. Defaultly not enable secondary light. - intensity: 0, - // Color of tertiary light. - color: '#fff', - alpha: 89, - beta: 0, - - $padAngle: [0, 89 / 90] - }, - // Configuration of constant ambient light. - // Which will add a constant color on any surface. - ambientLight: { - // ambient light intensity. - intensity: 0.0, - // ambient light color. - color: '#fff' - }, - ambientCubemapLight: { - // Environment panorama texture url for cubemap lighting - texture: __WEBPACK_IMPORTED_MODULE_0__env__["a" /* default */].ENV_TEXTURE_ROOT + 'pisa.hdr', - - $texture: 'pisa', - $textureOptions: ['pisa', 'Barce_Rooftop_C', 'Factory_Catwalk', 'Grand_Canyon_C', 'Ice_Lake', 'Hall', 'Old_Industrial_Hall'], - - // Exposure factor when parsing hdr format. - exposure: 3, - // Intensity of diffuse radiance. - diffuseIntensity: 0.5, - // Intensity of specular radiance. - specularIntensity: 0.5, - - $intensity: 0.5 - }, - // Configuration about post effects. - postEffect: { - // If enable post effects. - enable: true, - // Configuration about bloom post effect - bloom: { - // If enable bloom - enable: true, - // Intensity of bloom - intensity: 0.1 - }, - // Configuration about depth of field - depthOfField: { - enable: false, - // Focal distance of camera in word space. - focalDistance: 4, - // Focal range of camera in word space. in this range image will be absolutely sharp. - focalRange: 1, - // Max out of focus blur radius. - blurRadius: 5, - // fstop of camera. Smaller fstop will have shallow depth of field - fstop: 10, - // Blur quality. 'low'|'medium'|'high'|'ultra' - quality: 'medium', - - $qualityOptions: ['low', 'medium', 'high', 'ultra'] - }, - // Configuration about screen space ambient occulusion - screenSpaceAmbientOcclusion: { - // If enable SSAO - enable: false, - // Sampling radius in work space. - // Larger will produce more soft concat shadow. - // But also needs higher quality or it will have more obvious artifacts - radius: 1.5, - // Quality of SSAO. 'low'|'medium'|'high'|'ultra' - quality: 'medium', - // Intensity of SSAO - intensity: 1, - - $qualityOptions: ['low', 'medium', 'high', 'ultra'] - }, - // Configuration about screen space reflection - screenSpaceReflection: { - enable: false, - // Quality of SSR. 'low'|'medium'|'high'|'ultra' - quality: 'medium', - // Surface with less roughness will have reflection. - maxRoughness: 0.8, - - $qualityOptions: ['low', 'medium', 'high', 'ultra'] - }, - // Configuration about color correction - colorCorrection: { - // If enable color correction - enable: true, - exposure: 0, - brightness: 0, - contrast: 1, - saturation: 1, - // Lookup texture for color correction. - // See https://ecomfe.github.io/echarts-doc/public/cn/option-gl.html#globe.postEffect.colorCorrection.lookupTexture - lookupTexture: '' - }, - FXAA: { - // If enable FXAA - enable: false - } - } - }; -});; - -/***/ }), -/* 146 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; - -/* harmony default export */ __webpack_exports__["a"] = (function () { - return { - - name: '', - - type: 'pbrMetallicRoughness', - - color: '#fff', - - transparent: false, - alpha: 1, - alphaCutoff: 0, - - diffuseMap: '', - normalMap: '', - parallaxOcclusionScale: 0.01, - parallaxOcclusionMap: '', - - emission: '#fff', - emissionIntensity: 0, - emissiveMap: '', - - uvRepeat: [1, 1], - - // Metallic and roughness - metalness: 0, - roughness: 0.5, - metalnessMap: '', - roughnessMap: '', - - // Specular and glossiness - glossiness: 0.5, - specularColor: '#111', - glossinessMap: '', - specularMap: '', - - $alphaRange: [0, 1], - $alphaCutoffRange: [0, 1], - $metalnessRange: [0, 1], - $roughnessRange: [0, 1], - $glossinessRange: [0, 1], - $parallaxOcclusionScaleRange: [0, 0.1], - - $textureTiling: 1 - }; -}); - -/***/ }), -/* 147 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return init; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "e", function() { return saveModelFiles; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return createModelFilesURL; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "f", function() { return saveSceneConfig; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "g", function() { return writeTextureImage; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "d", function() { return removeProject; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return downloadProject; }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__env__ = __webpack_require__(38); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__glTFHelper__ = __webpack_require__(148); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_vendor_convert__ = __webpack_require__(149); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_mime_types__ = __webpack_require__(150); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_mime_types___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_3_mime_types__); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4_vendor_download__ = __webpack_require__(155); - - - - - - - -var fs; -var Buffer = BrowserFS.BFSRequire('buffer').Buffer; - -var FS_NOT_PREPARED_ERROR = 'File system not prepared yet.'; - -function extname(fileName) { - var idx = fileName.lastIndexOf('.'); - return idx >= 0 ? fileName.substr(idx + 1).toLowerCase() : ''; -} -// Simple method handling mkdir and dirname. -function mkdir(path, parentDir) { - var pathList = path.split('/'); - parentDir = parentDir || ''; - if (path.indexOf('/') === 0) { - pathList.shift(); - } - // Handle xxx//xxx - pathList = pathList.filter(function (item) { - return !!item; - }); - return new Promise(function (resolve, reject) { - if (!fs) { - reject(FS_NOT_PREPARED_ERROR); - return; - } - var current = pathList.shift(); - var dirName = parentDir + '/' + current; - fs.mkdir(dirName, function (err) { - if (!err || err.code === 'EEXIST') { - if (pathList.length) { - mkdir(pathList.join('/'), dirName).then(resolve).catch(reject); - } - else { - resolve(); - } - } - else { - reject(err.toString()); - } - }); - }); -} - -function rmdir(path) { - return new Promise(function (resolve, reject) { - if (!fs) { - reject(FS_NOT_PREPARED_ERROR); - return; - } - - ls(path).then(function (files) { - return Promise.all(files.map(function (fileName) { - return new Promise(function (resolve, reject) { - var filePath = path + '/' + fileName; - fs.lstat(filePath, function (err, stat) { - if (err) { - reject(err.toString()); - } - else { - stat.isDirectory() - ? rmdir(filePath).then(resolve, reject) - : fs.unlink(filePath, function (err) { - err ? reject(err.toString()) : resolve(); - }); - } - }); - }); - })); - }, reject) - .then(function () { - fs.rmdir(path, function (err) { - err ? reject(err.toString()) : resolve(); - }); - }, reject); - }); -} - -function dirname(path) { - var arr = path.split('/'); - arr.pop(); - return arr.join('/'); -} - -function writeFile(path, file) { - return new Promise(function (resolve, reject) { - if (!fs) { - reject(FS_NOT_PREPARED_ERROR); - } - FileAPI.readAsArrayBuffer(file, function (evt) { - if (evt.type === 'load') { - fs.writeFile(path, Buffer.from(evt.result), function (err) { - // Don't know why there is EEXIST error. - if (err && err.code !== 'EEXIST') { - reject(err); - } - else { - console.log('Writed file ' + file.name + ' ' + evt.result.byteLength); - resolve(); - } - }); - } - }); - }); -} - -function ls(path) { - return new Promise(function (resolve, reject) { - fs.readdir(path, function (err, files) { - if (err) { - reject(err); - } - else { - resolve(files); - } - }); - }); -} - -function init(cb) { - BrowserFS.install(window); - // Configures BrowserFS to use the LocalStorage file system. - BrowserFS.configure({ - fs: 'IndexedDB', - options: {} - // options: { - // size: 1024 * 1024 * 100, - // type: PERSISTENT - // } - }, function(e) { - if (e) { - // An error happened! - throw e; - } - fs = BrowserFS.BFSRequire('fs'); - - mkdir('/project').then(function () { - Promise.all([ - loadModelFromFS(), - loadSceneFromFS() - ]).then(function (result) { - if (!result[0]) { - cb(); - } - else { - cb && cb(result[0].glTF, result[0].filesMap, result[1]); - } - }).catch(function (err) { - cb(); - }); - }, function (err) { - cb(); - }); - }); -} - -function saveModelFiles(files) { - function doSave() { - return mkdir('/project/model').then(function () { - return Promise.all(files.map(function (file) { - return writeFile('/project/model/' + file.name, file); - })); - }); - } - - return rmdir('/project/model').then(function () { - return doSave(); - }, function (err) { - return doSave(); - }); -} - -function saveSceneConfig(sceneCfg) { - return mkdir('/project').then(function () { - return writeFile('/project/scene.json', new File( - [JSON.stringify(sceneCfg)], - 'scene.json', - { type: 'application/json' } - )); - }); -} - -function loadSceneFromFS() { - return new Promise(function (resolve, reject) { - if (!fs) { - reject(FS_NOT_PREPARED_ERROR); - return; - } - fs.readFile('/project/scene.json', 'utf-8', function (err, data) { - if (err) { - resolve(null); - } - else { - var json = null; - try { - json = JSON.parse(data); - } - catch(e) { - console.error(e); - } - resolve(json); - } - }); - }); -} - -function loadModelFromFS() { - return readModelFilesFromFS().then(function (files) { - return createModelFilesURL(files); - }); -} - -function writeTextureImage(file) { - return mkdir('/project/model').then(function () { - return writeFile('/project/model/' + file.name, file); - }); -} - -function removeProject() { - return rmdir('/project'); -} - -function readModelFilesFromFS() { - return ls('/project/model').then(function (files) { - return Promise.all(files.map(function (fileName) { - return new Promise(function (resolve, reject) { - fs.readFile('/project/model/' + fileName, function (err, data) { - if (err) { - reject(err); - } - else { - resolve(new File( - [data], - fileName, - { type: __WEBPACK_IMPORTED_MODULE_3_mime_types___default.a.lookup(extname(fileName))} - )); - } - }); - }); - })); - }); -} - -/** - * Create urls from files need for model loading. - */ -var currentFilesMap = {}; -function createModelFilesURL(files) { - return new Promise(function (resolve, reject) { - var glTFFile = files.find(function (file) { - return file.name.endsWith('.gltf'); - }); - var glBFile = files.find(function (file) { - return file.name.endsWith('.glb'); - }); - if (!glTFFile && !glBFile) { - if (undefined === 'electron') { - var validModelFiles = files.filter(function (file) { - var ext = extname(file.name); - return __WEBPACK_IMPORTED_MODULE_0__env__["a" /* default */].SUPPORTED_MODEL_FILES.indexOf(ext) >= 0; - }); - if (validModelFiles.length > 0) { - Object(__WEBPACK_IMPORTED_MODULE_2_vendor_convert__["a" /* default */])(validModelFiles).then(function (result) { - var _buffer = result.buffer; - // Buffer to array buffer - var glTFBuffer = _buffer.buffer.slice(_buffer.byteOffset, _buffer.byteOffset + _buffer.byteLength); - afterFileConvert(result.name, result.json, glTFBuffer); - }, function (err) { - reject('Failed to convert model:' + err.toString()); - }); - } - else { - reject('No model file found'); - } - } - else { - reject('No glTF file found'); - } - } - else { - afterFileConvert(); - } - - function afterFileConvert(glTFName, glTFText, glTFBuffer) { - files = files.filter(function (file) { - return file.name.match(/.(gltf|bin|glb)$/) - || file.type.match(/image/); - }); - - // Unload urls after use - for (var name in currentFilesMap) { - URL.revokeObjectURL(currentFilesMap[name]); - } - var filesMap = {}; - currentFilesMap = filesMap; - - function readAllFiles(cb) { - var count = 0; - files.forEach(function (file) { - if (file !== glTFFile) { - count++; - filesMap[file.name] = URL.createObjectURL(file); - } - }); - cb && cb(filesMap); - } - - if (glTFText) { - readAllFiles(function (filesMap) { - files.push(new File( - [glTFText], glTFName + '.gltf', { type: 'application/json' } - ), new File( - [glTFBuffer], glTFName + '.bin', { type: 'application/octet-stream' } - )); - resolve({ - glTF: JSON.parse(glTFText), filesMap: filesMap, - buffers: [glTFBuffer], - allFiles: files - }); - }); - } - else { - if (glBFile) { - FileAPI.readAsArrayBuffer(glBFile, function (evt) { - if (evt.type === 'load') { - readAllFiles(function (filesMap) { - resolve({ - glTF: evt.result, filesMap: filesMap, allFiles: files - }); - }); - } - }); - } - else if (glTFFile) { - FileAPI.readAsText(glTFFile, 'utf-8', function (evt) { - if (evt.type === 'load') { - // Success - // TODO json parse maybe failed - var json; - try { - json = JSON.parse(evt.result); - } - catch (e) { - resolve(null); - return; - } - readAllFiles(function (filesMap) { - resolve({ - glTF: json, filesMap: filesMap, allFiles: files - }); - }); - } - }); - } - } - } - }); -} - -function downloadProject(format, onsuccess, onerror) { - Promise.all([ - readModelFilesFromFS(), - loadSceneFromFS() - ]).then(function (result) { - var files = result[0]; - var loadedSceneCfg = result[1]; - - var zip = new JSZip(); - - var glTFFile; - var filesMap = {}; - files = (files || []).filter(function (file) { - if (file.name.endsWith('.gltf')) { - glTFFile = file; - } - else { - filesMap[file.name] = file; - return true; - } - }); - - if (!glTFFile) { - swal('No glTF file in project!'); - onerror && onerror(); - return; - } - - Promise.all(loadedSceneCfg.materials.map(function (matConfig, idx) { - // TODO Different material use same metalnessMap and roughnessMap. - if (matConfig.metalnessMap || matConfig.roughnessMap) { - var metalnessFile = filesMap[matConfig.metalnessMap]; - var roughnessFile = filesMap[matConfig.roughnessMap]; - return new Promise(function (resolve) { - Object(__WEBPACK_IMPORTED_MODULE_1__glTFHelper__["b" /* mergeMetallicRoughness */])(metalnessFile, roughnessFile, matConfig.metalness, matConfig.roughness).then(function (canvas) { - var fileName = matConfig.name + '$' + idx + '_metallicRoughness.png'; - var dataUrl = canvas.toDataURL(); - dataUrl = dataUrl.slice('data:image/png;base64,'.length); - zip.file(fileName, dataUrl, { - base64: true - }); - matConfig.metalnessMap = matConfig.roughnessMap = fileName; - - console.log('Merged %s, %s to %s', matConfig.metalnessMap, matConfig.roughnessMap, fileName); - - resolve(); - }); - }); - } - else if (matConfig.specularMap || matConfig.glossinessMap) { - var specularFile = filesMap[matConfig.specularMap]; - var glossinessFile = filesMap[matConfig.glossinessMap]; - return new Promise(function (resolve) { - Object(__WEBPACK_IMPORTED_MODULE_1__glTFHelper__["c" /* mergeSpecularGlossiness */])(specularFile, glossinessFile, matConfig.specularColor, matConfig.glossiness).then(function (canvas) { - var fileName = matConfig.name + '$' + idx + '_specularGlossiness.png'; - var dataUrl = canvas.toDataURL(); - dataUrl = dataUrl.slice('data:image/png;base64,'.length); - zip.file(fileName, dataUrl, { - base64: true - }); - matConfig.specularMap = matConfig.glossinessMap = fileName; - - console.log('Merged %s, %s to %s', matConfig.specularMap, matConfig.glossinessMap, fileName); - - resolve(); - }); - }); - } - return null; - }).filter(function (p) { return p != null; })).then(function () { - FileAPI.readAsText(glTFFile, 'utf-8', function (e) { - if (e.type == 'load') { - var newGLTF = Object(__WEBPACK_IMPORTED_MODULE_1__glTFHelper__["d" /* updateGLTFMaterials */])(JSON.parse(e.result), loadedSceneCfg); - newGLTF.extensionsUsed = newGLTF.extensionsUsed || []; - if (newGLTF.extensionsUsed.indexOf('KHR_materials_pbrSpecularGlossiness') < 0) { - newGLTF.extensionsUsed.push('KHR_materials_pbrSpecularGlossiness'); - } - ['extensionsUsed', 'images', 'textures', 'samplers', 'animations'].forEach(function (key) { - if (newGLTF[key] && !newGLTF[key].length) { - delete newGLTF[key]; - } - }); - if (!newGLTF.textures) { - delete newGLTF.samplers; - } - // Remove unused images - files = files.filter(function (file) { - if (file.type.match(/image/)) { - return newGLTF.images && newGLTF.images.some(function (img) { - return img.uri === file.name; - }); - } - // Other is binary file. - else if (file.name.endsWith('.bin')) { - return true; - } - }); - files.forEach(function (file) { - zip.file(file.name, file); - }); - - if (format === 'glb') { - var binaryFiles = []; - var imageFiles = []; - zip.forEach(function (path, file) { - (path.endsWith('.bin') ? binaryFiles : imageFiles).push({ - reader: zip.file(path).async('arraybuffer'), - name: path - }); - }); - Promise.all([ - Promise.all(binaryFiles.map(function (a) {return a.reader; })), - Promise.all(imageFiles.map(function (a) { return a.reader; })) - ]).then(function (res) { - var ab = Object(__WEBPACK_IMPORTED_MODULE_1__glTFHelper__["a" /* convertToBinary */])(newGLTF, res[0], res[1].reduce(function (obj, ab, idx) { - obj[imageFiles[idx].name] = ab; - return obj; - }, {})); - Object(__WEBPACK_IMPORTED_MODULE_4_vendor_download__["a" /* default */])(new Blob([ab], {type: 'model/json-binary'}), 'model.glb'); - onsuccess && onsuccess(); - }).catch(onerror); - } - else { - zip.file(glTFFile.name, JSON.stringify(newGLTF, null, 2)); - zip.generateAsync({ type: 'blob' }) - .then(function (blob) { - Object(__WEBPACK_IMPORTED_MODULE_4_vendor_download__["a" /* default */])(blob, 'model.zip'); - onsuccess && onsuccess(); - }).catch(onerror); - } - } - }); - }); - }).catch(function (err) { - swal(err.toString()); - onerror && onerror(); - }) -} - - - - -/***/ }), -/* 148 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "d", function() { return updateGLTFMaterials; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return mergeMetallicRoughness; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "c", function() { return mergeSpecularGlossiness; }); -/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return convertToBinary; }); -/* unused harmony export TEXTURES */ -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_graphic_helper__ = __webpack_require__(26); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_claygl_src_loader_GLTF__ = __webpack_require__(41); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture__ = __webpack_require__(3); - - - - -var TEXTURES = ['diffuseMap', 'normalMap', 'emissiveMap', 'metalnessMap', 'roughnessMap', 'specularMap', 'glossinessMap'] - -function prepareImageData(imgFiles, updateImgData) { - return new Promise(function (resolve, reject) { - Promise.all(imgFiles.map(function (imgFile) { - var imgUrl = imgFile && URL.createObjectURL(imgFile); - return new Promise(function (resolve, reject) { - if (!imgUrl) { - resolve(null); - } - else { - var img = new Image(); - img.src = imgUrl; - img.onload = function () { resolve(img); }; - } - }); - })).then(function (imgs) { - var firstImg = imgs.find(function (img) { - return img != null; - }); - if (!firstImg) { - resolve(null); - } - - var canvas = document.createElement('canvas'); - var ctx = canvas.getContext('2d'); - var width = canvas.width = firstImg.width; - var height = canvas.height = firstImg.height; - - var imageDataList = imgs.map(function (img) { - if (img) { - ctx.drawImage(img, 0, 0, width, height); - return ctx.getImageData(0, 0, width, height).data; - } - return null; - }); - resolve({ - canvas: canvas, - imageDataList: imageDataList - }); - }); - }); -} - -function mergeMetallicRoughness(metallicFile, roughnessFile, metallicFactor, roughnessFactor) { - return new Promise(function (resolve, reject) { - prepareImageData([metallicFile, roughnessFile]) - .then(function (result) { - var canvas = result.canvas; - var ctx = canvas.getContext('2d'); - var metallicImgData = result.imageDataList[0]; - var roughnessImgData = result.imageDataList[1]; - var finalImgData = ctx.createImageData(canvas.width, canvas.height); - for (var i = 0; i < (metallicImgData || roughnessImgData).length; i += 4) { - var m = metallicFactor; - if (metallicImgData) { - // Metallic use B channel. - // TODO Specified channel ? - var m2 = metallicImgData[i + 2] / 255; - m = Math.min(Math.max(m2 + (m - 0.5) * 2, 0), 1); - } - var r = roughnessFactor; - if (roughnessImgData) { - // Roughness use G channel. - // TODO Specified channel ? - var r2 = roughnessImgData[i + 1] / 255; - r = Math.min(Math.max(r2 + (r - 0.5) * 2, 0), 1); - } - finalImgData.data[i] = finalImgData.data[i + 3] = 0; - finalImgData.data[i + 1] = Math.round(r * 255); - finalImgData.data[i + 2] = Math.round(m * 255); - } - ctx.putImageData(finalImgData, 0, 0); - - resolve(canvas); - }); - }); -} - -function mergeSpecularGlossiness(specularFile, glossinessFile, specularFactor, glossinessFactor) { - specularFactor = __WEBPACK_IMPORTED_MODULE_0__src_graphic_helper__["a" /* default */].parseColor(specularFactor).slice(0, 3); - return new Promise(function (resolve, reject) { - prepareImageData([specularFile, glossinessFile]) - .then(function (result) { - var canvas = result.canvas; - var ctx = canvas.getContext('2d'); - var specularImgData = result.imageDataList[0]; - var glossinessImgData = result.imageDataList[1]; - var finalImgData = ctx.createImageData(canvas.width, canvas.height); - for (var i = 0; i < (specularImgData || glossinessImgData).length; i += 4) { - var spec = specularFactor.slice(); - if (specularImgData) { - spec[0] *= specularImgData[i] / 255; - spec[1] *= specularImgData[i + 1] / 255; - spec[2] *= specularImgData[i + 2] / 255; - } - var g = glossinessFactor; - if (glossinessImgData) { - // Roughness use G channel. - // TODO Specified channel ? - var g2 = glossinessImgData[i + 3] / 255; - g = Math.min(Math.max(g2 + (g - 0.5) * 2, 0), 1); - } - for (var k = 0; k < 3; k++) { - finalImgData.data[i + k] = Math.round(spec[k] * 255); - } - finalImgData.data[i + 3] = Math.round(g * 255); - } - ctx.putImageData(finalImgData, 0, 0); - - resolve(canvas); - }); - }); -} - -function writeTextures(glTF, sceneConfig) { - var textureIndices = {}; - var currentIndex = 0; - glTF.images = []; - glTF.textures = []; - glTF.samplers = [{ - minFilter: __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture__["a" /* default */].LINEAR_MIPMAP_LINEAR, - magFilter: __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture__["a" /* default */].LINEAR, - wrapS: __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture__["a" /* default */].REPEAT, - wrapT: __WEBPACK_IMPORTED_MODULE_2_claygl_src_Texture__["a" /* default */].REPEAT - }]; - sceneConfig.materials.forEach(function (matConfig, idx) { - // metalnessMap is already merged with roughnessMap - TEXTURES.forEach(function (texName) { - if (matConfig[texName] && !textureIndices.hasOwnProperty(texName)) { - glTF.images.push({ - uri: matConfig[texName] - }); - glTF.textures.push({ - sampler: 0, - source: currentIndex - }); - textureIndices[matConfig[texName]] = currentIndex++; - } - }); - }); - - return textureIndices; -} - -function getMetallicRoughnessMat(matConfig, textureIndices) { - var metallicRoughness = { - baseColorFactor: __WEBPACK_IMPORTED_MODULE_0__src_graphic_helper__["a" /* default */].parseColor(matConfig.color), - metallicFactor: matConfig.metalness, - roughnessFactor: matConfig.roughness - }; - metallicRoughness.baseColorFactor[3] = matConfig.alpha; - if (matConfig.diffuseMap) { - metallicRoughness.baseColorTexture = { - index: textureIndices[matConfig.diffuseMap], - texCoord: 0 - }; - } - if (matConfig.metalnessMap) { - // metalnessMap is already merged with roughnessMap - metallicRoughness.metallicRoughnessTexture = { - index: textureIndices[matConfig.metalnessMap], - texCoord: 0 - }; - metallicRoughness.metallicFactor = 1; - metallicRoughness.roughnessFactor = 1; - } - - return metallicRoughness; -} - -function getSpecularGlossiness(matConfig, textureIndices) { - var specularGlossiness = { - diffuseFactor: __WEBPACK_IMPORTED_MODULE_0__src_graphic_helper__["a" /* default */].parseColor(matConfig.color), - specularFactor: __WEBPACK_IMPORTED_MODULE_0__src_graphic_helper__["a" /* default */].parseColor(matConfig.specularColor).slice(0, 3), - glossinessFactor: matConfig.glossiness - }; - specularGlossiness.diffuseFactor[3] = matConfig.alpha; - if (matConfig.diffuseMap) { - specularGlossiness.diffuseTexture = { - index: textureIndices[matConfig.diffuseMap], - texCoord: 0 - }; - } - if (matConfig.specularMap) { - // specularMap is already merged with glossinessMap - specularGlossiness.specularGlossinessTexture = { - index: textureIndices[matConfig.specularMap], - texCoord: 0 - }; - specularGlossiness.specularFactor = [1, 1, 1]; - specularGlossiness.glossinessFactor = 1; - } - - return specularGlossiness; -} - -function updateGLTFMaterials(glTF, sceneConfig) { - if (!glTF.materials) { - return; - } - var textureIndices = writeTextures(glTF, sceneConfig); - - var primitivesMap = {}; - glTF.materials = []; - glTF.nodes.forEach(function (nodeInfo, nodeIdx) { - if (nodeInfo.mesh != null) { - var meshInfo = glTF.meshes[nodeInfo.mesh]; - if (meshInfo.primitives.length === 1) { - // Use node name instead of mesh name. - // FIXME Hard coded - primitivesMap[nodeInfo.name] = meshInfo.primitives[0]; - } - else { - meshInfo.primitives.forEach(function (primitive, idx) { - primitivesMap[__WEBPACK_IMPORTED_MODULE_1_claygl_src_loader_GLTF__["a" /* default */].generateMeshName(glTF.meshes, nodeInfo.mesh, idx)] = primitive; - }); - } - } - }); - - sceneConfig.materials.forEach(function (matConfig, idx) { - var gltfMat = { - name: matConfig.name, - emissiveFactor: __WEBPACK_IMPORTED_MODULE_0__src_graphic_helper__["a" /* default */].parseColor(matConfig.emission).slice(0, 3).map(function (channel) { - return channel * matConfig.emissionIntensity; - }) - // TODO Alpha mode - // TODO texture tiling. - }; - if (matConfig.normalMap) { - gltfMat.normalTexture = { - texCoord: 0, - scale: 1, - index: textureIndices[matConfig.normalMap] - }; - } - if (matConfig.emissiveMap) { - gltfMat.emissiveTexture = { - texCoord: 0, - index: textureIndices[matConfig.emissiveMap] - }; - } - - if (matConfig.type === 'pbrMetallicRoughness') { - gltfMat.pbrMetallicRoughness = getMetallicRoughnessMat(matConfig, textureIndices); - } - else { - gltfMat.extensions = { - 'KHR_materials_pbrSpecularGlossiness': getSpecularGlossiness(matConfig, textureIndices) - }; - } - matConfig.targetMeshes.forEach(function (meshName) { - primitivesMap[meshName].material = idx; - }); - glTF.materials[idx] = gltfMat; - }); - - glTF.extras = glTF.extras || {}; - glTF.extras.clayViewerConfig = sceneConfig; - return glTF; -} - -function convertToBinary(glTF, binaryBuffers, imageBuffersMap) { - - function alignedLength(len) { - return Math.ceil(len / 4) * 4; - } - - var bufferOffset = 0; - var bufferOffsets = []; - var buffers = binaryBuffers.slice(); - glTF.buffers.forEach(function (buffer) { - bufferOffsets.push(bufferOffset); - bufferOffset += alignedLength(buffer.byteLength); - delete buffer.uri; - }); - - glTF.bufferViews.forEach(function (bufferView) { - if (bufferView.byteOffset == null) { - bufferView.byteOffset = 0; - } - else { - bufferView.byteOffset = bufferView.byteOffset + bufferOffsets[bufferView.buffer]; - } - }); - - (glTF.images || []).forEach(function (imageInfo, idx) { - var uri = imageInfo.uri; - var imageBuffer = imageBuffersMap[uri]; - delete imageInfo.uri; - if (!imageBuffer) { - return; - } - var bufferView = { - buffer: 0, - byteOffset: bufferOffset, - byteLength: imageBuffer.byteLength - }; - bufferOffsets.push(bufferOffset); - bufferOffset += alignedLength(imageBuffer.byteLength); - imageInfo.bufferView = glTF.bufferViews.length; - imageInfo.mimeType = getMimeType(uri); - glTF.bufferViews.push(bufferView); - buffers.push(imageBuffer); - }); - var binBufferSize = bufferOffset; - glTF.buffers = [{ - byteLength: binBufferSize - }]; - var enc = new TextEncoder(); - var jsonBuffer = enc.encode(JSON.stringify(glTF)); - var jsonAlignedLength = alignedLength(jsonBuffer.length); - var padding; - if (jsonAlignedLength !== jsonBuffer.length) { - padding = jsonAlignedLength - jsonBuffer.length; - } - var totalSize = 12 + // file header: magic + version + length - 8 + // json chunk header: json length + type - jsonAlignedLength + - 8 + // bin chunk header: chunk length + type - binBufferSize; - var outBuffer = new ArrayBuffer(totalSize); - var dataView = new DataView(outBuffer); - var bufIndex = 0; - // Magic number - dataView.setUint32(bufIndex, 0x46546C67, true); - bufIndex += 4; - // Version - dataView.setUint32(bufIndex, 2, true); - bufIndex += 4; - dataView.setUint32(bufIndex, totalSize, true); - bufIndex += 4; - // JSON - dataView.setUint32(bufIndex, jsonAlignedLength, true); - bufIndex += 4; - dataView.setUint32(bufIndex, 0x4E4F534A, true); - bufIndex += 4; - for (var j = 0; j< jsonBuffer.length; j++){ - dataView.setUint8(bufIndex++, jsonBuffer[j]); - } - if (padding != null) { - for (var j = 0; j< padding;j++) { - dataView.setUint8(bufIndex++, 0x20); - } - } - // BIN - dataView.setUint32(bufIndex, binBufferSize, true); - bufIndex += 4; - dataView.setUint32(bufIndex, 0x004E4942, true); - bufIndex += 4; - for (var i = 0; i < buffers.length; i++) { - var bufoffset = bufIndex + bufferOffsets[i]; - var buf = new Uint8Array(buffers[i]); - var thisbufindex = bufoffset; - for (var j = 0; j < buf.byteLength; j++) { - dataView.setUint8(thisbufindex, buf[j]); - thisbufindex++; - } - } - - return outBuffer; -} -// https://github.com/sbtron/makeglb/blob/master/index.html -function getMimeType(filename) { - for (var mimeType in MILE_TYPES) { - for (var extensionIndex in MILE_TYPES[mimeType]) { - var extension = MILE_TYPES[mimeType][extensionIndex]; - if (filename.toLowerCase().endsWith('.' + extension)) { - return mimeType; - } - } - } - return 'application/octet-stream'; -} -var MILE_TYPES = { - 'image/png': ['png'], - 'image/jpeg': ['jpg', 'jpeg'], - 'text/plain': ['glsl', 'vert', 'vs', 'frag', 'fs', 'txt'], - 'image/vnd-ms.dds': ['dds'] -}; - - - -/***/ }), -/* 149 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = (function () { - -}); - -/***/ }), -/* 150 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! +!function(e){function t(a){if(n[a])return n[a].exports;var i=n[a]={i:a,l:!1,exports:{}};return e[a].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};t.m=e,t.c=n,t.d=function(e,n,a){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:a})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=66)}([function(e,t,n){(function(e){!function(n){"use strict";var a={};a.exports=t,function(t){var n="undefined"==typeof window?e:window,a=n.GLMAT_EPSILON;null==a&&(a=1e-6);var i=n.GLMAT_ARRAY_TYPE||Array,r=n.GLMAT_RANDOM;r||(r=Math.random);var o={};o.setMatrixArrayType=function(e){i=e},void 0!==t&&(t.glMatrix=o);var s=Math.PI/180;o.toRadian=function(e){return e*s};var c={};c.create=function(){var e=new i(2);return e[0]=0,e[1]=0,e},c.clone=function(e){var t=new i(2);return t[0]=e[0],t[1]=e[1],t},c.fromValues=function(e,t){var n=new i(2);return n[0]=e,n[1]=t,n},c.copy=function(e,t){return e[0]=t[0],e[1]=t[1],e},c.set=function(e,t,n){return e[0]=t,e[1]=n,e},c.add=function(e,t,n){return e[0]=t[0]+n[0],e[1]=t[1]+n[1],e},c.subtract=function(e,t,n){return e[0]=t[0]-n[0],e[1]=t[1]-n[1],e},c.sub=c.subtract,c.multiply=function(e,t,n){return e[0]=t[0]*n[0],e[1]=t[1]*n[1],e},c.mul=c.multiply,c.divide=function(e,t,n){return e[0]=t[0]/n[0],e[1]=t[1]/n[1],e},c.div=c.divide,c.min=function(e,t,n){return e[0]=Math.min(t[0],n[0]),e[1]=Math.min(t[1],n[1]),e},c.max=function(e,t,n){return e[0]=Math.max(t[0],n[0]),e[1]=Math.max(t[1],n[1]),e},c.scale=function(e,t,n){return e[0]=t[0]*n,e[1]=t[1]*n,e},c.scaleAndAdd=function(e,t,n,a){return e[0]=t[0]+n[0]*a,e[1]=t[1]+n[1]*a,e},c.distance=function(e,t){var n=t[0]-e[0],a=t[1]-e[1];return Math.sqrt(n*n+a*a)},c.dist=c.distance,c.squaredDistance=function(e,t){var n=t[0]-e[0],a=t[1]-e[1];return n*n+a*a},c.sqrDist=c.squaredDistance,c.length=function(e){var t=e[0],n=e[1];return Math.sqrt(t*t+n*n)},c.len=c.length,c.squaredLength=function(e){var t=e[0],n=e[1];return t*t+n*n},c.sqrLen=c.squaredLength,c.negate=function(e,t){return e[0]=-t[0],e[1]=-t[1],e},c.inverse=function(e,t){return e[0]=1/t[0],e[1]=1/t[1],e},c.normalize=function(e,t){var n=t[0],a=t[1],i=n*n+a*a;return i>0&&(i=1/Math.sqrt(i),e[0]=t[0]*i,e[1]=t[1]*i),e},c.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]},c.cross=function(e,t,n){var a=t[0]*n[1]-t[1]*n[0];return e[0]=e[1]=0,e[2]=a,e},c.lerp=function(e,t,n,a){var i=t[0],r=t[1];return e[0]=i+a*(n[0]-i),e[1]=r+a*(n[1]-r),e},c.random=function(e,t){t=t||1;var n=2*r()*Math.PI;return e[0]=Math.cos(n)*t,e[1]=Math.sin(n)*t,e},c.transformMat2=function(e,t,n){var a=t[0],i=t[1];return e[0]=n[0]*a+n[2]*i,e[1]=n[1]*a+n[3]*i,e},c.transformMat2d=function(e,t,n){var a=t[0],i=t[1];return e[0]=n[0]*a+n[2]*i+n[4],e[1]=n[1]*a+n[3]*i+n[5],e},c.transformMat3=function(e,t,n){var a=t[0],i=t[1];return e[0]=n[0]*a+n[3]*i+n[6],e[1]=n[1]*a+n[4]*i+n[7],e},c.transformMat4=function(e,t,n){var a=t[0],i=t[1];return e[0]=n[0]*a+n[4]*i+n[12],e[1]=n[1]*a+n[5]*i+n[13],e},c.forEach=function(){var e=c.create();return function(t,n,a,i,r,o){var s,c;for(n||(n=2),a||(a=0),c=i?Math.min(i*n+a,t.length):t.length,s=a;s0&&(r=1/Math.sqrt(r),e[0]=t[0]*r,e[1]=t[1]*r,e[2]=t[2]*r),e},l.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]},l.cross=function(e,t,n){var a=t[0],i=t[1],r=t[2],o=n[0],s=n[1],c=n[2];return e[0]=i*c-r*s,e[1]=r*o-a*c,e[2]=a*s-i*o,e},l.lerp=function(e,t,n,a){var i=t[0],r=t[1],o=t[2];return e[0]=i+a*(n[0]-i),e[1]=r+a*(n[1]-r),e[2]=o+a*(n[2]-o),e},l.random=function(e,t){t=t||1;var n=2*r()*Math.PI,a=2*r()-1,i=Math.sqrt(1-a*a)*t;return e[0]=Math.cos(n)*i,e[1]=Math.sin(n)*i,e[2]=a*t,e},l.transformMat4=function(e,t,n){var a=t[0],i=t[1],r=t[2],o=n[3]*a+n[7]*i+n[11]*r+n[15];return o=o||1,e[0]=(n[0]*a+n[4]*i+n[8]*r+n[12])/o,e[1]=(n[1]*a+n[5]*i+n[9]*r+n[13])/o,e[2]=(n[2]*a+n[6]*i+n[10]*r+n[14])/o,e},l.transformMat3=function(e,t,n){var a=t[0],i=t[1],r=t[2];return e[0]=a*n[0]+i*n[3]+r*n[6],e[1]=a*n[1]+i*n[4]+r*n[7],e[2]=a*n[2]+i*n[5]+r*n[8],e},l.transformQuat=function(e,t,n){var a=t[0],i=t[1],r=t[2],o=n[0],s=n[1],c=n[2],l=n[3],u=l*a+s*r-c*i,p=l*i+c*a-o*r,d=l*r+o*i-s*a,f=-o*a-s*i-c*r;return e[0]=u*l+f*-o+p*-c-d*-s,e[1]=p*l+f*-s+d*-o-u*-c,e[2]=d*l+f*-c+u*-s-p*-o,e},l.rotateX=function(e,t,n,a){var i=[],r=[];return i[0]=t[0]-n[0],i[1]=t[1]-n[1],i[2]=t[2]-n[2],r[0]=i[0],r[1]=i[1]*Math.cos(a)-i[2]*Math.sin(a),r[2]=i[1]*Math.sin(a)+i[2]*Math.cos(a),e[0]=r[0]+n[0],e[1]=r[1]+n[1],e[2]=r[2]+n[2],e},l.rotateY=function(e,t,n,a){var i=[],r=[];return i[0]=t[0]-n[0],i[1]=t[1]-n[1],i[2]=t[2]-n[2],r[0]=i[2]*Math.sin(a)+i[0]*Math.cos(a),r[1]=i[1],r[2]=i[2]*Math.cos(a)-i[0]*Math.sin(a),e[0]=r[0]+n[0],e[1]=r[1]+n[1],e[2]=r[2]+n[2],e},l.rotateZ=function(e,t,n,a){var i=[],r=[];return i[0]=t[0]-n[0],i[1]=t[1]-n[1],i[2]=t[2]-n[2],r[0]=i[0]*Math.cos(a)-i[1]*Math.sin(a),r[1]=i[0]*Math.sin(a)+i[1]*Math.cos(a),r[2]=i[2],e[0]=r[0]+n[0],e[1]=r[1]+n[1],e[2]=r[2]+n[2],e},l.forEach=function(){var e=l.create();return function(t,n,a,i,r,o){var s,c;for(n||(n=3),a||(a=0),c=i?Math.min(i*n+a,t.length):t.length,s=a;s1?0:Math.acos(i)},l.str=function(e){return"vec3("+e[0]+", "+e[1]+", "+e[2]+")"},void 0!==t&&(t.vec3=l);var u={};u.create=function(){var e=new i(4);return e[0]=0,e[1]=0,e[2]=0,e[3]=0,e},u.clone=function(e){var t=new i(4);return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t},u.fromValues=function(e,t,n,a){var r=new i(4);return r[0]=e,r[1]=t,r[2]=n,r[3]=a,r},u.copy=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e},u.set=function(e,t,n,a,i){return e[0]=t,e[1]=n,e[2]=a,e[3]=i,e},u.add=function(e,t,n){return e[0]=t[0]+n[0],e[1]=t[1]+n[1],e[2]=t[2]+n[2],e[3]=t[3]+n[3],e},u.subtract=function(e,t,n){return e[0]=t[0]-n[0],e[1]=t[1]-n[1],e[2]=t[2]-n[2],e[3]=t[3]-n[3],e},u.sub=u.subtract,u.multiply=function(e,t,n){return e[0]=t[0]*n[0],e[1]=t[1]*n[1],e[2]=t[2]*n[2],e[3]=t[3]*n[3],e},u.mul=u.multiply,u.divide=function(e,t,n){return e[0]=t[0]/n[0],e[1]=t[1]/n[1],e[2]=t[2]/n[2],e[3]=t[3]/n[3],e},u.div=u.divide,u.min=function(e,t,n){return e[0]=Math.min(t[0],n[0]),e[1]=Math.min(t[1],n[1]),e[2]=Math.min(t[2],n[2]),e[3]=Math.min(t[3],n[3]),e},u.max=function(e,t,n){return e[0]=Math.max(t[0],n[0]),e[1]=Math.max(t[1],n[1]),e[2]=Math.max(t[2],n[2]),e[3]=Math.max(t[3],n[3]),e},u.scale=function(e,t,n){return e[0]=t[0]*n,e[1]=t[1]*n,e[2]=t[2]*n,e[3]=t[3]*n,e},u.scaleAndAdd=function(e,t,n,a){return e[0]=t[0]+n[0]*a,e[1]=t[1]+n[1]*a,e[2]=t[2]+n[2]*a,e[3]=t[3]+n[3]*a,e},u.distance=function(e,t){var n=t[0]-e[0],a=t[1]-e[1],i=t[2]-e[2],r=t[3]-e[3];return Math.sqrt(n*n+a*a+i*i+r*r)},u.dist=u.distance,u.squaredDistance=function(e,t){var n=t[0]-e[0],a=t[1]-e[1],i=t[2]-e[2],r=t[3]-e[3];return n*n+a*a+i*i+r*r},u.sqrDist=u.squaredDistance,u.length=function(e){var t=e[0],n=e[1],a=e[2],i=e[3];return Math.sqrt(t*t+n*n+a*a+i*i)},u.len=u.length,u.squaredLength=function(e){var t=e[0],n=e[1],a=e[2],i=e[3];return t*t+n*n+a*a+i*i},u.sqrLen=u.squaredLength,u.negate=function(e,t){return e[0]=-t[0],e[1]=-t[1],e[2]=-t[2],e[3]=-t[3],e},u.inverse=function(e,t){return e[0]=1/t[0],e[1]=1/t[1],e[2]=1/t[2],e[3]=1/t[3],e},u.normalize=function(e,t){var n=t[0],a=t[1],i=t[2],r=t[3],o=n*n+a*a+i*i+r*r;return o>0&&(o=1/Math.sqrt(o),e[0]=t[0]*o,e[1]=t[1]*o,e[2]=t[2]*o,e[3]=t[3]*o),e},u.dot=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]+e[3]*t[3]},u.lerp=function(e,t,n,a){var i=t[0],r=t[1],o=t[2],s=t[3];return e[0]=i+a*(n[0]-i),e[1]=r+a*(n[1]-r),e[2]=o+a*(n[2]-o),e[3]=s+a*(n[3]-s),e},u.random=function(e,t){return t=t||1,e[0]=r(),e[1]=r(),e[2]=r(),e[3]=r(),u.normalize(e,e),u.scale(e,e,t),e},u.transformMat4=function(e,t,n){var a=t[0],i=t[1],r=t[2],o=t[3];return e[0]=n[0]*a+n[4]*i+n[8]*r+n[12]*o,e[1]=n[1]*a+n[5]*i+n[9]*r+n[13]*o,e[2]=n[2]*a+n[6]*i+n[10]*r+n[14]*o,e[3]=n[3]*a+n[7]*i+n[11]*r+n[15]*o,e},u.transformQuat=function(e,t,n){var a=t[0],i=t[1],r=t[2],o=n[0],s=n[1],c=n[2],l=n[3],u=l*a+s*r-c*i,p=l*i+c*a-o*r,d=l*r+o*i-s*a,f=-o*a-s*i-c*r;return e[0]=u*l+f*-o+p*-c-d*-s,e[1]=p*l+f*-s+d*-o-u*-c,e[2]=d*l+f*-c+u*-s-p*-o,e},u.forEach=function(){var e=u.create();return function(t,n,a,i,r,o){var s,c;for(n||(n=4),a||(a=0),c=i?Math.min(i*n+a,t.length):t.length,s=a;s.999999?(a[0]=0,a[1]=0,a[2]=0,a[3]=1,a):(l.cross(e,i,r),a[0]=e[0],a[1]=e[1],a[2]=e[2],a[3]=1+o,m.normalize(a,a))}}(),m.setAxes=function(){var e=f.create();return function(t,n,a,i){return e[0]=a[0],e[3]=a[1],e[6]=a[2],e[1]=i[0],e[4]=i[1],e[7]=i[2],e[2]=-n[0],e[5]=-n[1],e[8]=-n[2],m.normalize(t,m.fromMat3(t,e))}}(),m.clone=u.clone,m.fromValues=u.fromValues,m.copy=u.copy,m.set=u.set,m.identity=function(e){return e[0]=0,e[1]=0,e[2]=0,e[3]=1,e},m.setAxisAngle=function(e,t,n){n*=.5;var a=Math.sin(n);return e[0]=a*t[0],e[1]=a*t[1],e[2]=a*t[2],e[3]=Math.cos(n),e},m.add=u.add,m.multiply=function(e,t,n){var a=t[0],i=t[1],r=t[2],o=t[3],s=n[0],c=n[1],l=n[2],u=n[3];return e[0]=a*u+o*s+i*l-r*c,e[1]=i*u+o*c+r*s-a*l,e[2]=r*u+o*l+a*c-i*s,e[3]=o*u-a*s-i*c-r*l,e},m.mul=m.multiply,m.scale=u.scale,m.rotateX=function(e,t,n){n*=.5;var a=t[0],i=t[1],r=t[2],o=t[3],s=Math.sin(n),c=Math.cos(n);return e[0]=a*c+o*s,e[1]=i*c+r*s,e[2]=r*c-i*s,e[3]=o*c-a*s,e},m.rotateY=function(e,t,n){n*=.5;var a=t[0],i=t[1],r=t[2],o=t[3],s=Math.sin(n),c=Math.cos(n);return e[0]=a*c-r*s,e[1]=i*c+o*s,e[2]=r*c+a*s,e[3]=o*c-i*s,e},m.rotateZ=function(e,t,n){n*=.5;var a=t[0],i=t[1],r=t[2],o=t[3],s=Math.sin(n),c=Math.cos(n);return e[0]=a*c+i*s,e[1]=i*c-a*s,e[2]=r*c+o*s,e[3]=o*c-r*s,e},m.calculateW=function(e,t){var n=t[0],a=t[1],i=t[2];return e[0]=n,e[1]=a,e[2]=i,e[3]=Math.sqrt(Math.abs(1-n*n-a*a-i*i)),e},m.dot=u.dot,m.lerp=u.lerp,m.slerp=function(e,t,n,a){var i,r,o,s,c,l=t[0],u=t[1],p=t[2],d=t[3],f=n[0],h=n[1],m=n[2],v=n[3];return r=l*f+u*h+p*m+d*v,r<0&&(r=-r,f=-f,h=-h,m=-m,v=-v),1-r>1e-6?(i=Math.acos(r),o=Math.sin(i),s=Math.sin((1-a)*i)/o,c=Math.sin(a*i)/o):(s=1-a,c=a),e[0]=s*l+c*f,e[1]=s*u+c*h,e[2]=s*p+c*m,e[3]=s*d+c*v,e},m.invert=function(e,t){var n=t[0],a=t[1],i=t[2],r=t[3],o=n*n+a*a+i*i+r*r,s=o?1/o:0;return e[0]=-n*s,e[1]=-a*s,e[2]=-i*s,e[3]=r*s,e},m.conjugate=function(e,t){return e[0]=-t[0],e[1]=-t[1],e[2]=-t[2],e[3]=t[3],e},m.length=u.length,m.len=m.length,m.squaredLength=u.squaredLength,m.sqrLen=m.squaredLength,m.normalize=u.normalize,m.fromMat3=function(e,t){var n,a=t[0]+t[4]+t[8];if(a>0)n=Math.sqrt(a+1),e[3]=.5*n,n=.5/n,e[0]=(t[5]-t[7])*n,e[1]=(t[6]-t[2])*n,e[2]=(t[1]-t[3])*n;else{var i=0;t[4]>t[0]&&(i=1),t[8]>t[3*i+i]&&(i=2);var r=(i+1)%3,o=(i+2)%3;n=Math.sqrt(t[3*i+i]-t[3*r+r]-t[3*o+o]+1),e[i]=.5*n,n=.5/n,e[3]=(t[3*r+o]-t[3*o+r])*n,e[r]=(t[3*r+i]+t[3*i+r])*n,e[o]=(t[3*o+i]+t[3*i+o])*n}return e},m.str=function(e){return"quat("+e[0]+", "+e[1]+", "+e[2]+", "+e[3]+")"},void 0!==t&&(t.quat=m)}(a.exports)}()}).call(t,n(37))},function(e,t,n){"use strict";var a=n(69),i=n(20),r=n(7),o=function(){this.__uid__=r.a.genGUID()};o.__initializers__=[function(e){r.a.extend(this,e)}],r.a.extend(o,a.a),r.a.extend(o.prototype,i.a),t.a=o},function(e,t,n){"use strict";function a(e,t){var n="vertex:"+e+"fragment:"+t;if(w[n])return w[n];var a=c.a.genGUID();return w[n]=a,A[a]={vertex:e,fragment:t},a}function i(e){return e.replace(/[ \t]*\/\/.*\n/g,"").replace(/[ \t]*\/\*[\s\S]*?\*\//g,"")}function r(){console.error("Wrong uniform/attributes syntax")}function o(e,t){function n(e){e||r();var t=e.match(/\[(.*?)\]/);c=e.replace(/\[(.*?)\]/,""),p[c]={},t&&(p[c].isArray=!0,p[c].arraySize=t[1])}for(var a=/[,=\(\):]/,i=t.replace(/:\s*\[\s*(.*)\s*\]/g,"="+e+"($1)").replace(/\s+/g,"").split(/(?=[,=\(\):])/g),o=[],s=0;s=0){if(1!==u&&4!==u){r();break}u=2,d=[]}else if(1!==u)if(4!==u)n(f),u=0;else{var h=f;y.indexOf(h)>=0||b.indexOf(h)>=0||T.indexOf(h)>=0?p[c].semantic=h:"ignore"===h||"unconfigurable"===h?p[c].ignore=!0:p[c].value="bool"===e?"true"===h:parseFloat(h)}else p[c].value="bool"===e?"true"===f:parseFloat(f),d=null;else{if(2!==u){r();break}if(!(d instanceof Array)){r();break}d.push(+i[++s])}else p[c].value=new l.a.Float32Array(d),d=null,u=5;else if(2===u){if(!(d instanceof Array)){r();break}d.push(+i[++s])}else u=5;else u=4;else{if(0!==u&&3!==u){r();break}u=1}}return p}function s(e,t){"object"==typeof e&&(t=e.fragment,e=e.vertex),e=i(e),t=i(t),this._shaderID=a(e,t),this._vertexCode=s.parseImport(e),this._fragmentCode=s.parseImport(t),this.attributeSemantics={},this.matrixSemantics={},this.uniformSemantics={},this.matrixSemanticKeys=[],this.uniformTemplates={},this.attributes={},this.textures={},this.vertexDefines={},this.fragmentDefines={},this._parseAttributes(),this._parseUniforms(),this._parseDefines()}var c=n(7),l=n(12),u=n(0),p=n.n(u),d=p.a.mat2,f=p.a.mat3,h=p.a.mat4,m=/uniform\s+(bool|float|int|vec2|vec3|vec4|ivec2|ivec3|ivec4|mat2|mat3|mat4|sampler2D|samplerCube)\s+([\s\S]*?);/g,v=/attribute\s+(float|int|vec2|vec3|vec4)\s+([\s\S]*?);/g,g=/#define\s+(\w+)?(\s+[\w-.]+)?\s*;?\s*\n/g,x={bool:"1i",int:"1i",sampler2D:"t",samplerCube:"t",float:"1f",vec2:"2f",vec3:"3f",vec4:"4f",ivec2:"2i",ivec3:"3i",ivec4:"4i",mat2:"m2",mat3:"m3",mat4:"m4"},_={bool:function(){return!0},int:function(){return 0},float:function(){return 0},sampler2D:function(){return null},samplerCube:function(){return null},vec2:function(){return[0,0]},vec3:function(){return[0,0,0]},vec4:function(){return[0,0,0,0]},ivec2:function(){return[0,0]},ivec3:function(){return[0,0,0]},ivec4:function(){return[0,0,0,0]},mat2:function(){return d.create()},mat3:function(){return f.create()},mat4:function(){return h.create()},array:function(){return[]}},y=["POSITION","NORMAL","BINORMAL","TANGENT","TEXCOORD","TEXCOORD_0","TEXCOORD_1","COLOR","JOINT","WEIGHT"],b=["SKIN_MATRIX","VIEWPORT_SIZE","VIEWPORT","DEVICEPIXELRATIO","WINDOW_SIZE","NEAR","FAR","TIME"],T=["WORLD","VIEW","PROJECTION","WORLDVIEW","VIEWPROJECTION","WORLDVIEWPROJECTION","WORLDINVERSE","VIEWINVERSE","PROJECTIONINVERSE","WORLDVIEWINVERSE","VIEWPROJECTIONINVERSE","WORLDVIEWPROJECTIONINVERSE","WORLDTRANSPOSE","VIEWTRANSPOSE","PROJECTIONTRANSPOSE","WORLDVIEWTRANSPOSE","VIEWPROJECTIONTRANSPOSE","WORLDVIEWPROJECTIONTRANSPOSE","WORLDINVERSETRANSPOSE","VIEWINVERSETRANSPOSE","PROJECTIONINVERSETRANSPOSE","WORLDVIEWINVERSETRANSPOSE","VIEWPROJECTIONINVERSETRANSPOSE","WORLDVIEWPROJECTIONINVERSETRANSPOSE"],E={vec4:4,vec3:3,vec2:2,float:1},w={},A={};s.prototype={constructor:s,createUniforms:function(){var e={};for(var t in this.uniformTemplates){var n=this.uniformTemplates[t];e[t]={type:n.type,value:n.value()}}return e},_parseImport:function(){this._vertexCode=s.parseImport(this.vertex),this._fragmentCode=s.parseImport(this.fragment)},_addSemanticUniform:function(e,t,n){if(y.indexOf(n)>=0)this.attributeSemantics[n]={symbol:e,type:t};else if(T.indexOf(n)>=0){var a=!1,i=n;n.match(/TRANSPOSE$/)&&(a=!0,i=n.slice(0,-9)),this.matrixSemantics[n]={symbol:e,type:t,isTranspose:a,semanticNoTranspose:i}}else b.indexOf(n)>=0&&(this.uniformSemantics[n]={symbol:e,type:t})},_addMaterialUniform:function(e,t,n,a,i,r){r[e]={type:n,value:i?_.array:a||_[t],semantic:null}},_parseUniforms:function(){function e(e){return null!=e?function(){return e}:null}function t(t,r,s){var c=o(r,s),l=[];for(var u in c){var p=c[u],d=p.semantic,f=u,h=x[r],m=e(c[u].value);c[u].isArray&&(f+="["+c[u].arraySize+"]",h+="v"),l.push(f),a._uniformList.push(u),p.ignore||("sampler2D"!==r&&"samplerCube"!==r||(a.textures[u]={shaderType:i,type:r}),d?a._addSemanticUniform(u,h,d):a._addMaterialUniform(u,r,h,m,c[u].isArray,n))}return l.length>0?"uniform "+r+" "+l.join(",")+";\n":""}var n={},a=this,i="vertex";this._uniformList=[],this._vertexCode=this._vertexCode.replace(m,t),i="fragment",this._fragmentCode=this._fragmentCode.replace(m,t),a.matrixSemanticKeys=Object.keys(this.matrixSemantics),this.uniformTemplates=n},_parseAttributes:function(){function e(e,a,i){var r=o(a,i),s=E[a]||1,c=[];for(var l in r){var u=r[l].semantic;if(t[l]={type:"float",size:s,semantic:u||null},u){if(y.indexOf(u)<0)throw new Error('Unkown semantic "'+u+'"');n.attributeSemantics[u]={symbol:l,type:a}}c.push(l)}return"attribute "+a+" "+c.join(",")+";\n"}var t={},n=this;this._vertexCode=this._vertexCode.replace(v,e),this.attributes=t},_parseDefines:function(){function e(e,a,i){var r="vertex"===n?t.vertexDefines:t.fragmentDefines;return r[a]||(r[a]="false"!==i&&("true"===i||(i?isNaN(parseFloat(i))?i.trim():parseFloat(i):null))),""}var t=this,n="vertex";this._vertexCode=this._vertexCode.replace(g,e),n="fragment",this._fragmentCode=this._fragmentCode.replace(g,e)},clone:function(){var e=A[this._shaderID];return new s(e.vertex,e.fragment)}},Object.defineProperty&&(Object.defineProperty(s.prototype,"shaderID",{get:function(){return this._shaderID}}),Object.defineProperty(s.prototype,"vertex",{get:function(){return this._vertexCode}}),Object.defineProperty(s.prototype,"fragment",{get:function(){return this._fragmentCode}}),Object.defineProperty(s.prototype,"uniforms",{get:function(){return this._uniformList}}));var S=/(@import)\s*([0-9a-zA-Z_\-\.]*)/g;s.parseImport=function(e){return e=e.replace(S,function(e,t,n){var e=s.source(n);return e?s.parseImport(e):(console.error('Shader chunk "'+n+'" not existed in library'),"")})};var C=/(@export)\s*([0-9a-zA-Z_\-\.]*)\s*\n([\s\S]*?)@end/g;s.import=function(e){e.replace(C,function(e,t,n,a){var a=a.replace(/(^[\s\t\xa0\u3000]+)|([\u3000\xa0\s\t]+\x24)/g,"");if(a){for(var i,r=n.split("."),o=s.codes,c=0;c>t;return e+1},dispose:function(e){var t=this._cache;t.use(e.__uid__);var n=t.get("webgl_texture");n&&e.gl.deleteTexture(n),t.deleteContext(e.__uid__)},isRenderable:function(){},isPowerOfTwo:function(){}});Object.defineProperty(o.prototype,"width",{get:function(){return this._width},set:function(e){this._width=e}}),Object.defineProperty(o.prototype,"height",{get:function(){return this._height},set:function(e){this._height=e}}),o.BYTE=i.a.BYTE,o.UNSIGNED_BYTE=i.a.UNSIGNED_BYTE,o.SHORT=i.a.SHORT,o.UNSIGNED_SHORT=i.a.UNSIGNED_SHORT,o.INT=i.a.INT,o.UNSIGNED_INT=i.a.UNSIGNED_INT,o.FLOAT=i.a.FLOAT,o.HALF_FLOAT=36193,o.UNSIGNED_INT_24_8_WEBGL=34042,o.DEPTH_COMPONENT=i.a.DEPTH_COMPONENT,o.DEPTH_STENCIL=i.a.DEPTH_STENCIL,o.ALPHA=i.a.ALPHA,o.RGB=i.a.RGB,o.RGBA=i.a.RGBA,o.LUMINANCE=i.a.LUMINANCE,o.LUMINANCE_ALPHA=i.a.LUMINANCE_ALPHA,o.SRGB=35904,o.SRGB_ALPHA=35906,o.COMPRESSED_RGB_S3TC_DXT1_EXT=33776,o.COMPRESSED_RGBA_S3TC_DXT1_EXT=33777,o.COMPRESSED_RGBA_S3TC_DXT3_EXT=33778,o.COMPRESSED_RGBA_S3TC_DXT5_EXT=33779,o.NEAREST=i.a.NEAREST,o.LINEAR=i.a.LINEAR,o.NEAREST_MIPMAP_NEAREST=i.a.NEAREST_MIPMAP_NEAREST,o.LINEAR_MIPMAP_NEAREST=i.a.LINEAR_MIPMAP_NEAREST,o.NEAREST_MIPMAP_LINEAR=i.a.NEAREST_MIPMAP_LINEAR,o.LINEAR_MIPMAP_LINEAR=i.a.LINEAR_MIPMAP_LINEAR,o.REPEAT=i.a.REPEAT,o.CLAMP_TO_EDGE=i.a.CLAMP_TO_EDGE,o.MIRRORED_REPEAT=i.a.MIRRORED_REPEAT,t.a=o},function(e,t,n){"use strict";function a(e,t,n){return en?n:e}var i=n(0),r=n.n(i),o=r.a.vec3,s=function(e,t,n){e=e||0,t=t||0,n=n||0,this.array=o.fromValues(e,t,n),this._dirty=!0};s.prototype={constructor:s,add:function(e){return o.add(this.array,this.array,e.array),this._dirty=!0,this},set:function(e,t,n){return this.array[0]=e,this.array[1]=t,this.array[2]=n,this._dirty=!0,this},setArray:function(e){return this.array[0]=e[0],this.array[1]=e[1],this.array[2]=e[2],this._dirty=!0,this},clone:function(){return new s(this.x,this.y,this.z)},copy:function(e){return o.copy(this.array,e.array),this._dirty=!0,this},cross:function(e,t){return o.cross(this.array,e.array,t.array),this._dirty=!0,this},dist:function(e){return o.dist(this.array,e.array)},distance:function(e){return o.distance(this.array,e.array)},div:function(e){return o.div(this.array,this.array,e.array),this._dirty=!0,this},divide:function(e){return o.divide(this.array,this.array,e.array),this._dirty=!0,this},dot:function(e){return o.dot(this.array,e.array)},len:function(){return o.len(this.array)},length:function(){return o.length(this.array)},lerp:function(e,t,n){return o.lerp(this.array,e.array,t.array,n),this._dirty=!0,this},min:function(e){return o.min(this.array,this.array,e.array),this._dirty=!0,this},max:function(e){return o.max(this.array,this.array,e.array),this._dirty=!0,this},mul:function(e){return o.mul(this.array,this.array,e.array),this._dirty=!0,this},multiply:function(e){return o.multiply(this.array,this.array,e.array),this._dirty=!0,this},negate:function(){return o.negate(this.array,this.array),this._dirty=!0,this},normalize:function(){return o.normalize(this.array,this.array),this._dirty=!0,this},random:function(e){return o.random(this.array,e),this._dirty=!0,this},scale:function(e){return o.scale(this.array,this.array,e),this._dirty=!0,this},scaleAndAdd:function(e,t){return o.scaleAndAdd(this.array,this.array,e.array,t),this._dirty=!0,this},sqrDist:function(e){return o.sqrDist(this.array,e.array)},squaredDistance:function(e){return o.squaredDistance(this.array,e.array)},sqrLen:function(){return o.sqrLen(this.array)},squaredLength:function(){return o.squaredLength(this.array)},sub:function(e){return o.sub(this.array,this.array,e.array),this._dirty=!0,this},subtract:function(e){return o.subtract(this.array,this.array,e.array),this._dirty=!0,this},transformMat3:function(e){return o.transformMat3(this.array,this.array,e.array),this._dirty=!0,this},transformMat4:function(e){return o.transformMat4(this.array,this.array,e.array),this._dirty=!0,this},transformQuat:function(e){return o.transformQuat(this.array,this.array,e.array),this._dirty=!0,this},applyProjection:function(e){var t=this.array;if(e=e.array,0===e[15]){var n=-1/t[2];t[0]=e[0]*t[0]*n,t[1]=e[5]*t[1]*n,t[2]=(e[10]*t[2]+e[14])*n}else t[0]=e[0]*t[0]+e[12],t[1]=e[5]*t[1]+e[13],t[2]=e[10]*t[2]+e[14];return this._dirty=!0,this},eulerFromQuat:function(e,t){s.eulerFromQuat(this,e,t)},eulerFromMat3:function(e,t){s.eulerFromMat3(this,e,t)},toString:function(){return"["+Array.prototype.join.call(this.array,",")+"]"},toArray:function(){return Array.prototype.slice.call(this.array)}};var c=Object.defineProperty;if(c){var l=s.prototype;c(l,"x",{get:function(){return this.array[0]},set:function(e){this.array[0]=e,this._dirty=!0}}),c(l,"y",{get:function(){return this.array[1]},set:function(e){this.array[1]=e,this._dirty=!0}}),c(l,"z",{get:function(){return this.array[2]},set:function(e){this.array[2]=e,this._dirty=!0}})}s.add=function(e,t,n){return o.add(e.array,t.array,n.array),e._dirty=!0,e},s.set=function(e,t,n,a){o.set(e.array,t,n,a),e._dirty=!0},s.copy=function(e,t){return o.copy(e.array,t.array),e._dirty=!0,e},s.cross=function(e,t,n){return o.cross(e.array,t.array,n.array),e._dirty=!0,e},s.dist=function(e,t){return o.distance(e.array,t.array)},s.distance=s.dist,s.div=function(e,t,n){return o.divide(e.array,t.array,n.array),e._dirty=!0,e},s.divide=s.div,s.dot=function(e,t){return o.dot(e.array,t.array)},s.len=function(e){return o.length(e.array)},s.lerp=function(e,t,n,a){return o.lerp(e.array,t.array,n.array,a),e._dirty=!0,e},s.min=function(e,t,n){return o.min(e.array,t.array,n.array),e._dirty=!0,e},s.max=function(e,t,n){return o.max(e.array,t.array,n.array),e._dirty=!0,e},s.mul=function(e,t,n){return o.multiply(e.array,t.array,n.array),e._dirty=!0,e},s.multiply=s.mul,s.negate=function(e,t){return o.negate(e.array,t.array),e._dirty=!0,e},s.normalize=function(e,t){return o.normalize(e.array,t.array),e._dirty=!0,e},s.random=function(e,t){return o.random(e.array,t),e._dirty=!0,e},s.scale=function(e,t,n){return o.scale(e.array,t.array,n),e._dirty=!0,e},s.scaleAndAdd=function(e,t,n,a){return o.scaleAndAdd(e.array,t.array,n.array,a),e._dirty=!0,e},s.sqrDist=function(e,t){return o.sqrDist(e.array,t.array)},s.squaredDistance=s.sqrDist,s.sqrLen=function(e){return o.sqrLen(e.array)},s.squaredLength=s.sqrLen,s.sub=function(e,t,n){return o.subtract(e.array,t.array,n.array),e._dirty=!0,e},s.subtract=s.sub,s.transformMat3=function(e,t,n){return o.transformMat3(e.array,t.array,n.array),e._dirty=!0,e},s.transformMat4=function(e,t,n){return o.transformMat4(e.array,t.array,n.array),e._dirty=!0,e},s.transformQuat=function(e,t,n){return o.transformQuat(e.array,t.array,n.array),e._dirty=!0,e};var u=Math.atan2,p=Math.asin,d=Math.abs;s.eulerFromQuat=function(e,t,n){e._dirty=!0,t=t.array;var i=e.array,r=t[0],o=t[1],s=t[2],c=t[3],l=r*r,d=o*o,f=s*s,h=c*c,n=(n||"XYZ").toUpperCase();switch(n){case"XYZ":i[0]=u(2*(r*c-o*s),h-l-d+f),i[1]=p(a(2*(r*s+o*c),-1,1)),i[2]=u(2*(s*c-r*o),h+l-d-f);break;case"YXZ":i[0]=p(a(2*(r*c-o*s),-1,1)),i[1]=u(2*(r*s+o*c),h-l-d+f),i[2]=u(2*(r*o+s*c),h-l+d-f);break;case"ZXY":i[0]=p(a(2*(r*c+o*s),-1,1)),i[1]=u(2*(o*c-s*r),h-l-d+f),i[2]=u(2*(s*c-r*o),h-l+d-f);break;case"ZYX":i[0]=u(2*(r*c+s*o),h-l-d+f),i[1]=p(a(2*(o*c-r*s),-1,1)),i[2]=u(2*(r*o+s*c),h+l-d-f);break;case"YZX":i[0]=u(2*(r*c-s*o),h-l+d-f),i[1]=u(2*(o*c-r*s),h+l-d-f),i[2]=p(a(2*(r*o+s*c),-1,1));break;case"XZY":i[0]=u(2*(r*c+o*s),h-l+d-f),i[1]=u(2*(r*s+o*c),h+l-d-f),i[2]=p(a(2*(s*c-r*o),-1,1));break;default:console.warn("Unkown order: "+n)}return e},s.eulerFromMat3=function(e,t,n){var i=t.array,r=i[0],o=i[3],s=i[6],c=i[1],l=i[4],f=i[7],h=i[2],m=i[5],v=i[8],g=e.array,n=(n||"XYZ").toUpperCase();switch(n){case"XYZ":g[1]=p(a(s,-1,1)),d(s)<.99999?(g[0]=u(-f,v),g[2]=u(-o,r)):(g[0]=u(m,l),g[2]=0);break;case"YXZ":g[0]=p(-a(f,-1,1)),d(f)<.99999?(g[1]=u(s,v),g[2]=u(c,l)):(g[1]=u(-h,r),g[2]=0);break;case"ZXY":g[0]=p(a(m,-1,1)),d(m)<.99999?(g[1]=u(-h,v),g[2]=u(-o,l)):(g[1]=0,g[2]=u(c,r));break;case"ZYX":g[1]=p(-a(h,-1,1)),d(h)<.99999?(g[0]=u(m,v),g[2]=u(c,r)):(g[0]=0,g[2]=u(-o,l));break;case"YZX":g[2]=p(a(c,-1,1)),d(c)<.99999?(g[0]=u(-f,l),g[1]=u(-h,r)):(g[0]=0,g[1]=u(s,v));break;case"XZY":g[2]=p(-a(o,-1,1)),d(o)<.99999?(g[0]=u(m,l),g[1]=u(s,r)):(g[0]=u(-f,v),g[1]=0);break;default:console.warn("Unkown order: "+n)}return e._dirty=!0,e},s.POSITIVE_X=new s(1,0,0),s.NEGATIVE_X=new s(-1,0,0),s.POSITIVE_Y=new s(0,1,0),s.NEGATIVE_Y=new s(0,-1,0),s.POSITIVE_Z=new s(0,0,1),s.NEGATIVE_Z=new s(0,0,-1),s.UP=new s(0,1,0),s.ZERO=new s(0,0,0),t.a=s},function(e,t,n){"use strict";function a(e){return Math.pow(2,Math.round(Math.log(e)/Math.LN2))}function i(e,t){var n=a(e.width),i=a(e.height);return t=t||document.createElement("canvas"),t.width=n,t.height=i,t.getContext("2d").drawImage(e.image,0,0,n,i),t}var r=n(3),o=n(6),s=n(47),c=s.a.isPowerOfTwo,l=r.a.extend(function(){return{image:null,pixels:null,mipmaps:[],convertToPOT:!1}},{textureType:"texture2D",update:function(e){var t=e.gl;t.bindTexture(t.TEXTURE_2D,this._cache.get("webgl_texture")),this.updateCommon(e);var n=this.format,a=this.type,i=!(!this.convertToPOT||this.mipmaps.length||!this.image||this.wrapS!==r.a.REPEAT&&this.wrapT!==r.a.REPEAT||!this.NPOT);t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_S,i?this.wrapS:this.getAvailableWrapS()),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_WRAP_T,i?this.wrapT:this.getAvailableWrapT()),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MAG_FILTER,i?this.magFilter:this.getAvailableMagFilter()),t.texParameteri(t.TEXTURE_2D,t.TEXTURE_MIN_FILTER,i?this.minFilter:this.getAvailableMinFilter());var s=e.getGLExtension("EXT_texture_filter_anisotropic");if(s&&this.anisotropic>1&&t.texParameterf(t.TEXTURE_2D,s.TEXTURE_MAX_ANISOTROPY_EXT,this.anisotropic),36193===a){e.getGLExtension("OES_texture_half_float")||(a=o.a.FLOAT)}if(this.mipmaps.length)for(var c=this.width,l=this.height,u=0;u=r.a.COMPRESSED_RGB_S3TC_DXT1_EXT?e.compressedTexImage2D(e.TEXTURE_2D,n,s,a,o,0,t.pixels):e.texImage2D(e.TEXTURE_2D,n,s,a,o,0,s,c,t.pixels)},generateMipmap:function(e){var t=e.gl;this.useMipmap&&!this.NPOT&&(t.bindTexture(t.TEXTURE_2D,this._cache.get("webgl_texture")),t.generateMipmap(t.TEXTURE_2D))},isPowerOfTwo:function(){return c(this.width)&&c(this.height)},isRenderable:function(){return this.image?"CANVAS"===this.image.nodeName||"VIDEO"===this.image.nodeName||this.image.complete:!(!this.width||!this.height)},bind:function(e){e.gl.bindTexture(e.gl.TEXTURE_2D,this.getWebGLTexture(e))},unbind:function(e){e.gl.bindTexture(e.gl.TEXTURE_2D,null)},load:function(e,t){var n=new Image;t&&(n.crossOrigin=t);var a=this;return n.onload=function(){a.dirty(),a.trigger("success",a),n.onload=null},n.onerror=function(){a.trigger("error",a),n.onerror=null},n.src=e,this.image=n,this}});Object.defineProperty(l.prototype,"width",{get:function(){return this.image?this.image.width:this._width},set:function(e){this.image?console.warn("Texture from image can't set width"):(this._width!==e&&this.dirty(),this._width=e)}}),Object.defineProperty(l.prototype,"height",{get:function(){return this.image?this.image.height:this._height},set:function(e){this.image?console.warn("Texture from image can't set height"):(this._height!==e&&this.dirty(),this._height=e)}}),t.a=l},function(e,t,n){"use strict";t.a={DEPTH_BUFFER_BIT:256,STENCIL_BUFFER_BIT:1024,COLOR_BUFFER_BIT:16384,POINTS:0,LINES:1,LINE_LOOP:2,LINE_STRIP:3,TRIANGLES:4,TRIANGLE_STRIP:5,TRIANGLE_FAN:6,ZERO:0,ONE:1,SRC_COLOR:768,ONE_MINUS_SRC_COLOR:769,SRC_ALPHA:770,ONE_MINUS_SRC_ALPHA:771,DST_ALPHA:772,ONE_MINUS_DST_ALPHA:773,DST_COLOR:774,ONE_MINUS_DST_COLOR:775,SRC_ALPHA_SATURATE:776,FUNC_ADD:32774,BLEND_EQUATION:32777,BLEND_EQUATION_RGB:32777,BLEND_EQUATION_ALPHA:34877,FUNC_SUBTRACT:32778,FUNC_REVERSE_SUBTRACT:32779,BLEND_DST_RGB:32968,BLEND_SRC_RGB:32969,BLEND_DST_ALPHA:32970,BLEND_SRC_ALPHA:32971,CONSTANT_COLOR:32769,ONE_MINUS_CONSTANT_COLOR:32770,CONSTANT_ALPHA:32771,ONE_MINUS_CONSTANT_ALPHA:32772,BLEND_COLOR:32773,ARRAY_BUFFER:34962,ELEMENT_ARRAY_BUFFER:34963,ARRAY_BUFFER_BINDING:34964,ELEMENT_ARRAY_BUFFER_BINDING:34965,STREAM_DRAW:35040,STATIC_DRAW:35044,DYNAMIC_DRAW:35048,BUFFER_SIZE:34660,BUFFER_USAGE:34661,CURRENT_VERTEX_ATTRIB:34342,FRONT:1028,BACK:1029,FRONT_AND_BACK:1032,CULL_FACE:2884,BLEND:3042,DITHER:3024,STENCIL_TEST:2960,DEPTH_TEST:2929,SCISSOR_TEST:3089,POLYGON_OFFSET_FILL:32823,SAMPLE_ALPHA_TO_COVERAGE:32926,SAMPLE_COVERAGE:32928,NO_ERROR:0,INVALID_ENUM:1280,INVALID_VALUE:1281,INVALID_OPERATION:1282,OUT_OF_MEMORY:1285,CW:2304,CCW:2305,LINE_WIDTH:2849,ALIASED_POINT_SIZE_RANGE:33901,ALIASED_LINE_WIDTH_RANGE:33902,CULL_FACE_MODE:2885,FRONT_FACE:2886,DEPTH_RANGE:2928,DEPTH_WRITEMASK:2930,DEPTH_CLEAR_VALUE:2931,DEPTH_FUNC:2932,STENCIL_CLEAR_VALUE:2961,STENCIL_FUNC:2962,STENCIL_FAIL:2964,STENCIL_PASS_DEPTH_FAIL:2965,STENCIL_PASS_DEPTH_PASS:2966,STENCIL_REF:2967,STENCIL_VALUE_MASK:2963,STENCIL_WRITEMASK:2968,STENCIL_BACK_FUNC:34816,STENCIL_BACK_FAIL:34817,STENCIL_BACK_PASS_DEPTH_FAIL:34818,STENCIL_BACK_PASS_DEPTH_PASS:34819,STENCIL_BACK_REF:36003,STENCIL_BACK_VALUE_MASK:36004,STENCIL_BACK_WRITEMASK:36005,VIEWPORT:2978,SCISSOR_BOX:3088,COLOR_CLEAR_VALUE:3106,COLOR_WRITEMASK:3107,UNPACK_ALIGNMENT:3317,PACK_ALIGNMENT:3333,MAX_TEXTURE_SIZE:3379,MAX_VIEWPORT_DIMS:3386,SUBPIXEL_BITS:3408,RED_BITS:3410,GREEN_BITS:3411,BLUE_BITS:3412,ALPHA_BITS:3413,DEPTH_BITS:3414,STENCIL_BITS:3415,POLYGON_OFFSET_UNITS:10752,POLYGON_OFFSET_FACTOR:32824,TEXTURE_BINDING_2D:32873,SAMPLE_BUFFERS:32936,SAMPLES:32937,SAMPLE_COVERAGE_VALUE:32938,SAMPLE_COVERAGE_INVERT:32939,COMPRESSED_TEXTURE_FORMATS:34467,DONT_CARE:4352,FASTEST:4353,NICEST:4354,GENERATE_MIPMAP_HINT:33170,BYTE:5120,UNSIGNED_BYTE:5121,SHORT:5122,UNSIGNED_SHORT:5123,INT:5124,UNSIGNED_INT:5125,FLOAT:5126,DEPTH_COMPONENT:6402,ALPHA:6406,RGB:6407,RGBA:6408,LUMINANCE:6409,LUMINANCE_ALPHA:6410,UNSIGNED_SHORT_4_4_4_4:32819,UNSIGNED_SHORT_5_5_5_1:32820,UNSIGNED_SHORT_5_6_5:33635,FRAGMENT_SHADER:35632,VERTEX_SHADER:35633,MAX_VERTEX_ATTRIBS:34921,MAX_VERTEX_UNIFORM_VECTORS:36347,MAX_VARYING_VECTORS:36348,MAX_COMBINED_TEXTURE_IMAGE_UNITS:35661,MAX_VERTEX_TEXTURE_IMAGE_UNITS:35660,MAX_TEXTURE_IMAGE_UNITS:34930,MAX_FRAGMENT_UNIFORM_VECTORS:36349,SHADER_TYPE:35663,DELETE_STATUS:35712,LINK_STATUS:35714,VALIDATE_STATUS:35715,ATTACHED_SHADERS:35717,ACTIVE_UNIFORMS:35718,ACTIVE_ATTRIBUTES:35721,SHADING_LANGUAGE_VERSION:35724,CURRENT_PROGRAM:35725,NEVER:512,LESS:513,EQUAL:514,LEQUAL:515,GREATER:516,NOTEQUAL:517,GEQUAL:518,ALWAYS:519,KEEP:7680,REPLACE:7681,INCR:7682,DECR:7683,INVERT:5386,INCR_WRAP:34055,DECR_WRAP:34056,VENDOR:7936,RENDERER:7937,VERSION:7938,NEAREST:9728,LINEAR:9729,NEAREST_MIPMAP_NEAREST:9984,LINEAR_MIPMAP_NEAREST:9985,NEAREST_MIPMAP_LINEAR:9986,LINEAR_MIPMAP_LINEAR:9987,TEXTURE_MAG_FILTER:10240,TEXTURE_MIN_FILTER:10241,TEXTURE_WRAP_S:10242,TEXTURE_WRAP_T:10243,TEXTURE_2D:3553,TEXTURE:5890,TEXTURE_CUBE_MAP:34067,TEXTURE_BINDING_CUBE_MAP:34068,TEXTURE_CUBE_MAP_POSITIVE_X:34069,TEXTURE_CUBE_MAP_NEGATIVE_X:34070,TEXTURE_CUBE_MAP_POSITIVE_Y:34071,TEXTURE_CUBE_MAP_NEGATIVE_Y:34072,TEXTURE_CUBE_MAP_POSITIVE_Z:34073,TEXTURE_CUBE_MAP_NEGATIVE_Z:34074,MAX_CUBE_MAP_TEXTURE_SIZE:34076,TEXTURE0:33984,TEXTURE1:33985,TEXTURE2:33986,TEXTURE3:33987,TEXTURE4:33988,TEXTURE5:33989,TEXTURE6:33990,TEXTURE7:33991,TEXTURE8:33992,TEXTURE9:33993,TEXTURE10:33994,TEXTURE11:33995,TEXTURE12:33996,TEXTURE13:33997,TEXTURE14:33998,TEXTURE15:33999,TEXTURE16:34e3,TEXTURE17:34001,TEXTURE18:34002,TEXTURE19:34003,TEXTURE20:34004,TEXTURE21:34005,TEXTURE22:34006,TEXTURE23:34007,TEXTURE24:34008,TEXTURE25:34009,TEXTURE26:34010,TEXTURE27:34011,TEXTURE28:34012,TEXTURE29:34013,TEXTURE30:34014,TEXTURE31:34015,ACTIVE_TEXTURE:34016,REPEAT:10497,CLAMP_TO_EDGE:33071,MIRRORED_REPEAT:33648,FLOAT_VEC2:35664,FLOAT_VEC3:35665,FLOAT_VEC4:35666,INT_VEC2:35667,INT_VEC3:35668,INT_VEC4:35669,BOOL:35670,BOOL_VEC2:35671,BOOL_VEC3:35672,BOOL_VEC4:35673,FLOAT_MAT2:35674,FLOAT_MAT3:35675,FLOAT_MAT4:35676,SAMPLER_2D:35678,SAMPLER_CUBE:35680,VERTEX_ATTRIB_ARRAY_ENABLED:34338,VERTEX_ATTRIB_ARRAY_SIZE:34339,VERTEX_ATTRIB_ARRAY_STRIDE:34340,VERTEX_ATTRIB_ARRAY_TYPE:34341,VERTEX_ATTRIB_ARRAY_NORMALIZED:34922,VERTEX_ATTRIB_ARRAY_POINTER:34373,VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:34975,COMPILE_STATUS:35713,LOW_FLOAT:36336,MEDIUM_FLOAT:36337,HIGH_FLOAT:36338,LOW_INT:36339,MEDIUM_INT:36340,HIGH_INT:36341,FRAMEBUFFER:36160,RENDERBUFFER:36161,RGBA4:32854,RGB5_A1:32855,RGB565:36194,DEPTH_COMPONENT16:33189,STENCIL_INDEX:6401,STENCIL_INDEX8:36168,DEPTH_STENCIL:34041,RENDERBUFFER_WIDTH:36162,RENDERBUFFER_HEIGHT:36163,RENDERBUFFER_INTERNAL_FORMAT:36164,RENDERBUFFER_RED_SIZE:36176,RENDERBUFFER_GREEN_SIZE:36177,RENDERBUFFER_BLUE_SIZE:36178,RENDERBUFFER_ALPHA_SIZE:36179,RENDERBUFFER_DEPTH_SIZE:36180,RENDERBUFFER_STENCIL_SIZE:36181,FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:36048,FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:36049,FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:36050,FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:36051,COLOR_ATTACHMENT0:36064,DEPTH_ATTACHMENT:36096,STENCIL_ATTACHMENT:36128,DEPTH_STENCIL_ATTACHMENT:33306,NONE:0,FRAMEBUFFER_COMPLETE:36053,FRAMEBUFFER_INCOMPLETE_ATTACHMENT:36054,FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:36055,FRAMEBUFFER_INCOMPLETE_DIMENSIONS:36057,FRAMEBUFFER_UNSUPPORTED:36061,FRAMEBUFFER_BINDING:36006,RENDERBUFFER_BINDING:36007,MAX_RENDERBUFFER_SIZE:34024,INVALID_FRAMEBUFFER_OPERATION:1286,UNPACK_FLIP_Y_WEBGL:37440,UNPACK_PREMULTIPLY_ALPHA_WEBGL:37441,CONTEXT_LOST_WEBGL:37442,UNPACK_COLORSPACE_CONVERSION_WEBGL:37443,BROWSER_DEFAULT_WEBGL:37444}},function(e,t,n){"use strict";var a=0,i=Array.prototype,r=i.forEach,o={genGUID:function(){return++a},relative2absolute:function(e,t){if(!t||e.match(/^\//))return e;for(var n=e.split("/"),a=t.split("/"),i=n[0];"."===i||".."===i;)".."===i&&a.pop(),n.shift(),i=n[0];return a.join("/")+"/"+n.join("/")},extend:function(e,t){if(t)for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e},defaults:function(e,t){if(t)for(var n in t)void 0===e[n]&&(e[n]=t[n]);return e},extendWithPropList:function(e,t,n){if(t)for(var a=0;a0){var t=this.min,n=this.max,a=t.array,i=n.array;s(a,e[0]),s(i,e[0]);for(var r=1;ri[0]&&(i[0]=o[0]),o[1]>i[1]&&(i[1]=o[1]),o[2]>i[2]&&(i[2]=o[2])}t._dirty=!0,n._dirty=!0}},union:function(e){var t=this.min,n=this.max;return o.min(t.array,t.array,e.min.array),o.max(n.array,n.array,e.max.array),t._dirty=!0,n._dirty=!0,this},intersection:function(e){var t=this.min,n=this.max;return o.max(t.array,t.array,e.min.array),o.min(n.array,n.array,e.max.array),t._dirty=!0,n._dirty=!0,this},intersectBoundingBox:function(e){var t=this.min.array,n=this.max.array,a=e.min.array,i=e.max.array;return!(t[0]>i[0]||t[1]>i[1]||t[2]>i[2]||n[0]=i[0]&&n[1]>=i[1]&&n[2]>=i[2]},containPoint:function(e){var t=this.min.array,n=this.max.array,a=e.array;return t[0]<=a[0]&&t[1]<=a[1]&&t[2]<=a[2]&&n[0]>=a[0]&&n[1]>=a[1]&&n[2]>=a[2]},isFinite:function(){var e=this.min.array,t=this.max.array;return isFinite(e[0])&&isFinite(e[1])&&isFinite(e[2])&&isFinite(t[0])&&isFinite(t[1])&&isFinite(t[2])},applyTransform:function(e){this.transformFrom(this,e)},transformFrom:function(){var e=o.create(),t=o.create(),n=o.create(),a=o.create(),i=o.create(),r=o.create();return function(o,s){var c=o.min.array,l=o.max.array,u=s.array;return e[0]=u[0]*c[0],e[1]=u[1]*c[0],e[2]=u[2]*c[0],t[0]=u[0]*l[0],t[1]=u[1]*l[0],t[2]=u[2]*l[0],n[0]=u[4]*c[1],n[1]=u[5]*c[1],n[2]=u[6]*c[1],a[0]=u[4]*l[1],a[1]=u[5]*l[1],a[2]=u[6]*l[1],i[0]=u[8]*c[2],i[1]=u[9]*c[2],i[2]=u[10]*c[2],r[0]=u[8]*l[2],r[1]=u[9]*l[2],r[2]=u[10]*l[2],c=this.min.array,l=this.max.array,c[0]=Math.min(e[0],t[0])+Math.min(n[0],a[0])+Math.min(i[0],r[0])+u[12],c[1]=Math.min(e[1],t[1])+Math.min(n[1],a[1])+Math.min(i[1],r[1])+u[13],c[2]=Math.min(e[2],t[2])+Math.min(n[2],a[2])+Math.min(i[2],r[2])+u[14],l[0]=Math.max(e[0],t[0])+Math.max(n[0],a[0])+Math.max(i[0],r[0])+u[12],l[1]=Math.max(e[1],t[1])+Math.max(n[1],a[1])+Math.max(i[1],r[1])+u[13],l[2]=Math.max(e[2],t[2])+Math.max(n[2],a[2])+Math.max(i[2],r[2])+u[14],this.min._dirty=!0,this.max._dirty=!0,this}}(),applyProjection:function(e){var t=this.min.array,n=this.max.array,a=e.array,i=t[0],r=t[1],o=t[2],s=n[0],c=n[1],l=t[2],u=n[0],p=n[1],d=n[2];if(1===a[15])t[0]=a[0]*i+a[12],t[1]=a[5]*r+a[13],n[2]=a[10]*o+a[14],n[0]=a[0]*u+a[12],n[1]=a[5]*p+a[13],t[2]=a[10]*d+a[14];else{var f=-1/o;t[0]=a[0]*i*f,t[1]=a[5]*r*f,n[2]=(a[10]*o+a[14])*f,f=-1/l,n[0]=a[0]*s*f,n[1]=a[5]*c*f,f=-1/d,t[2]=(a[10]*d+a[14])*f}return this.min._dirty=!0,this.max._dirty=!0,this},updateVertices:function(){var e=this.vertices;if(!e){e=[];for(var t=0;t<8;t++)e[t]=o.fromValues(0,0,0);this.vertices=e}var n=this.min.array,a=this.max.array;return c(e[0],n[0],n[1],n[2]),c(e[1],n[0],a[1],n[2]),c(e[2],a[0],n[1],n[2]),c(e[3],a[0],a[1],n[2]),c(e[4],n[0],n[1],a[2]),c(e[5],n[0],a[1],a[2]),c(e[6],a[0],n[1],a[2]),c(e[7],a[0],a[1],a[2]),this},copy:function(e){var t=this.min,n=this.max;return s(t.array,e.min.array),s(n.array,e.max.array),t._dirty=!0,n._dirty=!0,this},clone:function(){var e=new l;return e.copy(this),e}},t.a=l},function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=n(4),o=i.a.mat4,s=i.a.vec3,c=i.a.mat3,l=i.a.quat,u=function(){this._axisX=new r.a,this._axisY=new r.a,this._axisZ=new r.a,this.array=o.create(),this._dirty=!0};u.prototype={constructor:u,setArray:function(e){for(var t=0;t=0},getEnabledUniforms:function(){return this._enabledUniforms},getTextureUniforms:function(){return this._textureUniforms},set:function(e,t){if("object"==typeof e)for(var n in e){var a=e[n];this.setUniform(n,a)}else this.setUniform(e,t)},get:function(e){var t=this.uniforms[e];if(t)return t.value},attachShader:function(e,t){var n=this.uniforms;this.uniforms=e.createUniforms(),this.shader=e;var a=this.uniforms;this._enabledUniforms=Object.keys(a),this._enabledUniforms.sort(),this._textureUniforms=this._enabledUniforms.filter(function(e){var t=this.uniforms[e].type;return"t"===t||"tv"===t},this);var i=this.vertexDefines,r=this.fragmentDefines;if(this.vertexDefines=o.a.clone(e.vertexDefines),this.fragmentDefines=o.a.clone(e.fragmentDefines),t){for(var s in n)a[s]&&(a[s].value=n[s].value);o.a.defaults(this.vertexDefines,i),o.a.defaults(this.fragmentDefines,r)}var c={};for(var l in e.textures)c[l]={shaderType:e.textures[l].shaderType,type:e.textures[l].type,enabled:!(!t||!this._textureStatus[l])&&this._textureStatus[l].enabled};this._textureStatus=c,this._programKey=""},clone:function(){var e=new this.constructor({name:this.name,shader:this.shader});for(var t in this.uniforms)e.uniforms[t].value=this.uniforms[t].value;return e.depthTest=this.depthTest,e.depthMask=this.depthMask,e.transparent=this.transparent,e.blend=this.blend,e.vertexDefines=o.a.clone(this.vertexDefines),e.fragmentDefines=o.a.clone(this.fragmentDefines),e.enableTexture(this.getEnabledTextures()),e.precision=this.precision,e},define:function(e,t,n){var a=this.vertexDefines,i=this.fragmentDefines;"vertex"!==e&&"fragment"!==e&&"both"!==e&&arguments.length<3&&(n=t,t=e,e="both"),n=null!=n?n:null,"vertex"!==e&&"both"!==e||a[t]!==n&&(a[t]=n,this._programKey=""),"fragment"!==e&&"both"!==e||i[t]!==n&&(i[t]=n,"both"!==e&&(this._programKey=""))},undefine:function(e,t){"vertex"!==e&&"fragment"!==e&&"both"!==e&&arguments.length<2&&(t=e,e="both"),"vertex"!==e&&"both"!==e||this.isDefined("vertex",t)&&(delete this.vertexDefines[t],this._programKey=""),"fragment"!==e&&"both"!==e||this.isDefined("fragment",t)&&(delete this.fragmentDefines[t],"both"!==e&&(this._programKey=""))},isDefined:function(e,t){switch(e){case"vertex":return void 0!==this.vertexDefines[t];case"fragment":return void 0!==this.fragmentDefines[t]}},getDefine:function(e,t){switch(e){case"vertex":return this.vertexDefines[t];case"fragment":return this.fragmentDefines[t]}},enableTexture:function(e){if(Array.isArray(e))for(var t=0;t=n.COLOR_ATTACHMENT0&&r<=n.COLOR_ATTACHMENT0+8&&i.push(r);a.drawBuffersEXT(i)}}this.trigger("beforerender",this,e);var o=this.clearDepth?n.DEPTH_BUFFER_BIT:0;if(n.depthMask(!0),this.clearColor){o|=n.COLOR_BUFFER_BIT,n.colorMask(!0,!0,!0,!0);var s=this.clearColor;Array.isArray(s)&&n.clearColor(s[0],s[1],s[2],s[3])}n.clear(o),this.blendWithPrevious?(n.enable(n.BLEND),this.material.transparent=!0):(n.disable(n.BLEND),this.material.transparent=!1),this.renderQuad(e),this.trigger("afterrender",this,e),t&&this.unbind(e,t)},renderQuad:function(e){d.material=this.material,e.renderPass([d],f)},dispose:function(e){}});t.a=h},function(e,t,n){"use strict";var a=n(1),i=n(4),r=n(76),o=n(9),s=n(0),c=n.n(s),l=n(8),u=c.a.mat4,p=0,d=a.a.extend({name:"",position:null,rotation:null,scale:null,worldTransform:null,localTransform:null,autoUpdateLocalTransform:!0,_parent:null,_scene:null,_needsUpdateWorldTransform:!0,_inIterating:!1,__depth:0},function(){this.name||(this.name=(this.type||"NODE")+"_"+p++),this.position||(this.position=new i.a),this.rotation||(this.rotation=new r.a),this.scale||(this.scale=new i.a(1,1,1)),this.worldTransform=new o.a,this.localTransform=new o.a,this._children=[]},{target:null,invisible:!1,isSkinnedMesh:function(){return!1},isRenderable:function(){return!1},setName:function(e){var t=this._scene;if(t){var n=t._nodeRepository;delete n[this.name],n[e]=this}this.name=e},add:function(e){var t=e._parent;if(t!==this){t&&t.remove(e),e._parent=this,this._children.push(e);var n=this._scene;n&&n!==e.scene&&e.traverse(this._addSelfToScene,this),e._needsUpdateWorldTransform=!0}},remove:function(e){var t=this._children,n=t.indexOf(e);n<0||(t.splice(n,1),e._parent=null,this._scene&&e.traverse(this._removeSelfFromScene,this))},removeAll:function(){for(var e=this._children,t=0;t1&&t.texParameterf(t.TEXTURE_CUBE_MAP,i.TEXTURE_MAX_ANISOTROPY_EXT,this.anisotropic),36193===a){e.getGLExtension("OES_texture_half_float")||(a=r.a.FLOAT)}if(this.mipmaps.length)for(var o=this.width,s=this.height,c=0;c0)},getSkinMatricesTexture:function(){return this._skinMatricesTexture=this._skinMatricesTexture||new r.a({type:i.a.FLOAT,minFilter:i.a.NEAREST,magFilter:i.a.NEAREST,useMipmap:!1,flipY:!1}),this._skinMatricesTexture},clone:function(){var e=a.a.prototype.clone.call(this);return e.skeleton=this.skeleton,this.joints&&(e.joints=this.joints.slice()),e}});o.POINTS=i.a.POINTS,o.LINES=i.a.LINES,o.LINE_LOOP=i.a.LINE_LOOP,o.LINE_STRIP=i.a.LINE_STRIP,o.TRIANGLES=i.a.TRIANGLES,o.TRIANGLE_STRIP=i.a.TRIANGLE_STRIP,o.TRIANGLE_FAN=i.a.TRIANGLE_FAN,o.BACK=i.a.BACK,o.FRONT=i.a.FRONT,o.FRONT_AND_BACK=i.a.FRONT_AND_BACK,o.CW=i.a.CW,o.CCW=i.a.CCW,t.a=o},function(e,t,n){"use strict";function a(e){var t=[],n=Object.keys(e);n.sort();for(var a=0;a0&&console.warn("Found multiple camera in one scene. Use the fist one."),this._cameraList.push(e)):e instanceof s.a&&this.lights.push(e),e.name&&(this._nodeRepository[e.name]=e)},removeFromScene:function(e){var t;e instanceof c.a?(t=this._cameraList.indexOf(e))>=0&&this._cameraList.splice(t,1):e instanceof s.a&&(t=this.lights.indexOf(e))>=0&&this.lights.splice(t,1),e.name&&delete this._nodeRepository[e.name]},getNode:function(e){return this._nodeRepository[e]},setMainCamera:function(e){var t=this._cameraList.indexOf(e);t>=0&&this._cameraList.splice(t,1),this._cameraList.unshift(e)},getMainCamera:function(){return this._cameraList[0]},getLights:function(){return this.lights},updateLights:function(){var e=this.lights;this._previousLightNumber=this._lightNumber;for(var t={},n=0;n0&&this._doUpdateRenderList(r,t,n,a)}},isFrustumCulled:function(){var e=new l.a,t=new h.a;return function(n,a,i){var r=n.boundingBox||n.geometry.boundingBox;if(t.array=i,e.transformFrom(r,t),n.castShadow&&this.viewBoundingBoxLastFrame.union(e),n.frustumCulling&&!n.isSkinnedMesh()){if(!e.intersectBoundingBox(a.frustum.boundingBox))return!0;t.array=a.projectionMatrix.array,e.max.array[2]>0&&e.min.array[2]<0&&(e.max.array[2]=-1e-20),e.applyProjection(t);var o=e.min.array,s=e.max.array;if(s[0]<-1||o[0]>1||s[1]<-1||o[1]>1||s[2]<-1||o[2]>1)return!0}return!1}}(),_updateLightUniforms:function(){var e=this.lights;e.sort(r);var t=this._lightUniforms;for(var n in t)for(var a in t[n])t[n][a].value.length=0;for(var i=0;ir[0]&&(r[0]=s),c>r[1]&&(r[1]=c),l>r[2]&&(r[2]=l)}n._dirty=!0,a._dirty=!0}},dirty:function(){for(var e=this.getEnabledAttributes(),t=0;t=0){t||(t=g());var n=this.indices;return t[0]=n[3*e],t[1]=n[3*e+1],t[2]=n[3*e+2],t}},setTriangleIndices:function(e,t){var n=this.indices;n[3*e]=t[0],n[3*e+1]=t[1],n[3*e+2]=t[2]},isUseIndices:function(){return!!this.indices},initIndicesFromArray:function(e){var t,n=this.vertexCount>65535?p.a.Uint32Array:p.a.Uint16Array;if(e[0]&&e[0].length){var a=0;t=new n(3*e.length);for(var i=0;i=0&&(t.splice(n,1),delete this.attributes[e],!0)},getAttribute:function(e){return this.attributes[e]},getEnabledAttributes:function(){var e=this._enabledAttributes,t=this._attributeList;if(e)return e;for(var n=[],a=this.vertexCount,i=0;i65535&&(this.indices=new p.a.Uint32Array(this.indices));for(var e=this.attributes,t=this.indices,n=this.getEnabledAttributes(),a={},i=0;i0){var t=this.outputs[e];t.keepLastFrame?(this._prevOutputTextures[e]&&this._compositor.releaseTexture(this._prevOutputTextures[e]),this._prevOutputTextures[e]=this._outputTextures[e]):this._compositor.releaseTexture(this._outputTextures[e])}}});t.a=i},function(e,t,n){"use strict";function a(e,t){for(var n=0,a=1/t,i=e;i>0;)n+=a*(i%t),i=Math.floor(i/t),a/=t;return n}t.a=a},function(e,t,n){"use strict";function a(e){return!e||"none"===e}function i(e){return e instanceof HTMLCanvasElement||e instanceof HTMLImageElement||e instanceof HTMLVideoElement||e instanceof Image}var r=(n(3),n(10)),o=n(65),s=n(32),c=n(125),l=n(126),u=n(127),p=n(129),d=n(5);r.a.prototype.setTextureImage=function(e,t,n,i){if(this.shader){var r,o=this;return o.disableTexture(e),a(t)||(r=f.loadTexture(t,n,i,function(t){o.enableTexture(e),n.refresh()}),o.set(e,r)),r}};var f={},h=s.a.createBlank("rgba(255,255,255,0)").image;f.firstNotNull=function(){for(var e=0,t=arguments.length;e3?t[3]=e[3]:t[3]=1,t):(t=p.a(e||"#000",t)||[0,0,0,0],t[0]/=255,t[1]/=255,t[2]/=255,t)},f.stringifyColor=function(e,t){return e=e.slice(),e[0]=Math.round(255*e[0]),e[1]=Math.round(255*e[1]),e[2]=Math.round(255*e[2]),"hex"===t?"#"+((1<<24)+(e[0]<<16)+(e[1]<<8)+e[2]).toString(16).slice(1):p.b(e,t)},f.directionFromAlphaBeta=function(e,t){var n=e/180*Math.PI+Math.PI/2,a=-t/180*Math.PI+Math.PI/2,i=[],r=Math.sin(n);return i[0]=r*Math.cos(a),i[1]=-Math.cos(n),i[2]=r*Math.sin(a),i},t.a=f},function(e,t,n){"use strict";function a(e){return e.material}function i(){}function r(e,t,n){this.availableAttributes=e,this.availableAttributeSymbols=t,this.indicesBuffer=n,this.vao=null}var o=n(1),s=n(70),c=n(6),l=(n(12),n(8),n(9),n(10)),u=n(21),p=n(73),d=n(2),f=n(39),h=n(40),m=n(0),v=n.n(m);d.a.import(f.a),d.a.import(h.a);var g=v.a.mat4,x=v.a.vec3,_=g.create,y={},b={float:c.a.FLOAT,byte:c.a.BYTE,ubyte:c.a.UNSIGNED_BYTE,short:c.a.SHORT,ushort:c.a.UNSIGNED_SHORT},T=o.a.extend(function(){return{canvas:null,_width:100,_height:100,devicePixelRatio:window&&window.devicePixelRatio||1,clearColor:[0,0,0,0],clearBit:17664,alpha:!0,depth:!0,stencil:!1,antialias:!0,premultipliedAlpha:!0,preserveDrawingBuffer:!1,throwError:!0,gl:null,viewport:{},__currentFrameBuffer:null,_viewportStack:[],_clearStack:[],_sceneRendering:null}},function(){this.canvas||(this.canvas=document.createElement("canvas"));var e=this.canvas;try{var t={alpha:this.alpha,depth:this.depth,stencil:this.stencil,antialias:this.antialias,premultipliedAlpha:this.premultipliedAlpha,preserveDrawingBuffer:this.preserveDrawingBuffer};if(this.gl=e.getContext("webgl",t)||e.getContext("experimental-webgl",t),!this.gl)throw new Error;this._glinfo=new s.a(this.gl),this.gl.targetRenderer&&console.error("Already created a renderer"),this.gl.targetRenderer=this,this.resize()}catch(e){throw"Error creating WebGL Context "+e}this._programMgr=new p.a(this)},{resize:function(e,t){var n=this.canvas,a=this.devicePixelRatio;null!=e?(n.style.width=e+"px",n.style.height=t+"px",n.width=e*a,n.height=t*a,this._width=e,this._height=t):(this._width=n.width/a,this._height=n.height/a),this.setViewport(0,0,this._width,this._height)},getWidth:function(){return this._width},getHeight:function(){return this._height},getViewportAspect:function(){var e=this.viewport;return e.width/e.height},setDevicePixelRatio:function(e){this.devicePixelRatio=e,this.resize(this._width,this._height)},getDevicePixelRatio:function(){return this.devicePixelRatio},getGLExtension:function(e){return this._glinfo.getExtension(e)},getGLParameter:function(e){return this._glinfo.getParameter(e)},setViewport:function(e,t,n,a,i){if("object"==typeof e){var r=e;e=r.x,t=r.y,n=r.width,a=r.height,i=r.devicePixelRatio}i=i||this.devicePixelRatio,this.gl.viewport(e*i,t*i,n*i,a*i),this.viewport={x:e,y:t,width:n,height:a,devicePixelRatio:i}},saveViewport:function(){this._viewportStack.push(this.viewport)},restoreViewport:function(){this._viewportStack.length>0&&this.setViewport(this._viewportStack.pop())},saveClear:function(){this._clearStack.push({clearBit:this.clearBit,clearColor:this.clearColor})},restoreClear:function(){if(this._clearStack.length>0){var e=this._clearStack.pop();this.clearColor=e.clearColor,this.clearBit=e.clearBit}},bindSceneRendering:function(e){this._sceneRendering=e},render:function(e,t,n,a){var i=this.gl,r=this.clearColor;if(this.clearBit){i.colorMask(!0,!0,!0,!0),i.depthMask(!0);var o=this.viewport,s=!1,c=o.devicePixelRatio;(o.width!==this._width||o.height!==this._height||c&&c!==this.devicePixelRatio||o.x||o.y)&&(s=!0,i.enable(i.SCISSOR_TEST),i.scissor(o.x*c,o.y*c,o.width*c,o.height*c)),i.clearColor(r[0],r[1],r[2],r[3]),i.clear(this.clearBit),s&&i.disable(i.SCISSOR_TEST)}if(n||e.update(!1),e.updateLights(),!(t=t||e.getMainCamera()))return void console.error("Can't find camera in the scene.");t.update();var l=e.updateRenderList(t);this._sceneRendering=e;var u=l.opaque,p=l.transparent,d=e.material;e.trigger("beforerender",this,e,t,l),a?(this.renderPreZ(u,e,t),i.depthFunc(i.LEQUAL)):i.depthFunc(i.LESS);for(var f=_(),h=x.create(),m=0;m0){var c=e[r-1],l=c.joints?c.joints.length:0;if((o.joints?o.joints.length:0)===l&&o.material===c.material&&o.lightGroup===c.lightGroup){o.__program=c.__program;continue}}var u=this._programMgr.getProgram(o,s,t);this.validateProgram(u),o.__program=u}},renderPass:function(e,t,n){this.trigger("beforerenderpass",this,e,t,n),n=n||{},n.getMaterial=n.getMaterial||a,n.beforeRender=n.beforeRender||i,n.afterRender=n.afterRender||i,this.updatePrograms(e,this._sceneRendering,n),n.sortCompare&&e.sort(n.sortCompare);var r=this.viewport,o=r.devicePixelRatio,s=[r.x*o,r.y*o,r.width*o,r.height*o],c=this.devicePixelRatio,l=this.__currentFrameBuffer?[this.__currentFrameBuffer.getTextureWidth(),this.__currentFrameBuffer.getTextureHeight()]:[this._width*c,this._height*c],u=[s[2],s[3]],p=Date.now();g.copy(E.VIEW,t.viewMatrix.array),g.copy(E.PROJECTION,t.projectionMatrix.array),g.multiply(E.VIEWPROJECTION,t.projectionMatrix.array,E.VIEW),g.copy(E.VIEWINVERSE,t.worldTransform.array),g.invert(E.PROJECTIONINVERSE,E.PROJECTION),g.invert(E.VIEWPROJECTIONINVERSE,E.VIEWPROJECTION);for(var d,f,h,m,v,x,_,y,b,T,w=this.gl,A=this._sceneRendering,S=this.getGLExtension("OES_vertex_array_object"),C=0;C=400?e.onerror&&e.onerror():e.onload&&e.onload(t.response)},e.onerror&&(t.onerror=e.onerror),t.send(null)}t.a={get:a}},function(e,t,n){"use strict";var a=n(14),i=n(9),r=n(42),o=n(43),s=n(0),c=n.n(s),l=c.a.vec3,u=c.a.vec4,p=a.a.extend(function(){return{projectionMatrix:new i.a,invProjectionMatrix:new i.a,viewMatrix:new i.a,frustum:new r.a}},function(){this.update(!0)},{update:function(e){a.a.prototype.update.call(this,e),i.a.invert(this.viewMatrix,this.worldTransform),this.updateProjectionMatrix(),i.a.invert(this.invProjectionMatrix,this.projectionMatrix),this.frustum.setFromProjection(this.projectionMatrix)},setViewMatrix:function(e){i.a.copy(this.viewMatrix,e),i.a.invert(this.worldTransform,e),this.decomposeWorldTransform()},decomposeProjectionMatrix:function(){},setProjectionMatrix:function(e){i.a.copy(this.projectionMatrix,e),i.a.invert(this.invProjectionMatrix,e),this.decomposeProjectionMatrix()},updateProjectionMatrix:function(){},castRay:function(){var e=u.create();return function(t,n){var a=void 0!==n?n:new o.a,i=t.array[0],r=t.array[1];return u.set(e,i,r,-1,1),u.transformMat4(e,e,this.invProjectionMatrix.array),u.transformMat4(e,e,this.worldTransform.array),l.scale(a.origin.array,e,1/e[3]),u.set(e,i,r,1,1),u.transformMat4(e,e,this.invProjectionMatrix.array),u.transformMat4(e,e,this.worldTransform.array),l.scale(e,e,1/e[3]),l.sub(a.direction.array,e,a.origin.array),l.normalize(a.direction.array,a.direction.array),a.direction._dirty=!0,a.origin._dirty=!0,a}}()});t.a=p},function(e,t,n){"use strict";var a=n(19),i=n(8),r=a.a.extend({dynamic:!1,widthSegments:1,heightSegments:1},function(){this.build()},{build:function(){for(var e=this.heightSegments,t=this.widthSegments,n=this.attributes,a=[],r=[],o=[],s=[],c=0;c<=e;c++)for(var l=c/e,u=0;u<=t;u++){var p=u/t;if(a.push([2*p-1,2*l-1,0]),r&&r.push([p,l]),o&&o.push([0,0,1]),u20)return console.warn("Given image is not a height map"),e}var d,f,h,m;c%(4*a)==0?(d=o.data[c],h=o.data[c+4]):c%(4*a)==4*(a-1)?(d=o.data[c-4],h=o.data[c]):(d=o.data[c-4],h=o.data[c+4]),c<4*a?(f=o.data[c],m=o.data[c+4*a]):c>a*(i-1)*4?(f=o.data[c-4*a],m=o.data[c]):(f=o.data[c-4*a],m=o.data[c+4*a]),s.data[c]=d-h+127,s.data[c+1]=f-m+127,s.data[c+2]=255,s.data[c+3]=255}return r.putImageData(s,0,0),n},isHeightImage:function(e,t,n){if(!e||!e.width||!e.height)return!1;var a=document.createElement("canvas"),i=a.getContext("2d"),r=t||32;n=n||20,a.width=a.height=r,i.drawImage(e,0,0,r,r);for(var o=i.getImageData(0,0,r,r),s=0;sn)return!1}return!0},_fetchTexture:function(e,t,n){r.a.get({url:e,responseType:"arraybuffer",onload:t,onerror:n})},createChessboard:function(e,t,n,i){e=e||512,t=t||64,n=n||"black",i=i||"white";var r=Math.ceil(e/t),o=document.createElement("canvas");o.width=e,o.height=e;var s=o.getContext("2d");s.fillStyle=i,s.fillRect(0,0,e,e),s.fillStyle=n;for(var c=0;c0?this.material.define("fragment","LOD"):this.material.undefine("fragment","LOD"),e.renderPass([this],t)}});t.a=c},function(e,t,n){"use strict";t.a={ENV_TEXTURE_ROOT:"./asset/texture/",SUPPORTED_MODEL_FILES:["fbx","obj","mtl","dae","dxf"],AUTO_SAVE:!0}},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";var a=n(72),i=function(e){this._list=new a.a,this._map={},this._maxSize=e||10};i.prototype.setMaxSize=function(e){this._maxSize=e},i.prototype.put=function(e,t){if(void 0===this._map[e]){var n=this._list.length();if(n>=this._maxSize&&n>0){var a=this._list.head;this._list.remove(a),delete this._map[a.key]}var i=this._list.insert(t);i.key=e,this._map[e]=i}},i.prototype.get=function(e){var t=this._map[e];if(void 0!==t)return t!==this._list.tail&&(this._list.remove(t),this._list.insertEntry(t)),t.value},i.prototype.remove=function(e){var t=this._map[e];void 0!==t&&(delete this._map[e],this._list.remove(t))},i.prototype.clear=function(){this._list.clear(),this._map={}},t.a=i},function(e,t,n){"use strict";var a=n(75),i=":unconfigurable;";t.a=["@export clay.header.directional_light","uniform vec3 directionalLightDirection[DIRECTIONAL_LIGHT_COUNT]"+i,"uniform vec3 directionalLightColor[DIRECTIONAL_LIGHT_COUNT]"+i,"@end","@export clay.header.ambient_light","uniform vec3 ambientLightColor[AMBIENT_LIGHT_COUNT]"+i,"@end","@export clay.header.ambient_sh_light","uniform vec3 ambientSHLightColor[AMBIENT_SH_LIGHT_COUNT]"+i,"uniform vec3 ambientSHLightCoefficients[AMBIENT_SH_LIGHT_COUNT * 9]"+i,a.a,"@end","@export clay.header.ambient_cubemap_light","uniform vec3 ambientCubemapLightColor[AMBIENT_CUBEMAP_LIGHT_COUNT]"+i,"uniform samplerCube ambientCubemapLightCubemap[AMBIENT_CUBEMAP_LIGHT_COUNT]"+i,"uniform sampler2D ambientCubemapLightBRDFLookup[AMBIENT_CUBEMAP_LIGHT_COUNT]"+i,"@end","@export clay.header.point_light","uniform vec3 pointLightPosition[POINT_LIGHT_COUNT]"+i,"uniform float pointLightRange[POINT_LIGHT_COUNT]"+i,"uniform vec3 pointLightColor[POINT_LIGHT_COUNT]"+i,"@end","@export clay.header.spot_light","uniform vec3 spotLightPosition[SPOT_LIGHT_COUNT]"+i,"uniform vec3 spotLightDirection[SPOT_LIGHT_COUNT]"+i,"uniform float spotLightRange[SPOT_LIGHT_COUNT]"+i,"uniform float spotLightUmbraAngleCosine[SPOT_LIGHT_COUNT]"+i,"uniform float spotLightPenumbraAngleCosine[SPOT_LIGHT_COUNT]"+i,"uniform float spotLightFalloffFactor[SPOT_LIGHT_COUNT]"+i,"uniform vec3 spotLightColor[SPOT_LIGHT_COUNT]"+i,"@end"].join("\n")},function(e,t,n){"use strict";t.a="@export clay.prez.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\n@import clay.chunk.skinning_header\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n}\n@end\n@export clay.prez.fragment\nvoid main()\n{\n gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n}\n@end"},function(e,t,n){"use strict";function a(e,t,n,a){var i=e.accessors[n],r=t.bufferViews[i.bufferView],o=i.byteOffset||0,c=C[i.componentType]||s.a.Float32Array,l=R[i.type];null==l&&a&&(l=1);var u=new c(r,o,l*i.count),p=i.extensions&&i.extensions.WEB3D_quantized_attributes;if(p){for(var d,f,h=new s.a.Float32Array(l*i.count),m=p.decodeMatrix,d=new Array(l),f=new Array(l),v=0;vp)){var d=Math.sqrt(p-u),f=c-d,h=c+d;return i||(i=new a.a),f<0?h<0?null:(o.scaleAndAdd(i.array,r,s,h),i):(o.scaleAndAdd(i.array,r,s,f),i)}}}(),intersectBoundingBox:function(e,t){var n,i,r,s,c,l,u=this.direction.array,p=this.origin.array,d=e.min.array,f=e.max.array,h=1/u[0],m=1/u[1],v=1/u[2];if(h>=0?(n=(d[0]-p[0])*h,i=(f[0]-p[0])*h):(i=(d[0]-p[0])*h,n=(f[0]-p[0])*h),m>=0?(r=(d[1]-p[1])*m,s=(f[1]-p[1])*m):(s=(d[1]-p[1])*m,r=(f[1]-p[1])*m),n>s||r>i)return null;if((r>n||n!==n)&&(n=r),(s=0?(c=(d[2]-p[2])*v,l=(f[2]-p[2])*v):(l=(d[2]-p[2])*v,c=(f[2]-p[2])*v),n>l||c>i)return null;if((c>n||n!==n)&&(n=c),(l=0?n:i;return t||(t=new a.a),o.scaleAndAdd(t.array,p,u,g),t},intersectTriangle:function(){var e=o.create(),t=o.create(),n=o.create(),i=o.create();return function(r,s,c,l,u,p){var d=this.direction.array,f=this.origin.array;r=r.array,s=s.array,c=c.array,o.sub(e,s,r),o.sub(t,c,r),o.cross(i,t,d);var h=o.dot(e,i);if(l){if(h>-1e-5)return null}else if(h>-1e-5&&h<1e-5)return null;o.sub(n,f,r);var m=o.dot(i,n)/h;if(m<0||m>1)return null;o.cross(i,e,n);var v=o.dot(d,i)/h;if(v<0||v>1||m+v>1)return null;o.cross(i,e,t);var g=-o.dot(n,i)/h;return g<0?null:(u||(u=new a.a),p&&a.a.set(p,1-m-v,m,v),o.scaleAndAdd(u.array,f,d,g),u)}}(),applyTransform:function(e){a.a.add(this.direction,this.direction,this.origin),a.a.transformMat4(this.origin,this.origin,e),a.a.transformMat4(this.direction,this.direction,e),a.a.sub(this.direction,this.direction,this.origin),a.a.normalize(this.direction,this.direction)},copy:function(e){a.a.copy(this.origin,e.origin),a.a.copy(this.direction,e.direction)},clone:function(){var e=new s;return e.copy(this),e}},t.a=s},function(e,t,n){"use strict";var a=n(10),i=n(2),r=n(45),o=n(7);i.a.import(r.a);var s,c=["diffuseMap","normalMap","roughnessMap","metalnessMap","emissiveMap","environmentMap","brdfLookup","ssaoMap","aoMap"],l=["color","emission","emissionIntensity","alpha","roughness","metalness","uvRepeat","uvOffset","aoIntensity","alphaCutoff"],u=["linear","encodeRGBM","decodeRGBM","doubleSided","alphaTest","roughnessChannel","metalnessChannel","environmentMapPrefiltered"],p={roughnessChannel:"ROUGHNESS_CHANNEL",metalnessChannel:"METALNESS_CHANNEL"},d={linear:"SRGB_DECODE",encodeRGBM:"RGBM_ENCODE",decodeRGBM:"RGBM_DECODE",doubleSided:"DOUBLE_SIDED",alphaTest:"ALPHA_TEST",environmentMapPrefiltered:"ENVIRONMENTMAP_PREFILTER"},f=a.a.extend(function(){return s||(s=new i.a(i.a.source("clay.standard.vertex"),i.a.source("clay.standard.fragment"))),{shader:s}},function(e){o.a.extend(this,e),o.a.defaults(this,{color:[1,1,1],emission:[0,0,0],emissionIntensity:0,roughness:.5,metalness:0,alpha:1,alphaTest:!1,alphaCutoff:.9,doubleSided:!1,uvRepeat:[1,1],uvOffset:[0,0],aoIntensity:1,environmentMapPrefiltered:!1,linear:!1,encodeRGBM:!1,decodeRGBM:!1,roughnessChannel:0,metalnessChannel:1}),this.define("fragment","USE_METALNESS"),this.define("fragment","USE_ROUGHNESS")},{clone:function(){var e=new f({name:this.name});return c.forEach(function(t){this[t]&&(e[t]=this[t])},this),l.concat(u).forEach(function(t){e[t]=this[t]},this),e}});l.forEach(function(e){Object.defineProperty(f.prototype,e,{get:function(){return this.get(e)},set:function(t){this.setUniform(e,t)}})}),c.forEach(function(e){Object.defineProperty(f.prototype,e,{get:function(){return this.get(e)},set:function(t){this.setUniform(e,t)}})}),u.forEach(function(e){var t="_"+e;Object.defineProperty(f.prototype,e,{get:function(){return this[t]},set:function(n){if(this[t]=n,e in p){var a=p[e];this.define("fragment",a,n)}else{var a=d[e];n?this.define("fragment",a):this.undefine("fragment",a)}}})}),Object.defineProperty(f.prototype,"environmentBox",{get:function(){var e=this._environmentBox;return e&&(e.min.setArray(this.get("environmentBoxMin")),e.max.setArray(this.get("environmentBoxMax"))),e},set:function(e){this._environmentBox=e;var t=this.uniforms=this.uniforms||{};t.environmentBoxMin=t.environmentBoxMin||{value:null},t.environmentBoxMax=t.environmentBoxMax||{value:null},e&&(this.setUniform("environmentBoxMin",e.min.array),this.setUniform("environmentBoxMax",e.max.array)),e?this.define("fragment","PARALLAX_CORRECTED"):this.undefine("fragment","PARALLAX_CORRECTED")}}),t.a=f},function(e,t,n){"use strict";t.a="\n@export clay.standard.chunk.varying\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nvarying vec3 v_Barycentric;\n#if defined(PARALLAXOCCLUSIONMAP_ENABLED) || defined(NORMALMAP_ENABLED)\nvarying vec3 v_Tangent;\nvarying vec3 v_Bitangent;\n#endif\n#if defined(AOMAP_ENABLED)\nvarying vec2 v_Texcoord2;\n#endif\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\n@end\n@export clay.standard.chunk.light_header\n#ifdef AMBIENT_LIGHT_COUNT\n@import clay.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import clay.header.ambient_sh_light\n#endif\n#ifdef AMBIENT_CUBEMAP_LIGHT_COUNT\n@import clay.header.ambient_cubemap_light\n#endif\n#ifdef POINT_LIGHT_COUNT\n@import clay.header.point_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n#ifdef SPOT_LIGHT_COUNT\n@import clay.header.spot_light\n#endif\n@end\n@export clay.standard.vertex\n#define SHADER_NAME standard\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\n#if defined(AOMAP_ENABLED)\nattribute vec2 texcoord2 : TEXCOORD_1;\n#endif\nattribute vec3 normal : NORMAL;\nattribute vec4 tangent : TANGENT;\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\n#endif\nattribute vec3 barycentric;\n@import clay.standard.chunk.varying\n@import clay.chunk.skinning_header\nvoid main()\n{\n vec3 skinnedPosition = position;\n vec3 skinnedNormal = normal;\n vec3 skinnedTangent = tangent.xyz;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n skinnedTangent = (skinMatrixWS * vec4(tangent.xyz, 0.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_WorldPosition = (world * vec4(skinnedPosition, 1.0)).xyz;\n v_Barycentric = barycentric;\n v_Normal = normalize((worldInverseTranspose * vec4(skinnedNormal, 0.0)).xyz);\n#if defined(PARALLAXOCCLUSIONMAP_ENABLED) || defined(NORMALMAP_ENABLED)\n v_Tangent = normalize((worldInverseTranspose * vec4(skinnedTangent, 0.0)).xyz);\n v_Bitangent = normalize(cross(v_Normal, v_Tangent) * tangent.w);\n#endif\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n#if defined(AOMAP_ENABLED)\n v_Texcoord2 = texcoord2;\n#endif\n}\n@end\n@export clay.standard.fragment\n#define PI 3.14159265358979\n#define GLOSSINESS_CHANNEL 0\n#define ROUGHNESS_CHANNEL 0\n#define METALNESS_CHANNEL 1\n@import clay.standard.chunk.varying\nuniform mat4 viewInverse : VIEWINVERSE;\n#ifdef NORMALMAP_ENABLED\nuniform sampler2D normalMap;\n#endif\n#ifdef DIFFUSEMAP_ENABLED\nuniform sampler2D diffuseMap;\n#endif\n#ifdef SPECULARMAP_ENABLED\nuniform sampler2D specularMap;\n#endif\n#ifdef USE_ROUGHNESS\nuniform float roughness : 0.5;\n #ifdef ROUGHNESSMAP_ENABLED\nuniform sampler2D roughnessMap;\n #endif\n#else\nuniform float glossiness: 0.5;\n #ifdef GLOSSINESSMAP_ENABLED\nuniform sampler2D glossinessMap;\n #endif\n#endif\n#ifdef METALNESSMAP_ENABLED\nuniform sampler2D metalnessMap;\n#endif\n#ifdef ENVIRONMENTMAP_ENABLED\nuniform samplerCube environmentMap;\n #ifdef PARALLAX_CORRECTED\nuniform vec3 environmentBoxMin;\nuniform vec3 environmentBoxMax;\n #endif\n#endif\n#ifdef BRDFLOOKUP_ENABLED\nuniform sampler2D brdfLookup;\n#endif\n#ifdef EMISSIVEMAP_ENABLED\nuniform sampler2D emissiveMap;\n#endif\n#ifdef SSAOMAP_ENABLED\nuniform sampler2D ssaoMap;\nuniform vec4 viewport : VIEWPORT;\n#endif\n#ifdef AOMAP_ENABLED\nuniform sampler2D aoMap;\nuniform float aoIntensity;\n#endif\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\n#ifdef USE_METALNESS\nuniform float metalness : 0.0;\n#else\nuniform vec3 specularColor : [0.1, 0.1, 0.1];\n#endif\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float emissionIntensity: 1;\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\n#ifdef ENVIRONMENTMAP_PREFILTER\nuniform float maxMipmapLevel: 5;\n#endif\n@import clay.standard.chunk.light_header\n@import clay.util.calculate_attenuation\n@import clay.util.edge_factor\n@import clay.util.rgbm\n@import clay.util.srgb\n@import clay.plugin.compute_shadow_map\n@import clay.util.parallax_correct\n@import clay.util.ACES\nfloat G_Smith(float g, float ndv, float ndl)\n{\n float roughness = 1.0 - g;\n float k = roughness * roughness / 2.0;\n float G1V = ndv / (ndv * (1.0 - k) + k);\n float G1L = ndl / (ndl * (1.0 - k) + k);\n return G1L * G1V;\n}\nvec3 F_Schlick(float ndv, vec3 spec) {\n return spec + (1.0 - spec) * pow(1.0 - ndv, 5.0);\n}\nfloat D_Phong(float g, float ndh) {\n float a = pow(8192.0, g);\n return (a + 2.0) / 8.0 * pow(ndh, a);\n}\nfloat D_GGX(float g, float ndh) {\n float r = 1.0 - g;\n float a = r * r;\n float tmp = ndh * ndh * (a - 1.0) + 1.0;\n return a / (PI * tmp * tmp);\n}\n#ifdef PARALLAXOCCLUSIONMAP_ENABLED\nuniform float parallaxOcclusionScale : 0.02;\nuniform float parallaxMaxLayers : 20;\nuniform float parallaxMinLayers : 5;\nuniform sampler2D parallaxOcclusionMap;\nmat3 transpose(in mat3 inMat)\n{\n vec3 i0 = inMat[0];\n vec3 i1 = inMat[1];\n vec3 i2 = inMat[2];\n return mat3(\n vec3(i0.x, i1.x, i2.x),\n vec3(i0.y, i1.y, i2.y),\n vec3(i0.z, i1.z, i2.z)\n );\n}\nvec2 parallaxUv(vec2 uv, vec3 viewDir)\n{\n float numLayers = mix(parallaxMaxLayers, parallaxMinLayers, abs(dot(vec3(0.0, 0.0, 1.0), viewDir)));\n float layerHeight = 1.0 / numLayers;\n float curLayerHeight = 0.0;\n vec2 deltaUv = viewDir.xy * parallaxOcclusionScale / (viewDir.z * numLayers);\n vec2 curUv = uv;\n float height = 1.0 - texture2D(parallaxOcclusionMap, curUv).r;\n for (int i = 0; i < 30; i++) {\n curLayerHeight += layerHeight;\n curUv -= deltaUv;\n height = 1.0 - texture2D(parallaxOcclusionMap, curUv).r;\n if (height < curLayerHeight) {\n break;\n }\n }\n vec2 prevUv = curUv + deltaUv;\n float next = height - curLayerHeight;\n float prev = 1.0 - texture2D(parallaxOcclusionMap, prevUv).r - curLayerHeight + layerHeight;\n return mix(curUv, prevUv, next / (next - prev));\n}\n#endif\nvoid main() {\n vec4 albedoColor = vec4(color, alpha);\n#ifdef VERTEX_COLOR\n albedoColor *= v_Color;\n#endif\n vec3 eyePos = viewInverse[3].xyz;\n vec3 V = normalize(eyePos - v_WorldPosition);\n vec2 uv = v_Texcoord;\n#if defined(PARALLAXOCCLUSIONMAP_ENABLED) || defined(NORMALMAP_ENABLED)\n mat3 tbn = mat3(v_Tangent, v_Bitangent, v_Normal);\n#endif\n#ifdef PARALLAXOCCLUSIONMAP_ENABLED\n uv = parallaxUv(v_Texcoord, normalize(transpose(tbn) * -V));\n#endif\n#ifdef DIFFUSEMAP_ENABLED\n vec4 texel = texture2D(diffuseMap, uv);\n #ifdef SRGB_DECODE\n texel = sRGBToLinear(texel);\n #endif\n albedoColor.rgb *= texel.rgb;\n #ifdef DIFFUSEMAP_ALPHA_ALPHA\n albedoColor.a *= texel.a;\n #endif\n#endif\n#ifdef USE_METALNESS\n float m = metalness;\n #ifdef METALNESSMAP_ENABLED\n float m2 = texture2D(metalnessMap, uv)[METALNESS_CHANNEL];\n m = clamp(m2 + (m - 0.5) * 2.0, 0.0, 1.0);\n #endif\n vec3 baseColor = albedoColor.rgb;\n albedoColor.rgb = baseColor * (1.0 - m);\n vec3 spec = mix(vec3(0.04), baseColor, m);\n#else\n vec3 spec = specularColor;\n#endif\n#ifdef USE_ROUGHNESS\n float g = 1.0 - roughness;\n #ifdef ROUGHNESSMAP_ENABLED\n float g2 = 1.0 - texture2D(roughnessMap, uv)[ROUGHNESS_CHANNEL];\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n #endif\n#else\n float g = glossiness;\n #ifdef GLOSSINESSMAP_ENABLED\n float g2 = texture2D(glossinessMap, uv)[GLOSSINESS_CHANNEL];\n g = clamp(g2 + (g - 0.5) * 2.0, 0.0, 1.0);\n #endif\n#endif\n#ifdef SPECULARMAP_ENABLED\n spec *= sRGBToLinear(texture2D(specularMap, uv)).rgb;\n#endif\n vec3 N = v_Normal;\n#ifdef DOUBLE_SIDED\n if (dot(N, V) < 0.0) {\n N = -N;\n }\n#endif\n#ifdef NORMALMAP_ENABLED\n if (dot(v_Tangent, v_Tangent) > 0.0) {\n vec3 normalTexel = texture2D(normalMap, uv).xyz;\n if (dot(normalTexel, normalTexel) > 0.0) { N = normalTexel * 2.0 - 1.0;\n tbn[1] = -tbn[1];\n N = normalize(tbn * N);\n }\n }\n#endif\n vec3 diffuseTerm = vec3(0.0, 0.0, 0.0);\n vec3 specularTerm = vec3(0.0, 0.0, 0.0);\n float ndv = clamp(dot(N, V), 0.0, 1.0);\n vec3 fresnelTerm = F_Schlick(ndv, spec);\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {{\n diffuseTerm += ambientLightColor[_idx_];\n }}\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseTerm += calcAmbientSHLight(_idx_, N) * ambientSHLightColor[_idx_];\n }}\n#endif\n#ifdef POINT_LIGHT_COUNT\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsPoint[POINT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfPointLights(v_WorldPosition, shadowContribsPoint);\n }\n#endif\n for(int _idx_ = 0; _idx_ < POINT_LIGHT_COUNT; _idx_++)\n {{\n vec3 lightPosition = pointLightPosition[_idx_];\n vec3 lc = pointLightColor[_idx_];\n float range = pointLightRange[_idx_];\n vec3 L = lightPosition - v_WorldPosition;\n float dist = length(L);\n float attenuation = lightAttenuation(dist, range);\n L /= dist;\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n if(shadowEnabled)\n {\n shadowContrib = shadowContribsPoint[_idx_];\n }\n#endif\n vec3 li = lc * ndl * attenuation * shadowContrib;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }}\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int _idx_ = 0; _idx_ < DIRECTIONAL_LIGHT_COUNT; _idx_++)\n {{\n vec3 L = -normalize(directionalLightDirection[_idx_]);\n vec3 lc = directionalLightColor[_idx_];\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if(shadowEnabled)\n {\n shadowContrib = shadowContribsDir[_idx_];\n }\n#endif\n vec3 li = lc * ndl * shadowContrib;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }}\n#endif\n#ifdef SPOT_LIGHT_COUNT\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsSpot[SPOT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfSpotLights(v_WorldPosition, shadowContribsSpot);\n }\n#endif\n for(int i = 0; i < SPOT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = spotLightPosition[i];\n vec3 spotLightDirection = -normalize(spotLightDirection[i]);\n vec3 lc = spotLightColor[i];\n float range = spotLightRange[i];\n float a = spotLightUmbraAngleCosine[i];\n float b = spotLightPenumbraAngleCosine[i];\n float falloffFactor = spotLightFalloffFactor[i];\n vec3 L = lightPosition - v_WorldPosition;\n float dist = length(L);\n float attenuation = lightAttenuation(dist, range);\n L /= dist;\n float c = dot(spotLightDirection, L);\n float falloff;\n falloff = clamp((c - a) /(b - a), 0.0, 1.0);\n falloff = pow(falloff, falloffFactor);\n vec3 H = normalize(L + V);\n float ndl = clamp(dot(N, L), 0.0, 1.0);\n float ndh = clamp(dot(N, H), 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n if (shadowEnabled)\n {\n shadowContrib = shadowContribsSpot[i];\n }\n#endif\n vec3 li = lc * attenuation * (1.0 - falloff) * shadowContrib * ndl;\n diffuseTerm += li;\n specularTerm += li * fresnelTerm * D_Phong(g, ndh);\n }\n#endif\n vec4 outColor = albedoColor;\n outColor.rgb *= max(diffuseTerm, vec3(0.0));\n outColor.rgb += max(specularTerm, vec3(0.0));\n#ifdef AMBIENT_CUBEMAP_LIGHT_COUNT\n vec3 L = reflect(-V, N);\n float rough2 = clamp(1.0 - g, 0.0, 1.0);\n float bias2 = rough2 * 5.0;\n vec2 brdfParam2 = texture2D(ambientCubemapLightBRDFLookup[0], vec2(rough2, ndv)).xy;\n vec3 envWeight2 = spec * brdfParam2.x + brdfParam2.y;\n vec3 envTexel2;\n for(int _idx_ = 0; _idx_ < AMBIENT_CUBEMAP_LIGHT_COUNT; _idx_++)\n {{\n envTexel2 = RGBMDecode(textureCubeLodEXT(ambientCubemapLightCubemap[_idx_], L, bias2), 8.12);\n outColor.rgb += ambientCubemapLightColor[_idx_] * envTexel2 * envWeight2;\n }}\n#endif\n#ifdef ENVIRONMENTMAP_ENABLED\n vec3 envWeight = g * fresnelTerm;\n vec3 L = reflect(-V, N);\n #ifdef PARALLAX_CORRECTED\n L = parallaxCorrect(L, v_WorldPosition, environmentBoxMin, environmentBoxMax);\n#endif\n #ifdef ENVIRONMENTMAP_PREFILTER\n float rough = clamp(1.0 - g, 0.0, 1.0);\n float bias = rough * maxMipmapLevel;\n vec3 envTexel = decodeHDR(textureCubeLodEXT(environmentMap, L, bias)).rgb;\n #ifdef BRDFLOOKUP_ENABLED\n vec2 brdfParam = texture2D(brdfLookup, vec2(rough, ndv)).xy;\n envWeight = spec * brdfParam.x + brdfParam.y;\n #endif\n #else\n vec3 envTexel = textureCube(environmentMap, L).xyz;\n #endif\n outColor.rgb += envTexel * envWeight;\n#endif\n float aoFactor = 1.0;\n#ifdef SSAOMAP_ENABLED\n aoFactor = min(texture2D(ssaoMap, (gl_FragCoord.xy - viewport.xy) / viewport.zw).r, aoFactor);\n#endif\n#ifdef AOMAP_ENABLED\n aoFactor = min(1.0 - clamp((1.0 - texture2D(aoMap, v_Texcoord2).r) * aoIntensity, 0.0, 1.0), aoFactor);\n#endif\n outColor.rgb *= aoFactor;\n vec3 lEmission = emission;\n#ifdef EMISSIVEMAP_ENABLED\n lEmission *= texture2D(emissiveMap, uv).rgb;\n#endif\n outColor.rgb += lEmission * emissionIntensity;\n if(lineWidth > 0.)\n {\n outColor.rgb = mix(outColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (outColor.a < alphaCutoff) {\n discard;\n }\n#endif\n#ifdef TONEMAPPING\n outColor.rgb = ACESToneMapping(outColor.rgb);\n#endif\n#ifdef SRGB_ENCODE\n outColor = linearTosRGB(outColor);\n#endif\n gl_FragColor = encodeHDR(outColor);\n}\n@end\n@export clay.standardMR.vertex\n@import clay.standard.vertex\n@end\n@export clay.standardMR.fragment\n#define USE_METALNESS\n#define USE_ROUGHNESS\n@import clay.standard.fragment\n@end"},function(e,t,n){"use strict";var a=n(14),i=n(6),r=a.a.extend({material:null,geometry:null,mode:i.a.TRIANGLES,_renderInfo:null},{__program:null,lightGroup:0,renderOrder:0,culling:!0,cullFace:i.a.BACK,frontFace:i.a.CCW,frustumCulling:!0,receiveShadow:!0,castShadow:!0,ignorePicking:!1,ignorePreZ:!1,ignoreGBuffer:!1,isRenderable:function(){return this.geometry&&this.material&&this.material.shader&&!this.invisible&&this.geometry.vertexCount>0},beforeRender:function(e){},afterRender:function(e,t){},getBoundingBox:function(e,t){return t=a.a.prototype.getBoundingBox.call(this,e,t),this.geometry&&this.geometry.boundingBox&&t.union(this.geometry.boundingBox),t},clone:function(){var e=["castShadow","receiveShadow","mode","culling","cullFace","frontFace","frustumCulling","renderOrder","lineWidth","ignorePicking","ignorePreZ","ignoreGBuffer"];return function(){var t=a.a.prototype.clone.call(this);t.geometry=this.geometry,t.material=this.material;for(var n=0;n>1,e|=e>>2,e|=e>>4,e|=e>>8,e|=e>>16,++e},a.nearestPowerOfTwo=function(e){return Math.pow(2,Math.round(Math.log(e)/Math.LN2))},t.a=a},function(e,t,n){"use strict";function a(){this._pool={}}function i(e,t,n){o[e]={vertex:t,fragment:n}}var r=n(2),o={};a.prototype.get=function(e){var t=e;if(this._pool[t])return this._pool[t];var n=o[e];if(!n)return void console.error('Shader "'+e+'" is not in the library');var a=new r.a(n.vertex,n.fragment);return this._pool[t]=a,a},a.prototype.clear=function(){this._pool={}};var s=new a;t.a={createLibrary:function(){return new a},get:function(){return s.get.apply(s,arguments)},template:i,clear:function(){return s.clear()}}},function(e,t,n){"use strict";var a=n(1),i=a.a.extend({name:"",index:-1,node:null});t.a=i},function(e,t,n){"use strict";function a(){}var i=n(51),r=function(e){e=e||{},this.name=e.name||"",this.target=e.target,this.life=e.life||1e3,this.delay=e.delay||0,this.gap=e.gap||0,this.playbackRate=e.playbackRate||1,this._initialized=!1,this._elapsedTime=0,this._loop=null!=e.loop&&e.loop,this.setLoop(this._loop),null!=e.easing&&this.setEasing(e.easing),this.onframe=e.onframe||a,this.onfinish=e.onfinish||a,this.onrestart=e.onrestart||a,this._paused=!1};r.prototype={gap:0,life:0,delay:0,setLoop:function(e){this._loop=e,e&&(this._loopRemained="number"==typeof e?e:1/0)},setEasing:function(e){"string"==typeof e&&(e=i.a[e]),this.easing=e},step:function(e,t,n){if(this._initialized||(this._startTime=e+this.delay,this._initialized=!0),null!=this._currentTime&&(t=e-this._currentTime),this._currentTime=e,this._paused)return"paused";if(!(e0?(this._restartInLoop(e),this._loopRemained--,"restart"):(this._needsRemove=!0,"finish"):null}}},setTime:function(e){return this.step(e+this._startTime)},restart:function(e){var t=0;e&&(this._elapse(e),t=this._elapsedTime%this.life),e=e||Date.now(),this._startTime=e-t+this.delay,this._elapsedTime=0,this._needsRemove=!1,this._paused=!1},getElapsedTime:function(){return this._elapsedTime},_restartInLoop:function(e){this._startTime=e+this.gap,this._elapsedTime=0},_elapse:function(e,t){this._elapsedTime+=t*this.playbackRate},fire:function(e,t){var n="on"+e;this[n]&&this[n](this.target,t)},clone:function(){var e=new this.constructor;return e.name=this.name,e._loop=this._loop,e._loopRemained=this._loopRemained,e.life=this.life,e.gap=this.gap,e.delay=this.delay,e},pause:function(){this._paused=!0},resume:function(){this._paused=!1}},r.prototype.constructor=r,t.a=r},function(e,t,n){"use strict";var a={linear:function(e){return e},quadraticIn:function(e){return e*e},quadraticOut:function(e){return e*(2-e)},quadraticInOut:function(e){return(e*=2)<1?.5*e*e:-.5*(--e*(e-2)-1)},cubicIn:function(e){return e*e*e},cubicOut:function(e){return--e*e*e+1},cubicInOut:function(e){return(e*=2)<1?.5*e*e*e:.5*((e-=2)*e*e+2)},quarticIn:function(e){return e*e*e*e},quarticOut:function(e){return 1- --e*e*e*e},quarticInOut:function(e){return(e*=2)<1?.5*e*e*e*e:-.5*((e-=2)*e*e*e-2)},quinticIn:function(e){return e*e*e*e*e},quinticOut:function(e){return--e*e*e*e*e+1},quinticInOut:function(e){return(e*=2)<1?.5*e*e*e*e*e:.5*((e-=2)*e*e*e*e+2)},sinusoidalIn:function(e){return 1-Math.cos(e*Math.PI/2)},sinusoidalOut:function(e){return Math.sin(e*Math.PI/2)},sinusoidalInOut:function(e){return.5*(1-Math.cos(Math.PI*e))},exponentialIn:function(e){return 0===e?0:Math.pow(1024,e-1)},exponentialOut:function(e){return 1===e?1:1-Math.pow(2,-10*e)},exponentialInOut:function(e){return 0===e?0:1===e?1:(e*=2)<1?.5*Math.pow(1024,e-1):.5*(2-Math.pow(2,-10*(e-1)))},circularIn:function(e){return 1-Math.sqrt(1-e*e)},circularOut:function(e){return Math.sqrt(1- --e*e)},circularInOut:function(e){return(e*=2)<1?-.5*(Math.sqrt(1-e*e)-1):.5*(Math.sqrt(1-(e-=2)*e)+1)},elasticIn:function(e){var t,n=.1;return 0===e?0:1===e?1:(!n||n<1?(n=1,t=.1):t=.4*Math.asin(1/n)/(2*Math.PI),-n*Math.pow(2,10*(e-=1))*Math.sin((e-t)*(2*Math.PI)/.4))},elasticOut:function(e){var t,n=.1;return 0===e?0:1===e?1:(!n||n<1?(n=1,t=.1):t=.4*Math.asin(1/n)/(2*Math.PI),n*Math.pow(2,-10*e)*Math.sin((e-t)*(2*Math.PI)/.4)+1)},elasticInOut:function(e){var t,n=.1;return 0===e?0:1===e?1:(!n||n<1?(n=1,t=.1):t=.4*Math.asin(1/n)/(2*Math.PI),(e*=2)<1?n*Math.pow(2,10*(e-=1))*Math.sin((e-t)*(2*Math.PI)/.4)*-.5:n*Math.pow(2,-10*(e-=1))*Math.sin((e-t)*(2*Math.PI)/.4)*.5+1)},backIn:function(e){var t=1.70158;return e*e*((t+1)*e-t)},backOut:function(e){var t=1.70158;return--e*e*((t+1)*e+t)+1},backInOut:function(e){var t=2.5949095;return(e*=2)<1?e*e*((t+1)*e-t)*.5:.5*((e-=2)*e*((t+1)*e+t)+2)},bounceIn:function(e){return 1-a.bounceOut(1-e)},bounceOut:function(e){return e<1/2.75?7.5625*e*e:e<2/2.75?7.5625*(e-=1.5/2.75)*e+.75:e<2.5/2.75?7.5625*(e-=2.25/2.75)*e+.9375:7.5625*(e-=2.625/2.75)*e+.984375},bounceInOut:function(e){return e<.5?.5*a.bounceIn(2*e):.5*a.bounceOut(2*e-1)+.5}};t.a=a},function(e,t,n){"use strict";t.a="@export clay.skybox.vertex\n#define SHADER_NAME skybox\nuniform mat4 world : WORLD;\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nattribute vec3 position : POSITION;\nvarying vec3 v_WorldPosition;\nvoid main()\n{\n v_WorldPosition = (world * vec4(position, 1.0)).xyz;\n gl_Position = worldViewProjection * vec4(position, 1.0);\n}\n@end\n@export clay.skybox.fragment\nuniform mat4 viewInverse : VIEWINVERSE;\nuniform samplerCube environmentMap;\nuniform float lod: 0.0;\nvarying vec3 v_WorldPosition;\n@import clay.util.rgbm\n@import clay.util.srgb\n@import clay.util.ACES\nvoid main()\n{\n vec3 eyePos = viewInverse[3].xyz;\n vec3 viewDirection = normalize(v_WorldPosition - eyePos);\n#ifdef LOD\n vec4 texel = decodeHDR(textureCubeLodEXT(environmentMap, viewDirection, lod));\n#else\n vec4 texel = decodeHDR(textureCube(environmentMap, viewDirection));\n#endif\n#ifdef SRGB_DECODE\n texel = sRGBToLinear(texel);\n#endif\n#ifdef TONEMAPPING\n texel.rgb = ACESToneMapping(texel.rgb);\n#endif\n#ifdef SRGB_ENCODE\n texel = linearTosRGB(texel);\n#endif\n gl_FragColor = encodeHDR(vec4(texel.rgb, 1.0));\n}\n@end"},function(e,t,n){"use strict";function a(e,t){var n=new s;return r.a.get({url:e,responseType:t,onload:function(e){n.resolve(e)},onerror:function(e){n.reject(e)}}),n}var i=n(20),r=n(29),o=n(7),s=function(){this._fullfilled=!1,this._rejected=!1};s.prototype.resolve=function(e){this._fullfilled=!0,this._rejected=!1,this.trigger("success",e)},s.prototype.reject=function(e){this._rejected=!0,this._fullfilled=!1,this.trigger("error",e)},s.prototype.isFullfilled=function(){return this._fullfilled},s.prototype.isRejected=function(){return this._rejected},s.prototype.isSettled=function(){return this._fullfilled||this._rejected},o.a.extend(s.prototype,i.a),s.makeRequestTask=function(e,t){if("string"==typeof e)return a(e,t);if(e.url){var n=e;return a(n.url,n.responseType)}if(Array.isArray(e)){var i=e,r=[];return i.forEach(function(e){var t,n;"string"==typeof e?t=e:Object(e)===e&&(t=e.url,n=e.responseType),r.push(a(t,n))}),r}},s.makeTask=function(){return new s},o.a.extend(s.prototype,i.a),t.a=s},function(e,t,n){"use strict";function a(e){c.a.defaultsWithPropList(e,u,p),i(e);for(var t="",n=0;n=32&&(D/=4),S.material.set("maxSampleNumber",Math.min(D,1024));for(var I=N.width,F=2*Math.atan(I/(I-.5))/Math.PI*180,k=0;k>>16)>>>0;p=((1431655765&p)<<1|(2863311530&p)>>>1)>>>0,p=((858993459&p)<<2|(3435973836&p)>>>2)>>>0,p=((252645135&p)<<4|(4042322160&p)>>>4)>>>0,p=(((16711935&p)<<8|(4278255360&p)>>>8)>>>0)/4294967296;var d=Math.sqrt((1-p)/(1+(l*l-1)*p));o[u]=d}for(var u=0;u=this._maxSize&&o>0){var c=n.head;n.remove(c),delete a[c.key],i=c.value,this._lastRemovedEntry=c}s?s.value=t:s=new r(t),s.key=e,n.insertEntry(s),a[e]=s}return i},s.get=function(e){var t=this._map[e],n=this._list;if(null!=t)return t!==n.tail&&(n.remove(t),n.insertEntry(t)),t.value},s.clear=function(){this._list.clear(),this._map={}},t.a=o},function(e,t,n){"use strict";function a(){["mainLight","secondaryLight","tertiaryLight"].forEach(function(e){j[e].alpha=90*j[e].$padAngle[1],j[e].beta=180*j[e].$padAngle[0]}),A.setMainLight(j.mainLight),A.setSecondaryLight(j.secondaryLight),A.setTertiaryLight(j.tertiaryLight),A.setAmbientLight(j.ambientLight)}function i(){A.setPostEffect(j.postEffect)}function r(){j.ambientCubemapLight.texture=I.a.ENV_TEXTURE_ROOT+j.ambientCubemapLight.$texture+".hdr",A.setAmbientCubemapLight(j.ambientCubemapLight)}function o(){A.setGround(j.ground)}function s(){a(),i(),r(),o()}function c(){var e=Math.max(G.$textureTiling,.01);G.uvRepeat=[e,e],G.transparent=G.alpha<1,A.setMaterial(G.name,G)}function l(e){G.name=e.name;var t=A.getMaterial(e.name);t.$textureTiling=t.uvRepeat[0],F.a.extend(G,t),null==t.specularColor?(C.enable(),R.disable()):(R.enable(),C.disable()),V.update()}function u(e){return e&&"none"!==e}function p(e,t,n){var a=!1;u(n)&&([["diffuseMap","color","#fff"],["metalnessMap","metalness",.5],["roughnessMap","roughness",.5],["glossinessMap","glossiness",.5],["specularMap","specularColor","#fff"],["emissiveMap","emission","#fff"]].forEach(function(t){e===t[0]&&(console.warn("Force %s to be %s after set %s",t[1],t[2],t[0]),G[t[1]]=t[2],a=!0)},this),g(),I.a.AUTO_SAVE&&D.g(t).then(_).catch(_),N[n]=t.name,a&&V.update()),c()}function d(){document.getElementById("tip").style.display="block"}function f(){document.getElementById("tip").style.display="none"}function h(){A=new L.a(document.getElementById("viewport"),j),A.enablePicking(),A.setCameraControl(j.viewControl),A.start(),A.on("select",function(e){A.refresh(),l(e.target.material),M=e.target}),A.on("doffocus",function(e){j.postEffect.depthOfField.enable&&(j.postEffect.depthOfField.focalDistance=e.distance,V.update())}),A.on("unselect",function(){A.refresh(),C.disable(),R.disable(),M=null}),A.on("afterrender",function(e,t,n){M&&Object(H.a)(A,[M],n)}),A.on("updatecamera",function(e){j.viewControl={center:e.center,alpha:e.alpha,beta:e.beta,distance:e.distance}})}function m(e){document.body.appendChild(W),W.querySelector("#loading-text").innerHTML=e||"LOADING"}function v(){W.parentNode&&W.parentNode.removeChild(W)}function g(){X.style.display="block",X.querySelector("#background-progress-text").innerHTML="Saving...DONT close the page."}function x(){X.style.display="block",X.querySelector("#background-progress-text").innerHTML="Preparing for download...DONT close the page."}function _(){X.style.display="none"}function y(){v(),document.getElementById("toolbar").style.display="block",document.getElementById("reset").addEventListener("click",T),document.getElementById("download").addEventListener("click",E),h(),FileAPI.event.dnd(document.getElementById("main"),function(e){},function(e){m("Loading model"),U.a(),D.a(e).then(function(e){var t=e.glTF,n=e.filesMap,a=e.buffers,i=e.allFiles;N={};for(var r in n)N[n[r]]=r;var o=!(!t.extras||!t.extras.clayViewerConfig);o&&(k.merge(j,t.extras.clayViewerConfig,!0),A.setCameraControl(j.viewControl),s(),V.update()),A.loadModel(t,{files:n,buffers:a,textureFlipY:j.textureFlipY,doubleSided:!0,upAxis:j.zUpToYUp?"z":"y",includeTexture:!o}).on("ready",function(){f(),v(),o&&(t.extras.clayViewerConfig.materials||[]).forEach(function(e){for(var t in e)n[e[t]]&&(e[t]=n[e[t]]);A.setMaterial(e.name,e)}),setTimeout(function(){g(),I.a.AUTO_SAVE&&D.e(i).then(_).catch(_)},200)}).on("loadmodel",w).on("error",function(){v(),swal("Model load error")}),C.disable(),R.disable()}).catch(function(e){v(),A.getModelRoot()||d(),U.b(A),console.log(e),swal(e.toString())})}),b(),q=!0}function b(){function e(e){return N&&N[e]}function t(t){t.addStringOutput(G,"name",{label:"Name"}).addColor(G,"color",{label:"Base Color",onChange:c}).addSlider(G,"alpha","$alphaRange",{label:"Alpha",onChange:c}).addSlider(G,"alphaCutoff","$alphaCutoffRange",{label:"Alpha Cutoff",onChange:c}).addNumberInput(G,"$textureTiling",{label:"Tiling",onChange:c,step:.5}).addCustomComponent(B.a,G,"diffuseMap",{label:"Base Map",onChange:p.bind(null,"diffuseMap"),getFileName:e}).addCustomComponent(B.a,G,"normalMap",{label:"Normal/Bump Map",onChange:p.bind(null,"normalMap"),getFileName:e})}function n(t){t.addCustomComponent(B.a,G,"parallaxOcclusionMap",{label:"Parallax Occlusion Map",onChange:p.bind(null,"parallaxOcclusionMap"),getFileName:e}).addSlider(G,"parallaxOcclusionScale","$parallaxOcclusionScaleRange",{label:"Scale",onChange:c}).addColor(G,"emission",{label:"Emission",onChange:c}).addNumberInput(G,"emissionIntensity",{label:"Emission Intensity",onChange:c}).addCustomComponent(B.a,G,"emissiveMap",{label:"Emissive Map",onChange:p.bind(null,"emissiveMap"),getFileName:e})}S=V.addPanel({label:"Settings",width:250}),S.addGroup({label:"Global"}).addSubGroup({label:"Load Option"}).addCheckbox(j,"textureFlipY",{label:"Flip Texture",onChange:function(){A.setTextureFlipY(j.textureFlipY)}}).addCheckbox(j,"zUpToYUp",{label:"Z Up",onChange:function(){A.setModelUpAxis(j.zUpToYUp?"Z":"Y")}}).addSubGroup({label:"Ground"}).addCheckbox(j.ground,"show",{label:"Show",onChange:o}).addCheckbox(j.ground,"grid",{label:"Grid",onChange:o}),S.addGroup({label:"Environment",enable:!1}).addSelect(j.ambientCubemapLight,"$textureOptions",{label:"HDR Texture",onChange:r,target:"$texture"}).addNumberInput(j.ambientCubemapLight,"diffuseIntensity",{label:"Diffuse Intensity",onChange:r,step:.1}).addNumberInput(j.ambientCubemapLight,"specularIntensity",{label:"Specular Intensity",onChange:r,step:.1}),S.addGroup({label:"Light",enable:!1}).addSubGroup({label:"Main",enable:!1}).addCheckbox(j.mainLight,"shadow",{label:"Cast Shadow",onChange:a}).addNumberInput(j.mainLight,"intensity",{label:"Intensity",step:.1,onChange:a}).addColor(j.mainLight,"color",{label:"Color",onChange:a}).addPad(j.mainLight,"$padAngle",{label:"Direction",onChange:a}).addSubGroup({label:"Secondary",enable:!1}).addNumberInput(j.secondaryLight,"intensity",{label:"Intensity",step:.1,onChange:a}).addColor(j.secondaryLight,"color",{label:"Color",onChange:a}).addPad(j.secondaryLight,"$padAngle",{label:"Direction",onChange:a}).addSubGroup({label:"Tertiary",enable:!1}).addNumberInput(j.tertiaryLight,"intensity",{label:"Intensity",step:.1,onChange:a}).addColor(j.tertiaryLight,"color",{label:"Color",onChange:a}).addPad(j.tertiaryLight,"$padAngle",{label:"Direction",onChange:a}).addSubGroup({label:"Ambient",enable:!1}).addNumberInput(j.ambientLight,"intensity",{label:"Intensity",step:.1,onChange:a}).addColor(j.ambientLight,"color",{label:"Color",onChange:a}),S.addGroup({label:"Post Effect",enable:!1}).addCheckbox(j.postEffect,"enable",{label:"Enable",onChange:i}).addSubGroup({label:"Bloom",enable:!1}).addCheckbox(j.postEffect.bloom,"enable",{label:"Enable",onChange:i}).addNumberInput(j.postEffect.bloom,"intensity",{label:"Intensity",step:.1,onChange:i}).addSubGroup({label:"Screen Space Ambient Occulusion",enable:!1}).addCheckbox(j.postEffect.screenSpaceAmbientOcclusion,"enable",{label:"Enable",onChange:i}).addNumberInput(j.postEffect.screenSpaceAmbientOcclusion,"radius",{label:"Radius",step:.1,onChange:i}).addNumberInput(j.postEffect.screenSpaceAmbientOcclusion,"intensity",{label:"Intensity",step:.1,onChange:i}).addSelect(j.postEffect.screenSpaceAmbientOcclusion,"$qualityOptions",{label:"Quality",onChange:i,target:"quality"}).addSubGroup({label:"Screen Space Reflection",enable:!1}).addCheckbox(j.postEffect.screenSpaceReflection,"enable",{label:"Enable",onChange:i}).addCheckbox(j.postEffect.screenSpaceReflection,"physical",{label:"Physical",onChange:i}).addNumberInput(j.postEffect.screenSpaceReflection,"maxRoughness",{label:"Max Roughness",step:.01,onChange:i}).addSelect(j.postEffect.screenSpaceReflection,"$qualityOptions",{label:"Quality",onChange:i,target:"quality"}).addSubGroup({label:"Depth of Field",enable:!1}).addCheckbox(j.postEffect.depthOfField,"enable",{label:"Enable",onChange:i}).addNumberInput(j.postEffect.depthOfField,"fstop",{label:"f-stop",step:.1,onChange:i}).addNumberInput(j.postEffect.depthOfField,"focalDistance",{label:"Focal Distance",step:.1,onChange:i}).addNumberInput(j.postEffect.depthOfField,"focalRange",{label:"Focal Range",step:.1,onChange:i}).addNumberInput(j.postEffect.depthOfField,"blurRadius",{label:"Blur Radius",step:.1,onChange:i}).addSelect(j.postEffect.depthOfField,"$qualityOptions",{label:"Quality",onChange:i,target:"quality"}).addSubGroup({label:"Color Correction",enable:!1}).addNumberInput(j.postEffect.colorCorrection,"exposure",{label:"Exposure",step:.1,onChange:i}).addNumberInput(j.postEffect.colorCorrection,"brightness",{label:"Brightness",step:.1,onChange:i}).addNumberInput(j.postEffect.colorCorrection,"contrast",{label:"Contrast",step:.1,onChange:i}).addNumberInput(j.postEffect.colorCorrection,"saturation",{label:"Saturation",step:.1,onChange:i}),C=V.addPanel({label:"Material - Metalllic Roughness",width:240,fixed:!1,align:"left",position:[10,10]}),t(C),C.addCustomComponent(B.a,G,"metalnessMap",{label:"Metalness Map",onChange:p.bind(null,"metalnessMap"),getFileName:e}).addSlider(G,"metalness","$metalnessRange",{label:"Metalness",onChange:c}).addCustomComponent(B.a,G,"roughnessMap",{label:"Roughness Map",onChange:p.bind(null,"roughnessMap"),getFileName:e}).addSlider(G,"roughness","$roughnessRange",{label:"Roughness",onChange:c}),n(C),C.disable(),R=V.addPanel({label:"Material - Specular Glossiness",width:240,fixed:!1,align:"left",position:[10,10]}),t(R),R.addCustomComponent(B.a,G,"specularMap",{label:"Specular Map",onChange:p.bind(null,"specularMap"),getFileName:e}).addColor(G,"specularColor",{label:"Specular Factor",onChange:c}).addCustomComponent(B.a,G,"glossinessMap",{label:"Glossiness Map",onChange:p.bind(null,"glossinessMap"),getFileName:e}).addSlider(G,"glossiness","$glossinessRange",{label:"Glossiness",onChange:c}),n(R),R.disable()}function T(){swal({title:"Reset?",text:"Reset the viewer",type:"warning",showCancelButton:!0,confirmButtonColor:"#3085d6",cancelButtonColor:"#d33",confirmButtonText:"Yes!"}).then(function(){k.merge(j,Object(O.a)(),!0),k.merge(G,Object(P.a)(),!0),V.update(),C.disable(),R.disable(),M=null,A.dispose(),h(),D.d(),d(),U.b(A),_()}).catch(function(){})}function E(){swal({title:"Select download format.",input:"radio",inputOptions:{glb:"GLB",zip:"ZIP"}}).then(function(e){x(),D.b(e,_,_)})}function w(){M=null,A.stopAnimation(),U.b(A)}Object.defineProperty(t,"__esModule",{value:!0});var A,S,C,R,M,N,L=n(67),O=n(145),P=n(146),D=n(147),I=n(36),F=n(7),k=n(156),B=(n.n(k),n(157)),U=n(158),H=n(159),z=n(161),j=Object(O.a)(),G=Object(P.a)(),V=new ControlKit({loadAndSave:!1,useExternalStyle:!0}),W=document.getElementById("loading"),X=document.getElementById("background-progress"),q=!1;D.c(function(e,t,n){if(n&&k.merge(j,n,!0),!q)if(y(),e){N={};for(var a in t)N[t[a]]=a;A.loadModel(e,{files:t,textureFlipY:j.textureFlipY,upAxis:j.zUpToYUp?"z":"y",doubleSided:!0,includeTexture:!1}).on("ready",function(){n&&n.materials&&n.materials.forEach(function(e){for(var n in e)t[e[n]]&&(e[n]=t[e[n]]);A.setMaterial(e.name,e)})}).on("loadmodel",w).on("error",function(){d(),swal("Model load error")})}else d()}),setTimeout(function(){q||(console.warn("Init time out"),y())},5e3),setInterval(function(){if(A&&!document.hidden){var e={};j.materials=A.getMaterialsNames().map(function(t){var n=A.getMaterial(t);for(var a in n)N[n[a]]&&(n[a]=N[n[a]]);return n.targetMeshes=[],e[t]=n,n}),A.getModelRoot()&&A.getModelRoot().traverse(function(t){t.material&&e[t.material.name]&&e[t.material.name].targetMeshes.push(t.originalMeshName||t.name)}),g(),I.a.AUTO_SAVE&&D.f(j).then(function(){_(),console.log("Saved")}).catch(_)}},5e3),window.addEventListener("resize",function(){A.resize()}),window.addEventListener("dragover",function(e){e.preventDefault()}),window.addEventListener("drop",function(e){e.preventDefault()}),$(document).on("click",'a[href^="http"]',function(e){e.preventDefault(),Object(z.a)(this.href)})},function(e,t,n){"use strict";var a=n(68);t.a=a.a},function(e,t,n){"use strict";function a(e,t){t=A.a(t),A.b(t,w.a),this.init(e,t)}var i=n(27),r=n(41),o=n(4),s=n(86),c=n(89),l=n(53),u=n(90),p=n(7),d=n(14),f=n(16),h=n(10),m=n(31),v=n(2),g=n(91),x=n(20),_=n(32),y=n(15),b=n(96),T=n(26),E=n(134),w=n(137),A=n(138),S=n(139),C=n(140),R=n(142),M=n(144);v.a.import(M.a);var N=["diffuseMap","normalMap","emissiveMap","metalnessMap","roughnessMap","specularMap","glossinessMap"];a.prototype.init=function(e,t){t=t||{},this.root=e,this._timeline=new s.a;var n=new i.a({devicePixelRatio:t.devicePixelRatio||window.devicePixelRatio});e.appendChild(n.canvas),n.canvas.style.cssText="position:absolute;left:0;top:0",this._renderer=n,this._renderMain=new b.a(n,t.shadow,"perspective"),this._renderMain.afterRenderScene=function(e,t,n){this.trigger("renderscene",e,t,n)}.bind(this),this._renderMain.afterRenderAll=function(e,t,n){this.trigger("afterrender",e,t,n)}.bind(this),this._renderMain.preZ=t.preZ||!1;var a=this._cameraControl=new C.a({renderer:n,timeline:this._timeline,domElement:e});a.target=this._renderMain.camera,a.init(),this._hotspotManager=new R.a({dom:e,renderer:n,camera:this._renderMain.camera}),this._skeletons=[],this._clips=[],this._takes=[],this._materialsMap={},this._sceneHelper=new E.a(this._renderMain.scene),this._sceneHelper.initLight(this._renderMain.scene),this.resize(),t.postEffect&&this.setPostEffect(t.postEffect),t.mainLight&&this.setMainLight(t.mainLight),t.secondaryLight&&this.setSecondaryLight(t.secondaryLight),t.tertiaryLight&&this.setTertiaryLight(t.tertiaryLight),t.ambientCubemapLight&&this.setAmbientCubemapLight(t.ambientCubemapLight),t.ambientLight&&this.setAmbientLight(t.ambientLight),t.environment&&this.setEnvironment(t.environment),this._createGround(),t.ground&&this.setGround(t.ground),this.setCameraControl({distance:20,minDisntance:2,maxDistance:100,center:[0,0,0]}),this._enablePicking=t.picking||!1,this._initHandlers(),a.on("update",function(){this.trigger("updatecamera",{center:a.getCenter(),alpha:a.getAlpha(),beta:a.getBeta(),distance:a.getDistance()}),this.refresh()},this)},a.prototype._createGround=function(){var e=new f.a({isGround:!0,material:new h.a({shader:new v.a({vertex:v.a.source("qmv.ground.vertex"),fragment:v.a.source("qmv.ground.fragment")}),transparent:!0}),castShadow:!1,geometry:new m.a,renderOrder:-10});e.material.set("color",[1,1,1,1]),e.scale.set(40,40,1),e.rotation.rotateX(-Math.PI/2),this._groundMesh=e,this._renderMain.scene.add(e)},a.prototype._addModel=function(e,t,n,a){this.removeModel(),this._renderMain.scene.add(e),this._skeletons=n.slice(),this._modelNode=e,this._setAnimationClips(a),t&&t.length&&(this._nodes=t);var i={};e.traverse(function(e){if(e.material){var t=e.material;i[t.name]=i[t.name]||[],i[t.name].push(t)}},this),this._materialsMap=i,this._updateMaterialsSRGB(),this._stopAccumulating()},a.prototype._removeAnimationClips=function(){this._clips.forEach(function(e){this._timeline.removeClip(e)},this),this._clips=[],this._takes=[]},a.prototype._setAnimationClips=function(e){function t(){n.refresh()}var n=this;e.forEach(function(e){e.tracks.forEach(function(e){e.target||(e.target=this._nodes[e.targetNodeIndex])},this),e.onframe=t,this._timeline.addClip(e),this._takes.push({name:e.name,range:[0,e.life],clip:e})},this),this._clips=e.slice()},a.prototype._initHandlers=function(){this._picking=new g.a({renderer:this._renderer,scene:this._renderMain.scene,camera:this._renderMain.camera}),this._clickHandler=this._clickHandler.bind(this),this._mouseDownHandler=this._mouseDownHandler.bind(this),this.root.addEventListener("mousedown",this._mouseDownHandler),this.root.addEventListener("click",this._clickHandler)},a.prototype._mouseDownHandler=function(e){this._startX=e.clientX,this._startY=e.clientY},a.prototype._clickHandler=function(e){if(this._enablePicking||this._renderMain.isDOFEnabled()){var t=e.clientX-this._startX,n=e.clientY-this._startY;if(!(Math.sqrt(t*t+n*n)>=5)){var a=this._picking.pick(e.clientX,e.clientY,!0);a&&!a.target.isGround?(this._renderMain.setDOFFocusOnPoint(a.distance),this.trigger("doffocus",a),this._selectResult=a,this.trigger("select",a),this.refresh()):(this._selectResult&&this.trigger("unselect",this._selectResult),this._selectResult=null)}}},a.prototype.enablePicking=function(){this._enablePicking=!0},a.prototype.disablePicking=function(){this._enablePicking=!1},a.prototype.setModelUpAxis=function(e){var t=this._modelNode;t&&(t.position.set(0,0,0),t.scale.set(1,1,1),t.rotation.identity(),"z"===e.toLowerCase()&&t.rotation.identity().rotateX(-Math.PI/2),this.autoFitModel())},a.prototype.setTextureFlipY=function(e){if(this._modelNode){for(var t in this._materialsMap)for(var n=0;n255?255:e}function i(e){return e=Math.round(e),e<0?0:e>360?360:e}function r(e){return e<0?0:e>1?1:e}function o(e){return a(e.length&&"%"===e.charAt(e.length-1)?parseFloat(e)/100*255:parseInt(e,10))}function s(e){return r(e.length&&"%"===e.charAt(e.length-1)?parseFloat(e)/100:parseFloat(e))}function c(e,t,n){return n<0?n+=1:n>1&&(n-=1),6*n<1?e+(t-e)*n*6:2*n<1?t:3*n<2?e+(t-e)*(2/3-n)*6:e}function l(e,t,n){return e+(t-e)*n}function u(e,t,n,a,i){return e[0]=t,e[1]=n,e[2]=a,e[3]=i,e}function p(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e}function d(e,t){_&&p(_,t),_=x.put(e,_||t.slice())}function f(e,t){var n=(parseFloat(e[0])%360+360)%360/360,i=s(e[1]),r=s(e[2]),o=r<=.5?r*(i+1):r+i-r*i,l=2*r-o;return t=t||[],u(t,a(255*c(l,o,n+1/3)),a(255*c(l,o,n)),a(255*c(l,o,n-1/3)),1),4===e.length&&(t[3]=e[3]),t}function h(e){if(e){var t,n,a=e[0]/255,i=e[1]/255,r=e[2]/255,o=Math.min(a,i,r),s=Math.max(a,i,r),c=s-o,l=(s+o)/2;if(0===c)t=0,n=0;else{n=l<.5?c/(s+o):c/(2-s-o);var u=((s-a)/6+c/2)/c,p=((s-i)/6+c/2)/c,d=((s-r)/6+c/2)/c;a===s?t=d-p:i===s?t=1/3+u-d:r===s&&(t=2/3+p-u),t<0&&(t+=1),t>1&&(t-=1)}var f=[360*t,n,l];return null!=e[3]&&f.push(e[3]),f}}var m=n(38),v={},g={transparent:[0,0,0,0],aliceblue:[240,248,255,1],antiquewhite:[250,235,215,1],aqua:[0,255,255,1],aquamarine:[127,255,212,1],azure:[240,255,255,1],beige:[245,245,220,1],bisque:[255,228,196,1],black:[0,0,0,1],blanchedalmond:[255,235,205,1],blue:[0,0,255,1],blueviolet:[138,43,226,1],brown:[165,42,42,1],burlywood:[222,184,135,1],cadetblue:[95,158,160,1],chartreuse:[127,255,0,1],chocolate:[210,105,30,1],coral:[255,127,80,1],cornflowerblue:[100,149,237,1],cornsilk:[255,248,220,1],crimson:[220,20,60,1],cyan:[0,255,255,1],darkblue:[0,0,139,1],darkcyan:[0,139,139,1],darkgoldenrod:[184,134,11,1],darkgray:[169,169,169,1],darkgreen:[0,100,0,1],darkgrey:[169,169,169,1],darkkhaki:[189,183,107,1],darkmagenta:[139,0,139,1],darkolivegreen:[85,107,47,1],darkorange:[255,140,0,1],darkorchid:[153,50,204,1],darkred:[139,0,0,1],darksalmon:[233,150,122,1],darkseagreen:[143,188,143,1],darkslateblue:[72,61,139,1],darkslategray:[47,79,79,1],darkslategrey:[47,79,79,1],darkturquoise:[0,206,209,1],darkviolet:[148,0,211,1],deeppink:[255,20,147,1],deepskyblue:[0,191,255,1],dimgray:[105,105,105,1],dimgrey:[105,105,105,1],dodgerblue:[30,144,255,1],firebrick:[178,34,34,1],floralwhite:[255,250,240,1],forestgreen:[34,139,34,1],fuchsia:[255,0,255,1],gainsboro:[220,220,220,1],ghostwhite:[248,248,255,1],gold:[255,215,0,1],goldenrod:[218,165,32,1],gray:[128,128,128,1],green:[0,128,0,1],greenyellow:[173,255,47,1],grey:[128,128,128,1],honeydew:[240,255,240,1],hotpink:[255,105,180,1],indianred:[205,92,92,1],indigo:[75,0,130,1],ivory:[255,255,240,1],khaki:[240,230,140,1],lavender:[230,230,250,1],lavenderblush:[255,240,245,1],lawngreen:[124,252,0,1],lemonchiffon:[255,250,205,1],lightblue:[173,216,230,1],lightcoral:[240,128,128,1],lightcyan:[224,255,255,1],lightgoldenrodyellow:[250,250,210,1],lightgray:[211,211,211,1],lightgreen:[144,238,144,1],lightgrey:[211,211,211,1],lightpink:[255,182,193,1],lightsalmon:[255,160,122,1],lightseagreen:[32,178,170,1],lightskyblue:[135,206,250,1],lightslategray:[119,136,153,1],lightslategrey:[119,136,153,1],lightsteelblue:[176,196,222,1],lightyellow:[255,255,224,1],lime:[0,255,0,1],limegreen:[50,205,50,1],linen:[250,240,230,1],magenta:[255,0,255,1],maroon:[128,0,0,1],mediumaquamarine:[102,205,170,1],mediumblue:[0,0,205,1],mediumorchid:[186,85,211,1],mediumpurple:[147,112,219,1],mediumseagreen:[60,179,113,1],mediumslateblue:[123,104,238,1],mediumspringgreen:[0,250,154,1],mediumturquoise:[72,209,204,1],mediumvioletred:[199,21,133,1],midnightblue:[25,25,112,1],mintcream:[245,255,250,1],mistyrose:[255,228,225,1],moccasin:[255,228,181,1],navajowhite:[255,222,173,1],navy:[0,0,128,1],oldlace:[253,245,230,1],olive:[128,128,0,1],olivedrab:[107,142,35,1],orange:[255,165,0,1],orangered:[255,69,0,1],orchid:[218,112,214,1],palegoldenrod:[238,232,170,1],palegreen:[152,251,152,1],paleturquoise:[175,238,238,1],palevioletred:[219,112,147,1],papayawhip:[255,239,213,1],peachpuff:[255,218,185,1],peru:[205,133,63,1],pink:[255,192,203,1],plum:[221,160,221,1],powderblue:[176,224,230,1],purple:[128,0,128,1],red:[255,0,0,1],rosybrown:[188,143,143,1],royalblue:[65,105,225,1],saddlebrown:[139,69,19,1],salmon:[250,128,114,1],sandybrown:[244,164,96,1],seagreen:[46,139,87,1],seashell:[255,245,238,1],sienna:[160,82,45,1],silver:[192,192,192,1],skyblue:[135,206,235,1],slateblue:[106,90,205,1],slategray:[112,128,144,1],slategrey:[112,128,144,1],snow:[255,250,250,1],springgreen:[0,255,127,1],steelblue:[70,130,180,1],tan:[210,180,140,1],teal:[0,128,128,1],thistle:[216,191,216,1],tomato:[255,99,71,1],turquoise:[64,224,208,1],violet:[238,130,238,1],wheat:[245,222,179,1],white:[255,255,255,1],whitesmoke:[245,245,245,1],yellow:[255,255,0,1],yellowgreen:[154,205,50,1]},x=new m.a(20),_=null;v.parse=function(e,t){if(e){t=t||[];var n=x.get(e);if(n)return p(t,n);e+="";var a=e.replace(/ /g,"").toLowerCase();if(a in g)return p(t,g[a]),d(e,t),t;if("#"!==a.charAt(0)){var i=a.indexOf("("),r=a.indexOf(")");if(-1!==i&&r+1===a.length){var c=a.substr(0,i),l=a.substr(i+1,r-(i+1)).split(","),h=1;switch(c){case"rgba":if(4!==l.length)return void u(t,0,0,0,1);h=s(l.pop());case"rgb":return 3!==l.length?void u(t,0,0,0,1):(u(t,o(l[0]),o(l[1]),o(l[2]),h),d(e,t),t);case"hsla":return 4!==l.length?void u(t,0,0,0,1):(l[3]=s(l[3]),f(l,t),d(e,t),t);case"hsl":return 3!==l.length?void u(t,0,0,0,1):(f(l,t),d(e,t),t);default:return}}u(t,0,0,0,1)}else{if(4===a.length){var m=parseInt(a.substr(1),16);return m>=0&&m<=4095?(u(t,(3840&m)>>4|(3840&m)>>8,240&m|(240&m)>>4,15&m|(15&m)<<4,1),d(e,t),t):void u(t,0,0,0,1)}if(7===a.length){var m=parseInt(a.substr(1),16);return m>=0&&m<=16777215?(u(t,(16711680&m)>>16,(65280&m)>>8,255&m,1),d(e,t),t):void u(t,0,0,0,1)}}}},v.parseToFloat=function(e,t){if(t=v.parse(e,t))return t[0]/=255,t[1]/=255,t[2]/=255,t},v.lift=function(e,t){var n=v.parse(e);if(n){for(var a=0;a<3;a++)n[a]=t<0?n[a]*(1-t)|0:(255-n[a])*t+n[a]|0;return v.stringify(n,4===n.length?"rgba":"rgb")}},v.toHex=function(e){var t=v.parse(e);if(t)return((1<<24)+(t[0]<<16)+(t[1]<<8)+ +t[2]).toString(16).slice(1)},v.fastLerp=function(e,t,n){if(t&&t.length&&e>=0&&e<=1){n=n||[];var i=e*(t.length-1),o=Math.floor(i),s=Math.ceil(i),c=t[o],u=t[s],p=i-o;return n[0]=a(l(c[0],u[0],p)),n[1]=a(l(c[1],u[1],p)),n[2]=a(l(c[2],u[2],p)),n[3]=r(l(c[3],u[3],p)),n}},v.fastMapToColor=v.fastLerp,v.lerp=function(e,t,n){if(t&&t.length&&e>=0&&e<=1){var i=e*(t.length-1),o=Math.floor(i),s=Math.ceil(i),c=v.parse(t[o]),u=v.parse(t[s]),p=i-o,d=v.stringify([a(l(c[0],u[0],p)),a(l(c[1],u[1],p)),a(l(c[2],u[2],p)),r(l(c[3],u[3],p))],"rgba");return n?{color:d,leftIndex:o,rightIndex:s,value:i}:d}},v.mapToColor=v.lerp,v.modifyHSL=function(e,t,n,a){if(e=v.parse(e))return e=h(e),null!=t&&(e[0]=i(t)),null!=n&&(e[1]=s(n)),null!=a&&(e[2]=s(a)),v.stringify(f(e),"rgba")},v.modifyAlpha=function(e,t){if((e=v.parse(e))&&null!=t)return e[3]=r(t),v.stringify(e,"rgba")},v.stringify=function(e,t){if(e&&e.length){var n=e[0]+","+e[1]+","+e[2];return"rgba"!==t&&"hsva"!==t&&"hsla"!==t||(n+=","+e[3]),t+"("+n+")"}},t.a=v},function(e,t,n){"use strict";var a=function(){this.head=null,this.tail=null,this._length=0};a.prototype.insert=function(e){var t=new a.Entry(e);return this.insertEntry(t),t},a.prototype.insertAt=function(e,t){if(!(e<0)){for(var n=this.head,i=0;n&&i!=e;)n=n.next,i++;if(n){var r=new a.Entry(t),o=n.prev;o?(o.next=r,r.prev=o):this.head=r,r.next=n,n.prev=r}else this.insert(t)}},a.prototype.insertBeforeEntry=function(e,t){var n=new a.Entry(e),i=t.prev;i?(i.next=n,n.prev=i):this.head=n,n.next=t,t.prev=n,this._length++},a.prototype.insertEntry=function(e){this.head?(this.tail.next=e,e.prev=this.tail,this.tail=e):this.head=this.tail=e,this._length++},a.prototype.remove=function(e){var t=e.prev,n=e.next;t?t.next=n:this.head=n,n?n.prev=t:this.tail=t,e.next=e.prev=null,this._length--},a.prototype.removeAt=function(e){if(!(e<0)){for(var t=this.head,n=0;t&&n!=e;)t=t.next,n++;return t?(this.remove(t),t.value):void 0}},a.prototype.getHead=function(){if(this.head)return this.head.value},a.prototype.getTail=function(){if(this.tail)return this.tail.value},a.prototype.getAt=function(e){if(!(e<0)){for(var t=this.head,n=0;t&&n!=e;)t=t.next,n++;return t.value}},a.prototype.indexOf=function(e){for(var t=this.head,n=0;t;){if(t.value===e)return n;t=t.next,n++}},a.prototype.length=function(){return this._length},a.prototype.isEmpty=function(){return 0===this._length},a.prototype.forEach=function(e,t){for(var n=this.head,a=0,i=void 0!==t;n;)i?e.call(t,n.value,a):e(n.value,a),n=n.next,a++},a.prototype.clear=function(){this.tail=this.head=null,this._length=0},a.Entry=function(e){this.value=e,this.next=null,this.prev=null},t.a=a},function(e,t,n){"use strict";function a(e,t,n){function a(e,n,a,r){var o="";isNaN(n)&&(n=n in t?t[n]:i[n]),isNaN(a)&&(a=a in t?t[a]:i[a]);for(var s=parseInt(n);s0&&a.push("#define "+i.toUpperCase()+"_COUNT "+r)}if(n)for(var o=0;othis.distance,i=1;i<8;i++)if(o.dot(t[i].array,n)>this.distance!=a)return!0},intersectLine:function(){var e=o.create();return function(t,n,i){var r=this.distanceToPoint(t),s=this.distanceToPoint(n);if(r>0&&s>0||r<0&&s<0)return null;var c=this.normal.array,l=this.distance,u=t.array;o.sub(e,n.array,t.array),o.normalize(e,e);var p=o.dot(c,e);if(0===p)return null;i||(i=new a.a);var d=(o.dot(c,u)-l)/p;return o.scaleAndAdd(i.array,u,e,-d),i._dirty=!0,i}}(),applyTransform:function(){var e=s.create(),t=c.create(),n=c.create();return n[3]=1,function(a){a=a.array,o.scale(n,this.normal.array,this.distance),c.transformMat4(n,n,a),this.distance=o.dot(n,this.normal.array),s.invert(e,a),s.transpose(e,e),t[3]=0,o.copy(t,this.normal.array),c.transformMat4(t,t,e),o.copy(this.normal.array,t)}}(),copy:function(e){o.copy(this.normal.array,e.normal.array),this.normal._dirty=!0,this.distance=e.distance},clone:function(){var e=new l;return e.copy(this),e}},t.a=l},function(e,t,n){"use strict";var a=n(1),i=n(49),r=n(0),o=n.n(r),s=o.a.quat,c=o.a.vec3,l=o.a.mat4,u=a.a.extend(function(){return{relativeRootNode:null,name:"",joints:[],_clips:[],_invBindPoseMatricesArray:null,_jointMatricesSubArrays:[],_skinMatricesArray:null,_skinMatricesSubArrays:[],_subSkinMatricesArray:{}}},{addClip:function(e,t){for(var n=0;n0&&this._clips.splice(t,1)},removeClipsAll:function(){this._clips=[]},getClip:function(e){if(this._clips[e])return this._clips[e].clip},getClipNumber:function(){return this._clips.length},updateJointMatrices:function(){var e=l.create();return function(){this._invBindPoseMatricesArray=new Float32Array(16*this.joints.length),this._skinMatricesArray=new Float32Array(16*this.joints.length);for(var t=0;t=0&&this.tracks.splice(t,1)},c.prototype.getSubClip=function(e,t,n){for(var a=new c({name:this.name}),i=0;i1e-6?(o=Math.acos(s),c=Math.sin(o),l=Math.sin((1-a)*o)/c,u=Math.sin(a*o)/c):(l=1-a,u=a),e[0]=l*p+u*m,e[1]=l*d+u*v,e[2]=l*f+u*g,e[3]=l*h+u*x,e}var r=n(0),o=n.n(r),s=o.a.quat,c=o.a.vec3,l=function(e){e=e||{},this.name=e.name||"",this.target=e.target||null,this.position=c.create(),this.rotation=s.create(),this.scale=c.fromValues(1,1,1),this.channels={time:null,position:null,rotation:null,scale:null},this._cacheKey=0,this._cacheTime=0};l.prototype.setTime=function(e){if(this.channels.time){var t=this.channels,n=t.time.length,r=-1;if(1===n)return t.rotation&&s.copy(this.rotation,t.rotation),t.position&&c.copy(this.position,t.position),void(t.scale&&c.copy(this.scale,t.scale));if(e<=t.time[0])e=t.time[0],r=0;else if(e>=t.time[n-1])e=t.time[n-1],r=n-2;else if(e=0;l--)if(t.time[l-1]<=e&&t.time[l]>e){r=l-1;break}}else for(var l=this._cacheKey;le){r=l;break}if(r>-1){this._cacheKey=r,this._cacheTime=e;var u=r,p=r+1,d=t.time[u],f=t.time[p],h=f-d,m=0===h?0:(e-d)/h;t.rotation&&i(this.rotation,t.rotation,t.rotation,m,4*u,4*p),t.position&&a(this.position,t.position,t.position,m,3*u,3*p),t.scale&&a(this.scale,t.scale,t.scale,m,3*u,3*p)}r===n-2&&(this._cacheKey=0,this._cacheTime=0),this.updateTarget()}},l.prototype.updateTarget=function(){var e=this.channels;this.target&&(e.position&&this.target.position.setArray(this.position),e.rotation&&this.target.rotation.setArray(this.rotation),e.scale&&this.target.scale.setArray(this.scale))},l.prototype.getMaxTime=function(){return this.channels.time[this.channels.time.length-1]},l.prototype.getSubTrack=function(e,t){var n=new l({name:this.name}),a=this.channels.time[0];e=Math.min(Math.max(e,a),this.life),t=Math.min(Math.max(t,a),this.life);var i=this._findRange(e),r=this._findRange(t),o=r[0]-i[0]+1;0===i[1]&&0===r[1]&&(o-=1),this.channels.rotation&&(n.channels.rotation=new Float32Array(4*o)),this.channels.position&&(n.channels.position=new Float32Array(3*o)),this.channels.scale&&(n.channels.scale=new Float32Array(3*o)),this.channels.time&&(n.channels.time=new Float32Array(o)),this.setTime(e);for(var s=0;s<3;s++)n.channels.rotation[s]=this.rotation[s],n.channels.position[s]=this.position[s],n.channels.scale[s]=this.scale[s];n.channels.time[0]=0,n.channels.rotation[3]=this.rotation[3];for(var s=1;se&&(a=i);var r=0;if(a>=0)var o=t.time[a],s=t.time[a+1],r=(e-o)/(s-o);return[a,r]},l.prototype.blend1D=function(e,t,n){c.lerp(this.position,e.position,t.position,n),c.lerp(this.scale,e.scale,t.scale,n),s.slerp(this.rotation,e.rotation,t.rotation,n)},l.prototype.blend2D=function(){var e=s.create(),t=s.create();return function(n,a,i,r,o){var c=1-r-o;this.position[0]=n.position[0]*c+a.position[0]*r+i.position[0]*o,this.position[1]=n.position[1]*c+a.position[1]*r+i.position[1]*o,this.position[2]=n.position[2]*c+a.position[2]*r+i.position[2]*o,this.scale[0]=n.scale[0]*c+a.scale[0]*r+i.scale[0]*o,this.scale[1]=n.scale[1]*c+a.scale[1]*r+i.scale[1]*o,this.scale[2]=n.scale[2]*c+a.scale[2]*r+i.scale[2]*o;var l=r+o;0===l?s.copy(this.rotation,n.rotation):(s.slerp(e,n.rotation,a.rotation,l),s.slerp(t,n.rotation,i.rotation,l),s.slerp(this.rotation,e,t,o/l))}}(),l.prototype.additiveBlend=function(e,t){c.add(this.position,e.position,t.position),c.add(this.scale,e.scale,t.scale),s.multiply(this.rotation,t.rotation,e.rotation)},l.prototype.subtractiveBlend=function(e,t){c.sub(this.position,e.position,t.position),c.sub(this.scale,e.scale,t.scale),s.invert(this.rotation,t.rotation),s.multiply(this.rotation,this.rotation,e.rotation)},l.prototype.clone=function(){var e=l.prototype.clone.call(this);return e.channels={time:this.channels.time||null,position:this.channels.position||null,rotation:this.channels.rotation||null,scale:this.channels.scale||null},c.copy(e.position,this.position),s.copy(e.rotation,this.rotation),c.copy(e.scale,this.scale),e.target=this.target,e.updateTarget(),e},t.a=l},function(e,t,n){"use strict";var a=n(39),i=n(82),r=n(83),o=n(84),s=n(45),c=n(85),l=n(52),u=n(40),p=n(48),d=n(2);d.a.import(a.a),d.a.import(i.a),d.a.import(r.a),d.a.import(o.a),d.a.import(s.a),d.a.import(c.a),d.a.import(l.a),d.a.import(u.a),p.a.template("clay.basic",d.a.source("clay.basic.vertex"),d.a.source("clay.basic.fragment")),p.a.template("clay.lambert",d.a.source("clay.lambert.vertex"),d.a.source("clay.lambert.fragment")),p.a.template("clay.wireframe",d.a.source("clay.wireframe.vertex"),d.a.source("clay.wireframe.fragment")),p.a.template("clay.skybox",d.a.source("clay.skybox.vertex"),d.a.source("clay.skybox.fragment")),p.a.template("clay.prez",d.a.source("clay.prez.vertex"),d.a.source("clay.prez.fragment")),p.a.template("clay.standard",d.a.source("clay.standard.vertex"),d.a.source("clay.standard.fragment")),p.a.template("clay.standardMR",d.a.source("clay.standardMR.vertex"),d.a.source("clay.standardMR.fragment"))},function(e,t,n){"use strict";t.a="\n@export clay.util.rand\nhighp float rand(vec2 uv) {\n const highp float a = 12.9898, b = 78.233, c = 43758.5453;\n highp float dt = dot(uv.xy, vec2(a,b)), sn = mod(dt, 3.141592653589793);\n return fract(sin(sn) * c);\n}\n@end\n@export clay.util.calculate_attenuation\nuniform float attenuationFactor : 5.0;\nfloat lightAttenuation(float dist, float range)\n{\n float attenuation = 1.0;\n attenuation = dist*dist/(range*range+1.0);\n float att_s = attenuationFactor;\n attenuation = 1.0/(attenuation*att_s+1.0);\n att_s = 1.0/(att_s+1.0);\n attenuation = attenuation - att_s;\n attenuation /= 1.0 - att_s;\n return clamp(attenuation, 0.0, 1.0);\n}\n@end\n@export clay.util.edge_factor\nfloat edgeFactor(float width)\n{\n vec3 d = fwidth(v_Barycentric);\n vec3 a3 = smoothstep(vec3(0.0), d * width, v_Barycentric);\n return min(min(a3.x, a3.y), a3.z);\n}\n@end\n@export clay.util.encode_float\nvec4 encodeFloat(const in float depth)\n{\n const vec4 bitShifts = vec4(256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0);\n const vec4 bit_mask = vec4(0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0);\n vec4 res = fract(depth * bitShifts);\n res -= res.xxyz * bit_mask;\n return res;\n}\n@end\n@export clay.util.decode_float\nfloat decodeFloat(const in vec4 color)\n{\n const vec4 bitShifts = vec4(1.0/(256.0*256.0*256.0), 1.0/(256.0*256.0), 1.0/256.0, 1.0);\n return dot(color, bitShifts);\n}\n@end\n@export clay.util.float\n@import clay.util.encode_float\n@import clay.util.decode_float\n@end\n@export clay.util.rgbm_decode\nvec3 RGBMDecode(vec4 rgbm, float range) {\n return range * rgbm.rgb * rgbm.a;\n}\n@end\n@export clay.util.rgbm_encode\nvec4 RGBMEncode(vec3 color, float range) {\n if (dot(color, color) == 0.0) {\n return vec4(0.0);\n }\n vec4 rgbm;\n color /= range;\n rgbm.a = clamp(max(max(color.r, color.g), max(color.b, 1e-6)), 0.0, 1.0);\n rgbm.a = ceil(rgbm.a * 255.0) / 255.0;\n rgbm.rgb = color / rgbm.a;\n return rgbm;\n}\n@end\n@export clay.util.rgbm\n@import clay.util.rgbm_decode\n@import clay.util.rgbm_encode\nvec4 decodeHDR(vec4 color)\n{\n#if defined(RGBM_DECODE) || defined(RGBM)\n return vec4(RGBMDecode(color, 8.12), 1.0);\n#else\n return color;\n#endif\n}\nvec4 encodeHDR(vec4 color)\n{\n#if defined(RGBM_ENCODE) || defined(RGBM)\n return RGBMEncode(color.xyz, 8.12);\n#else\n return color;\n#endif\n}\n@end\n@export clay.util.srgb\nvec4 sRGBToLinear(in vec4 value) {\n return vec4(mix(pow(value.rgb * 0.9478672986 + vec3(0.0521327014), vec3(2.4)), value.rgb * 0.0773993808, vec3(lessThanEqual(value.rgb, vec3(0.04045)))), value.w);\n}\nvec4 linearTosRGB(in vec4 value) {\n return vec4(mix(pow(value.rgb, vec3(0.41666)) * 1.055 - vec3(0.055), value.rgb * 12.92, vec3(lessThanEqual(value.rgb, vec3(0.0031308)))), value.w);\n}\n@end\n@export clay.chunk.skinning_header\n#ifdef SKINNING\nattribute vec3 weight : WEIGHT;\nattribute vec4 joint : JOINT;\nuniform mat4 skinMatrix[JOINT_COUNT] : SKIN_MATRIX;\nmat4 getSkinMatrix(float idx) {\n return skinMatrix[int(idx)];\n}\n#endif\n@end\n@export clay.chunk.skin_matrix\nmat4 skinMatrixWS = getSkinMatrix(joint.x) * weight.x;\nif (weight.y > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.y) * weight.y;\n}\nif (weight.z > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.z) * weight.z;\n}\nfloat weightW = 1.0-weight.x-weight.y-weight.z;\nif (weightW > 1e-4)\n{\n skinMatrixWS += getSkinMatrix(joint.w) * weightW;\n}\n@end\n@export clay.util.parallax_correct\nvec3 parallaxCorrect(in vec3 dir, in vec3 pos, in vec3 boxMin, in vec3 boxMax) {\n vec3 first = (boxMax - pos) / dir;\n vec3 second = (boxMin - pos) / dir;\n vec3 further = max(first, second);\n float dist = min(further.x, min(further.y, further.z));\n vec3 fixedPos = pos + dir * dist;\n vec3 boxCenter = (boxMax + boxMin) * 0.5;\n return normalize(fixedPos - boxCenter);\n}\n@end\n@export clay.util.clamp_sample\nvec4 clampSample(const in sampler2D texture, const in vec2 coord)\n{\n#ifdef STEREO\n float eye = step(0.5, coord.x) * 0.5;\n vec2 coordClamped = clamp(coord, vec2(eye, 0.0), vec2(0.5 + eye, 1.0));\n#else\n vec2 coordClamped = clamp(coord, vec2(0.0), vec2(1.0));\n#endif\n return texture2D(texture, coordClamped);\n}\n@end\n@export clay.util.ACES\nvec3 ACESToneMapping(vec3 color)\n{\n const float A = 2.51;\n const float B = 0.03;\n const float C = 2.43;\n const float D = 0.59;\n const float E = 0.14;\n return (color * (A * color + B)) / (color * (C * color + D) + E);\n}\n@end"},function(e,t,n){"use strict";t.a="@export clay.basic.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec2 texcoord : TEXCOORD_0;\nattribute vec3 position : POSITION;\nattribute vec3 barycentric;\n@import clay.chunk.skinning_header\nvarying vec2 v_Texcoord;\nvarying vec3 v_Barycentric;\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n#endif\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_Barycentric = barycentric;\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0);\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n}\n@end\n@export clay.basic.fragment\nvarying vec2 v_Texcoord;\nuniform sampler2D diffuseMap;\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\nvarying vec3 v_Barycentric;\n@import clay.util.edge_factor\n@import clay.util.rgbm\n@import clay.util.srgb\n@import clay.util.ACES\nvoid main()\n{\n#ifdef RENDER_TEXCOORD\n gl_FragColor = vec4(v_Texcoord, 1.0, 1.0);\n return;\n#endif\n gl_FragColor = vec4(color, alpha);\n#ifdef VERTEX_COLOR\n gl_FragColor *= v_Color;\n#endif\n#ifdef DIFFUSEMAP_ENABLED\n vec4 texel = decodeHDR(texture2D(diffuseMap, v_Texcoord));\n#ifdef SRGB_DECODE\n texel = sRGBToLinear(texel);\n#endif\n#if defined(DIFFUSEMAP_ALPHA_ALPHA)\n gl_FragColor.a = texel.a;\n#endif\n gl_FragColor.rgb *= texel.rgb;\n#endif\n gl_FragColor.rgb += emission;\n if( lineWidth > 0.)\n {\n gl_FragColor.rgb = mix(gl_FragColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (gl_FragColor.a < alphaCutoff) {\n discard;\n }\n#endif\n#ifdef TONEMAPPING\n gl_FragColor.rgb = ACESToneMapping(gl_FragColor.rgb);\n#endif\n#ifdef SRGB_ENCODE\n gl_FragColor = linearTosRGB(gl_FragColor);\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n}\n@end"},function(e,t,n){"use strict";t.a="\n@export clay.lambert.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 worldInverseTranspose : WORLDINVERSETRANSPOSE;\nuniform mat4 world : WORLD;\nuniform vec2 uvRepeat : [1.0, 1.0];\nuniform vec2 uvOffset : [0.0, 0.0];\nattribute vec3 position : POSITION;\nattribute vec2 texcoord : TEXCOORD_0;\nattribute vec3 normal : NORMAL;\nattribute vec3 barycentric;\n#ifdef VERTEX_COLOR\nattribute vec4 a_Color : COLOR;\nvarying vec4 v_Color;\n#endif\n@import clay.chunk.skinning_header\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nvarying vec3 v_Barycentric;\nvoid main()\n{\n vec3 skinnedPosition = position;\n vec3 skinnedNormal = normal;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n skinnedNormal = (skinMatrixWS * vec4(normal, 0.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4( skinnedPosition, 1.0 );\n v_Texcoord = texcoord * uvRepeat + uvOffset;\n v_Normal = normalize( ( worldInverseTranspose * vec4(skinnedNormal, 0.0) ).xyz );\n v_WorldPosition = ( world * vec4( skinnedPosition, 1.0) ).xyz;\n v_Barycentric = barycentric;\n#ifdef VERTEX_COLOR\n v_Color = a_Color;\n#endif\n}\n@end\n@export clay.lambert.fragment\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\nuniform sampler2D diffuseMap;\nuniform sampler2D alphaMap;\nuniform vec3 color : [1.0, 1.0, 1.0];\nuniform vec3 emission : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\n#ifdef ALPHA_TEST\nuniform float alphaCutoff: 0.9;\n#endif\nuniform float lineWidth : 0.0;\nuniform vec4 lineColor : [0.0, 0.0, 0.0, 0.6];\nvarying vec3 v_Barycentric;\n#ifdef VERTEX_COLOR\nvarying vec4 v_Color;\n#endif\n#ifdef AMBIENT_LIGHT_COUNT\n@import clay.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import clay.header.ambient_sh_light\n#endif\n#ifdef POINT_LIGHT_COUNT\n@import clay.header.point_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n#ifdef SPOT_LIGHT_COUNT\n@import clay.header.spot_light\n#endif\n@import clay.util.calculate_attenuation\n@import clay.util.edge_factor\n@import clay.util.rgbm\n@import clay.plugin.compute_shadow_map\n@import clay.util.ACES\nvoid main()\n{\n#ifdef RENDER_NORMAL\n gl_FragColor = vec4(v_Normal * 0.5 + 0.5, 1.0);\n return;\n#endif\n#ifdef RENDER_TEXCOORD\n gl_FragColor = vec4(v_Texcoord, 1.0, 1.0);\n return;\n#endif\n gl_FragColor = vec4(color, alpha);\n#ifdef VERTEX_COLOR\n gl_FragColor *= v_Color;\n#endif\n#ifdef DIFFUSEMAP_ENABLED\n vec4 tex = texture2D( diffuseMap, v_Texcoord );\n#ifdef SRGB_DECODE\n tex.rgb = pow(tex.rgb, vec3(2.2));\n#endif\n gl_FragColor.rgb *= tex.rgb;\n#ifdef DIFFUSEMAP_ALPHA_ALPHA\n gl_FragColor.a *= tex.a;\n#endif\n#endif\n vec3 diffuseColor = vec3(0.0, 0.0, 0.0);\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {\n diffuseColor += ambientLightColor[_idx_];\n }\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseColor += calcAmbientSHLight(_idx_, v_Normal) * ambientSHLightColor[_idx_];\n }}\n#endif\n#ifdef POINT_LIGHT_COUNT\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsPoint[POINT_LIGHT_COUNT];\n if( shadowEnabled )\n {\n computeShadowOfPointLights(v_WorldPosition, shadowContribsPoint);\n }\n#endif\n for(int i = 0; i < POINT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = pointLightPosition[i];\n vec3 lightColor = pointLightColor[i];\n float range = pointLightRange[i];\n vec3 lightDirection = lightPosition - v_WorldPosition;\n float dist = length(lightDirection);\n float attenuation = lightAttenuation(dist, range);\n lightDirection /= dist;\n float ndl = dot( v_Normal, lightDirection );\n float shadowContrib = 1.0;\n#if defined(POINT_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsPoint[i];\n }\n#endif\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * attenuation * shadowContrib;\n }\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++)\n {\n vec3 lightDirection = -directionalLightDirection[i];\n vec3 lightColor = directionalLightColor[i];\n float ndl = dot(v_Normal, normalize(lightDirection));\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsDir[i];\n }\n#endif\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * shadowContrib;\n }\n#endif\n#ifdef SPOT_LIGHT_COUNT\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsSpot[SPOT_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfSpotLights(v_WorldPosition, shadowContribsSpot);\n }\n#endif\n for(int i = 0; i < SPOT_LIGHT_COUNT; i++)\n {\n vec3 lightPosition = -spotLightPosition[i];\n vec3 spotLightDirection = -normalize( spotLightDirection[i] );\n vec3 lightColor = spotLightColor[i];\n float range = spotLightRange[i];\n float a = spotLightUmbraAngleCosine[i];\n float b = spotLightPenumbraAngleCosine[i];\n float falloffFactor = spotLightFalloffFactor[i];\n vec3 lightDirection = lightPosition - v_WorldPosition;\n float dist = length(lightDirection);\n float attenuation = lightAttenuation(dist, range);\n lightDirection /= dist;\n float c = dot(spotLightDirection, lightDirection);\n float falloff;\n falloff = clamp((c - a) /( b - a), 0.0, 1.0);\n falloff = pow(falloff, falloffFactor);\n float ndl = dot(v_Normal, lightDirection);\n ndl = clamp(ndl, 0.0, 1.0);\n float shadowContrib = 1.0;\n#if defined(SPOT_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsSpot[i];\n }\n#endif\n diffuseColor += lightColor * ndl * attenuation * (1.0-falloff) * shadowContrib;\n }\n#endif\n gl_FragColor.rgb *= diffuseColor;\n gl_FragColor.rgb += emission;\n if(lineWidth > 0.)\n {\n gl_FragColor.rgb = mix(gl_FragColor.rgb, lineColor.rgb, (1.0 - edgeFactor(lineWidth)) * lineColor.a);\n }\n#ifdef ALPHA_TEST\n if (gl_FragColor.a < alphaCutoff) {\n discard;\n }\n#endif\n#ifdef TONEMAPPING\n gl_FragColor.rgb = ACESToneMapping(gl_FragColor.rgb);\n#endif\n#ifdef SRGB_ENCODE\n gl_FragColor = linearTosRGB(gl_FragColor);\n#endif\n gl_FragColor = encodeHDR(gl_FragColor);\n}\n@end"},function(e,t,n){"use strict";t.a="@export clay.wireframe.vertex\nuniform mat4 worldViewProjection : WORLDVIEWPROJECTION;\nuniform mat4 world : WORLD;\nattribute vec3 position : POSITION;\nattribute vec3 barycentric;\n@import clay.chunk.skinning_header\nvarying vec3 v_Barycentric;\nvoid main()\n{\n vec3 skinnedPosition = position;\n#ifdef SKINNING\n @import clay.chunk.skin_matrix\n skinnedPosition = (skinMatrixWS * vec4(position, 1.0)).xyz;\n#endif\n gl_Position = worldViewProjection * vec4(skinnedPosition, 1.0 );\n v_Barycentric = barycentric;\n}\n@end\n@export clay.wireframe.fragment\nuniform vec3 color : [0.0, 0.0, 0.0];\nuniform float alpha : 1.0;\nuniform float lineWidth : 1.0;\nvarying vec3 v_Barycentric;\n@import clay.util.edge_factor\nvoid main()\n{\n gl_FragColor.rgb = color;\n gl_FragColor.a = (1.0-edgeFactor(lineWidth)) * alpha;\n}\n@end"},function(e,t,n){"use strict";var a=n(87);t.a=a.a},function(e,t,n){"use strict";(function(e){var a=n(1),i=n(88),r="undefined"==typeof window?e:window,o=r.requestAnimationFrame||r.msRequestAnimationFrame||r.mozRequestAnimationFrame||r.webkitRequestAnimationFrame||function(e){setTimeout(e,16)},s=a.a.extend(function(){return{stage:null,_clips:[],_running:!1,_time:0,_paused:!1,_pausedTime:0}},{addAnimator:function(e){e.animation=this;for(var t=e.getClips(),n=0;n=0&&this._clips.splice(t,1)},removeAnimator:function(e){for(var t=e.getClips(),n=0;ni)e.length=i;else for(var r=a;r=0&&!(T[C]<=t);C--);C=Math.min(C,x-2)}else{for(C=F;Ct);C++);C=Math.min(C-1,x-2)}F=C,k=t;var n=T[C+1]-T[C];0!==n&&(L=(t-T[C])/n,L=Math.max(Math.min(1,L),0),L=w[C+1](L),g?(P=E[C],O=E[0===C?C:C-1],D=E[C>x-2?x-1:C+1],I=E[C>x-3?x-1:C+2],c?m(e,i,c(h(e,i),O,P,D,I,L)):y?l(O,P,D,I,L,L*L,L*L*L,h(e,i),b):m(e,i,u(O,P,D,I,L,L*L,L*L*L))):c?m(e,i,c(h(e,i),E[C],E[C+1],L)):y?o(E[C],E[C+1],L,h(e,i),b):m(e,i,r(E[C],E[C+1],L)))},U=new v.a({target:e._target,life:f,loop:e._loop,delay:e._delay,onframe:B,onfinish:n});return t&&"spline"!==t&&U.setEasing(t),U}}}function h(e,t,n,r,o){this._tracks={},this._target=e,this._loop=t||!1,this._getter=n||a,this._setter=r||i,this._interpolater=o||null,this._delay=0,this._doneList=[],this._onframeList=[],this._clipList=[],this._maxTime=0,this._lastKFTime=0}function m(e){return e}var v=n(50),g=n(51),x=Array.prototype.slice;h.prototype={constructor:h,when:function(e,t,n){this._maxTime=Math.max(e,this._maxTime),n=("function"==typeof n?n:g.a[n])||m;for(var a in t)this._tracks[a]||(this._tracks[a]=[],0!==e&&this._tracks[a].push({time:0,value:c(this._getter(this._target,a)),easing:n})),this._tracks[a].push({time:parseInt(e),value:t[a],easing:n});return this},then:function(e,t,n){return this.when(e+this._lastKFTime,t,n),this._lastKFTime+=e,this},during:function(e){return this._onframeList.push(e),this},_doneCallback:function(){this._tracks={},this._clipList.length=0;for(var e=this._doneList,t=e.length,n=0;n=65535?new Uint32Array(3*g):new Uint16Array(3*g);for(var b=0,T=0,E=r.isUseIndices(),w=0;w0;){for(var _=[],y=[],b=[],T=0,m=0;m=0&&-1===y[R]&&(T65535?new Uint32Array(3*P.triangles.length):new Uint16Array(3*P.triangles.length);var G=0;k=0;for(var m=0;m=0?D[R]:-1}k++}I.indices[G++]=L[S]}I.updateBoundingBox(),M.add(F)}for(var Y=e.children(),m=0;m=0&&A[E]>1e-4&&(d.transformMat4(R,w,b[S[E]]),d.scaleAndAdd(C,C,R,A[E]));M.set(T,C)}}for(var T=0;T65535?Uint32Array:Uint16Array,m=this.indices=new h(t*e*6),v=this.radius,g=this.phiStart,x=this.phiLength,_=this.thetaStart,y=this.thetaLength,v=this.radius,b=[],T=[],E=0,w=1/v;for(f=0;f<=e;f++)for(d=0;d<=t;d++)u=d/t,p=f/e,s=-v*Math.cos(g+u*x)*Math.sin(_+p*y),c=v*Math.cos(_+p*y),l=v*Math.sin(g+u*x)*Math.sin(_+p*y),b[0]=s,b[1]=c,b[2]=l,T[0]=u,T[1]=p,n.set(E,b),a.set(E,T),b[0]*=w,b[1]*=w,b[2]*=w,r.set(E,b),E++;var A,S,C,R,M=t+1,N=0;for(f=0;f0){var i=Math.pow(2,e[3]-128-8+a);t[n+0]=e[0]*i,t[n+1]=e[1]*i,t[n+2]=e[2]*i}else t[n+0]=0,t[n+1]=0,t[n+2]=0;return t[n+3]=1,t}function i(e,t,n){for(var a="",i=t;i0;)if(e[o][0]=t[n++],e[o][1]=t[n++],e[o][2]=t[n++],e[o][3]=t[n++],1===e[o][0]&&1===e[o][1]&&1===e[o][2]){for(var c=e[o][3]<>>0;c>0;c--)r(e[o-1],e[o]),o++,s--;i+=8}else o++,s--,i=0;return n}function s(e,t,n,a){if(ad)return o(e,t,n,a);var i=t[n++];if(2!=i)return o(e,t,n-1,a);if(e[0][1]=t[n++],e[0][2]=t[n++],i=t[n++],(e[0][2]<<8>>>0|i)>>>0!==a)return null;for(var i=0;i<4;i++)for(var r=0;r128){s=(127&s)>>>0;for(var c=t[n++];s--;)e[r++][i]=c}else for(;s--;)e[r++][i]=t[n++]}return n}var c=n(3),l=n(5),u=String.fromCharCode,p=8,d=32767,f={parseRGBE:function(e,t,n){null==n&&(n=0);var r=new Uint8Array(e),o=r.length;if("#?"===i(r,0,2)){for(var p=2;p=o)){p+=2;for(var d="";p=n.x&&t>=n.y&&e<=n.x+n.width&&t<=n.y+n.height};var d=new c.a;a.prototype.castRay=function(e,t,n){var a=this.layer.renderer,i=a.viewport;return a.viewport=this.viewport,a.screenToNDC(e,t,d),this.camera.castRay(d,n),a.viewport=i,n},a.prototype.prepareRender=function(){this.scene.update(),this.scene.updateLights(),this.scene.updateRenderList(this.camera),this.camera.update(),this._frame=0,this._temporalSS.resetFrame();for(var e=this.scene.getLights(),t=0;tthis.camera.far||e4){console.warn("Support at most 4 cascade");continue}m.shadowCascade>1&&(s=m),this.renderDirectionalLightShadow(e,t,n,m,d,p,u)}else"SPOT_LIGHT"===m.type?this.renderSpotLightShadow(e,t,m,l,c):"POINT_LIGHT"===m.type&&this.renderPointLightShadow(e,t,m,f);this._shadowMapNumber[m.type]++}for(var v in this._shadowMapNumber)for(var g=this._shadowMapNumber[v],x=v+"_SHADOWMAP_COUNT",h=0;h0?y.define("fragment",x,g):y.isDefined("fragment",x)&&y.undefine("fragment",x))}for(var h=0;h0){var T=u.map(i);if(b.directionalLightShadowMaps={value:u,type:"tv"},b.directionalLightMatrices={value:p,type:"m4v"},b.directionalLightShadowMapSizes={value:T,type:"1fv"},s){var E=d.slice(),w=d.slice();E.pop(),w.shift(),E.reverse(),w.reverse(),p.reverse(),b.shadowCascadeClipsNear={value:E,type:"1fv"},b.shadowCascadeClipsFar={value:w,type:"1fv"}}}if(c.length>0){var A=c.map(i),b=t.shadowUniforms;b.spotLightShadowMaps={value:c,type:"tv"},b.spotLightMatrices={value:l,type:"m4v"},b.spotLightShadowMapSizes={value:A,type:"1fv"}}f.length>0&&(b.pointLightShadowMaps={value:f,type:"tv"})}},renderDirectionalLightShadow:function(){var e=new s.a,t=new c.a,n=new o.a,a=new c.a,i=new c.a,r=new c.a,u=new c.a;return function(o,s,p,d,f,h,m){var g=this._getDepthMaterial(d),x={getMaterial:function(e){return e.shadowDepthMaterial||g},ifRender:function(e){return e.castShadow},sortCompare:l.a.opaqueSortCompare};if(!s.viewBoundingBoxLastFrame.isFinite()){var _=s.getBoundingBox();s.viewBoundingBoxLastFrame.copy(_).applyTransform(p.viewMatrix)}var y=Math.min(-s.viewBoundingBoxLastFrame.min.z,p.far),b=Math.max(-s.viewBoundingBoxLastFrame.max.z,p.near),T=this._getDirectionalLightCamera(d,s,p),w=r.array;u.copy(T.projectionMatrix),E.invert(i.array,T.worldTransform.array),E.multiply(i.array,i.array,p.worldTransform.array),E.multiply(w,u.array,i.array);for(var S=[],C=p instanceof v.a,R=(p.near+p.far)/(p.near-p.far),M=2*p.near*p.far/(p.near-p.far),N=0;N<=d.shadowCascade;N++){var L=b*Math.pow(y/b,N/d.shadowCascade),O=b+(y-b)*N/d.shadowCascade,P=L*d.cascadeSplitLogFactor+O*(1-d.cascadeSplitLogFactor);S.push(P),f.push(-(-P*R+M)/-P)}var D=this._getTexture(d,d.shadowCascade);m.push(D);var I=o.viewport,F=o.gl;this._frameBuffer.attach(D),this._frameBuffer.bind(o),F.clear(F.COLOR_BUFFER_BIT|F.DEPTH_BUFFER_BIT);for(var N=0;Nc?s>l?g[i>0?"px":"nx"]=!0:g[o>0?"pz":"nz"]=!0:c>l?g[r>0?"py":"ny"]=!0:g[o>0?"pz":"nz"]=!0}for(var n=0;n=0||(this.nodes.push(e),this._dirty=!0)},removeNode:function(e){"string"==typeof e&&(e=this.getNodeByName(e));var t=this.nodes.indexOf(e);t>=0&&(this.nodes.splice(t,1),this._dirty=!0)},getNodeByName:function(e){for(var t=0;t=t.COLOR_ATTACHMENT0&&l<=t.COLOR_ATTACHMENT0+8&&p.push(l);u.drawBuffersEXT(p)}e.saveClear(),e.clearBit=i.a.DEPTH_BUFFER_BIT|i.a.COLOR_BUFFER_BIT,n=e.render(this.scene,this.camera,!this.autoUpdateScene,this.preZ),e.restoreClear(),a.unbind(e)}else n=e.render(this.scene,this.camera,!this.autoUpdateScene,this.preZ);this.trigger("afterrender",n),this._rendering=!1,this._rendered=!0}});t.a=o},function(e,t,n){"use strict";var a=n(24),i=a.a.extend(function(){return{texture:null,outputs:{color:{}}}},function(){},{getOutput:function(e,t){return this.texture},beforeFrame:function(){},afterFrame:function(){}});t.a=i},function(e,t,n){"use strict";var a=n(13),i=n(24),r=i.a.extend(function(){return{name:"",inputs:{},outputs:null,shader:"",inputLinks:{},outputLinks:{},pass:null,_prevOutputTextures:{},_outputTextures:{},_outputReferences:{},_rendering:!1,_rendered:!1,_compositor:null}},function(){var e=new a.a({fragment:this.shader});this.pass=e},{render:function(e,t){this.trigger("beforerender",e),this._rendering=!0;var n=e.gl;for(var a in this.inputLinks){var i=this.inputLinks[a],r=i.node.getOutput(e,i.pin);this.pass.setUniform(a,r)}if(this.outputs){this.pass.outputs={};var o={};for(var s in this.outputs){var c=this.updateParameter(s,e);isNaN(c.width)&&this.updateParameter(s,e);var l=this.outputs[s],u=this._compositor.allocateTexture(c);this._outputTextures[s]=u;var p=l.attachment||n.COLOR_ATTACHMENT0;"string"==typeof p&&(p=n[p]),o[p]=u}this._compositor.getFrameBuffer().bind(e);for(var p in o)this._compositor.getFrameBuffer().attach(o[p],p);this.pass.render(e),this._compositor.getFrameBuffer().updateMipmap(e.gl)}else this.pass.outputs=null,this._compositor.getFrameBuffer().unbind(e),this.pass.render(e,t);for(var a in this.inputLinks){var i=this.inputLinks[a];i.node.removeReference(i.pin)}this._rendering=!1,this._rendered=!0,this.trigger("afterrender",e)},updateParameter:function(e,t){var n=this.outputs[e],a=n.parameters,i=n._parametersCopy;if(i||(i=n._parametersCopy={}),a)for(var r in a)"width"!==r&&"height"!==r&&(i[r]=a[r]);var o,s;return o=a.width instanceof Function?a.width.call(this,t):a.width,s=a.height instanceof Function?a.height.call(this,t):a.height,i.width===o&&i.height===s||this._outputTextures[e]&&this._outputTextures[e].dispose(t),i.width=o,i.height=s,i},setParameter:function(e,t){this.pass.setUniform(e,t)},getParameter:function(e){return this.pass.getUniform(e)},setParameters:function(e){for(var t in e)this.setParameter(t,e[t])},define:function(e,t){this.pass.material.define("fragment",e,t)},undefine:function(e){this.pass.material.undefine("fragment",e)},removeReference:function(e){if(0===--this._outputReferences[e]){this.outputs[e].keepLastFrame?(this._prevOutputTextures[e]&&this._compositor.releaseTexture(this._prevOutputTextures[e]),this._prevOutputTextures[e]=this._outputTextures[e]):this._compositor.releaseTexture(this._outputTextures[e])}},clear:function(){i.a.prototype.clear.call(this),this.pass.material.disableTexturesAll()}});t.a=r},function(e,t,n){"use strict";var a=n(2),i=n(109),r=n(55),o=n(110),s=n(111),c=n(112),l=n(56),u=n(57),p=n(58),d=n(59),f=n(60),h=n(113),m=n(114),v=n(61),g=n(62);a.a.import(i.a),a.a.import(r.a),a.a.import(o.a),a.a.import(s.a),a.a.import(c.a),a.a.import(l.a),a.a.import(u.a),a.a.import(p.a),a.a.import(d.a),a.a.import(f.a),a.a.import(h.a),a.a.import(m.a),a.a.import(v.a),a.a.import(g.a)},function(e,t,n){"use strict";t.a="@export clay.compositor.coloradjust\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float brightness : 0.0;\nuniform float contrast : 1.0;\nuniform float exposure : 0.0;\nuniform float gamma : 1.0;\nuniform float saturation : 1.0;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = clamp(tex.rgb + vec3(brightness), 0.0, 1.0);\n color = clamp( (color-vec3(0.5))*contrast+vec3(0.5), 0.0, 1.0);\n color = clamp( color * pow(2.0, exposure), 0.0, 1.0);\n color = clamp( pow(color, vec3(gamma)), 0.0, 1.0);\n float luminance = dot( color, w );\n color = mix(vec3(luminance), color, saturation);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.brightness\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float brightness : 0.0;\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = tex.rgb + vec3(brightness);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.contrast\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float contrast : 1.0;\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord);\n vec3 color = (tex.rgb-vec3(0.5))*contrast+vec3(0.5);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.exposure\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float exposure : 0.0;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = tex.rgb * pow(2.0, exposure);\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.gamma\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float gamma : 1.0;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = pow(tex.rgb, vec3(gamma));\n gl_FragColor = vec4(color, tex.a);\n}\n@end\n@export clay.compositor.saturation\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float saturation : 1.0;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n vec3 color = tex.rgb;\n float luminance = dot(color, w);\n color = mix(vec3(luminance), color, saturation);\n gl_FragColor = vec4(color, tex.a);\n}\n@end"},function(e,t,n){"use strict";t.a="@export clay.compositor.hdr.log_lum\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\n@import clay.util.rgbm\nvoid main()\n{\n vec4 tex = decodeHDR(texture2D(texture, v_Texcoord));\n float luminance = dot(tex.rgb, w);\n luminance = log(luminance + 0.001);\n gl_FragColor = encodeHDR(vec4(vec3(luminance), 1.0));\n}\n@end\n@export clay.compositor.hdr.lum_adaption\nvarying vec2 v_Texcoord;\nuniform sampler2D adaptedLum;\nuniform sampler2D currentLum;\nuniform float frameTime : 0.02;\n@import clay.util.rgbm\nvoid main()\n{\n float fAdaptedLum = decodeHDR(texture2D(adaptedLum, vec2(0.5, 0.5))).r;\n float fCurrentLum = exp(encodeHDR(texture2D(currentLum, vec2(0.5, 0.5))).r);\n fAdaptedLum += (fCurrentLum - fAdaptedLum) * (1.0 - pow(0.98, 30.0 * frameTime));\n gl_FragColor = encodeHDR(vec4(vec3(fAdaptedLum), 1.0));\n}\n@end\n@export clay.compositor.lum\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nconst vec3 w = vec3(0.2125, 0.7154, 0.0721);\nvoid main()\n{\n vec4 tex = texture2D( texture, v_Texcoord );\n float luminance = dot(tex.rgb, w);\n gl_FragColor = vec4(vec3(luminance), 1.0);\n}\n@end"},function(e,t,n){"use strict";t.a="\n@export clay.compositor.lut\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform sampler2D lookup;\nvoid main()\n{\n vec4 tex = texture2D(texture, v_Texcoord);\n float blueColor = tex.b * 63.0;\n vec2 quad1;\n quad1.y = floor(floor(blueColor) / 8.0);\n quad1.x = floor(blueColor) - (quad1.y * 8.0);\n vec2 quad2;\n quad2.y = floor(ceil(blueColor) / 8.0);\n quad2.x = ceil(blueColor) - (quad2.y * 8.0);\n vec2 texPos1;\n texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.r);\n texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.g);\n vec2 texPos2;\n texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.r);\n texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * tex.g);\n vec4 newColor1 = texture2D(lookup, texPos1);\n vec4 newColor2 = texture2D(lookup, texPos2);\n vec4 newColor = mix(newColor1, newColor2, fract(blueColor));\n gl_FragColor = vec4(newColor.rgb, tex.w);\n}\n@end"},function(e,t,n){"use strict";t.a="@export clay.compositor.vignette\n#define OUTPUT_ALPHA\nvarying vec2 v_Texcoord;\nuniform sampler2D texture;\nuniform float darkness: 1;\nuniform float offset: 1;\n@import clay.util.rgbm\nvoid main()\n{\n vec4 texel = decodeHDR(texture2D(texture, v_Texcoord));\n gl_FragColor.rgb = texel.rgb;\n vec2 uv = (v_Texcoord - vec2(0.5)) * vec2(offset);\n gl_FragColor = encodeHDR(vec4(mix(texel.rgb, vec3(1.0 - darkness), dot(uv, uv)), texel.a));\n}\n@end"},function(e,t,n){"use strict";t.a="@export clay.compositor.dof.coc\nuniform sampler2D depth;\nuniform float zNear: 0.1;\nuniform float zFar: 2000;\nuniform float focalDist: 3;\nuniform float focalRange: 1;\nuniform float focalLength: 30;\nuniform float fstop: 2.8;\nvarying vec2 v_Texcoord;\n@import clay.util.encode_float\nvoid main()\n{\n float z = texture2D(depth, v_Texcoord).r * 2.0 - 1.0;\n float dist = 2.0 * zNear * zFar / (zFar + zNear - z * (zFar - zNear));\n float aperture = focalLength / fstop;\n float coc;\n float uppper = focalDist + focalRange;\n float lower = focalDist - focalRange;\n if (dist <= uppper && dist >= lower) {\n coc = 0.5;\n }\n else {\n float focalAdjusted = dist > uppper ? uppper : lower;\n coc = abs(aperture * (focalLength * (dist - focalAdjusted)) / (dist * (focalAdjusted - focalLength)));\n coc = clamp(coc, 0.0, 0.4) / 0.4000001;\n if (dist < lower) {\n coc = -coc;\n }\n coc = coc * 0.5 + 0.5;\n }\n gl_FragColor = encodeFloat(coc);\n}\n@end\n@export clay.compositor.dof.premultiply\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.decode_float\nvoid main() {\n float fCoc = max(abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0), 0.1);\n gl_FragColor = encodeHDR(\n vec4(decodeHDR(texture2D(texture, v_Texcoord)).rgb * fCoc, 1.0)\n );\n}\n@end\n@export clay.compositor.dof.min_coc\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.float\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zy)));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.xw)));\n fCoc = min(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zw)));\n gl_FragColor = encodeFloat(fCoc);\n}\n@end\n@export clay.compositor.dof.max_coc\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.float\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zy)));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.xw)));\n fCoc = max(fCoc, decodeFloat(texture2D(coc, v_Texcoord + d.zw)));\n gl_FragColor = encodeFloat(fCoc);\n}\n@end\n@export clay.compositor.dof.coc_upsample\n#define HIGH_QUALITY\nuniform sampler2D coc;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import clay.util.float\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n float s;\n s = decodeFloat(texture2D(coc, v_Texcoord - d.xy));\n s += decodeFloat(texture2D(coc, v_Texcoord - d.wy)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord - d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zw)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord )) * 4.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xw)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.wy)) * 2.0;\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n gl_FragColor = encodeFloat(s / 16.0);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n float s;\n s = decodeFloat(texture2D(coc, v_Texcoord + d.xy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zy));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.xw));\n s += decodeFloat(texture2D(coc, v_Texcoord + d.zw));\n gl_FragColor = encodeFloat(s / 4.0);\n#endif\n}\n@end\n@export clay.compositor.dof.upsample\n#define HIGH_QUALITY\nuniform sampler2D coc;\nuniform sampler2D texture;\nuniform vec2 textureSize : [512, 512];\nuniform float sampleScale: 0.5;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.decode_float\nfloat tap(vec2 uv, inout vec4 color, float baseWeight) {\n float weight = abs(decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0) * baseWeight;\n color += decodeHDR(texture2D(texture, uv)) * weight;\n return weight;\n}\nvoid main()\n{\n#ifdef HIGH_QUALITY\n vec4 d = vec4(1.0, 1.0, -1.0, 0.0) / textureSize.xyxy * sampleScale;\n vec4 color = vec4(0.0);\n float baseWeight = 1.0 / 16.0;\n float w = tap(v_Texcoord - d.xy, color, baseWeight);\n w += tap(v_Texcoord - d.wy, color, baseWeight * 2.0);\n w += tap(v_Texcoord - d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.zw, color, baseWeight * 2.0);\n w += tap(v_Texcoord , color, baseWeight * 4.0);\n w += tap(v_Texcoord + d.xw, color, baseWeight * 2.0);\n w += tap(v_Texcoord + d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.wy, color, baseWeight * 2.0);\n w += tap(v_Texcoord + d.xy, color, baseWeight);\n gl_FragColor = encodeHDR(color / w);\n#else\n vec4 d = vec4(-1.0, -1.0, +1.0, +1.0) / textureSize.xyxy;\n vec4 color = vec4(0.0);\n float baseWeight = 1.0 / 4.0;\n float w = tap(v_Texcoord + d.xy, color, baseWeight);\n w += tap(v_Texcoord + d.zy, color, baseWeight);\n w += tap(v_Texcoord + d.xw, color, baseWeight);\n w += tap(v_Texcoord + d.zw, color, baseWeight);\n gl_FragColor = encodeHDR(color / w);\n#endif\n}\n@end\n@export clay.compositor.dof.downsample\nuniform sampler2D texture;\nuniform sampler2D coc;\nuniform vec2 textureSize : [512, 512];\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.decode_float\nfloat tap(vec2 uv, inout vec4 color) {\n float weight = abs(decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0) * 0.25;\n color += decodeHDR(texture2D(texture, uv)) * weight;\n return weight;\n}\nvoid main()\n{\n vec4 d = vec4(-1.0, -1.0, 1.0, 1.0) / textureSize.xyxy;\n vec4 color = vec4(0.0);\n float weight = tap(v_Texcoord + d.xy, color);\n weight += tap(v_Texcoord + d.zy, color);\n weight += tap(v_Texcoord + d.xw, color);\n weight += tap(v_Texcoord + d.zw, color);\n color /= weight;\n gl_FragColor = encodeHDR(color);\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_frag\n@import clay.util.float\nvec4 doBlur(sampler2D targetTexture, vec2 offset) {\n#ifdef BLUR_COC\n float cocSum = 0.0;\n#else\n vec4 color = vec4(0.0);\n#endif\n float weightSum = 0.0;\n float kernelWeight = 1.0 / float(KERNEL_SIZE);\n for (int i = 0; i < KERNEL_SIZE; i++) {\n vec2 coord = v_Texcoord + offset * float(i);\n float w = kernelWeight;\n#ifdef BLUR_COC\n float fCoc = decodeFloat(texture2D(targetTexture, coord)) * 2.0 - 1.0;\n cocSum += clamp(fCoc, -1.0, 0.0) * w;\n#else\n float fCoc = decodeFloat(texture2D(coc, coord)) * 2.0 - 1.0;\n vec4 texel = texture2D(targetTexture, coord);\n #if !defined(BLUR_NEARFIELD)\n w *= abs(fCoc);\n #endif\n color += decodeHDR(texel) * w;\n#endif\n weightSum += w;\n }\n#ifdef BLUR_COC\n return encodeFloat(clamp(cocSum / weightSum, -1.0, 0.0) * 0.5 + 0.5);\n#else\n return color / weightSum;\n#endif\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_1\n#define KERNEL_SIZE 5\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.rgbm\n@import clay.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n gl_FragColor = doBlur(texture, vec2(0.0, offset.y));\n#if !defined(BLUR_COC)\n gl_FragColor = encodeHDR(gl_FragColor);\n#endif\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_2\n#define KERNEL_SIZE 5\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.rgbm\n@import clay.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n offset.y /= 2.0;\n gl_FragColor = doBlur(texture, -offset);\n#if !defined(BLUR_COC)\n gl_FragColor = encodeHDR(gl_FragColor);\n#endif\n}\n@end\n@export clay.compositor.dof.hexagonal_blur_3\n#define KERNEL_SIZE 5\nuniform sampler2D texture1;\nuniform sampler2D texture2;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\nuniform float blurSize : 1.0;\nuniform vec2 textureSize : [512.0, 512.0];\n@import clay.util.rgbm\n@import clay.compositor.dof.hexagonal_blur_frag\nvoid main()\n{\n vec2 offset = blurSize / textureSize;\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n offset.y /= 2.0;\n vec2 vDownRight = vec2(offset.x, -offset.y);\n vec4 texel1 = doBlur(texture1, -offset);\n vec4 texel2 = doBlur(texture1, vDownRight);\n vec4 texel3 = doBlur(texture2, vDownRight);\n#ifdef BLUR_COC\n float coc1 = decodeFloat(texel1) * 2.0 - 1.0;\n float coc2 = decodeFloat(texel2) * 2.0 - 1.0;\n float coc3 = decodeFloat(texel3) * 2.0 - 1.0;\n gl_FragColor = encodeFloat(\n ((coc1 + coc2 + coc3) / 3.0) * 0.5 + 0.5\n );\n#else\n vec4 color = (texel1 + texel2 + texel3) / 3.0;\n gl_FragColor = encodeHDR(color);\n#endif\n}\n@end\n@export clay.compositor.dof.composite\n#define DEBUG 0\nuniform sampler2D original;\nuniform sampler2D blurred;\nuniform sampler2D nearfield;\nuniform sampler2D coc;\nuniform sampler2D nearcoc;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\n@import clay.util.float\nvoid main()\n{\n vec4 blurredColor = decodeHDR(texture2D(blurred, v_Texcoord));\n vec4 originalColor = decodeHDR(texture2D(original, v_Texcoord));\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord));\n fCoc = abs(fCoc * 2.0 - 1.0);\n float weight = smoothstep(0.0, 1.0, fCoc);\n#ifdef NEARFIELD_ENABLED\n vec4 nearfieldColor = decodeHDR(texture2D(nearfield, v_Texcoord));\n float fNearCoc = decodeFloat(texture2D(nearcoc, v_Texcoord));\n fNearCoc = abs(fNearCoc * 2.0 - 1.0);\n gl_FragColor = encodeHDR(\n mix(\n nearfieldColor, mix(originalColor, blurredColor, weight),\n pow(1.0 - fNearCoc, 4.0)\n )\n );\n#else\n gl_FragColor = encodeHDR(mix(originalColor, blurredColor, weight));\n#endif\n#if DEBUG == 1\n gl_FragColor = vec4(vec3(fCoc), 1.0);\n#elif DEBUG == 2\n gl_FragColor = vec4(vec3(fNearCoc), 1.0);\n#elif DEBUG == 3\n gl_FragColor = encodeHDR(blurredColor);\n#elif DEBUG == 4\n gl_FragColor = encodeHDR(nearfieldColor);\n#endif\n}\n@end"},function(e,t,n){"use strict";t.a="@export clay.compositor.lensflare\n#define SAMPLE_NUMBER 8\nuniform sampler2D texture;\nuniform sampler2D lenscolor;\nuniform vec2 textureSize : [512, 512];\nuniform float dispersal : 0.3;\nuniform float haloWidth : 0.4;\nuniform float distortion : 1.0;\nvarying vec2 v_Texcoord;\n@import clay.util.rgbm\nvec4 textureDistorted(\n in vec2 texcoord,\n in vec2 direction,\n in vec3 distortion\n) {\n return vec4(\n decodeHDR(texture2D(texture, texcoord + direction * distortion.r)).r,\n decodeHDR(texture2D(texture, texcoord + direction * distortion.g)).g,\n decodeHDR(texture2D(texture, texcoord + direction * distortion.b)).b,\n 1.0\n );\n}\nvoid main()\n{\n vec2 texcoord = -v_Texcoord + vec2(1.0); vec2 textureOffset = 1.0 / textureSize;\n vec2 ghostVec = (vec2(0.5) - texcoord) * dispersal;\n vec2 haloVec = normalize(ghostVec) * haloWidth;\n vec3 distortion = vec3(-textureOffset.x * distortion, 0.0, textureOffset.x * distortion);\n vec4 result = vec4(0.0);\n for (int i = 0; i < SAMPLE_NUMBER; i++)\n {\n vec2 offset = fract(texcoord + ghostVec * float(i));\n float weight = length(vec2(0.5) - offset) / length(vec2(0.5));\n weight = pow(1.0 - weight, 10.0);\n result += textureDistorted(offset, normalize(ghostVec), distortion) * weight;\n }\n result *= texture2D(lenscolor, vec2(length(vec2(0.5) - texcoord)) / length(vec2(0.5)));\n float weight = length(vec2(0.5) - fract(texcoord + haloVec)) / length(vec2(0.5));\n weight = pow(1.0 - weight, 10.0);\n vec2 offset = fract(texcoord + haloVec);\n result += textureDistorted(offset, normalize(ghostVec), distortion) * weight;\n gl_FragColor = result;\n}\n@end"},function(e,t,n){"use strict";function a(e){for(var t=new Uint8Array(e*e*4),n=0,a=new c.a,i=0;i30},t.a=o},function(e,t,n){"use strict";t.a="@export ecgl.ssao.estimate\n\n#define SHADER_NAME SSAO\n\nuniform sampler2D depthTex;\n\nuniform sampler2D normalTex;\n\nuniform sampler2D noiseTex;\n\nuniform vec2 depthTexSize;\n\nuniform vec2 noiseTexSize;\n\nuniform mat4 projection;\n\nuniform mat4 projectionInv;\n\nuniform mat4 viewInverseTranspose;\n\nuniform vec3 kernel[KERNEL_SIZE];\n\nuniform float radius : 1;\n\nuniform float power : 1;\n\nuniform float bias: 0.01;\n\nuniform float intensity: 1.0;\n\nvarying vec2 v_Texcoord;\n\nfloat ssaoEstimator(in vec3 originPos, in vec3 N, in mat3 kernelBasis) {\n float occlusion = 0.0;\n\n for (int i = 0; i < KERNEL_SIZE; i++) {\n vec3 samplePos = kernel[i];\n#ifdef NORMALTEX_ENABLED\n samplePos = kernelBasis * samplePos;\n#endif\n samplePos = samplePos * radius + originPos;\n\n vec4 texCoord = projection * vec4(samplePos, 1.0);\n texCoord.xy /= texCoord.w;\n texCoord.xy = texCoord.xy * 0.5 + 0.5;\n\n vec4 depthTexel = texture2D(depthTex, texCoord.xy);\n float z = depthTexel.r * 2.0 - 1.0;\n#ifdef ALCHEMY\n vec4 projectedPos = vec4(texCoord.xy * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * projectedPos;\n p4.xyz /= p4.w;\n vec3 cDir = p4.xyz - originPos;\n\n float vv = dot(cDir, cDir);\n float vn = dot(cDir, N);\n\n float radius2 = radius * radius;\n\n vn = max(vn + p4.z * bias, 0.0);\n float f = max(radius2 - vv, 0.0) / radius2;\n occlusion += f * f * f * max(vn / (0.01 + vv), 0.0);\n#else\n if (projection[3][3] == 0.0) {\n z = projection[3][2] / (z * projection[2][3] - projection[2][2]);\n }\n else {\n z = (z - projection[3][2]) / projection[2][2];\n }\n float factor = step(samplePos.z, z - bias);\n float rangeCheck = smoothstep(0.0, 1.0, radius / abs(originPos.z - z));\n occlusion += rangeCheck * factor;\n#endif\n }\n#ifdef NORMALTEX_ENABLED\n occlusion = 1.0 - occlusion / float(KERNEL_SIZE);\n#else\n occlusion = 1.0 - clamp((occlusion / float(KERNEL_SIZE) - 0.6) * 2.5, 0.0, 1.0);\n#endif\n return pow(occlusion, power);\n}\n\nvoid main()\n{\n\n vec4 depthTexel = texture2D(depthTex, v_Texcoord);\n\n#ifdef NORMALTEX_ENABLED\n vec4 tex = texture2D(normalTex, v_Texcoord);\n if (dot(tex.rgb, tex.rgb) == 0.0) {\n gl_FragColor = vec4(1.0);\n return;\n }\n vec3 N = tex.rgb * 2.0 - 1.0;\n N = (viewInverseTranspose * vec4(N, 0.0)).xyz;\n\n vec2 noiseTexCoord = depthTexSize / vec2(noiseTexSize) * v_Texcoord;\n vec3 rvec = texture2D(noiseTex, noiseTexCoord).rgb * 2.0 - 1.0;\n vec3 T = normalize(rvec - N * dot(rvec, N));\n vec3 BT = normalize(cross(N, T));\n mat3 kernelBasis = mat3(T, BT, N);\n#else\n if (depthTexel.r > 0.99999) {\n gl_FragColor = vec4(1.0);\n return;\n }\n mat3 kernelBasis;\n#endif\n\n float z = depthTexel.r * 2.0 - 1.0;\n\n vec4 projectedPos = vec4(v_Texcoord * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * projectedPos;\n\n vec3 position = p4.xyz / p4.w;\n\n float ao = ssaoEstimator(position, N, kernelBasis);\n ao = clamp(1.0 - (1.0 - ao) * intensity, 0.0, 1.0);\n gl_FragColor = vec4(vec3(ao), 1.0);\n}\n\n@end\n\n\n@export ecgl.ssao.blur\n#define SHADER_NAME SSAO_BLUR\n\nuniform sampler2D ssaoTexture;\n\n#ifdef NORMALTEX_ENABLED\nuniform sampler2D normalTex;\n#endif\n\nvarying vec2 v_Texcoord;\n\nuniform vec2 textureSize;\nuniform float blurSize : 1.0;\n\nuniform int direction: 0.0;\n\n#ifdef DEPTHTEX_ENABLED\nuniform sampler2D depthTex;\nuniform mat4 projection;\nuniform float depthRange : 0.05;\n\nfloat getLinearDepth(vec2 coord)\n{\n float depth = texture2D(depthTex, coord).r * 2.0 - 1.0;\n return projection[3][2] / (depth * projection[2][3] - projection[2][2]);\n}\n#endif\n\nvoid main()\n{\n float kernel[5];\n kernel[0] = 0.122581;\n kernel[1] = 0.233062;\n kernel[2] = 0.288713;\n kernel[3] = 0.233062;\n kernel[4] = 0.122581;\n\n vec2 off = vec2(0.0);\n if (direction == 0) {\n off[0] = blurSize / textureSize.x;\n }\n else {\n off[1] = blurSize / textureSize.y;\n }\n\n vec2 coord = v_Texcoord;\n\n float sum = 0.0;\n float weightAll = 0.0;\n\n#ifdef NORMALTEX_ENABLED\n vec3 centerNormal = texture2D(normalTex, v_Texcoord).rgb * 2.0 - 1.0;\n#endif\n#if defined(DEPTHTEX_ENABLED)\n float centerDepth = getLinearDepth(v_Texcoord);\n#endif\n\n for (int i = 0; i < 5; i++) {\n vec2 coord = clamp(v_Texcoord + vec2(float(i) - 2.0) * off, vec2(0.0), vec2(1.0));\n\n float w = kernel[i];\n#ifdef NORMALTEX_ENABLED\n vec3 normal = texture2D(normalTex, coord).rgb * 2.0 - 1.0;\n w *= clamp(dot(normal, centerNormal), 0.0, 1.0);\n#endif\n#ifdef DEPTHTEX_ENABLED\n float d = getLinearDepth(coord);\n w *= (1.0 - smoothstep(abs(centerDepth - d) / depthRange, 0.0, 1.0));\n#endif\n\n weightAll += w;\n sum += texture2D(ssaoTexture, coord).r * w;\n }\n\n gl_FragColor = vec4(vec3(sum / weightAll), 1.0);\n}\n@end\n"},function(e,t,n){"use strict";function a(e){e=e||{},this._ssrPass=new s.a({fragment:c.a.source("ecgl.ssr.main"),clearColor:[0,0,0,0]}),this._blurPass1=new s.a({fragment:c.a.source("ecgl.ssr.blur"),clearColor:[0,0,0,0]}),this._blurPass2=new s.a({fragment:c.a.source("ecgl.ssr.blur"),clearColor:[0,0,0,0]}),this._blendPass=new s.a({fragment:c.a.source("clay.compositor.blend")}),this._blendPass.material.disableTexturesAll(),this._blendPass.material.enableTexture(["texture1","texture2"]),this._ssrPass.setUniform("gBufferTexture1",e.normalTexture),this._ssrPass.setUniform("gBufferTexture2",e.depthTexture),this._ssrPass.setUniform("gBufferTexture3",e.albedoTexture),this._blurPass1.setUniform("gBufferTexture1",e.normalTexture),this._blurPass1.setUniform("gBufferTexture2",e.depthTexture),this._blurPass2.setUniform("gBufferTexture1",e.normalTexture),this._blurPass2.setUniform("gBufferTexture2",e.depthTexture),this._blurPass2.material.define("fragment","VERTICAL"),this._blurPass2.material.define("fragment","BLEND"),this._ssrTexture=new r.a({type:o.a.HALF_FLOAT}),this._texture2=new r.a({type:o.a.HALF_FLOAT}),this._texture3=new r.a({type:o.a.HALF_FLOAT}),this._prevTexture=new r.a({type:o.a.HALF_FLOAT}),this._currentTexture=new r.a({type:o.a.HALF_FLOAT}),this._frameBuffer=new l.a({depthBuffer:!1}),this._normalDistribution=null,this._totalSamples=256,this._samplePerFrame=4,this._ssrPass.material.define("fragment","SAMPLE_PER_FRAME",this._samplePerFrame),this._ssrPass.material.define("fragment","TOTAL_SAMPLES",this._totalSamples),this._downScale=1}var i=n(9),r=(n(4),n(5)),o=n(3),s=n(13),c=n(2),l=n(11),u=(n(25),n(63)),p=n(121);c.a.import(p.a),a.prototype.setAmbientCubemap=function(e,t){this._ssrPass.material.set("specularCubemap",e),this._ssrPass.material.set("specularIntensity",t);var n=e&&t;this._ssrPass.material[n?"enableTexture":"disableTexture"]("specularCubemap")},a.prototype.update=function(e,t,n,a){var r=e.getWidth(),o=e.getHeight(),s=this._ssrTexture,c=this._texture2,l=this._texture3;s.width=this._prevTexture.width=this._currentTexture.width=r/this._downScale,s.height=this._prevTexture.height=this._currentTexture.height=o/this._downScale,c.width=l.width=r,c.height=l.height=o;var u=this._frameBuffer,p=this._ssrPass,d=this._blurPass1,f=this._blurPass2,h=this._blendPass,m=new i.a,v=new i.a;i.a.transpose(m,t.worldTransform),i.a.transpose(v,t.viewMatrix),p.setUniform("sourceTexture",n),p.setUniform("projection",t.projectionMatrix.array),p.setUniform("projectionInv",t.invProjectionMatrix.array),p.setUniform("toViewSpace",m.array),p.setUniform("toWorldSpace",v.array),p.setUniform("nearZ",t.near);var g=a/this._totalSamples*this._samplePerFrame;if(p.setUniform("jitterOffset",g),p.setUniform("sampleOffset",a*this._samplePerFrame),d.setUniform("textureSize",[s.width,s.height]),f.setUniform("textureSize",[r,o]),f.setUniform("sourceTexture",n),d.setUniform("projection",t.projectionMatrix.array),f.setUniform("projection",t.projectionMatrix.array),u.attach(s),u.bind(e),p.render(e),this._physicallyCorrect&&(u.attach(this._currentTexture),h.setUniform("texture1",this._prevTexture),h.setUniform("texture2",s),h.material.set({weight1:a>=1?.95:0,weight2:a>=1?.05:1}),h.render(e)),u.attach(c),d.setUniform("texture",this._physicallyCorrect?this._currentTexture:s),d.render(e),u.attach(l),f.setUniform("texture",c),f.render(e),u.unbind(e),this._physicallyCorrect){var x=this._prevTexture;this._prevTexture=this._currentTexture,this._currentTexture=x}},a.prototype.getTargetTexture=function(){return this._texture3},a.prototype.setParameter=function(e,t){"maxIteration"===e?this._ssrPass.material.define("fragment","MAX_ITERATION",t):this._ssrPass.setUniform(e,t)},a.prototype.setPhysicallyCorrect=function(e){e?(this._normalDistribution||(this._normalDistribution=u.a.generateNormalDistribution(64,this._totalSamples)),this._ssrPass.material.define("fragment","PHYSICALLY_CORRECT"),this._ssrPass.material.set("normalDistribution",this._normalDistribution),this._ssrPass.material.set("normalDistributionSize",[64,this._totalSamples])):this._ssrPass.material.undefine("fragment","PHYSICALLY_CORRECT"),this._physicallyCorrect=e},a.prototype.setSSAOTexture=function(e){var t=this._blurPass2;e?(t.material.enableTexture("ssaoTex"),t.material.set("ssaoTex",e)):t.material.disableTexture("ssaoTex")},a.prototype.isFinished=function(e){return!this._physicallyCorrect||e>this._totalSamples/this._samplePerFrame},a.prototype.dispose=function(e){this._ssrTexture.dispose(e),this._texture2.dispose(e),this._texture3.dispose(e),this._prevTexture.dispose(e),this._currentTexture.dispose(e),this._frameBuffer.dispose(e)},t.a=a},function(e,t,n){"use strict";function a(e,t,n){u.identity();var a=new r.a({widthSegments:t,heightSegments:n});switch(e){case"px":o.a.translate(u,u,s.a.POSITIVE_X),o.a.rotateY(u,u,Math.PI/2);break;case"nx":o.a.translate(u,u,s.a.NEGATIVE_X),o.a.rotateY(u,u,-Math.PI/2);break;case"py":o.a.translate(u,u,s.a.POSITIVE_Y),o.a.rotateX(u,u,-Math.PI/2);break;case"ny":o.a.translate(u,u,s.a.NEGATIVE_Y),o.a.rotateX(u,u,Math.PI/2);break;case"pz":o.a.translate(u,u,s.a.POSITIVE_Z);break;case"nz":o.a.translate(u,u,s.a.NEGATIVE_Z),o.a.rotateY(u,u,Math.PI)}return a.applyTransform(u),a}var i=n(19),r=n(31),o=n(9),s=n(4),c=n(8),l=n(12),u=new o.a,p=i.a.extend({dynamic:!1,widthSegments:1,heightSegments:1,depthSegments:1,inside:!1},function(){this.build()},{build:function(){var e={px:a("px",this.depthSegments,this.heightSegments),nx:a("nx",this.depthSegments,this.heightSegments),py:a("py",this.widthSegments,this.depthSegments),ny:a("ny",this.widthSegments,this.depthSegments),pz:a("pz",this.widthSegments,this.heightSegments),nz:a("nz",this.widthSegments,this.heightSegments)},t=["position","texcoord0","normal"],n=0,i=0;for(var r in e)n+=e[r].vertexCount,i+=e[r].indices.length;for(var o=0;o255?255:e}function i(e){return e<0?0:e>1?1:e}function r(e){return a(e.length&&"%"===e.charAt(e.length-1)?parseFloat(e)/100*255:parseInt(e,10))}function o(e){return i(e.length&&"%"===e.charAt(e.length-1)?parseFloat(e)/100:parseFloat(e))}function s(e,t,n){return n<0?n+=1:n>1&&(n-=1),6*n<1?e+(t-e)*n*6:2*n<1?t:3*n<2?e+(t-e)*(2/3-n)*6:e}function c(e,t,n,a,i){return e[0]=t,e[1]=n,e[2]=a,e[3]=i,e}function l(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e}function u(e,t){g&&l(g,t),g=v.put(e,g||t.slice())}function p(e,t){if(e){t=t||[];var n=v.get(e);if(n)return l(t,n);e+="";var a=e.replace(/ /g,"").toLowerCase();if(a in m)return l(t,m[a]),u(e,t),t;if("#"!==a.charAt(0)){var i=a.indexOf("("),s=a.indexOf(")");if(-1!==i&&s+1===a.length){var p=a.substr(0,i),f=a.substr(i+1,s-(i+1)).split(","),h=1;switch(p){case"rgba":if(4!==f.length)return void c(t,0,0,0,1);h=o(f.pop());case"rgb":return 3!==f.length?void c(t,0,0,0,1):(c(t,r(f[0]),r(f[1]),r(f[2]),h),u(e,t),t);case"hsla":return 4!==f.length?void c(t,0,0,0,1):(f[3]=o(f[3]),d(f,t),u(e,t),t);case"hsl":return 3!==f.length?void c(t,0,0,0,1):(d(f,t),u(e,t),t);default:return}}c(t,0,0,0,1)}else{if(4===a.length){var g=parseInt(a.substr(1),16);return g>=0&&g<=4095?(c(t,(3840&g)>>4|(3840&g)>>8,240&g|(240&g)>>4,15&g|(15&g)<<4,1),u(e,t),t):void c(t,0,0,0,1)}if(7===a.length){var g=parseInt(a.substr(1),16);return g>=0&&g<=16777215?(c(t,(16711680&g)>>16,(65280&g)>>8,255&g,1),u(e,t),t):void c(t,0,0,0,1)}}}}function d(e,t){var n=(parseFloat(e[0])%360+360)%360/360,i=o(e[1]),r=o(e[2]),l=r<=.5?r*(i+1):r+i-r*i,u=2*r-l;return t=t||[],c(t,a(255*s(u,l,n+1/3)),a(255*s(u,l,n)),a(255*s(u,l,n-1/3)),1),4===e.length&&(t[3]=e[3]),t}function f(e,t){if(e&&e.length){var n=e[0]+","+e[1]+","+e[2];return"rgba"!==t&&"hsva"!==t&&"hsla"!==t||(n+=","+e[3]),t+"("+n+")"}}t.a=p,t.b=f;var h=n(65),m={transparent:[0,0,0,0],aliceblue:[240,248,255,1],antiquewhite:[250,235,215,1],aqua:[0,255,255,1],aquamarine:[127,255,212,1],azure:[240,255,255,1],beige:[245,245,220,1],bisque:[255,228,196,1],black:[0,0,0,1],blanchedalmond:[255,235,205,1],blue:[0,0,255,1],blueviolet:[138,43,226,1],brown:[165,42,42,1],burlywood:[222,184,135,1],cadetblue:[95,158,160,1],chartreuse:[127,255,0,1],chocolate:[210,105,30,1],coral:[255,127,80,1],cornflowerblue:[100,149,237,1],cornsilk:[255,248,220,1],crimson:[220,20,60,1],cyan:[0,255,255,1],darkblue:[0,0,139,1],darkcyan:[0,139,139,1],darkgoldenrod:[184,134,11,1],darkgray:[169,169,169,1],darkgreen:[0,100,0,1],darkgrey:[169,169,169,1],darkkhaki:[189,183,107,1],darkmagenta:[139,0,139,1],darkolivegreen:[85,107,47,1],darkorange:[255,140,0,1],darkorchid:[153,50,204,1],darkred:[139,0,0,1],darksalmon:[233,150,122,1],darkseagreen:[143,188,143,1],darkslateblue:[72,61,139,1],darkslategray:[47,79,79,1],darkslategrey:[47,79,79,1],darkturquoise:[0,206,209,1],darkviolet:[148,0,211,1],deeppink:[255,20,147,1],deepskyblue:[0,191,255,1],dimgray:[105,105,105,1],dimgrey:[105,105,105,1],dodgerblue:[30,144,255,1],firebrick:[178,34,34,1],floralwhite:[255,250,240,1],forestgreen:[34,139,34,1],fuchsia:[255,0,255,1],gainsboro:[220,220,220,1],ghostwhite:[248,248,255,1],gold:[255,215,0,1],goldenrod:[218,165,32,1],gray:[128,128,128,1],green:[0,128,0,1],greenyellow:[173,255,47,1],grey:[128,128,128,1],honeydew:[240,255,240,1],hotpink:[255,105,180,1],indianred:[205,92,92,1],indigo:[75,0,130,1],ivory:[255,255,240,1],khaki:[240,230,140,1],lavender:[230,230,250,1],lavenderblush:[255,240,245,1],lawngreen:[124,252,0,1],lemonchiffon:[255,250,205,1],lightblue:[173,216,230,1],lightcoral:[240,128,128,1],lightcyan:[224,255,255,1],lightgoldenrodyellow:[250,250,210,1],lightgray:[211,211,211,1],lightgreen:[144,238,144,1],lightgrey:[211,211,211,1],lightpink:[255,182,193,1],lightsalmon:[255,160,122,1],lightseagreen:[32,178,170,1],lightskyblue:[135,206,250,1],lightslategray:[119,136,153,1],lightslategrey:[119,136,153,1],lightsteelblue:[176,196,222,1],lightyellow:[255,255,224,1],lime:[0,255,0,1],limegreen:[50,205,50,1],linen:[250,240,230,1],magenta:[255,0,255,1],maroon:[128,0,0,1],mediumaquamarine:[102,205,170,1],mediumblue:[0,0,205,1],mediumorchid:[186,85,211,1],mediumpurple:[147,112,219,1],mediumseagreen:[60,179,113,1],mediumslateblue:[123,104,238,1],mediumspringgreen:[0,250,154,1],mediumturquoise:[72,209,204,1],mediumvioletred:[199,21,133,1],midnightblue:[25,25,112,1],mintcream:[245,255,250,1],mistyrose:[255,228,225,1],moccasin:[255,228,181,1],navajowhite:[255,222,173,1],navy:[0,0,128,1],oldlace:[253,245,230,1],olive:[128,128,0,1],olivedrab:[107,142,35,1],orange:[255,165,0,1],orangered:[255,69,0,1],orchid:[218,112,214,1],palegoldenrod:[238,232,170,1],palegreen:[152,251,152,1],paleturquoise:[175,238,238,1],palevioletred:[219,112,147,1],papayawhip:[255,239,213,1],peachpuff:[255,218,185,1],peru:[205,133,63,1],pink:[255,192,203,1],plum:[221,160,221,1],powderblue:[176,224,230,1],purple:[128,0,128,1],red:[255,0,0,1],rosybrown:[188,143,143,1],royalblue:[65,105,225,1],saddlebrown:[139,69,19,1],salmon:[250,128,114,1],sandybrown:[244,164,96,1],seagreen:[46,139,87,1],seashell:[255,245,238,1],sienna:[160,82,45,1],silver:[192,192,192,1],skyblue:[135,206,235,1],slateblue:[106,90,205,1],slategray:[112,128,144,1],slategrey:[112,128,144,1],snow:[255,250,250,1],springgreen:[0,255,127,1],steelblue:[70,130,180,1],tan:[210,180,140,1],teal:[0,128,128,1],thistle:[216,191,216,1],tomato:[255,99,71,1],turquoise:[64,224,208,1],violet:[238,130,238,1],wheat:[245,222,179,1],white:[255,255,255,1],whitesmoke:[245,245,245,1],yellow:[255,255,0,1],yellowgreen:[154,205,50,1]},v=new h.a(20),g=null},function(e,t,n){"use strict";t.a={type:"compositor",nodes:[{name:"source",type:"texture",outputs:{color:{}}},{name:"source_half",shader:"#source(clay.compositor.downsample)",inputs:{texture:"source"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0, height * 1.0] )"}},{name:"bright",shader:"#source(clay.compositor.bright)",inputs:{texture:"source_half"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{threshold:2,scale:4,textureSize:"expr([width * 1.0 / 2, height / 2])"}},{name:"bright_downsample_4",shader:"#source(clay.compositor.downsample)",inputs:{texture:"bright"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 4)",height:"expr(height * 1.0 / 4)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0 / 2, height / 2] )"}},{name:"bright_downsample_8",shader:"#source(clay.compositor.downsample)",inputs:{texture:"bright_downsample_4"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 8)",height:"expr(height * 1.0 / 8)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0 / 4, height / 4] )"}},{name:"bright_downsample_16",shader:"#source(clay.compositor.downsample)",inputs:{texture:"bright_downsample_8"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 16)",height:"expr(height * 1.0 / 16)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0 / 8, height / 8] )"}},{name:"bright_downsample_32",shader:"#source(clay.compositor.downsample)",inputs:{texture:"bright_downsample_16"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 32)",height:"expr(height * 1.0 / 32)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0 / 16, height / 16] )"}},{name:"bright_upsample_16_blur_h",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_downsample_32"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 16)",height:"expr(height * 1.0 / 16)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 32, height / 32] )"}},{name:"bright_upsample_16_blur_v",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_16_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 16)",height:"expr(height * 1.0 / 16)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 32, height * 1.0 / 32] )"}},{name:"bright_upsample_8_blur_h",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_downsample_16"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 8)",height:"expr(height * 1.0 / 8)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 16, height * 1.0 / 16] )"}},{name:"bright_upsample_8_blur_v",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_8_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 8)",height:"expr(height * 1.0 / 8)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 16, height * 1.0 / 16] )"}},{name:"bright_upsample_8_blend",shader:"#source(clay.compositor.blend)",inputs:{texture1:"bright_upsample_8_blur_v",texture2:"bright_upsample_16_blur_v"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 8)",height:"expr(height * 1.0 / 8)",type:"HALF_FLOAT"}}},parameters:{weight1:.3,weight2:.7}},{name:"bright_upsample_4_blur_h",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_downsample_8"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 4)",height:"expr(height * 1.0 / 4)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 8, height * 1.0 / 8] )"}},{name:"bright_upsample_4_blur_v",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_4_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 4)",height:"expr(height * 1.0 / 4)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 8, height * 1.0 / 8] )"}},{name:"bright_upsample_4_blend",shader:"#source(clay.compositor.blend)",inputs:{texture1:"bright_upsample_4_blur_v",texture2:"bright_upsample_8_blend"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 4)",height:"expr(height * 1.0 / 4)",type:"HALF_FLOAT"}}},parameters:{weight1:.3,weight2:.7}},{name:"bright_upsample_2_blur_h",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_downsample_4"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 4, height * 1.0 / 4] )"}},{name:"bright_upsample_2_blur_v",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_2_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 4, height * 1.0 / 4] )"}},{name:"bright_upsample_2_blend",shader:"#source(clay.compositor.blend)",inputs:{texture1:"bright_upsample_2_blur_v",texture2:"bright_upsample_4_blend"},outputs:{color:{parameters:{width:"expr(width * 1.0 / 2)",height:"expr(height * 1.0 / 2)",type:"HALF_FLOAT"}}},parameters:{weight1:.3,weight2:.7}},{name:"bright_upsample_full_blur_h",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:0,textureSize:"expr( [width * 1.0 / 2, height * 1.0 / 2] )"}},{name:"bright_upsample_full_blur_v",shader:"#source(clay.compositor.gaussian_blur)",inputs:{texture:"bright_upsample_full_blur_h"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{blurSize:1,blurDir:1,textureSize:"expr( [width * 1.0 / 2, height * 1.0 / 2] )"}},{name:"bloom_composite",shader:"#source(clay.compositor.blend)",inputs:{texture1:"bright_upsample_full_blur_v",texture2:"bright_upsample_2_blend"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{weight1:.3,weight2:.7}},{name:"coc",shader:"#source(ecgl.dof.coc)",outputs:{color:{parameters:{minFilter:"NEAREST",magFilter:"NEAREST",width:"expr(width * 1.0)",height:"expr(height * 1.0)"}}},parameters:{focalDist:50,focalRange:30}},{name:"dof_far_blur",shader:"#source(ecgl.dof.diskBlur)",inputs:{texture:"source",coc:"coc"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0, height * 1.0] )"}},{name:"dof_near_blur",shader:"#source(ecgl.dof.diskBlur)",inputs:{texture:"source",coc:"coc"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}},parameters:{textureSize:"expr( [width * 1.0, height * 1.0] )"},defines:{BLUR_NEARFIELD:null}},{name:"dof_coc_blur",shader:"#source(ecgl.dof.diskBlur)",inputs:{texture:"coc"},outputs:{color:{parameters:{minFilter:"NEAREST",magFilter:"NEAREST",width:"expr(width * 1.0)",height:"expr(height * 1.0)"}}},parameters:{textureSize:"expr( [width * 1.0, height * 1.0] )"},defines:{BLUR_COC:null}},{name:"dof_composite",shader:"#source(ecgl.dof.composite)",inputs:{original:"source",blurred:"dof_far_blur",nearfield:"dof_near_blur",coc:"coc",nearcoc:"dof_coc_blur"},outputs:{color:{parameters:{width:"expr(width * 1.0)",height:"expr(height * 1.0)",type:"HALF_FLOAT"}}}},{name:"composite",shader:"#source(clay.compositor.hdr.composite)",inputs:{texture:"source",bloom:"bloom_composite"},defines:{}},{name:"FXAA",shader:"#source(clay.compositor.fxaa)",inputs:{texture:"composite"}}]}},function(e,t,n){"use strict";t.a="@export ecgl.dof.coc\n\nuniform sampler2D depth;\n\nuniform float zNear: 0.1;\nuniform float zFar: 2000;\n\nuniform float focalDistance: 3;\nuniform float focalRange: 1;\nuniform float focalLength: 30;\nuniform float fstop: 2.8;\n\nvarying vec2 v_Texcoord;\n\n@import clay.util.encode_float\n\nvoid main()\n{\n float z = texture2D(depth, v_Texcoord).r * 2.0 - 1.0;\n\n float dist = 2.0 * zNear * zFar / (zFar + zNear - z * (zFar - zNear));\n\n float aperture = focalLength / fstop;\n\n float coc;\n\n float uppper = focalDistance + focalRange;\n float lower = focalDistance - focalRange;\n if (dist <= uppper && dist >= lower) {\n coc = 0.5;\n }\n else {\n float focalAdjusted = dist > uppper ? uppper : lower;\n\n coc = abs(aperture * (focalLength * (dist - focalAdjusted)) / (dist * (focalAdjusted - focalLength)));\n coc = clamp(coc, 0.0, 2.0) / 2.00001;\n\n if (dist < lower) {\n coc = -coc;\n }\n coc = coc * 0.5 + 0.5;\n }\n\n gl_FragColor = encodeFloat(coc);\n}\n@end\n\n\n@export ecgl.dof.composite\n\n#define DEBUG 0\n\nuniform sampler2D original;\nuniform sampler2D blurred;\nuniform sampler2D nearfield;\nuniform sampler2D coc;\nuniform sampler2D nearcoc;\nvarying vec2 v_Texcoord;\n\n@import clay.util.rgbm\n@import clay.util.float\n\nvoid main()\n{\n vec4 blurredColor = decodeHDR(texture2D(blurred, v_Texcoord));\n vec4 originalColor = decodeHDR(texture2D(original, v_Texcoord));\n\n float fCoc = decodeFloat(texture2D(coc, v_Texcoord));\n\n fCoc = abs(fCoc * 2.0 - 1.0);\n\n float weight = smoothstep(0.0, 1.0, fCoc);\n \n#ifdef NEARFIELD_ENABLED\n vec4 nearfieldColor = decodeHDR(texture2D(nearfield, v_Texcoord));\n float fNearCoc = decodeFloat(texture2D(nearcoc, v_Texcoord));\n fNearCoc = abs(fNearCoc * 2.0 - 1.0);\n\n gl_FragColor = encodeHDR(\n mix(\n nearfieldColor, mix(originalColor, blurredColor, weight),\n pow(1.0 - fNearCoc, 4.0)\n )\n );\n#else\n gl_FragColor = encodeHDR(mix(originalColor, blurredColor, weight));\n#endif\n\n}\n\n@end\n\n\n\n@export ecgl.dof.diskBlur\n\n#define POISSON_KERNEL_SIZE 16;\n\nuniform sampler2D texture;\nuniform sampler2D coc;\nvarying vec2 v_Texcoord;\n\nuniform float blurRadius : 10.0;\nuniform vec2 textureSize : [512.0, 512.0];\n\nuniform vec2 poissonKernel[POISSON_KERNEL_SIZE];\n\nuniform float percent;\n\nfloat nrand(const in vec2 n) {\n return fract(sin(dot(n.xy ,vec2(12.9898,78.233))) * 43758.5453);\n}\n\n@import clay.util.rgbm\n@import clay.util.float\n\n\nvoid main()\n{\n vec2 offset = blurRadius / textureSize;\n\n float rnd = 6.28318 * nrand(v_Texcoord + 0.07 * percent );\n float cosa = cos(rnd);\n float sina = sin(rnd);\n vec4 basis = vec4(cosa, -sina, sina, cosa);\n\n#if !defined(BLUR_NEARFIELD) && !defined(BLUR_COC)\n offset *= abs(decodeFloat(texture2D(coc, v_Texcoord)) * 2.0 - 1.0);\n#endif\n\n#ifdef BLUR_COC\n float cocSum = 0.0;\n#else\n vec4 color = vec4(0.0);\n#endif\n\n\n float weightSum = 0.0;\n\n for (int i = 0; i < POISSON_KERNEL_SIZE; i++) {\n vec2 ofs = poissonKernel[i];\n\n ofs = vec2(dot(ofs, basis.xy), dot(ofs, basis.zw));\n\n vec2 uv = v_Texcoord + ofs * offset;\n vec4 texel = texture2D(texture, uv);\n\n float w = 1.0;\n#ifdef BLUR_COC\n float fCoc = decodeFloat(texel) * 2.0 - 1.0;\n cocSum += clamp(fCoc, -1.0, 0.0) * w;\n#else\n texel = decodeHDR(texel);\n #if !defined(BLUR_NEARFIELD)\n float fCoc = decodeFloat(texture2D(coc, uv)) * 2.0 - 1.0;\n w *= abs(fCoc);\n #endif\n color += texel * w;\n#endif\n\n weightSum += w;\n }\n\n#ifdef BLUR_COC\n gl_FragColor = encodeFloat(clamp(cocSum / weightSum, -1.0, 0.0) * 0.5 + 0.5);\n#else\n color /= weightSum;\n gl_FragColor = encodeHDR(color);\n#endif\n}\n\n@end"},function(e,t,n){"use strict";t.a="@export ecgl.edge\n\nuniform sampler2D texture;\n\nuniform sampler2D normalTexture;\nuniform sampler2D depthTexture;\n\nuniform mat4 projectionInv;\n\nuniform vec2 textureSize;\n\nuniform vec4 edgeColor: [0,0,0,0.8];\n\nvarying vec2 v_Texcoord;\n\nvec3 packColor(vec2 coord) {\n float z = texture2D(depthTexture, coord).r * 2.0 - 1.0;\n vec4 p = vec4(v_Texcoord * 2.0 - 1.0, z, 1.0);\n vec4 p4 = projectionInv * p;\n\n return vec3(\n texture2D(normalTexture, coord).rg,\n -p4.z / p4.w / 5.0\n );\n}\n\nvoid main() {\n vec2 cc = v_Texcoord;\n vec3 center = packColor(cc);\n\n float size = clamp(1.0 - (center.z - 10.0) / 100.0, 0.0, 1.0) * 0.5;\n float dx = size / textureSize.x;\n float dy = size / textureSize.y;\n\n vec2 coord;\n vec3 topLeft = packColor(cc+vec2(-dx, -dy));\n vec3 top = packColor(cc+vec2(0.0, -dy));\n vec3 topRight = packColor(cc+vec2(dx, -dy));\n vec3 left = packColor(cc+vec2(-dx, 0.0));\n vec3 right = packColor(cc+vec2(dx, 0.0));\n vec3 bottomLeft = packColor(cc+vec2(-dx, dy));\n vec3 bottom = packColor(cc+vec2(0.0, dy));\n vec3 bottomRight = packColor(cc+vec2(dx, dy));\n\n vec3 v = -topLeft-2.0*top-topRight+bottomLeft+2.0*bottom+bottomRight;\n vec3 h = -bottomLeft-2.0*left-topLeft+bottomRight+2.0*right+topRight;\n\n float edge = sqrt(dot(h, h) + dot(v, v));\n\n edge = smoothstep(0.8, 1.0, edge);\n\n gl_FragColor = mix(texture2D(texture, v_Texcoord), vec4(edgeColor.rgb, 1.0), edgeColor.a * edge);\n}\n@end"},function(e,t,n){"use strict";function a(){for(var e=[],t=0;t<30;t++)e.push([Object(i.a)(t,2),Object(i.a)(t,3)]);this._haltonSequence=e,this._frame=0,this._sourceTex=new s.a,this._sourceFb=new o.a,this._sourceFb.attach(this._sourceTex),this._prevFrameTex=new s.a,this._outputTex=new s.a;var n=this._blendPass=new r.a({fragment:c.a.source("clay.compositor.blend")});n.material.disableTexturesAll(),n.material.enableTexture(["texture1","texture2"]),this._blendFb=new o.a({depthBuffer:!1}),this._outputPass=new r.a({fragment:c.a.source("clay.compositor.output"),blendWithPrevious:!0}),this._outputPass.material.define("fragment","OUTPUT_ALPHA"),this._outputPass.material.blend=function(e){e.blendEquationSeparate(e.FUNC_ADD,e.FUNC_ADD),e.blendFuncSeparate(e.ONE,e.ONE_MINUS_SRC_ALPHA,e.ONE,e.ONE_MINUS_SRC_ALPHA)}}var i=n(25),r=n(13),o=n(11),s=n(5),c=n(2),l=n(9);a.prototype={constructor:a,jitterProjection:function(e,t){var n=e.viewport,a=n.devicePixelRatio||e.getDevicePixelRatio(),i=n.width*a,r=n.height*a,o=this._haltonSequence[this._frame%this._haltonSequence.length],s=new l.a;s.array[12]=(2*o[0]-1)/i,s.array[13]=(2*o[1]-1)/r,l.a.mul(t.projectionMatrix,s,t.projectionMatrix),l.a.invert(t.invProjectionMatrix,t.projectionMatrix)},resetFrame:function(){this._frame=0},getFrame:function(){return this._frame},getSourceFrameBuffer:function(){return this._sourceFb},resize:function(e,t){this._sourceTex.width===e&&this._sourceTex.height===t||(this._prevFrameTex.width=e,this._prevFrameTex.height=t,this._outputTex.width=e,this._outputTex.height=t,this._sourceTex.width=e,this._sourceTex.height=t,this._prevFrameTex.dirty(),this._outputTex.dirty(),this._sourceTex.dirty())},isFinished:function(){return this._frame>=this._haltonSequence.length},render:function(e){var t=this._blendPass;0===this._frame?(t.setUniform("weight1",0),t.setUniform("weight2",1)):(t.setUniform("weight1",.9),t.setUniform("weight2",.1)),t.setUniform("texture1",this._prevFrameTex),t.setUniform("texture2",this._sourceTex),this._blendFb.attach(this._outputTex),this._blendFb.bind(e),t.render(e),this._blendFb.unbind(e),this._outputPass.setUniform("texture",this._outputTex),this._outputPass.render(e);var n=this._prevFrameTex;this._prevFrameTex=this._outputTex,this._outputTex=n,this._frame++},dispose:function(e){this._sourceFb.dispose(e),this._blendFb.dispose(e),this._prevFrameTex.dispose(e),this._outputTex.dispose(e),this._sourceTex.dispose(e),this._outputPass.dispose(e),this._blendPass.dispose(e)}},t.a=a},function(e,t,n){"use strict";function a(e){this.setScene(e)}var i=n(26),r=n(35),o=n(34),s=n(4),c=n(135),l=n(136);a.prototype={constructor:a,setScene:function(e){this._scene=e,this._skybox&&this._skybox.attachScene(this._scene)},initLight:function(e){this._lightRoot=e,this.mainLight=new c.a({shadowBias:.005}),this.secondaryLight=new c.a({shadowBias:.005}),this.tertiaryLight=new c.a({shadowBias:.005}),this.ambientLight=new l.a},dispose:function(e){this._lightRoot&&(this._lightRoot.remove(this.mainLight),this._lightRoot.remove(this.secondaryLight),this._lightRoot.remove(this.tertiaryLight),this._lightRoot.remove(this.ambientLight)),this._currentCubemapLights&&(this._lightRoot.remove(this._currentCubemapLights.diffuse),this._currentCubemapLights.specular&&(this._lightRoot.remove(this._currentCubemapLights.specular),this._currentCubemapLights.specular.cubemap.dispose(e)))},updateMainLight:function(e,t){this._updateDirectionalLight(this.mainLight,e,t)},updateSecondaryLight:function(e,t){this._updateDirectionalLight(this.secondaryLight,e,t)},updateTertiaryLight:function(e,t){this._updateDirectionalLight(this.tertiaryLight,e,t)},_updateDirectionalLight:function(e,t,n){t=t||{},null!=t.intensity&&(e.intensity=t.intensity,this._lightRoot[t.intensity?"add":"remove"](e)),null!=t.color&&(e.color=i.a.parseColor(t.color).slice(0,3));var a=i.a.firstNotNull(t.alpha,45),r=i.a.firstNotNull(t.beta,45);e.position.setArray(i.a.directionFromAlphaBeta(a,r)),e.lookAt(s.a.ZERO);var o={low:512,medium:1024,high:2048,ultra:4096}[t.quality]||1024;e.castShadow=i.a.firstNotNull(t.shadow,!0),e.shadowResolution=o},updateAmbientLight:function(e,t){e=e||{},null!=e.intensity&&(this.ambientLight.intensity=e.intensity,this._lightRoot[e.intensity?"add":"remove"](this.ambientLight)),null!=e.color&&(this.ambientLight.color=i.a.parseColor(e.color).slice(0,3))},updateAmbientCubemapLight:function(e,t){e=e||{};var n=t.getRenderer(),a=e.texture,o=this;if("texture"in e&&(!this._currentCubemapLights||a!==this._currentCubemapLights.textureUrl))if(this._currentCubemapLights&&(this._lightRoot.remove(this._currentCubemapLights.diffuse),this._currentCubemapLights.specular&&(this._lightRoot.remove(this._currentCubemapLights.specular),this._currentCubemapLights.specular.cubemap.dispose(n.gl))),a){var s=i.a.createAmbientCubemap(e,t,function(){s.specular&&o._skybox instanceof r.a&&o._skybox.setEnvironmentMap(s.specular.cubemap),t.refresh()});s.diffuse&&this._lightRoot.add(s.diffuse),s.specular&&this._lightRoot.add(s.specular),this._currentCubemapLights=s,this._currentCubemapLights.textureUrl=a}else this._currentCubemapLights&&(this._lightRoot.remove(this._currentCubemapLights.diffuse),this._lightRoot.remove(this._currentCubemapLights.specular),this._currentCubemapLights=null);this._currentCubemapLights&&(null!=e.specularIntensity&&this._currentCubemapLights.specular&&(this._currentCubemapLights.specular.intensity=e.specularIntensity),null!=e.diffuseIntensity&&this._currentCubemapLights.diffuse&&(this._currentCubemapLights.diffuse.intensity=e.diffuseIntensity))},updateSkybox:function(e,t,n){var a=n.getRenderer(),s=this;if(e&&"none"!==e)if("auto"===e)if(this._currentCubemapLights){var c=function(){return s._skybox instanceof r.a||(s._skybox&&s._skybox.dispose(a),s._skybox=new r.a),s._skybox}();if(this._currentCubemapLights.specular){var l=this._currentCubemapLights.specular.cubemap;c.setEnvironmentMap(l)}this._scene&&c.attachScene(this._scene),c.material.set("lod",2)}else this._skybox&&this._skybox.detachScene();else{var u=function(){return s._skybox instanceof o.a||(s._skybox&&s._skybox.dispose(a),s._skybox=new o.a),s._skybox}(),p=i.a.loadTexture(e,n,{flipY:!1},function(){n.refresh()});u.setEnvironmentMap(p),u.attachScene(this._scene)}else this._skybox&&this._skybox.detachScene(this._scene),this._skybox=null;if(this._skybox)if("auto"===e||e.match&&e.match(/.hdr$/))this._skybox.material.undefine("fragment","SRGB_DECODE");else{var d=t?"define":"undefine";this._skybox.material[d]("fragment","SRGB_DECODE")}}},t.a=a},function(e,t,n){"use strict";var a=n(18),i=n(4),r=a.a.extend({shadowBias:.001,shadowSlopeScale:2,shadowCascade:1,cascadeSplitLogFactor:.2},{type:"DIRECTIONAL_LIGHT",uniformTemplates:{directionalLightDirection:{type:"3f",value:function(e){return e.__dir=e.__dir||new i.a,e.__dir.copy(e.worldTransform.z).normalize().negate().array}},directionalLightColor:{type:"3f",value:function(e){var t=e.color,n=e.intensity;return[t[0]*n,t[1]*n,t[2]*n]}}},clone:function(){var e=a.a.prototype.clone.call(this);return e.shadowBias=this.shadowBias,e.shadowSlopeScale=this.shadowSlopeScale,e}});t.a=r},function(e,t,n){"use strict";var a=n(18),i=a.a.extend({castShadow:!1},{type:"AMBIENT_LIGHT",uniformTemplates:{ambientLightColor:{type:"3f",value:function(e){var t=e.color,n=e.intensity;return[t[0]*n,t[1]*n,t[2]*n]}}}});t.a=i},function(e,t,n){"use strict";t.a={devicePixelRatio:null,preZ:!1,picking:!1,shadow:!0,environment:"",ground:{show:!1,grid:!1},mainLight:{shadow:!0,shadowQuality:"medium",intensity:.8,color:"#fff",alpha:45,beta:45},secondaryLight:{shadow:!0,shadowQuality:"medium",intensity:0,color:"#fff",alpha:60,beta:-50},tertiaryLight:{shadow:!0,shadowQuality:"medium",intensity:0,color:"#fff",alpha:89,beta:0},ambientLight:{intensity:.3,color:"#fff"},ambientCubemapLight:{texture:"",exposure:3,diffuseIntensity:.5,specularIntensity:.5},postEffect:{enable:!1,bloom:{enable:!1,intensity:.1},depthOfField:{enable:!1,focalDistance:5,focalRange:1,blurRadius:5,fstop:2.8,quality:"medium"},screenSpaceAmbientOcculusion:{enable:!1,physical:!1,radius:.5,quality:"medium",intensity:1},screenSpaceReflection:{enable:!1,quality:"medium",maxRoughness:.8},colorCorrection:{enable:!0,exposure:0,brightness:0,contrast:1,saturation:1,lookupTexture:""},FXAA:{enable:!1}}}},function(e,t,n){"use strict";function a(e){if(null==e||"object"!=typeof e)return e;var t=e,n=m.call(e);if("[object Array]"===n){t=[];for(var i=0,r=e.length;i=0&&i[d]>1e-6&&(c.transformMat4(s,n,r[a[d]]),c.scaleAndAdd(o,o,s,i[d]));c.min(v,v,o),c.max(g,g,o)}t.min.setArray(v),t.max.setArray(g)}function i(e,t){t=t||new r.a;var n=new r.a;return e.traverse(function(e){e.geometry&&(e.isSkinnedMesh()?(a(e,n),e.geometry.boundingBox.copy(n)):(n.copy(e.geometry.boundingBox),n.applyTransform(e.worldTransform)),t.union(n))}),t}var r=n(8),o=n(0),s=n.n(o),c=s.a.vec3;t.a=i},function(e,t,n){"use strict";function a(e){return Array.isArray(e)||(e=[e,e]),e}var i=n(1),r=n(21),o=n(4),s=n(141),c=i.a.extend(function(){return{timeline:null,domElement:null,target:null,_center:new o.a,minDistance:.1,maxDistance:1e3,minAlpha:-90,maxAlpha:90,minBeta:-1/0,maxBeta:1/0,autoRotateAfterStill:0,autoRotateDirection:"cw",autoRotateSpeed:60,_mode:"rotate",damping:.8,rotateSensitivity:1,zoomSensitivity:1,panSensitivity:1,_needsUpdate:!1,_rotating:!1,_phi:0,_theta:0,_mouseX:0,_mouseY:0,_rotateVelocity:new r.a,_panVelocity:new r.a,_distance:20,_zoomSpeed:0,_stillTimeout:0,_animators:[],_gestureMgr:new s.a}},function(){this._mouseDownHandler=this._mouseDownHandler.bind(this),this._mouseWheelHandler=this._mouseWheelHandler.bind(this),this._mouseMoveHandler=this._mouseMoveHandler.bind(this),this._mouseUpHandler=this._mouseUpHandler.bind(this),this._pinchHandler=this._pinchHandler.bind(this),this.update=this.update.bind(this),this.init()},{init:function(){var e=this.domElement;e.addEventListener("touchstart",this._mouseDownHandler),e.addEventListener("mousedown",this._mouseDownHandler),e.addEventListener("mousewheel",this._mouseWheelHandler),this.timeline&&this.timeline.on("frame",this.update)},dispose:function(){var e=this.domElement;e.removeEventListener("touchstart",this._mouseDownHandler),e.removeEventListener("touchmove",this._mouseMoveHandler),e.removeEventListener("touchend",this._mouseUpHandler),e.removeEventListener("mousedown",this._mouseDownHandler),e.removeEventListener("mousemove",this._mouseMoveHandler),e.removeEventListener("mouseup",this._mouseUpHandler),e.removeEventListener("mousewheel",this._mouseWheelHandler),e.removeEventListener("mouseout",this._mouseUpHandler),this.timeline&&this.timeline.off("frame",this.update),this.stopAllAnimation()},getDistance:function(){return this._distance},setDistance:function(e){this._distance=e,this._needsUpdate=!0},getAlpha:function(){return this._theta/Math.PI*180},getBeta:function(){return-this._phi/Math.PI*180},getCenter:function(){return this._center.toArray()},setAlpha:function(e){e=Math.max(Math.min(this.maxAlpha,e),this.minAlpha),this._theta=e/180*Math.PI,this._needsUpdate=!0},setBeta:function(e){e=Math.max(Math.min(this.maxBeta,e),this.minBeta),this._phi=-e/180*Math.PI,this._needsUpdate=!0},setCenter:function(e){this._center.setArray(e)},setOption:function(e){e=e||{},["autoRotate","autoRotateAfterStill","autoRotateDirection","autoRotateSpeed","damping","minDistance","maxDistance","minAlpha","maxAlpha","minBeta","maxBeta","rotateSensitivity","zoomSensitivity","panSensitivity"].forEach(function(t){null!=e[t]&&(this[t]=e[t])},this),null!=e.distance&&this.setDistance(e.distance),null!=e.alpha&&this.setAlpha(e.alpha),null!=e.beta&&this.setBeta(e.beta),e.center&&this.setCenter(e.center)},animateTo:function(e){var t=this,n={},a={},i=this.timeline;if(i)return null!=e.distance&&(n.distance=this.getDistance(),a.distance=e.distance),null!=e.alpha&&(n.alpha=this.getAlpha(),a.alpha=e.alpha),null!=e.beta&&(n.beta=this.getBeta(),a.beta=e.beta),null!=e.center&&(n.center=this.getCenter(),a.center=e.center),this._addAnimator(i.animate(n).when(e.duration||1e3,a).during(function(){null!=n.alpha&&t.setAlpha(n.alpha),null!=n.beta&&t.setBeta(n.beta),null!=n.distance&&t.setDistance(n.distance),null!=n.center&&t.setCenter(n.center),t._needsUpdate=!0}).done(e.done)).start(e.easing||"linear")},stopAllAnimation:function(){for(var e=0;e0},update:function(e){if(e=e||16,this._rotating){var t=("cw"===this.autoRotateDirection?1:-1)*this.autoRotateSpeed/180*Math.PI;this._phi-=t*e/1e3,this._needsUpdate=!0}else this._rotateVelocity.len()>0&&(this._needsUpdate=!0);(Math.abs(this._zoomSpeed)>.01||this._panVelocity.len()>0)&&(this._needsUpdate=!0),this._needsUpdate&&(this._updateDistance(Math.min(e,50)),this._updatePan(Math.min(e,50)),this._updateRotate(Math.min(e,50)),this._updateTransform(),this.target.update(),this.trigger("update"),this._needsUpdate=!1)},_updateRotate:function(e){var t=this._rotateVelocity;this._phi=t.y*e/20+this._phi,this._theta=t.x*e/20+this._theta,this.setAlpha(this.getAlpha()),this.setBeta(this.getBeta()),this._vectorDamping(t,this.damping),t.x=t.y=0},_updateDistance:function(e){this._setDistance(this._distance+this._zoomSpeed*e/20),this._zoomSpeed*=this.damping},_setDistance:function(e){this._distance=Math.max(Math.min(e,this.maxDistance),this.minDistance)},_updatePan:function(e){var t=this._panVelocity,n=this._distance,a=this.target,i=a.worldTransform.y,r=a.worldTransform.x;this._center.scaleAndAdd(r,-t.x*n/200).scaleAndAdd(i,-t.y*n/200),this._vectorDamping(t,0),t.x=t.y=0},_updateTransform:function(){var e=this.target,t=new o.a,n=this._theta+Math.PI/2,a=this._phi+Math.PI/2,i=Math.sin(n);t.x=i*Math.cos(a),t.y=-Math.cos(n),t.z=i*Math.sin(a),e.position.copy(this._center).scaleAndAdd(t,this._distance),e.rotation.identity().rotateY(-this._phi).rotateX(-this._theta)},_startCountingStill:function(){clearTimeout(this._stillTimeout);var e=this.autoRotateAfterStill,t=this;!isNaN(e)&&e>0&&(this._stillTimeout=setTimeout(function(){t._rotating=!0},1e3*e))},_vectorDamping:function(e,t){var n=e.len();n*=t,n<1e-4&&(n=0),e.normalize().scale(n)},decomposeTransform:function(){if(this.target){this.target.updateWorldTransform();var e=this.target.worldTransform.z,t=Math.asin(e.y),n=Math.atan2(e.x,e.z);this._theta=t,this._phi=-n,this.setBeta(this.getBeta()),this.setAlpha(this.getAlpha()),this._setDistance(this.target.position.dist(this._center))}},_mouseDownHandler:function(e){if(!this._isAnimating()){var t=e.clientX,n=e.clientY;if(e.targetTouches){var a=e.targetTouches[0];t=a.clientX,n=a.clientY,this._mode="rotate",this._processGesture(e,"start")}var i=this.domElement;i.addEventListener("touchmove",this._mouseMoveHandler),i.addEventListener("touchend",this._mouseUpHandler),i.addEventListener("mousemove",this._mouseMoveHandler),i.addEventListener("mouseup",this._mouseUpHandler),i.addEventListener("mouseout",this._mouseUpHandler),0===e.button?this._mode="rotate":1===e.button?this._mode="pan":this._mode=null,this._rotateVelocity.set(0,0),this._rotating=!1,this.autoRotate&&this._startCountingStill(),this._mouseX=t,this._mouseY=n}},_mouseMoveHandler:function(e){if(!this._isAnimating()){var t,n=e.clientX,i=e.clientY;if(e.targetTouches){var r=e.targetTouches[0];n=r.clientX,i=r.clientY,t=this._processGesture(e,"change")}var o=a(this.panSensitivity),s=a(this.rotateSensitivity);t||("rotate"===this._mode?(this._rotateVelocity.y+=(n-this._mouseX)/this.domElement.clientWidth*2*s[0],this._rotateVelocity.x+=(i-this._mouseY)/this.domElement.clientHeight*2*s[1]):"pan"===this._mode&&(this._panVelocity.x+=(n-this._mouseX)/this.domElement.clientWidth*o[0]*400,this._panVelocity.y+=(-i+this._mouseY)/this.domElement.clientHeight*o[1]*400)),this._mouseX=n,this._mouseY=i,e.preventDefault()}},_mouseWheelHandler:function(e){if(!this._isAnimating()){var t=e.wheelDelta||-e.detail;0!==t&&this._zoomHandler(e,t>0?-1:1)}},_pinchHandler:function(e){this._isAnimating()||this._zoomHandler(e,e.pinchScale>1?-.4:.4)},_zoomHandler:function(e,t){var n=Math.max(Math.min(this._distance-this.minDistance,this.maxDistance-this._distance));this._zoomSpeed=t*Math.max(n/40*this.zoomSensitivity,.2),this._rotating=!1,this.autoRotate&&"rotate"===this._mode&&this._startCountingStill(),e.preventDefault()},_mouseUpHandler:function(e){var t=this.domElement;t.removeEventListener("touchmove",this._mouseMoveHandler),t.removeEventListener("touchend",this._mouseUpHandler),t.removeEventListener("mousemove",this._mouseMoveHandler),t.removeEventListener("mouseup",this._mouseUpHandler),t.removeEventListener("mouseout",this._mouseUpHandler),this._processGesture(e,"end")},_addAnimator:function(e){var t=this._animators;return t.push(e),e.done(function(){var n=t.indexOf(e);n>=0&&t.splice(n,1)}),e},_processGesture:function(e,t){var n=this._gestureMgr;"start"===t&&n.clear();var a=n.recognize(e,null,this.domElement);if("end"===t&&n.clear(),a){var i=a.type;e.gestureEvent=i,this._pinchHandler(a.event)}return a}});Object.defineProperty(c.prototype,"autoRotate",{get:function(){return this._autoRotate},set:function(e){this._autoRotate=e,this._rotating=e}}),Object.defineProperty(c.prototype,"target",{get:function(){return this._target},set:function(e){e&&e.target&&this.setCenter(e.target.toArray()),this._target=e,this.decomposeTransform()}}),t.a=c},function(e,t,n){"use strict";function a(e){var t=e[1][0]-e[0][0],n=e[1][1]-e[0][1];return Math.sqrt(t*t+n*n)}function i(e){return[(e[0][0]+e[1][0])/2,(e[0][1]+e[1][1])/2]}var r=function(){this._track=[]};r.prototype={constructor:r,recognize:function(e,t,n){return this._doTrack(e,t,n),this._recognize(e)},clear:function(){return this._track.length=0,this},_doTrack:function(e,t,n){var a=e.targetTouches;if(a){for(var i={points:[],touches:[],target:t,event:e},r=0,o=a.length;r1&&r&&r.length>1){var s=a(r)/a(o);!isFinite(s)&&(s=1),t.pinchScale=s;var c=i(r);return t.pinchX=c[0],t.pinchY=c[1],{type:"pinch",target:e[0].target,event:t}}}}};t.a=r},function(e,t,n){"use strict";var a=n(1),i=n(143),r=n(8),o=a.a.extend(function(){return{dom:null,renderer:null,camera:null,_boundingBox:new r.a,_hotspotRoot:null,_hotspots:[]}},function(){if(!this.dom||!this.renderer||!this.camera)throw new Error("Tip manager needs `root`, `camera`, `renderer`");var e=this._hotspotRoot=document.createElement("div");e.style.cssText="position:absolute;top:0;left:0;right:0;bottom:0;overflow:hidden;",this.dom.appendChild(e)},{setBoundingBox:function(e,t){this._boundingBox.min.setArray(e),this._boundingBox.max.setArray(t)},add:function(e,t){if("string"==typeof t){var n=document.createElement("div");n.innerHTML=t,t=n}return t.classList.add("qmv-annotation"),t.style.position="absolute",this._hotspotRoot.appendChild(t),this._hotspots.push({position:e,dom:t}),t},remove:function(e){for(var t=-1,n=0;n=0&&(this._hotspots.splice(t,1),this._hotspotRoot.removeChild(e))},update:function(){var e=new i.a,t=new r.a;this._hotspots.forEach(function(n){var a=n.position;e.set(a[0],a[1],a[2],1),e.transformMat4(this.camera.viewMatrix);var i=e.z;e.transformMat4(this.camera.projectionMatrix),e.scale(1/e.w);var r=.5*(e.x+1)*this.renderer.getWidth(),o=.5*(e.y+1)*this.renderer.getHeight();n.dom.style.left=r+"px",n.dom.style.top=this.renderer.getHeight()-o+"px";var s=null==n.farAlpha?.1:n.farAlpha,c=null==n.nearAlpha?1:n.nearAlpha;t.copy(this._boundingBox),t.applyTransform(this.camera.viewMatrix);var l=(i-t.max.z)/(t.min.z-t.max.z);Math.max(Math.min(l,1),0);n.dom.style.opacity=1,n.onupdate&&n.onupdate(r,o)},this)}});t.a=o},function(e,t,n){"use strict";var a=n(0),i=n.n(a),r=i.a.vec4,o=function(e,t,n,a){e=e||0,t=t||0,n=n||0,a=a||0,this.array=r.fromValues(e,t,n,a),this._dirty=!0};o.prototype={constructor:o,add:function(e){return r.add(this.array,this.array,e.array),this._dirty=!0,this},set:function(e,t,n,a){return this.array[0]=e,this.array[1]=t,this.array[2]=n,this.array[3]=a,this._dirty=!0,this},setArray:function(e){return this.array[0]=e[0],this.array[1]=e[1],this.array[2]=e[2],this.array[3]=e[3],this._dirty=!0,this},clone:function(){return new o(this.x,this.y,this.z,this.w)},copy:function(e){return r.copy(this.array,e.array),this._dirty=!0,this},dist:function(e){return r.dist(this.array,e.array)},distance:function(e){return r.distance(this.array,e.array)},div:function(e){return r.div(this.array,this.array,e.array),this._dirty=!0,this},divide:function(e){return r.divide(this.array,this.array,e.array),this._dirty=!0,this},dot:function(e){return r.dot(this.array,e.array)},len:function(){return r.len(this.array)},length:function(){return r.length(this.array)},lerp:function(e,t,n){return r.lerp(this.array,e.array,t.array,n),this._dirty=!0,this},min:function(e){return r.min(this.array,this.array,e.array),this._dirty=!0,this},max:function(e){return r.max(this.array,this.array,e.array),this._dirty=!0,this},mul:function(e){return r.mul(this.array,this.array,e.array),this._dirty=!0,this},multiply:function(e){return r.multiply(this.array,this.array,e.array),this._dirty=!0,this},negate:function(){return r.negate(this.array,this.array),this._dirty=!0,this},normalize:function(){return r.normalize(this.array,this.array),this._dirty=!0,this},random:function(e){return r.random(this.array,e),this._dirty=!0,this},scale:function(e){return r.scale(this.array,this.array,e),this._dirty=!0,this},scaleAndAdd:function(e,t){return r.scaleAndAdd(this.array,this.array,e.array,t),this._dirty=!0,this},sqrDist:function(e){return r.sqrDist(this.array,e.array)},squaredDistance:function(e){return r.squaredDistance(this.array,e.array)},sqrLen:function(){return r.sqrLen(this.array)},squaredLength:function(){return r.squaredLength(this.array)},sub:function(e){return r.sub(this.array,this.array,e.array),this._dirty=!0,this},subtract:function(e){return r.subtract(this.array,this.array,e.array),this._dirty=!0,this},transformMat4:function(e){return r.transformMat4(this.array,this.array,e.array),this._dirty=!0,this},transformQuat:function(e){return r.transformQuat(this.array,this.array,e.array),this._dirty=!0,this},toString:function(){return"["+Array.prototype.join.call(this.array,",")+"]"},toArray:function(){return Array.prototype.slice.call(this.array)}};var s=Object.defineProperty;if(s){var c=o.prototype;s(c,"x",{get:function(){return this.array[0]},set:function(e){this.array[0]=e,this._dirty=!0}}),s(c,"y",{get:function(){return this.array[1]},set:function(e){this.array[1]=e,this._dirty=!0}}),s(c,"z",{get:function(){return this.array[2]},set:function(e){this.array[2]=e,this._dirty=!0}}),s(c,"w",{get:function(){return this.array[3]},set:function(e){this.array[3]=e,this._dirty=!0}})}o.add=function(e,t,n){return r.add(e.array,t.array,n.array),e._dirty=!0,e},o.set=function(e,t,n,a,i){r.set(e.array,t,n,a,i),e._dirty=!0},o.copy=function(e,t){return r.copy(e.array,t.array),e._dirty=!0,e},o.dist=function(e,t){return r.distance(e.array,t.array)},o.distance=o.dist,o.div=function(e,t,n){return r.divide(e.array,t.array,n.array),e._dirty=!0,e},o.divide=o.div,o.dot=function(e,t){return r.dot(e.array,t.array)},o.len=function(e){return r.length(e.array)},o.lerp=function(e,t,n,a){return r.lerp(e.array,t.array,n.array,a),e._dirty=!0,e},o.min=function(e,t,n){return r.min(e.array,t.array,n.array),e._dirty=!0,e},o.max=function(e,t,n){return r.max(e.array,t.array,n.array),e._dirty=!0,e},o.mul=function(e,t,n){return r.multiply(e.array,t.array,n.array),e._dirty=!0,e},o.multiply=o.mul,o.negate=function(e,t){return r.negate(e.array,t.array),e._dirty=!0,e},o.normalize=function(e,t){return r.normalize(e.array,t.array),e._dirty=!0,e},o.random=function(e,t){return r.random(e.array,t),e._dirty=!0,e},o.scale=function(e,t,n){return r.scale(e.array,t.array,n),e._dirty=!0,e},o.scaleAndAdd=function(e,t,n,a){return r.scaleAndAdd(e.array,t.array,n.array,a),e._dirty=!0,e},o.sqrDist=function(e,t){return r.sqrDist(e.array,t.array)},o.squaredDistance=o.sqrDist,o.sqrLen=function(e){return r.sqrLen(e.array)},o.squaredLength=o.sqrLen,o.sub=function(e,t,n){return r.subtract(e.array,t.array,n.array),e._dirty=!0,e},o.subtract=o.sub,o.transformMat4=function(e,t,n){return r.transformMat4(e.array,t.array,n.array),e._dirty=!0,e},o.transformQuat=function(e,t,n){return r.transformQuat(e.array,t.array,n.array),e._dirty=!0,e},t.a=o},function(e,t,n){"use strict";t.a="@export qmv.ground.vertex\n@import clay.lambert.vertex\n@end\n\n\n@export qmv.ground.fragment\n\nvarying vec2 v_Texcoord;\nvarying vec3 v_Normal;\nvarying vec3 v_WorldPosition;\n\nuniform vec4 color : [1.0, 1.0, 1.0, 1.0];\nuniform float gridSize: 5;\nuniform float gridSize2: 1;\nuniform vec4 gridColor: [0, 0, 0, 1];\nuniform vec4 gridColor2: [0.3, 0.3, 0.3, 1];\n\nuniform bool showGrid: true;\n\nuniform float glossiness: 0.7;\n\n#ifdef SSAOMAP_ENABLED\nuniform sampler2D ssaoMap;\nuniform vec4 viewport : VIEWPORT;\n#endif\n\n#ifdef AMBIENT_LIGHT_COUNT\n@import clay.header.ambient_light\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n@import clay.header.ambient_sh_light\n#endif\n#ifdef DIRECTIONAL_LIGHT_COUNT\n@import clay.header.directional_light\n#endif\n\n@import clay.plugin.compute_shadow_map\n\nvoid main()\n{\n gl_FragColor = color;\n\n if (showGrid) {\n float wx = v_WorldPosition.x;\n float wz = v_WorldPosition.z;\n float x0 = abs(fract(wx / gridSize - 0.5) - 0.5) / fwidth(wx) * gridSize / 2.0;\n float z0 = abs(fract(wz / gridSize - 0.5) - 0.5) / fwidth(wz) * gridSize / 2.0;\n\n float x1 = abs(fract(wx / gridSize2 - 0.5) - 0.5) / fwidth(wx) * gridSize2;\n float z1 = abs(fract(wz / gridSize2 - 0.5) - 0.5) / fwidth(wz) * gridSize2;\n\n float v0 = 1.0 - clamp(min(x0, z0), 0.0, 1.0);\n float v1 = 1.0 - clamp(min(x1, z1), 0.0, 1.0);\n if (v0 > 0.1) {\n gl_FragColor = mix(gl_FragColor, gridColor, v0);\n }\n else {\n gl_FragColor = mix(gl_FragColor, gridColor2, v1);\n }\n }\n\n vec3 diffuseColor = vec3(0.0, 0.0, 0.0);\n\n#ifdef AMBIENT_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_LIGHT_COUNT; _idx_++)\n {\n diffuseColor += ambientLightColor[_idx_];\n }\n#endif\n#ifdef AMBIENT_SH_LIGHT_COUNT\n for(int _idx_ = 0; _idx_ < AMBIENT_SH_LIGHT_COUNT; _idx_++)\n {{\n diffuseColor += calcAmbientSHLight(_idx_, v_Normal) * ambientSHLightColor[_idx_];\n }}\n#endif\n\n#ifdef DIRECTIONAL_LIGHT_COUNT\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n float shadowContribsDir[DIRECTIONAL_LIGHT_COUNT];\n if(shadowEnabled)\n {\n computeShadowOfDirectionalLights(v_WorldPosition, shadowContribsDir);\n }\n#endif\n for(int i = 0; i < DIRECTIONAL_LIGHT_COUNT; i++)\n {\n vec3 lightDirection = -directionalLightDirection[i];\n vec3 lightColor = directionalLightColor[i];\n\n float ndl = dot(v_Normal, normalize(lightDirection));\n\n float shadowContrib = 1.0;\n#if defined(DIRECTIONAL_LIGHT_SHADOWMAP_COUNT)\n if( shadowEnabled )\n {\n shadowContrib = shadowContribsDir[i];\n }\n#endif\n\n diffuseColor += lightColor * clamp(ndl, 0.0, 1.0) * shadowContrib;\n }\n#endif\n\n#ifdef SSAOMAP_ENABLED\n diffuseColor *= texture2D(ssaoMap, (gl_FragCoord.xy - viewport.xy) / viewport.zw).r;\n#endif\n\n gl_FragColor.rgb *= diffuseColor;\n\n gl_FragColor.a *= 1.0 - clamp(length(v_WorldPosition.xz) / 30.0, 0.0, 1.0);\n\n}\n\n@end"},function(e,t,n){"use strict";var a=n(36);t.a=function(){return{preZ:!0,materials:[],takes:[],textureFlipY:!1,zUpToYUp:!1,shadow:!0,environment:"auto",viewControl:{alpha:20,beta:30,distance:18},ground:{show:!0,grid:!1},mainLight:{shadow:!0,shadowQuality:"medium",intensity:.8,color:"#fff",alpha:45,beta:45,$padAngle:[.25,.5]},secondaryLight:{shadow:!0,shadowQuality:"medium",intensity:0,color:"#fff",alpha:60,beta:-50,$padAngle:[-50/180,60/90]},tertiaryLight:{shadow:!0,shadowQuality:"medium",intensity:0,color:"#fff",alpha:89,beta:0,$padAngle:[0,89/90]},ambientLight:{intensity:0,color:"#fff"},ambientCubemapLight:{texture:a.a.ENV_TEXTURE_ROOT+"pisa.hdr",$texture:"pisa",$textureOptions:["pisa","Barce_Rooftop_C","Factory_Catwalk","Grand_Canyon_C","Ice_Lake","Hall","Old_Industrial_Hall"],exposure:3,diffuseIntensity:.3,specularIntensity:.5},postEffect:{enable:!0,bloom:{enable:!0,intensity:.1},depthOfField:{enable:!1,focalDistance:4,focalRange:1,blurRadius:5,fstop:10,quality:"medium",$qualityOptions:["low","medium","high","ultra"]},screenSpaceAmbientOcclusion:{enable:!1,radius:1.5,quality:"medium",intensity:1,$qualityOptions:["low","medium","high","ultra"]},screenSpaceReflection:{enable:!1,physical:!1,quality:"medium",maxRoughness:.8,$qualityOptions:["low","medium","high","ultra"]},colorCorrection:{enable:!0,exposure:0,brightness:0,contrast:1,saturation:1,lookupTexture:""},FXAA:{enable:!1}}}}},function(e,t,n){"use strict";t.a=function(){return{name:"",type:"pbrMetallicRoughness",color:"#fff",transparent:!1,alpha:1,alphaCutoff:0,diffuseMap:"",normalMap:"",parallaxOcclusionScale:.01,parallaxOcclusionMap:"",emission:"#fff",emissionIntensity:0,emissiveMap:"",uvRepeat:[1,1],metalness:0,roughness:.5,metalnessMap:"",roughnessMap:"",glossiness:.5,specularColor:"#111",glossinessMap:"",specularMap:"",$alphaRange:[0,1],$alphaCutoffRange:[0,1],$metalnessRange:[0,1],$roughnessRange:[0,1],$glossinessRange:[0,1],$parallaxOcclusionScaleRange:[0,.1],$textureTiling:1}}},function(e,t,n){"use strict";function a(e){var t=e.lastIndexOf(".");return t>=0?e.substr(t+1).toLowerCase():""}function i(e,t){var n=e.split("/");return t=t||"",0===e.indexOf("/")&&n.shift(),n=n.filter(function(e){return!!e}),new Promise(function(e,a){if(!x)return void a(w);var r=n.shift(),o=t+"/"+r;x.mkdir(o,function(t){t&&"EEXIST"!==t.code?a(t.toString()):n.length?i(n.join("/"),o).then(e).catch(a):e()})})}function r(e){return new Promise(function(t,n){if(!x)return void n(w);s(e).then(function(t){return Promise.all(t.map(function(t){return new Promise(function(n,a){var i=e+"/"+t;x.lstat(i,function(e,t){e?a(e.toString()):t.isDirectory()?r(i).then(n,a):x.unlink(i,function(e){e?a(e.toString()):n()})})})}))},n).then(function(){x.rmdir(e,function(e){e?n(e.toString()):t()})},n)})}function o(e,t){return new Promise(function(n,a){x||a(w),FileAPI.readAsArrayBuffer(t,function(i){"load"===i.type&&x.writeFile(e,E.from(i.result),function(e){e&&"EEXIST"!==e.code?a(e):(console.log("Writed file "+t.name+" "+i.result.byteLength),n())})})})}function s(e){return new Promise(function(t,n){x.readdir(e,function(e,a){e?n(e):t(a)})})}function c(e){BrowserFS.install(window),BrowserFS.configure({fs:"IndexedDB",options:{}},function(t){if(t)throw t;x=BrowserFS.BFSRequire("fs"),i("/project").then(function(){Promise.all([d(),p()]).then(function(t){t[0]?e&&e(t[0].glTF,t[0].filesMap,t[1]):e()}).catch(function(t){e()})},function(t){e()})})}function l(e){function t(){return i("/project/model").then(function(){return Promise.all(e.map(function(e){return o("/project/model/"+e.name,e)}))})}return r("/project/model").then(function(){return t()},function(e){return t()})}function u(e){return i("/project").then(function(){return o("/project/scene.json",new File([JSON.stringify(e)],"scene.json",{type:"application/json"}))})}function p(){return new Promise(function(e,t){if(!x)return void t(w);x.readFile("/project/scene.json","utf-8",function(t,n){if(t)e(null);else{var a=null;try{a=JSON.parse(n)}catch(e){console.error(e)}e(a)}})})}function d(){return m().then(function(e){return v(e)})}function f(e){return i("/project/model").then(function(){return o("/project/model/"+e.name,e)})}function h(){return r("/project")}function m(){return s("/project/model").then(function(e){return Promise.all(e.map(function(e){return new Promise(function(t,n){x.readFile("/project/model/"+e,function(i,r){i?n(i):t(new File([r],e,{type:b.a.lookup(a(e))}))})})}))})}function v(e){return new Promise(function(t,n){function a(n,a,o){function s(t){var n=0;e.forEach(function(e){e!==i&&(n++,l[e.name]=URL.createObjectURL(e))}),t&&t(l)}e=e.filter(function(e){return e.name.match(/.(gltf|bin|glb)$/)||e.type.match(/image/)});for(var c in A)URL.revokeObjectURL(A[c]);var l={};A=l,a?s(function(i){e.push(new File([a],n+".gltf",{type:"application/json"}),new File([o],n+".bin",{type:"application/octet-stream"})),t({glTF:JSON.parse(a),filesMap:i,buffers:[o],allFiles:e})}):r?FileAPI.readAsArrayBuffer(r,function(n){"load"===n.type&&s(function(a){t({glTF:n.result,filesMap:a,allFiles:e})})}):i&&FileAPI.readAsText(i,"utf-8",function(n){if("load"===n.type){var a;try{a=JSON.parse(n.result)}catch(e){return void t(null)}s(function(n){t({glTF:a,filesMap:n,allFiles:e})})}})}var i=e.find(function(e){return e.name.endsWith(".gltf")}),r=e.find(function(e){return e.name.endsWith(".glb")});if(i||r)a();else{n("No glTF file found")}})}function g(e,t,n){Promise.all([m(),p()]).then(function(a){var i,r=a[0],o=a[1],s=new JSZip,c={};if(r=(r||[]).filter(function(e){if(!e.name.endsWith(".gltf"))return c[e.name]=e,!0;i=e}),!i)return swal("No glTF file in project!"),void(n&&n());Promise.all(o.materials.map(function(e,t){if(e.metalnessMap||e.roughnessMap){var n=c[e.metalnessMap],a=c[e.roughnessMap];return new Promise(function(i){Object(_.b)(n,a,e.metalness,e.roughness).then(function(n){var a=e.name+"$"+t+"_metallicRoughness.png",r=n.toDataURL();r=r.slice("data:image/png;base64,".length),s.file(a,r,{base64:!0}),e.metalnessMap=e.roughnessMap=a,console.log("Merged %s, %s to %s",e.metalnessMap,e.roughnessMap,a),i()})})}if(e.specularMap||e.glossinessMap){var i=c[e.specularMap],r=c[e.glossinessMap];return new Promise(function(n){Object(_.c)(i,r,e.specularColor,e.glossiness).then(function(a){var i=e.name+"$"+t+"_specularGlossiness.png",r=a.toDataURL();r=r.slice("data:image/png;base64,".length),s.file(i,r,{base64:!0}),e.specularMap=e.glossinessMap=i,console.log("Merged %s, %s to %s",e.specularMap,e.glossinessMap,i),n()})})}return null}).filter(function(e){return null!=e})).then(function(){FileAPI.readAsText(i,"utf-8",function(a){if("load"==a.type){var c=Object(_.d)(JSON.parse(a.result),o);if(c.extensionsUsed=c.extensionsUsed||[],c.extensionsUsed.indexOf("KHR_materials_pbrSpecularGlossiness")<0&&c.extensionsUsed.push("KHR_materials_pbrSpecularGlossiness"),["extensionsUsed","images","textures","samplers","animations"].forEach(function(e){c[e]&&!c[e].length&&delete c[e]}),c.textures||delete c.samplers,r=r.filter(function(e){return e.type.match(/image/)?c.images&&c.images.some(function(t){return t.uri===e.name}):!!e.name.endsWith(".bin")||void 0}),r.forEach(function(e){s.file(e.name,e)}),"glb"===e){var l=[],u=[];s.forEach(function(e,t){(e.endsWith(".bin")?l:u).push({reader:s.file(e).async("arraybuffer"),name:e})}),Promise.all([Promise.all(l.map(function(e){return e.reader})),Promise.all(u.map(function(e){return e.reader}))]).then(function(e){var n=Object(_.a)(c,e[0],e[1].reduce(function(e,t,n){return e[u[n].name]=t,e},{}));Object(T.a)(new Blob([n],{type:"model/json-binary"}),"model.glb"),t&&t()}).catch(n)}else s.file(i.name,JSON.stringify(c,null,2)),s.generateAsync({type:"blob"}).then(function(e){Object(T.a)(e,"model.zip"),t&&t()}).catch(n)}})})}).catch(function(e){swal(e.toString()),n&&n()})}n.d(t,"c",function(){return c}),n.d(t,"e",function(){return l}),n.d(t,"a",function(){return v}),n.d(t,"f",function(){return u}),n.d(t,"g",function(){return f}),n.d(t,"d",function(){return h}),n.d(t,"b",function(){return g});var x,_=(n(36),n(148)),y=(n(149),n(150)),b=n.n(y),T=n(155),E=BrowserFS.BFSRequire("buffer").Buffer,w="File system not prepared yet.",A={}},function(e,t,n){"use strict";function a(e,t){return new Promise(function(t,n){Promise.all(e.map(function(e){var t=e&&URL.createObjectURL(e);return new Promise(function(e,n){if(t){var a=new Image;a.src=t,a.onload=function(){e(a)}}else e(null)})})).then(function(e){var n=e.find(function(e){return null!=e});n||t(null);var a=document.createElement("canvas"),i=a.getContext("2d"),r=a.width=n.width,o=a.height=n.height,s=e.map(function(e){return e?(i.drawImage(e,0,0,r,o),i.getImageData(0,0,r,o).data):null});t({canvas:a,imageDataList:s})})})}function i(e,t,n,i){return new Promise(function(r,o){a([e,t]).then(function(e){for(var t=e.canvas,a=t.getContext("2d"),o=e.imageDataList[0],s=e.imageDataList[1],c=a.createImageData(t.width,t.height),l=0;l<(o||s).length;l+=4){var u=n;if(o){var p=o[l+2]/255;u=Math.min(Math.max(p+2*(u-.5),0),1)}var d=i;if(s){var f=s[l+1]/255;d=Math.min(Math.max(f+2*(d-.5),0),1)}c.data[l]=c.data[l+3]=0,c.data[l+1]=Math.round(255*d),c.data[l+2]=Math.round(255*u)}a.putImageData(c,0,0),r(t)})})}function r(e,t,n,i){return n=d.a.parseColor(n).slice(0,3),new Promise(function(r,o){a([e,t]).then(function(e){for(var t=e.canvas,a=t.getContext("2d"),o=e.imageDataList[0],s=e.imageDataList[1],c=a.createImageData(t.width,t.height),l=0;l<(o||s).length;l+=4){var u=n.slice();o&&(u[0]*=o[l]/255,u[1]*=o[l+1]/255,u[2]*=o[l+2]/255);var p=i;if(s){var d=s[l+3]/255;p=Math.min(Math.max(d+2*(p-.5),0),1)}for(var f=0;f<3;f++)c.data[l+f]=Math.round(255*u[f]);c.data[l+3]=Math.round(255*p)}a.putImageData(c,0,0),r(t)})})}function o(e,t){var n={},a=0;return e.images=[],e.textures=[],e.samplers=[{minFilter:h.a.LINEAR_MIPMAP_LINEAR,magFilter:h.a.LINEAR,wrapS:h.a.REPEAT,wrapT:h.a.REPEAT}],t.materials.forEach(function(t,i){m.forEach(function(i){t[i]&&!n.hasOwnProperty(i)&&(e.images.push({uri:t[i]}),e.textures.push({sampler:0,source:a}),n[t[i]]=a++)})}),n}function s(e,t){var n={baseColorFactor:d.a.parseColor(e.color),metallicFactor:e.metalness,roughnessFactor:e.roughness};return n.baseColorFactor[3]=e.alpha,e.diffuseMap&&(n.baseColorTexture={index:t[e.diffuseMap],texCoord:0}),e.metalnessMap&&(n.metallicRoughnessTexture={index:t[e.metalnessMap],texCoord:0},n.metallicFactor=1,n.roughnessFactor=1),n}function c(e,t){var n={diffuseFactor:d.a.parseColor(e.color),specularFactor:d.a.parseColor(e.specularColor).slice(0,3),glossinessFactor:e.glossiness};return n.diffuseFactor[3]=e.alpha,e.diffuseMap&&(n.diffuseTexture={index:t[e.diffuseMap],texCoord:0}),e.specularMap&&(n.specularGlossinessTexture={index:t[e.specularMap],texCoord:0},n.specularFactor=[1,1,1],n.glossinessFactor=1),n}function l(e,t){if(e.materials){var n=o(e,t),a={};return e.materials=[],e.nodes.forEach(function(t,n){if(null!=t.mesh){var i=e.meshes[t.mesh];1===i.primitives.length?a[t.name]=i.primitives[0]:i.primitives.forEach(function(n,i){a[f.a.generateMeshName(e.meshes,t.mesh,i)]=n})}}),t.materials.forEach(function(t,i){var r={name:t.name,emissiveFactor:d.a.parseColor(t.emission).slice(0,3).map(function(e){return e*t.emissionIntensity}),alphaMode:t.transparent?"BLEND":"OPAQUE"};t.normalMap&&(r.normalTexture={texCoord:0,scale:1,index:n[t.normalMap]}),t.emissiveMap&&(r.emissiveTexture={texCoord:0,index:n[t.emissiveMap]}),"pbrMetallicRoughness"===t.type?r.pbrMetallicRoughness=s(t,n):r.extensions={KHR_materials_pbrSpecularGlossiness:c(t,n)},t.targetMeshes.forEach(function(e){a[e].material=i}),e.materials[i]=r}),e.extras=e.extras||{},e.extras.clayViewerConfig=t,e}}function u(e,t,n){function a(e){return 4*Math.ceil(e/4)}var i=0,r=[],o=t.slice();e.buffers.forEach(function(e){r.push(i),i+=a(e.byteLength),delete e.uri}),e.bufferViews.forEach(function(e){null==e.byteOffset?e.byteOffset=0:e.byteOffset=e.byteOffset+r[e.buffer]}),(e.images||[]).forEach(function(t,s){var c=t.uri,l=n[c];if(delete t.uri,l){var u={buffer:0,byteOffset:i,byteLength:l.byteLength};r.push(i),i+=a(l.byteLength),t.bufferView=e.bufferViews.length,t.mimeType=p(c),e.bufferViews.push(u),o.push(l)}});var s=i;e.buffers=[{byteLength:s}];var c,l=new TextEncoder,u=l.encode(JSON.stringify(e)),d=a(u.length);d!==u.length&&(c=d-u.length);var f=20+d+8+s,h=new ArrayBuffer(f),m=new DataView(h),v=0;m.setUint32(v,1179937895,!0),v+=4,m.setUint32(v,2,!0),v+=4,m.setUint32(v,f,!0),v+=4,m.setUint32(v,d,!0),v+=4,m.setUint32(v,1313821514,!0),v+=4;for(var g=0;g most) - var preference = ['nginx', 'apache', undefined, 'iana'] - - Object.keys(db).forEach(function forEachMimeType (type) { - var mime = db[type] - var exts = mime.extensions - - if (!exts || !exts.length) { - return - } - - // mime -> extensions - extensions[type] = exts - - // extension -> mime - for (var i = 0; i < exts.length; i++) { - var extension = exts[i] - - if (types[extension]) { - var from = preference.indexOf(db[types[extension]].source) - var to = preference.indexOf(mime.source) - - if (types[extension] !== 'application/octet-stream' && - (from > to || (from === to && types[extension].substr(0, 12) === 'application/'))) { - // skip the remapping - continue - } - } - - // set the extension -> mime - types[extension] = type - } - }) -} - - -/***/ }), -/* 151 */ -/***/ (function(module, exports, __webpack_require__) { - -/*! +var s=n(151),c=n(153).extname,l=/^\s*([^;\s]*)(?:;|\s|$)/,u=/^text\//i;t.charset=a,t.charsets={lookup:a},t.contentType=i,t.extension=r,t.extensions=Object.create(null),t.lookup=o,t.types=Object.create(null),function(e,t){var n=["nginx","apache",void 0,"iana"];Object.keys(s).forEach(function(a){var i=s[a],r=i.extensions;if(r&&r.length){e[a]=r;for(var o=0;ou||l===u&&"application/"===t[c].substr(0,12)))continue}t[c]=a}}})}(t.extensions,t.types)},function(e,t,n){/*! * mime-db * Copyright(c) 2014 Jonathan Ong * MIT Licensed */ - -/** - * Module exports. - */ - -module.exports = __webpack_require__(152) - - -/***/ }), -/* 152 */ -/***/ (function(module, exports) { - -module.exports = {"application/1d-interleaved-parityfec":{"source":"iana"},"application/3gpdash-qoe-report+xml":{"source":"iana"},"application/3gpp-ims+xml":{"source":"iana"},"application/a2l":{"source":"iana"},"application/activemessage":{"source":"iana"},"application/alto-costmap+json":{"source":"iana","compressible":true},"application/alto-costmapfilter+json":{"source":"iana","compressible":true},"application/alto-directory+json":{"source":"iana","compressible":true},"application/alto-endpointcost+json":{"source":"iana","compressible":true},"application/alto-endpointcostparams+json":{"source":"iana","compressible":true},"application/alto-endpointprop+json":{"source":"iana","compressible":true},"application/alto-endpointpropparams+json":{"source":"iana","compressible":true},"application/alto-error+json":{"source":"iana","compressible":true},"application/alto-networkmap+json":{"source":"iana","compressible":true},"application/alto-networkmapfilter+json":{"source":"iana","compressible":true},"application/aml":{"source":"iana"},"application/andrew-inset":{"source":"iana","extensions":["ez"]},"application/applefile":{"source":"iana"},"application/applixware":{"source":"apache","extensions":["aw"]},"application/atf":{"source":"iana"},"application/atfx":{"source":"iana"},"application/atom+xml":{"source":"iana","compressible":true,"extensions":["atom"]},"application/atomcat+xml":{"source":"iana","extensions":["atomcat"]},"application/atomdeleted+xml":{"source":"iana"},"application/atomicmail":{"source":"iana"},"application/atomsvc+xml":{"source":"iana","extensions":["atomsvc"]},"application/atxml":{"source":"iana"},"application/auth-policy+xml":{"source":"iana"},"application/bacnet-xdd+zip":{"source":"iana"},"application/batch-smtp":{"source":"iana"},"application/bdoc":{"compressible":false,"extensions":["bdoc"]},"application/beep+xml":{"source":"iana"},"application/calendar+json":{"source":"iana","compressible":true},"application/calendar+xml":{"source":"iana"},"application/call-completion":{"source":"iana"},"application/cals-1840":{"source":"iana"},"application/cbor":{"source":"iana"},"application/cccex":{"source":"iana"},"application/ccmp+xml":{"source":"iana"},"application/ccxml+xml":{"source":"iana","extensions":["ccxml"]},"application/cdfx+xml":{"source":"iana"},"application/cdmi-capability":{"source":"iana","extensions":["cdmia"]},"application/cdmi-container":{"source":"iana","extensions":["cdmic"]},"application/cdmi-domain":{"source":"iana","extensions":["cdmid"]},"application/cdmi-object":{"source":"iana","extensions":["cdmio"]},"application/cdmi-queue":{"source":"iana","extensions":["cdmiq"]},"application/cdni":{"source":"iana"},"application/cea":{"source":"iana"},"application/cea-2018+xml":{"source":"iana"},"application/cellml+xml":{"source":"iana"},"application/cfw":{"source":"iana"},"application/clue_info+xml":{"source":"iana"},"application/cms":{"source":"iana"},"application/cnrp+xml":{"source":"iana"},"application/coap-group+json":{"source":"iana","compressible":true},"application/coap-payload":{"source":"iana"},"application/commonground":{"source":"iana"},"application/conference-info+xml":{"source":"iana"},"application/cose":{"source":"iana"},"application/cose-key":{"source":"iana"},"application/cose-key-set":{"source":"iana"},"application/cpl+xml":{"source":"iana"},"application/csrattrs":{"source":"iana"},"application/csta+xml":{"source":"iana"},"application/cstadata+xml":{"source":"iana"},"application/csvm+json":{"source":"iana","compressible":true},"application/cu-seeme":{"source":"apache","extensions":["cu"]},"application/cybercash":{"source":"iana"},"application/dart":{"compressible":true},"application/dash+xml":{"source":"iana","extensions":["mpd"]},"application/dashdelta":{"source":"iana"},"application/davmount+xml":{"source":"iana","extensions":["davmount"]},"application/dca-rft":{"source":"iana"},"application/dcd":{"source":"iana"},"application/dec-dx":{"source":"iana"},"application/dialog-info+xml":{"source":"iana"},"application/dicom":{"source":"iana"},"application/dicom+json":{"source":"iana","compressible":true},"application/dicom+xml":{"source":"iana"},"application/dii":{"source":"iana"},"application/dit":{"source":"iana"},"application/dns":{"source":"iana"},"application/docbook+xml":{"source":"apache","extensions":["dbk"]},"application/dskpp+xml":{"source":"iana"},"application/dssc+der":{"source":"iana","extensions":["dssc"]},"application/dssc+xml":{"source":"iana","extensions":["xdssc"]},"application/dvcs":{"source":"iana"},"application/ecmascript":{"source":"iana","compressible":true,"extensions":["ecma"]},"application/edi-consent":{"source":"iana"},"application/edi-x12":{"source":"iana","compressible":false},"application/edifact":{"source":"iana","compressible":false},"application/efi":{"source":"iana"},"application/emergencycalldata.comment+xml":{"source":"iana"},"application/emergencycalldata.control+xml":{"source":"iana"},"application/emergencycalldata.deviceinfo+xml":{"source":"iana"},"application/emergencycalldata.ecall.msd":{"source":"iana"},"application/emergencycalldata.providerinfo+xml":{"source":"iana"},"application/emergencycalldata.serviceinfo+xml":{"source":"iana"},"application/emergencycalldata.subscriberinfo+xml":{"source":"iana"},"application/emergencycalldata.veds+xml":{"source":"iana"},"application/emma+xml":{"source":"iana","extensions":["emma"]},"application/emotionml+xml":{"source":"iana"},"application/encaprtp":{"source":"iana"},"application/epp+xml":{"source":"iana"},"application/epub+zip":{"source":"iana","extensions":["epub"]},"application/eshop":{"source":"iana"},"application/exi":{"source":"iana","extensions":["exi"]},"application/fastinfoset":{"source":"iana"},"application/fastsoap":{"source":"iana"},"application/fdt+xml":{"source":"iana"},"application/fido.trusted-apps+json":{"compressible":true},"application/fits":{"source":"iana"},"application/font-sfnt":{"source":"iana"},"application/font-tdpfr":{"source":"iana","extensions":["pfr"]},"application/font-woff":{"source":"iana","compressible":false,"extensions":["woff"]},"application/font-woff2":{"compressible":false,"extensions":["woff2"]},"application/framework-attributes+xml":{"source":"iana"},"application/geo+json":{"source":"iana","compressible":true,"extensions":["geojson"]},"application/geo+json-seq":{"source":"iana"},"application/geoxacml+xml":{"source":"iana"},"application/gml+xml":{"source":"iana","extensions":["gml"]},"application/gpx+xml":{"source":"apache","extensions":["gpx"]},"application/gxf":{"source":"apache","extensions":["gxf"]},"application/gzip":{"source":"iana","compressible":false,"extensions":["gz"]},"application/h224":{"source":"iana"},"application/held+xml":{"source":"iana"},"application/http":{"source":"iana"},"application/hyperstudio":{"source":"iana","extensions":["stk"]},"application/ibe-key-request+xml":{"source":"iana"},"application/ibe-pkg-reply+xml":{"source":"iana"},"application/ibe-pp-data":{"source":"iana"},"application/iges":{"source":"iana"},"application/im-iscomposing+xml":{"source":"iana"},"application/index":{"source":"iana"},"application/index.cmd":{"source":"iana"},"application/index.obj":{"source":"iana"},"application/index.response":{"source":"iana"},"application/index.vnd":{"source":"iana"},"application/inkml+xml":{"source":"iana","extensions":["ink","inkml"]},"application/iotp":{"source":"iana"},"application/ipfix":{"source":"iana","extensions":["ipfix"]},"application/ipp":{"source":"iana"},"application/isup":{"source":"iana"},"application/its+xml":{"source":"iana"},"application/java-archive":{"source":"apache","compressible":false,"extensions":["jar","war","ear"]},"application/java-serialized-object":{"source":"apache","compressible":false,"extensions":["ser"]},"application/java-vm":{"source":"apache","compressible":false,"extensions":["class"]},"application/javascript":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["js","mjs"]},"application/jf2feed+json":{"source":"iana","compressible":true},"application/jose":{"source":"iana"},"application/jose+json":{"source":"iana","compressible":true},"application/jrd+json":{"source":"iana","compressible":true},"application/json":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["json","map"]},"application/json-patch+json":{"source":"iana","compressible":true},"application/json-seq":{"source":"iana"},"application/json5":{"extensions":["json5"]},"application/jsonml+json":{"source":"apache","compressible":true,"extensions":["jsonml"]},"application/jwk+json":{"source":"iana","compressible":true},"application/jwk-set+json":{"source":"iana","compressible":true},"application/jwt":{"source":"iana"},"application/kpml-request+xml":{"source":"iana"},"application/kpml-response+xml":{"source":"iana"},"application/ld+json":{"source":"iana","compressible":true,"extensions":["jsonld"]},"application/lgr+xml":{"source":"iana"},"application/link-format":{"source":"iana"},"application/load-control+xml":{"source":"iana"},"application/lost+xml":{"source":"iana","extensions":["lostxml"]},"application/lostsync+xml":{"source":"iana"},"application/lxf":{"source":"iana"},"application/mac-binhex40":{"source":"iana","extensions":["hqx"]},"application/mac-compactpro":{"source":"apache","extensions":["cpt"]},"application/macwriteii":{"source":"iana"},"application/mads+xml":{"source":"iana","extensions":["mads"]},"application/manifest+json":{"charset":"UTF-8","compressible":true,"extensions":["webmanifest"]},"application/marc":{"source":"iana","extensions":["mrc"]},"application/marcxml+xml":{"source":"iana","extensions":["mrcx"]},"application/mathematica":{"source":"iana","extensions":["ma","nb","mb"]},"application/mathml+xml":{"source":"iana","extensions":["mathml"]},"application/mathml-content+xml":{"source":"iana"},"application/mathml-presentation+xml":{"source":"iana"},"application/mbms-associated-procedure-description+xml":{"source":"iana"},"application/mbms-deregister+xml":{"source":"iana"},"application/mbms-envelope+xml":{"source":"iana"},"application/mbms-msk+xml":{"source":"iana"},"application/mbms-msk-response+xml":{"source":"iana"},"application/mbms-protection-description+xml":{"source":"iana"},"application/mbms-reception-report+xml":{"source":"iana"},"application/mbms-register+xml":{"source":"iana"},"application/mbms-register-response+xml":{"source":"iana"},"application/mbms-schedule+xml":{"source":"iana"},"application/mbms-user-service-description+xml":{"source":"iana"},"application/mbox":{"source":"iana","extensions":["mbox"]},"application/media-policy-dataset+xml":{"source":"iana"},"application/media_control+xml":{"source":"iana"},"application/mediaservercontrol+xml":{"source":"iana","extensions":["mscml"]},"application/merge-patch+json":{"source":"iana","compressible":true},"application/metalink+xml":{"source":"apache","extensions":["metalink"]},"application/metalink4+xml":{"source":"iana","extensions":["meta4"]},"application/mets+xml":{"source":"iana","extensions":["mets"]},"application/mf4":{"source":"iana"},"application/mikey":{"source":"iana"},"application/mmt-usd+xml":{"source":"iana"},"application/mods+xml":{"source":"iana","extensions":["mods"]},"application/moss-keys":{"source":"iana"},"application/moss-signature":{"source":"iana"},"application/mosskey-data":{"source":"iana"},"application/mosskey-request":{"source":"iana"},"application/mp21":{"source":"iana","extensions":["m21","mp21"]},"application/mp4":{"source":"iana","extensions":["mp4s","m4p"]},"application/mpeg4-generic":{"source":"iana"},"application/mpeg4-iod":{"source":"iana"},"application/mpeg4-iod-xmt":{"source":"iana"},"application/mrb-consumer+xml":{"source":"iana"},"application/mrb-publish+xml":{"source":"iana"},"application/msc-ivr+xml":{"source":"iana"},"application/msc-mixer+xml":{"source":"iana"},"application/msword":{"source":"iana","compressible":false,"extensions":["doc","dot"]},"application/mud+json":{"source":"iana","compressible":true},"application/mxf":{"source":"iana","extensions":["mxf"]},"application/n-quads":{"source":"iana"},"application/n-triples":{"source":"iana"},"application/nasdata":{"source":"iana"},"application/news-checkgroups":{"source":"iana"},"application/news-groupinfo":{"source":"iana"},"application/news-transmission":{"source":"iana"},"application/nlsml+xml":{"source":"iana"},"application/nss":{"source":"iana"},"application/ocsp-request":{"source":"iana"},"application/ocsp-response":{"source":"iana"},"application/octet-stream":{"source":"iana","compressible":false,"extensions":["bin","dms","lrf","mar","so","dist","distz","pkg","bpk","dump","elc","deploy","exe","dll","deb","dmg","iso","img","msi","msp","msm","buffer"]},"application/oda":{"source":"iana","extensions":["oda"]},"application/odx":{"source":"iana"},"application/oebps-package+xml":{"source":"iana","extensions":["opf"]},"application/ogg":{"source":"iana","compressible":false,"extensions":["ogx"]},"application/omdoc+xml":{"source":"apache","extensions":["omdoc"]},"application/onenote":{"source":"apache","extensions":["onetoc","onetoc2","onetmp","onepkg"]},"application/oxps":{"source":"iana","extensions":["oxps"]},"application/p2p-overlay+xml":{"source":"iana"},"application/parityfec":{"source":"iana"},"application/passport":{"source":"iana"},"application/patch-ops-error+xml":{"source":"iana","extensions":["xer"]},"application/pdf":{"source":"iana","compressible":false,"extensions":["pdf"]},"application/pdx":{"source":"iana"},"application/pgp-encrypted":{"source":"iana","compressible":false,"extensions":["pgp"]},"application/pgp-keys":{"source":"iana"},"application/pgp-signature":{"source":"iana","extensions":["asc","sig"]},"application/pics-rules":{"source":"apache","extensions":["prf"]},"application/pidf+xml":{"source":"iana"},"application/pidf-diff+xml":{"source":"iana"},"application/pkcs10":{"source":"iana","extensions":["p10"]},"application/pkcs12":{"source":"iana"},"application/pkcs7-mime":{"source":"iana","extensions":["p7m","p7c"]},"application/pkcs7-signature":{"source":"iana","extensions":["p7s"]},"application/pkcs8":{"source":"iana","extensions":["p8"]},"application/pkix-attr-cert":{"source":"iana","extensions":["ac"]},"application/pkix-cert":{"source":"iana","extensions":["cer"]},"application/pkix-crl":{"source":"iana","extensions":["crl"]},"application/pkix-pkipath":{"source":"iana","extensions":["pkipath"]},"application/pkixcmp":{"source":"iana","extensions":["pki"]},"application/pls+xml":{"source":"iana","extensions":["pls"]},"application/poc-settings+xml":{"source":"iana"},"application/postscript":{"source":"iana","compressible":true,"extensions":["ai","eps","ps"]},"application/ppsp-tracker+json":{"source":"iana","compressible":true},"application/problem+json":{"source":"iana","compressible":true},"application/problem+xml":{"source":"iana"},"application/provenance+xml":{"source":"iana"},"application/prs.alvestrand.titrax-sheet":{"source":"iana"},"application/prs.cww":{"source":"iana","extensions":["cww"]},"application/prs.hpub+zip":{"source":"iana"},"application/prs.nprend":{"source":"iana"},"application/prs.plucker":{"source":"iana"},"application/prs.rdf-xml-crypt":{"source":"iana"},"application/prs.xsf+xml":{"source":"iana"},"application/pskc+xml":{"source":"iana","extensions":["pskcxml"]},"application/qsig":{"source":"iana"},"application/raptorfec":{"source":"iana"},"application/rdap+json":{"source":"iana","compressible":true},"application/rdf+xml":{"source":"iana","compressible":true,"extensions":["rdf"]},"application/reginfo+xml":{"source":"iana","extensions":["rif"]},"application/relax-ng-compact-syntax":{"source":"iana","extensions":["rnc"]},"application/remote-printing":{"source":"iana"},"application/reputon+json":{"source":"iana","compressible":true},"application/resource-lists+xml":{"source":"iana","extensions":["rl"]},"application/resource-lists-diff+xml":{"source":"iana","extensions":["rld"]},"application/rfc+xml":{"source":"iana"},"application/riscos":{"source":"iana"},"application/rlmi+xml":{"source":"iana"},"application/rls-services+xml":{"source":"iana","extensions":["rs"]},"application/route-apd+xml":{"source":"iana"},"application/route-s-tsid+xml":{"source":"iana"},"application/route-usd+xml":{"source":"iana"},"application/rpki-ghostbusters":{"source":"iana","extensions":["gbr"]},"application/rpki-manifest":{"source":"iana","extensions":["mft"]},"application/rpki-publication":{"source":"iana"},"application/rpki-roa":{"source":"iana","extensions":["roa"]},"application/rpki-updown":{"source":"iana"},"application/rsd+xml":{"source":"apache","extensions":["rsd"]},"application/rss+xml":{"source":"apache","compressible":true,"extensions":["rss"]},"application/rtf":{"source":"iana","compressible":true,"extensions":["rtf"]},"application/rtploopback":{"source":"iana"},"application/rtx":{"source":"iana"},"application/samlassertion+xml":{"source":"iana"},"application/samlmetadata+xml":{"source":"iana"},"application/sbml+xml":{"source":"iana","extensions":["sbml"]},"application/scaip+xml":{"source":"iana"},"application/scim+json":{"source":"iana","compressible":true},"application/scvp-cv-request":{"source":"iana","extensions":["scq"]},"application/scvp-cv-response":{"source":"iana","extensions":["scs"]},"application/scvp-vp-request":{"source":"iana","extensions":["spq"]},"application/scvp-vp-response":{"source":"iana","extensions":["spp"]},"application/sdp":{"source":"iana","extensions":["sdp"]},"application/sep+xml":{"source":"iana"},"application/sep-exi":{"source":"iana"},"application/session-info":{"source":"iana"},"application/set-payment":{"source":"iana"},"application/set-payment-initiation":{"source":"iana","extensions":["setpay"]},"application/set-registration":{"source":"iana"},"application/set-registration-initiation":{"source":"iana","extensions":["setreg"]},"application/sgml":{"source":"iana"},"application/sgml-open-catalog":{"source":"iana"},"application/shf+xml":{"source":"iana","extensions":["shf"]},"application/sieve":{"source":"iana"},"application/simple-filter+xml":{"source":"iana"},"application/simple-message-summary":{"source":"iana"},"application/simplesymbolcontainer":{"source":"iana"},"application/slate":{"source":"iana"},"application/smil":{"source":"iana"},"application/smil+xml":{"source":"iana","extensions":["smi","smil"]},"application/smpte336m":{"source":"iana"},"application/soap+fastinfoset":{"source":"iana"},"application/soap+xml":{"source":"iana","compressible":true},"application/sparql-query":{"source":"iana","extensions":["rq"]},"application/sparql-results+xml":{"source":"iana","extensions":["srx"]},"application/spirits-event+xml":{"source":"iana"},"application/sql":{"source":"iana"},"application/srgs":{"source":"iana","extensions":["gram"]},"application/srgs+xml":{"source":"iana","extensions":["grxml"]},"application/sru+xml":{"source":"iana","extensions":["sru"]},"application/ssdl+xml":{"source":"apache","extensions":["ssdl"]},"application/ssml+xml":{"source":"iana","extensions":["ssml"]},"application/tamp-apex-update":{"source":"iana"},"application/tamp-apex-update-confirm":{"source":"iana"},"application/tamp-community-update":{"source":"iana"},"application/tamp-community-update-confirm":{"source":"iana"},"application/tamp-error":{"source":"iana"},"application/tamp-sequence-adjust":{"source":"iana"},"application/tamp-sequence-adjust-confirm":{"source":"iana"},"application/tamp-status-query":{"source":"iana"},"application/tamp-status-response":{"source":"iana"},"application/tamp-update":{"source":"iana"},"application/tamp-update-confirm":{"source":"iana"},"application/tar":{"compressible":true},"application/tei+xml":{"source":"iana","extensions":["tei","teicorpus"]},"application/thraud+xml":{"source":"iana","extensions":["tfi"]},"application/timestamp-query":{"source":"iana"},"application/timestamp-reply":{"source":"iana"},"application/timestamped-data":{"source":"iana","extensions":["tsd"]},"application/trig":{"source":"iana"},"application/ttml+xml":{"source":"iana"},"application/tve-trigger":{"source":"iana"},"application/ulpfec":{"source":"iana"},"application/urc-grpsheet+xml":{"source":"iana"},"application/urc-ressheet+xml":{"source":"iana"},"application/urc-targetdesc+xml":{"source":"iana"},"application/urc-uisocketdesc+xml":{"source":"iana"},"application/vcard+json":{"source":"iana","compressible":true},"application/vcard+xml":{"source":"iana"},"application/vemmi":{"source":"iana"},"application/vividence.scriptfile":{"source":"apache"},"application/vnd.1000minds.decision-model+xml":{"source":"iana"},"application/vnd.3gpp-prose+xml":{"source":"iana"},"application/vnd.3gpp-prose-pc3ch+xml":{"source":"iana"},"application/vnd.3gpp.access-transfer-events+xml":{"source":"iana"},"application/vnd.3gpp.bsf+xml":{"source":"iana"},"application/vnd.3gpp.gmop+xml":{"source":"iana"},"application/vnd.3gpp.mcptt-info+xml":{"source":"iana"},"application/vnd.3gpp.mcptt-mbms-usage-info+xml":{"source":"iana"},"application/vnd.3gpp.mid-call+xml":{"source":"iana"},"application/vnd.3gpp.pic-bw-large":{"source":"iana","extensions":["plb"]},"application/vnd.3gpp.pic-bw-small":{"source":"iana","extensions":["psb"]},"application/vnd.3gpp.pic-bw-var":{"source":"iana","extensions":["pvb"]},"application/vnd.3gpp.sms":{"source":"iana"},"application/vnd.3gpp.sms+xml":{"source":"iana"},"application/vnd.3gpp.srvcc-ext+xml":{"source":"iana"},"application/vnd.3gpp.srvcc-info+xml":{"source":"iana"},"application/vnd.3gpp.state-and-event-info+xml":{"source":"iana"},"application/vnd.3gpp.ussd+xml":{"source":"iana"},"application/vnd.3gpp2.bcmcsinfo+xml":{"source":"iana"},"application/vnd.3gpp2.sms":{"source":"iana"},"application/vnd.3gpp2.tcap":{"source":"iana","extensions":["tcap"]},"application/vnd.3lightssoftware.imagescal":{"source":"iana"},"application/vnd.3m.post-it-notes":{"source":"iana","extensions":["pwn"]},"application/vnd.accpac.simply.aso":{"source":"iana","extensions":["aso"]},"application/vnd.accpac.simply.imp":{"source":"iana","extensions":["imp"]},"application/vnd.acucobol":{"source":"iana","extensions":["acu"]},"application/vnd.acucorp":{"source":"iana","extensions":["atc","acutc"]},"application/vnd.adobe.air-application-installer-package+zip":{"source":"apache","extensions":["air"]},"application/vnd.adobe.flash.movie":{"source":"iana"},"application/vnd.adobe.formscentral.fcdt":{"source":"iana","extensions":["fcdt"]},"application/vnd.adobe.fxp":{"source":"iana","extensions":["fxp","fxpl"]},"application/vnd.adobe.partial-upload":{"source":"iana"},"application/vnd.adobe.xdp+xml":{"source":"iana","extensions":["xdp"]},"application/vnd.adobe.xfdf":{"source":"iana","extensions":["xfdf"]},"application/vnd.aether.imp":{"source":"iana"},"application/vnd.ah-barcode":{"source":"iana"},"application/vnd.ahead.space":{"source":"iana","extensions":["ahead"]},"application/vnd.airzip.filesecure.azf":{"source":"iana","extensions":["azf"]},"application/vnd.airzip.filesecure.azs":{"source":"iana","extensions":["azs"]},"application/vnd.amazon.ebook":{"source":"apache","extensions":["azw"]},"application/vnd.amazon.mobi8-ebook":{"source":"iana"},"application/vnd.americandynamics.acc":{"source":"iana","extensions":["acc"]},"application/vnd.amiga.ami":{"source":"iana","extensions":["ami"]},"application/vnd.amundsen.maze+xml":{"source":"iana"},"application/vnd.android.package-archive":{"source":"apache","compressible":false,"extensions":["apk"]},"application/vnd.anki":{"source":"iana"},"application/vnd.anser-web-certificate-issue-initiation":{"source":"iana","extensions":["cii"]},"application/vnd.anser-web-funds-transfer-initiation":{"source":"apache","extensions":["fti"]},"application/vnd.antix.game-component":{"source":"iana","extensions":["atx"]},"application/vnd.apache.thrift.binary":{"source":"iana"},"application/vnd.apache.thrift.compact":{"source":"iana"},"application/vnd.apache.thrift.json":{"source":"iana"},"application/vnd.api+json":{"source":"iana","compressible":true},"application/vnd.apothekende.reservation+json":{"source":"iana","compressible":true},"application/vnd.apple.installer+xml":{"source":"iana","extensions":["mpkg"]},"application/vnd.apple.mpegurl":{"source":"iana","extensions":["m3u8"]},"application/vnd.apple.pkpass":{"compressible":false,"extensions":["pkpass"]},"application/vnd.arastra.swi":{"source":"iana"},"application/vnd.aristanetworks.swi":{"source":"iana","extensions":["swi"]},"application/vnd.artsquare":{"source":"iana"},"application/vnd.astraea-software.iota":{"source":"iana","extensions":["iota"]},"application/vnd.audiograph":{"source":"iana","extensions":["aep"]},"application/vnd.autopackage":{"source":"iana"},"application/vnd.avistar+xml":{"source":"iana"},"application/vnd.balsamiq.bmml+xml":{"source":"iana"},"application/vnd.balsamiq.bmpr":{"source":"iana"},"application/vnd.bekitzur-stech+json":{"source":"iana","compressible":true},"application/vnd.bint.med-content":{"source":"iana"},"application/vnd.biopax.rdf+xml":{"source":"iana"},"application/vnd.blink-idb-value-wrapper":{"source":"iana"},"application/vnd.blueice.multipass":{"source":"iana","extensions":["mpm"]},"application/vnd.bluetooth.ep.oob":{"source":"iana"},"application/vnd.bluetooth.le.oob":{"source":"iana"},"application/vnd.bmi":{"source":"iana","extensions":["bmi"]},"application/vnd.businessobjects":{"source":"iana","extensions":["rep"]},"application/vnd.cab-jscript":{"source":"iana"},"application/vnd.canon-cpdl":{"source":"iana"},"application/vnd.canon-lips":{"source":"iana"},"application/vnd.capasystems-pg+json":{"source":"iana","compressible":true},"application/vnd.cendio.thinlinc.clientconf":{"source":"iana"},"application/vnd.century-systems.tcp_stream":{"source":"iana"},"application/vnd.chemdraw+xml":{"source":"iana","extensions":["cdxml"]},"application/vnd.chess-pgn":{"source":"iana"},"application/vnd.chipnuts.karaoke-mmd":{"source":"iana","extensions":["mmd"]},"application/vnd.cinderella":{"source":"iana","extensions":["cdy"]},"application/vnd.cirpack.isdn-ext":{"source":"iana"},"application/vnd.citationstyles.style+xml":{"source":"iana"},"application/vnd.claymore":{"source":"iana","extensions":["cla"]},"application/vnd.cloanto.rp9":{"source":"iana","extensions":["rp9"]},"application/vnd.clonk.c4group":{"source":"iana","extensions":["c4g","c4d","c4f","c4p","c4u"]},"application/vnd.cluetrust.cartomobile-config":{"source":"iana","extensions":["c11amc"]},"application/vnd.cluetrust.cartomobile-config-pkg":{"source":"iana","extensions":["c11amz"]},"application/vnd.coffeescript":{"source":"iana"},"application/vnd.collection+json":{"source":"iana","compressible":true},"application/vnd.collection.doc+json":{"source":"iana","compressible":true},"application/vnd.collection.next+json":{"source":"iana","compressible":true},"application/vnd.comicbook+zip":{"source":"iana"},"application/vnd.commerce-battelle":{"source":"iana"},"application/vnd.commonspace":{"source":"iana","extensions":["csp"]},"application/vnd.contact.cmsg":{"source":"iana","extensions":["cdbcmsg"]},"application/vnd.coreos.ignition+json":{"source":"iana","compressible":true},"application/vnd.cosmocaller":{"source":"iana","extensions":["cmc"]},"application/vnd.crick.clicker":{"source":"iana","extensions":["clkx"]},"application/vnd.crick.clicker.keyboard":{"source":"iana","extensions":["clkk"]},"application/vnd.crick.clicker.palette":{"source":"iana","extensions":["clkp"]},"application/vnd.crick.clicker.template":{"source":"iana","extensions":["clkt"]},"application/vnd.crick.clicker.wordbank":{"source":"iana","extensions":["clkw"]},"application/vnd.criticaltools.wbs+xml":{"source":"iana","extensions":["wbs"]},"application/vnd.ctc-posml":{"source":"iana","extensions":["pml"]},"application/vnd.ctct.ws+xml":{"source":"iana"},"application/vnd.cups-pdf":{"source":"iana"},"application/vnd.cups-postscript":{"source":"iana"},"application/vnd.cups-ppd":{"source":"iana","extensions":["ppd"]},"application/vnd.cups-raster":{"source":"iana"},"application/vnd.cups-raw":{"source":"iana"},"application/vnd.curl":{"source":"iana"},"application/vnd.curl.car":{"source":"apache","extensions":["car"]},"application/vnd.curl.pcurl":{"source":"apache","extensions":["pcurl"]},"application/vnd.cyan.dean.root+xml":{"source":"iana"},"application/vnd.cybank":{"source":"iana"},"application/vnd.d2l.coursepackage1p0+zip":{"source":"iana"},"application/vnd.dart":{"source":"iana","compressible":true,"extensions":["dart"]},"application/vnd.data-vision.rdz":{"source":"iana","extensions":["rdz"]},"application/vnd.datapackage+json":{"source":"iana","compressible":true},"application/vnd.dataresource+json":{"source":"iana","compressible":true},"application/vnd.debian.binary-package":{"source":"iana"},"application/vnd.dece.data":{"source":"iana","extensions":["uvf","uvvf","uvd","uvvd"]},"application/vnd.dece.ttml+xml":{"source":"iana","extensions":["uvt","uvvt"]},"application/vnd.dece.unspecified":{"source":"iana","extensions":["uvx","uvvx"]},"application/vnd.dece.zip":{"source":"iana","extensions":["uvz","uvvz"]},"application/vnd.denovo.fcselayout-link":{"source":"iana","extensions":["fe_launch"]},"application/vnd.desmume-movie":{"source":"iana"},"application/vnd.desmume.movie":{"source":"apache"},"application/vnd.dir-bi.plate-dl-nosuffix":{"source":"iana"},"application/vnd.dm.delegation+xml":{"source":"iana"},"application/vnd.dna":{"source":"iana","extensions":["dna"]},"application/vnd.document+json":{"source":"iana","compressible":true},"application/vnd.dolby.mlp":{"source":"apache","extensions":["mlp"]},"application/vnd.dolby.mobile.1":{"source":"iana"},"application/vnd.dolby.mobile.2":{"source":"iana"},"application/vnd.doremir.scorecloud-binary-document":{"source":"iana"},"application/vnd.dpgraph":{"source":"iana","extensions":["dpg"]},"application/vnd.dreamfactory":{"source":"iana","extensions":["dfac"]},"application/vnd.drive+json":{"source":"iana","compressible":true},"application/vnd.ds-keypoint":{"source":"apache","extensions":["kpxx"]},"application/vnd.dtg.local":{"source":"iana"},"application/vnd.dtg.local.flash":{"source":"iana"},"application/vnd.dtg.local.html":{"source":"iana"},"application/vnd.dvb.ait":{"source":"iana","extensions":["ait"]},"application/vnd.dvb.dvbj":{"source":"iana"},"application/vnd.dvb.esgcontainer":{"source":"iana"},"application/vnd.dvb.ipdcdftnotifaccess":{"source":"iana"},"application/vnd.dvb.ipdcesgaccess":{"source":"iana"},"application/vnd.dvb.ipdcesgaccess2":{"source":"iana"},"application/vnd.dvb.ipdcesgpdd":{"source":"iana"},"application/vnd.dvb.ipdcroaming":{"source":"iana"},"application/vnd.dvb.iptv.alfec-base":{"source":"iana"},"application/vnd.dvb.iptv.alfec-enhancement":{"source":"iana"},"application/vnd.dvb.notif-aggregate-root+xml":{"source":"iana"},"application/vnd.dvb.notif-container+xml":{"source":"iana"},"application/vnd.dvb.notif-generic+xml":{"source":"iana"},"application/vnd.dvb.notif-ia-msglist+xml":{"source":"iana"},"application/vnd.dvb.notif-ia-registration-request+xml":{"source":"iana"},"application/vnd.dvb.notif-ia-registration-response+xml":{"source":"iana"},"application/vnd.dvb.notif-init+xml":{"source":"iana"},"application/vnd.dvb.pfr":{"source":"iana"},"application/vnd.dvb.service":{"source":"iana","extensions":["svc"]},"application/vnd.dxr":{"source":"iana"},"application/vnd.dynageo":{"source":"iana","extensions":["geo"]},"application/vnd.dzr":{"source":"iana"},"application/vnd.easykaraoke.cdgdownload":{"source":"iana"},"application/vnd.ecdis-update":{"source":"iana"},"application/vnd.ecowin.chart":{"source":"iana","extensions":["mag"]},"application/vnd.ecowin.filerequest":{"source":"iana"},"application/vnd.ecowin.fileupdate":{"source":"iana"},"application/vnd.ecowin.series":{"source":"iana"},"application/vnd.ecowin.seriesrequest":{"source":"iana"},"application/vnd.ecowin.seriesupdate":{"source":"iana"},"application/vnd.efi.img":{"source":"iana"},"application/vnd.efi.iso":{"source":"iana"},"application/vnd.emclient.accessrequest+xml":{"source":"iana"},"application/vnd.enliven":{"source":"iana","extensions":["nml"]},"application/vnd.enphase.envoy":{"source":"iana"},"application/vnd.eprints.data+xml":{"source":"iana"},"application/vnd.epson.esf":{"source":"iana","extensions":["esf"]},"application/vnd.epson.msf":{"source":"iana","extensions":["msf"]},"application/vnd.epson.quickanime":{"source":"iana","extensions":["qam"]},"application/vnd.epson.salt":{"source":"iana","extensions":["slt"]},"application/vnd.epson.ssf":{"source":"iana","extensions":["ssf"]},"application/vnd.ericsson.quickcall":{"source":"iana"},"application/vnd.espass-espass+zip":{"source":"iana"},"application/vnd.eszigno3+xml":{"source":"iana","extensions":["es3","et3"]},"application/vnd.etsi.aoc+xml":{"source":"iana"},"application/vnd.etsi.asic-e+zip":{"source":"iana"},"application/vnd.etsi.asic-s+zip":{"source":"iana"},"application/vnd.etsi.cug+xml":{"source":"iana"},"application/vnd.etsi.iptvcommand+xml":{"source":"iana"},"application/vnd.etsi.iptvdiscovery+xml":{"source":"iana"},"application/vnd.etsi.iptvprofile+xml":{"source":"iana"},"application/vnd.etsi.iptvsad-bc+xml":{"source":"iana"},"application/vnd.etsi.iptvsad-cod+xml":{"source":"iana"},"application/vnd.etsi.iptvsad-npvr+xml":{"source":"iana"},"application/vnd.etsi.iptvservice+xml":{"source":"iana"},"application/vnd.etsi.iptvsync+xml":{"source":"iana"},"application/vnd.etsi.iptvueprofile+xml":{"source":"iana"},"application/vnd.etsi.mcid+xml":{"source":"iana"},"application/vnd.etsi.mheg5":{"source":"iana"},"application/vnd.etsi.overload-control-policy-dataset+xml":{"source":"iana"},"application/vnd.etsi.pstn+xml":{"source":"iana"},"application/vnd.etsi.sci+xml":{"source":"iana"},"application/vnd.etsi.simservs+xml":{"source":"iana"},"application/vnd.etsi.timestamp-token":{"source":"iana"},"application/vnd.etsi.tsl+xml":{"source":"iana"},"application/vnd.etsi.tsl.der":{"source":"iana"},"application/vnd.eudora.data":{"source":"iana"},"application/vnd.evolv.ecig.profile":{"source":"iana"},"application/vnd.evolv.ecig.settings":{"source":"iana"},"application/vnd.evolv.ecig.theme":{"source":"iana"},"application/vnd.ezpix-album":{"source":"iana","extensions":["ez2"]},"application/vnd.ezpix-package":{"source":"iana","extensions":["ez3"]},"application/vnd.f-secure.mobile":{"source":"iana"},"application/vnd.fastcopy-disk-image":{"source":"iana"},"application/vnd.fdf":{"source":"iana","extensions":["fdf"]},"application/vnd.fdsn.mseed":{"source":"iana","extensions":["mseed"]},"application/vnd.fdsn.seed":{"source":"iana","extensions":["seed","dataless"]},"application/vnd.ffsns":{"source":"iana"},"application/vnd.filmit.zfc":{"source":"iana"},"application/vnd.fints":{"source":"iana"},"application/vnd.firemonkeys.cloudcell":{"source":"iana"},"application/vnd.flographit":{"source":"iana","extensions":["gph"]},"application/vnd.fluxtime.clip":{"source":"iana","extensions":["ftc"]},"application/vnd.font-fontforge-sfd":{"source":"iana"},"application/vnd.framemaker":{"source":"iana","extensions":["fm","frame","maker","book"]},"application/vnd.frogans.fnc":{"source":"iana","extensions":["fnc"]},"application/vnd.frogans.ltf":{"source":"iana","extensions":["ltf"]},"application/vnd.fsc.weblaunch":{"source":"iana","extensions":["fsc"]},"application/vnd.fujitsu.oasys":{"source":"iana","extensions":["oas"]},"application/vnd.fujitsu.oasys2":{"source":"iana","extensions":["oa2"]},"application/vnd.fujitsu.oasys3":{"source":"iana","extensions":["oa3"]},"application/vnd.fujitsu.oasysgp":{"source":"iana","extensions":["fg5"]},"application/vnd.fujitsu.oasysprs":{"source":"iana","extensions":["bh2"]},"application/vnd.fujixerox.art-ex":{"source":"iana"},"application/vnd.fujixerox.art4":{"source":"iana"},"application/vnd.fujixerox.ddd":{"source":"iana","extensions":["ddd"]},"application/vnd.fujixerox.docuworks":{"source":"iana","extensions":["xdw"]},"application/vnd.fujixerox.docuworks.binder":{"source":"iana","extensions":["xbd"]},"application/vnd.fujixerox.docuworks.container":{"source":"iana"},"application/vnd.fujixerox.hbpl":{"source":"iana"},"application/vnd.fut-misnet":{"source":"iana"},"application/vnd.fuzzysheet":{"source":"iana","extensions":["fzs"]},"application/vnd.genomatix.tuxedo":{"source":"iana","extensions":["txd"]},"application/vnd.geo+json":{"source":"iana","compressible":true},"application/vnd.geocube+xml":{"source":"iana"},"application/vnd.geogebra.file":{"source":"iana","extensions":["ggb"]},"application/vnd.geogebra.tool":{"source":"iana","extensions":["ggt"]},"application/vnd.geometry-explorer":{"source":"iana","extensions":["gex","gre"]},"application/vnd.geonext":{"source":"iana","extensions":["gxt"]},"application/vnd.geoplan":{"source":"iana","extensions":["g2w"]},"application/vnd.geospace":{"source":"iana","extensions":["g3w"]},"application/vnd.gerber":{"source":"iana"},"application/vnd.globalplatform.card-content-mgt":{"source":"iana"},"application/vnd.globalplatform.card-content-mgt-response":{"source":"iana"},"application/vnd.gmx":{"source":"iana","extensions":["gmx"]},"application/vnd.google-apps.document":{"compressible":false,"extensions":["gdoc"]},"application/vnd.google-apps.presentation":{"compressible":false,"extensions":["gslides"]},"application/vnd.google-apps.spreadsheet":{"compressible":false,"extensions":["gsheet"]},"application/vnd.google-earth.kml+xml":{"source":"iana","compressible":true,"extensions":["kml"]},"application/vnd.google-earth.kmz":{"source":"iana","compressible":false,"extensions":["kmz"]},"application/vnd.gov.sk.e-form+xml":{"source":"iana"},"application/vnd.gov.sk.e-form+zip":{"source":"iana"},"application/vnd.gov.sk.xmldatacontainer+xml":{"source":"iana"},"application/vnd.grafeq":{"source":"iana","extensions":["gqf","gqs"]},"application/vnd.gridmp":{"source":"iana"},"application/vnd.groove-account":{"source":"iana","extensions":["gac"]},"application/vnd.groove-help":{"source":"iana","extensions":["ghf"]},"application/vnd.groove-identity-message":{"source":"iana","extensions":["gim"]},"application/vnd.groove-injector":{"source":"iana","extensions":["grv"]},"application/vnd.groove-tool-message":{"source":"iana","extensions":["gtm"]},"application/vnd.groove-tool-template":{"source":"iana","extensions":["tpl"]},"application/vnd.groove-vcard":{"source":"iana","extensions":["vcg"]},"application/vnd.hal+json":{"source":"iana","compressible":true},"application/vnd.hal+xml":{"source":"iana","extensions":["hal"]},"application/vnd.handheld-entertainment+xml":{"source":"iana","extensions":["zmm"]},"application/vnd.hbci":{"source":"iana","extensions":["hbci"]},"application/vnd.hc+json":{"source":"iana","compressible":true},"application/vnd.hcl-bireports":{"source":"iana"},"application/vnd.hdt":{"source":"iana"},"application/vnd.heroku+json":{"source":"iana","compressible":true},"application/vnd.hhe.lesson-player":{"source":"iana","extensions":["les"]},"application/vnd.hp-hpgl":{"source":"iana","extensions":["hpgl"]},"application/vnd.hp-hpid":{"source":"iana","extensions":["hpid"]},"application/vnd.hp-hps":{"source":"iana","extensions":["hps"]},"application/vnd.hp-jlyt":{"source":"iana","extensions":["jlt"]},"application/vnd.hp-pcl":{"source":"iana","extensions":["pcl"]},"application/vnd.hp-pclxl":{"source":"iana","extensions":["pclxl"]},"application/vnd.httphone":{"source":"iana"},"application/vnd.hydrostatix.sof-data":{"source":"iana","extensions":["sfd-hdstx"]},"application/vnd.hyper-item+json":{"source":"iana","compressible":true},"application/vnd.hyperdrive+json":{"source":"iana","compressible":true},"application/vnd.hzn-3d-crossword":{"source":"iana"},"application/vnd.ibm.afplinedata":{"source":"iana"},"application/vnd.ibm.electronic-media":{"source":"iana"},"application/vnd.ibm.minipay":{"source":"iana","extensions":["mpy"]},"application/vnd.ibm.modcap":{"source":"iana","extensions":["afp","listafp","list3820"]},"application/vnd.ibm.rights-management":{"source":"iana","extensions":["irm"]},"application/vnd.ibm.secure-container":{"source":"iana","extensions":["sc"]},"application/vnd.iccprofile":{"source":"iana","extensions":["icc","icm"]},"application/vnd.ieee.1905":{"source":"iana"},"application/vnd.igloader":{"source":"iana","extensions":["igl"]},"application/vnd.imagemeter.folder+zip":{"source":"iana"},"application/vnd.imagemeter.image+zip":{"source":"iana"},"application/vnd.immervision-ivp":{"source":"iana","extensions":["ivp"]},"application/vnd.immervision-ivu":{"source":"iana","extensions":["ivu"]},"application/vnd.ims.imsccv1p1":{"source":"iana"},"application/vnd.ims.imsccv1p2":{"source":"iana"},"application/vnd.ims.imsccv1p3":{"source":"iana"},"application/vnd.ims.lis.v2.result+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolconsumerprofile+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolproxy+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolproxy.id+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolsettings+json":{"source":"iana","compressible":true},"application/vnd.ims.lti.v2.toolsettings.simple+json":{"source":"iana","compressible":true},"application/vnd.informedcontrol.rms+xml":{"source":"iana"},"application/vnd.informix-visionary":{"source":"iana"},"application/vnd.infotech.project":{"source":"iana"},"application/vnd.infotech.project+xml":{"source":"iana"},"application/vnd.innopath.wamp.notification":{"source":"iana"},"application/vnd.insors.igm":{"source":"iana","extensions":["igm"]},"application/vnd.intercon.formnet":{"source":"iana","extensions":["xpw","xpx"]},"application/vnd.intergeo":{"source":"iana","extensions":["i2g"]},"application/vnd.intertrust.digibox":{"source":"iana"},"application/vnd.intertrust.nncp":{"source":"iana"},"application/vnd.intu.qbo":{"source":"iana","extensions":["qbo"]},"application/vnd.intu.qfx":{"source":"iana","extensions":["qfx"]},"application/vnd.iptc.g2.catalogitem+xml":{"source":"iana"},"application/vnd.iptc.g2.conceptitem+xml":{"source":"iana"},"application/vnd.iptc.g2.knowledgeitem+xml":{"source":"iana"},"application/vnd.iptc.g2.newsitem+xml":{"source":"iana"},"application/vnd.iptc.g2.newsmessage+xml":{"source":"iana"},"application/vnd.iptc.g2.packageitem+xml":{"source":"iana"},"application/vnd.iptc.g2.planningitem+xml":{"source":"iana"},"application/vnd.ipunplugged.rcprofile":{"source":"iana","extensions":["rcprofile"]},"application/vnd.irepository.package+xml":{"source":"iana","extensions":["irp"]},"application/vnd.is-xpr":{"source":"iana","extensions":["xpr"]},"application/vnd.isac.fcs":{"source":"iana","extensions":["fcs"]},"application/vnd.jam":{"source":"iana","extensions":["jam"]},"application/vnd.japannet-directory-service":{"source":"iana"},"application/vnd.japannet-jpnstore-wakeup":{"source":"iana"},"application/vnd.japannet-payment-wakeup":{"source":"iana"},"application/vnd.japannet-registration":{"source":"iana"},"application/vnd.japannet-registration-wakeup":{"source":"iana"},"application/vnd.japannet-setstore-wakeup":{"source":"iana"},"application/vnd.japannet-verification":{"source":"iana"},"application/vnd.japannet-verification-wakeup":{"source":"iana"},"application/vnd.jcp.javame.midlet-rms":{"source":"iana","extensions":["rms"]},"application/vnd.jisp":{"source":"iana","extensions":["jisp"]},"application/vnd.joost.joda-archive":{"source":"iana","extensions":["joda"]},"application/vnd.jsk.isdn-ngn":{"source":"iana"},"application/vnd.kahootz":{"source":"iana","extensions":["ktz","ktr"]},"application/vnd.kde.karbon":{"source":"iana","extensions":["karbon"]},"application/vnd.kde.kchart":{"source":"iana","extensions":["chrt"]},"application/vnd.kde.kformula":{"source":"iana","extensions":["kfo"]},"application/vnd.kde.kivio":{"source":"iana","extensions":["flw"]},"application/vnd.kde.kontour":{"source":"iana","extensions":["kon"]},"application/vnd.kde.kpresenter":{"source":"iana","extensions":["kpr","kpt"]},"application/vnd.kde.kspread":{"source":"iana","extensions":["ksp"]},"application/vnd.kde.kword":{"source":"iana","extensions":["kwd","kwt"]},"application/vnd.kenameaapp":{"source":"iana","extensions":["htke"]},"application/vnd.kidspiration":{"source":"iana","extensions":["kia"]},"application/vnd.kinar":{"source":"iana","extensions":["kne","knp"]},"application/vnd.koan":{"source":"iana","extensions":["skp","skd","skt","skm"]},"application/vnd.kodak-descriptor":{"source":"iana","extensions":["sse"]},"application/vnd.las.las+json":{"source":"iana","compressible":true},"application/vnd.las.las+xml":{"source":"iana","extensions":["lasxml"]},"application/vnd.liberty-request+xml":{"source":"iana"},"application/vnd.llamagraphics.life-balance.desktop":{"source":"iana","extensions":["lbd"]},"application/vnd.llamagraphics.life-balance.exchange+xml":{"source":"iana","extensions":["lbe"]},"application/vnd.lotus-1-2-3":{"source":"iana","extensions":["123"]},"application/vnd.lotus-approach":{"source":"iana","extensions":["apr"]},"application/vnd.lotus-freelance":{"source":"iana","extensions":["pre"]},"application/vnd.lotus-notes":{"source":"iana","extensions":["nsf"]},"application/vnd.lotus-organizer":{"source":"iana","extensions":["org"]},"application/vnd.lotus-screencam":{"source":"iana","extensions":["scm"]},"application/vnd.lotus-wordpro":{"source":"iana","extensions":["lwp"]},"application/vnd.macports.portpkg":{"source":"iana","extensions":["portpkg"]},"application/vnd.mapbox-vector-tile":{"source":"iana"},"application/vnd.marlin.drm.actiontoken+xml":{"source":"iana"},"application/vnd.marlin.drm.conftoken+xml":{"source":"iana"},"application/vnd.marlin.drm.license+xml":{"source":"iana"},"application/vnd.marlin.drm.mdcf":{"source":"iana"},"application/vnd.mason+json":{"source":"iana","compressible":true},"application/vnd.maxmind.maxmind-db":{"source":"iana"},"application/vnd.mcd":{"source":"iana","extensions":["mcd"]},"application/vnd.medcalcdata":{"source":"iana","extensions":["mc1"]},"application/vnd.mediastation.cdkey":{"source":"iana","extensions":["cdkey"]},"application/vnd.meridian-slingshot":{"source":"iana"},"application/vnd.mfer":{"source":"iana","extensions":["mwf"]},"application/vnd.mfmp":{"source":"iana","extensions":["mfm"]},"application/vnd.micro+json":{"source":"iana","compressible":true},"application/vnd.micrografx.flo":{"source":"iana","extensions":["flo"]},"application/vnd.micrografx.igx":{"source":"iana","extensions":["igx"]},"application/vnd.microsoft.portable-executable":{"source":"iana"},"application/vnd.microsoft.windows.thumbnail-cache":{"source":"iana"},"application/vnd.miele+json":{"source":"iana","compressible":true},"application/vnd.mif":{"source":"iana","extensions":["mif"]},"application/vnd.minisoft-hp3000-save":{"source":"iana"},"application/vnd.mitsubishi.misty-guard.trustweb":{"source":"iana"},"application/vnd.mobius.daf":{"source":"iana","extensions":["daf"]},"application/vnd.mobius.dis":{"source":"iana","extensions":["dis"]},"application/vnd.mobius.mbk":{"source":"iana","extensions":["mbk"]},"application/vnd.mobius.mqy":{"source":"iana","extensions":["mqy"]},"application/vnd.mobius.msl":{"source":"iana","extensions":["msl"]},"application/vnd.mobius.plc":{"source":"iana","extensions":["plc"]},"application/vnd.mobius.txf":{"source":"iana","extensions":["txf"]},"application/vnd.mophun.application":{"source":"iana","extensions":["mpn"]},"application/vnd.mophun.certificate":{"source":"iana","extensions":["mpc"]},"application/vnd.motorola.flexsuite":{"source":"iana"},"application/vnd.motorola.flexsuite.adsi":{"source":"iana"},"application/vnd.motorola.flexsuite.fis":{"source":"iana"},"application/vnd.motorola.flexsuite.gotap":{"source":"iana"},"application/vnd.motorola.flexsuite.kmr":{"source":"iana"},"application/vnd.motorola.flexsuite.ttc":{"source":"iana"},"application/vnd.motorola.flexsuite.wem":{"source":"iana"},"application/vnd.motorola.iprm":{"source":"iana"},"application/vnd.mozilla.xul+xml":{"source":"iana","compressible":true,"extensions":["xul"]},"application/vnd.ms-3mfdocument":{"source":"iana"},"application/vnd.ms-artgalry":{"source":"iana","extensions":["cil"]},"application/vnd.ms-asf":{"source":"iana"},"application/vnd.ms-cab-compressed":{"source":"iana","extensions":["cab"]},"application/vnd.ms-color.iccprofile":{"source":"apache"},"application/vnd.ms-excel":{"source":"iana","compressible":false,"extensions":["xls","xlm","xla","xlc","xlt","xlw"]},"application/vnd.ms-excel.addin.macroenabled.12":{"source":"iana","extensions":["xlam"]},"application/vnd.ms-excel.sheet.binary.macroenabled.12":{"source":"iana","extensions":["xlsb"]},"application/vnd.ms-excel.sheet.macroenabled.12":{"source":"iana","extensions":["xlsm"]},"application/vnd.ms-excel.template.macroenabled.12":{"source":"iana","extensions":["xltm"]},"application/vnd.ms-fontobject":{"source":"iana","compressible":true,"extensions":["eot"]},"application/vnd.ms-htmlhelp":{"source":"iana","extensions":["chm"]},"application/vnd.ms-ims":{"source":"iana","extensions":["ims"]},"application/vnd.ms-lrm":{"source":"iana","extensions":["lrm"]},"application/vnd.ms-office.activex+xml":{"source":"iana"},"application/vnd.ms-officetheme":{"source":"iana","extensions":["thmx"]},"application/vnd.ms-opentype":{"source":"apache","compressible":true},"application/vnd.ms-outlook":{"compressible":false,"extensions":["msg"]},"application/vnd.ms-package.obfuscated-opentype":{"source":"apache"},"application/vnd.ms-pki.seccat":{"source":"apache","extensions":["cat"]},"application/vnd.ms-pki.stl":{"source":"apache","extensions":["stl"]},"application/vnd.ms-playready.initiator+xml":{"source":"iana"},"application/vnd.ms-powerpoint":{"source":"iana","compressible":false,"extensions":["ppt","pps","pot"]},"application/vnd.ms-powerpoint.addin.macroenabled.12":{"source":"iana","extensions":["ppam"]},"application/vnd.ms-powerpoint.presentation.macroenabled.12":{"source":"iana","extensions":["pptm"]},"application/vnd.ms-powerpoint.slide.macroenabled.12":{"source":"iana","extensions":["sldm"]},"application/vnd.ms-powerpoint.slideshow.macroenabled.12":{"source":"iana","extensions":["ppsm"]},"application/vnd.ms-powerpoint.template.macroenabled.12":{"source":"iana","extensions":["potm"]},"application/vnd.ms-printdevicecapabilities+xml":{"source":"iana"},"application/vnd.ms-printing.printticket+xml":{"source":"apache"},"application/vnd.ms-printschematicket+xml":{"source":"iana"},"application/vnd.ms-project":{"source":"iana","extensions":["mpp","mpt"]},"application/vnd.ms-tnef":{"source":"iana"},"application/vnd.ms-windows.devicepairing":{"source":"iana"},"application/vnd.ms-windows.nwprinting.oob":{"source":"iana"},"application/vnd.ms-windows.printerpairing":{"source":"iana"},"application/vnd.ms-windows.wsd.oob":{"source":"iana"},"application/vnd.ms-wmdrm.lic-chlg-req":{"source":"iana"},"application/vnd.ms-wmdrm.lic-resp":{"source":"iana"},"application/vnd.ms-wmdrm.meter-chlg-req":{"source":"iana"},"application/vnd.ms-wmdrm.meter-resp":{"source":"iana"},"application/vnd.ms-word.document.macroenabled.12":{"source":"iana","extensions":["docm"]},"application/vnd.ms-word.template.macroenabled.12":{"source":"iana","extensions":["dotm"]},"application/vnd.ms-works":{"source":"iana","extensions":["wps","wks","wcm","wdb"]},"application/vnd.ms-wpl":{"source":"iana","extensions":["wpl"]},"application/vnd.ms-xpsdocument":{"source":"iana","compressible":false,"extensions":["xps"]},"application/vnd.msa-disk-image":{"source":"iana"},"application/vnd.mseq":{"source":"iana","extensions":["mseq"]},"application/vnd.msign":{"source":"iana"},"application/vnd.multiad.creator":{"source":"iana"},"application/vnd.multiad.creator.cif":{"source":"iana"},"application/vnd.music-niff":{"source":"iana"},"application/vnd.musician":{"source":"iana","extensions":["mus"]},"application/vnd.muvee.style":{"source":"iana","extensions":["msty"]},"application/vnd.mynfc":{"source":"iana","extensions":["taglet"]},"application/vnd.ncd.control":{"source":"iana"},"application/vnd.ncd.reference":{"source":"iana"},"application/vnd.nearst.inv+json":{"source":"iana","compressible":true},"application/vnd.nervana":{"source":"iana"},"application/vnd.netfpx":{"source":"iana"},"application/vnd.neurolanguage.nlu":{"source":"iana","extensions":["nlu"]},"application/vnd.nintendo.nitro.rom":{"source":"iana"},"application/vnd.nintendo.snes.rom":{"source":"iana"},"application/vnd.nitf":{"source":"iana","extensions":["ntf","nitf"]},"application/vnd.noblenet-directory":{"source":"iana","extensions":["nnd"]},"application/vnd.noblenet-sealer":{"source":"iana","extensions":["nns"]},"application/vnd.noblenet-web":{"source":"iana","extensions":["nnw"]},"application/vnd.nokia.catalogs":{"source":"iana"},"application/vnd.nokia.conml+wbxml":{"source":"iana"},"application/vnd.nokia.conml+xml":{"source":"iana"},"application/vnd.nokia.iptv.config+xml":{"source":"iana"},"application/vnd.nokia.isds-radio-presets":{"source":"iana"},"application/vnd.nokia.landmark+wbxml":{"source":"iana"},"application/vnd.nokia.landmark+xml":{"source":"iana"},"application/vnd.nokia.landmarkcollection+xml":{"source":"iana"},"application/vnd.nokia.n-gage.ac+xml":{"source":"iana"},"application/vnd.nokia.n-gage.data":{"source":"iana","extensions":["ngdat"]},"application/vnd.nokia.n-gage.symbian.install":{"source":"iana","extensions":["n-gage"]},"application/vnd.nokia.ncd":{"source":"iana"},"application/vnd.nokia.pcd+wbxml":{"source":"iana"},"application/vnd.nokia.pcd+xml":{"source":"iana"},"application/vnd.nokia.radio-preset":{"source":"iana","extensions":["rpst"]},"application/vnd.nokia.radio-presets":{"source":"iana","extensions":["rpss"]},"application/vnd.novadigm.edm":{"source":"iana","extensions":["edm"]},"application/vnd.novadigm.edx":{"source":"iana","extensions":["edx"]},"application/vnd.novadigm.ext":{"source":"iana","extensions":["ext"]},"application/vnd.ntt-local.content-share":{"source":"iana"},"application/vnd.ntt-local.file-transfer":{"source":"iana"},"application/vnd.ntt-local.ogw_remote-access":{"source":"iana"},"application/vnd.ntt-local.sip-ta_remote":{"source":"iana"},"application/vnd.ntt-local.sip-ta_tcp_stream":{"source":"iana"},"application/vnd.oasis.opendocument.chart":{"source":"iana","extensions":["odc"]},"application/vnd.oasis.opendocument.chart-template":{"source":"iana","extensions":["otc"]},"application/vnd.oasis.opendocument.database":{"source":"iana","extensions":["odb"]},"application/vnd.oasis.opendocument.formula":{"source":"iana","extensions":["odf"]},"application/vnd.oasis.opendocument.formula-template":{"source":"iana","extensions":["odft"]},"application/vnd.oasis.opendocument.graphics":{"source":"iana","compressible":false,"extensions":["odg"]},"application/vnd.oasis.opendocument.graphics-template":{"source":"iana","extensions":["otg"]},"application/vnd.oasis.opendocument.image":{"source":"iana","extensions":["odi"]},"application/vnd.oasis.opendocument.image-template":{"source":"iana","extensions":["oti"]},"application/vnd.oasis.opendocument.presentation":{"source":"iana","compressible":false,"extensions":["odp"]},"application/vnd.oasis.opendocument.presentation-template":{"source":"iana","extensions":["otp"]},"application/vnd.oasis.opendocument.spreadsheet":{"source":"iana","compressible":false,"extensions":["ods"]},"application/vnd.oasis.opendocument.spreadsheet-template":{"source":"iana","extensions":["ots"]},"application/vnd.oasis.opendocument.text":{"source":"iana","compressible":false,"extensions":["odt"]},"application/vnd.oasis.opendocument.text-master":{"source":"iana","extensions":["odm"]},"application/vnd.oasis.opendocument.text-template":{"source":"iana","extensions":["ott"]},"application/vnd.oasis.opendocument.text-web":{"source":"iana","extensions":["oth"]},"application/vnd.obn":{"source":"iana"},"application/vnd.ocf+cbor":{"source":"iana"},"application/vnd.oftn.l10n+json":{"source":"iana","compressible":true},"application/vnd.oipf.contentaccessdownload+xml":{"source":"iana"},"application/vnd.oipf.contentaccessstreaming+xml":{"source":"iana"},"application/vnd.oipf.cspg-hexbinary":{"source":"iana"},"application/vnd.oipf.dae.svg+xml":{"source":"iana"},"application/vnd.oipf.dae.xhtml+xml":{"source":"iana"},"application/vnd.oipf.mippvcontrolmessage+xml":{"source":"iana"},"application/vnd.oipf.pae.gem":{"source":"iana"},"application/vnd.oipf.spdiscovery+xml":{"source":"iana"},"application/vnd.oipf.spdlist+xml":{"source":"iana"},"application/vnd.oipf.ueprofile+xml":{"source":"iana"},"application/vnd.oipf.userprofile+xml":{"source":"iana"},"application/vnd.olpc-sugar":{"source":"iana","extensions":["xo"]},"application/vnd.oma-scws-config":{"source":"iana"},"application/vnd.oma-scws-http-request":{"source":"iana"},"application/vnd.oma-scws-http-response":{"source":"iana"},"application/vnd.oma.bcast.associated-procedure-parameter+xml":{"source":"iana"},"application/vnd.oma.bcast.drm-trigger+xml":{"source":"iana"},"application/vnd.oma.bcast.imd+xml":{"source":"iana"},"application/vnd.oma.bcast.ltkm":{"source":"iana"},"application/vnd.oma.bcast.notification+xml":{"source":"iana"},"application/vnd.oma.bcast.provisioningtrigger":{"source":"iana"},"application/vnd.oma.bcast.sgboot":{"source":"iana"},"application/vnd.oma.bcast.sgdd+xml":{"source":"iana"},"application/vnd.oma.bcast.sgdu":{"source":"iana"},"application/vnd.oma.bcast.simple-symbol-container":{"source":"iana"},"application/vnd.oma.bcast.smartcard-trigger+xml":{"source":"iana"},"application/vnd.oma.bcast.sprov+xml":{"source":"iana"},"application/vnd.oma.bcast.stkm":{"source":"iana"},"application/vnd.oma.cab-address-book+xml":{"source":"iana"},"application/vnd.oma.cab-feature-handler+xml":{"source":"iana"},"application/vnd.oma.cab-pcc+xml":{"source":"iana"},"application/vnd.oma.cab-subs-invite+xml":{"source":"iana"},"application/vnd.oma.cab-user-prefs+xml":{"source":"iana"},"application/vnd.oma.dcd":{"source":"iana"},"application/vnd.oma.dcdc":{"source":"iana"},"application/vnd.oma.dd2+xml":{"source":"iana","extensions":["dd2"]},"application/vnd.oma.drm.risd+xml":{"source":"iana"},"application/vnd.oma.group-usage-list+xml":{"source":"iana"},"application/vnd.oma.lwm2m+json":{"source":"iana","compressible":true},"application/vnd.oma.lwm2m+tlv":{"source":"iana"},"application/vnd.oma.pal+xml":{"source":"iana"},"application/vnd.oma.poc.detailed-progress-report+xml":{"source":"iana"},"application/vnd.oma.poc.final-report+xml":{"source":"iana"},"application/vnd.oma.poc.groups+xml":{"source":"iana"},"application/vnd.oma.poc.invocation-descriptor+xml":{"source":"iana"},"application/vnd.oma.poc.optimized-progress-report+xml":{"source":"iana"},"application/vnd.oma.push":{"source":"iana"},"application/vnd.oma.scidm.messages+xml":{"source":"iana"},"application/vnd.oma.xcap-directory+xml":{"source":"iana"},"application/vnd.omads-email+xml":{"source":"iana"},"application/vnd.omads-file+xml":{"source":"iana"},"application/vnd.omads-folder+xml":{"source":"iana"},"application/vnd.omaloc-supl-init":{"source":"iana"},"application/vnd.onepager":{"source":"iana"},"application/vnd.onepagertamp":{"source":"iana"},"application/vnd.onepagertamx":{"source":"iana"},"application/vnd.onepagertat":{"source":"iana"},"application/vnd.onepagertatp":{"source":"iana"},"application/vnd.onepagertatx":{"source":"iana"},"application/vnd.openblox.game+xml":{"source":"iana"},"application/vnd.openblox.game-binary":{"source":"iana"},"application/vnd.openeye.oeb":{"source":"iana"},"application/vnd.openofficeorg.extension":{"source":"apache","extensions":["oxt"]},"application/vnd.openstreetmap.data+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.custom-properties+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.customxmlproperties+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.drawing+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.drawingml.chart+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.extended-properties+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml-template":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.comments+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.presentation":{"source":"iana","compressible":false,"extensions":["pptx"]},"application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.presprops+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.slide":{"source":"iana","extensions":["sldx"]},"application/vnd.openxmlformats-officedocument.presentationml.slide+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.slideshow":{"source":"iana","extensions":["ppsx"]},"application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.tags+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.template":{"source":"apache","extensions":["potx"]},"application/vnd.openxmlformats-officedocument.presentationml.template.main+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml-template":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{"source":"iana","compressible":false,"extensions":["xlsx"]},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.template":{"source":"apache","extensions":["xltx"]},"application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.theme+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.themeoverride+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.vmldrawing":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml-template":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.document":{"source":"iana","compressible":false,"extensions":["docx"]},"application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.template":{"source":"apache","extensions":["dotx"]},"application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml":{"source":"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml":{"source":"iana"},"application/vnd.openxmlformats-package.core-properties+xml":{"source":"iana"},"application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml":{"source":"iana"},"application/vnd.openxmlformats-package.relationships+xml":{"source":"iana"},"application/vnd.oracle.resource+json":{"source":"iana","compressible":true},"application/vnd.orange.indata":{"source":"iana"},"application/vnd.osa.netdeploy":{"source":"iana"},"application/vnd.osgeo.mapguide.package":{"source":"iana","extensions":["mgp"]},"application/vnd.osgi.bundle":{"source":"iana"},"application/vnd.osgi.dp":{"source":"iana","extensions":["dp"]},"application/vnd.osgi.subsystem":{"source":"iana","extensions":["esa"]},"application/vnd.otps.ct-kip+xml":{"source":"iana"},"application/vnd.oxli.countgraph":{"source":"iana"},"application/vnd.pagerduty+json":{"source":"iana","compressible":true},"application/vnd.palm":{"source":"iana","extensions":["pdb","pqa","oprc"]},"application/vnd.panoply":{"source":"iana"},"application/vnd.paos+xml":{"source":"iana"},"application/vnd.paos.xml":{"source":"apache"},"application/vnd.pawaafile":{"source":"iana","extensions":["paw"]},"application/vnd.pcos":{"source":"iana"},"application/vnd.pg.format":{"source":"iana","extensions":["str"]},"application/vnd.pg.osasli":{"source":"iana","extensions":["ei6"]},"application/vnd.piaccess.application-licence":{"source":"iana"},"application/vnd.picsel":{"source":"iana","extensions":["efif"]},"application/vnd.pmi.widget":{"source":"iana","extensions":["wg"]},"application/vnd.poc.group-advertisement+xml":{"source":"iana"},"application/vnd.pocketlearn":{"source":"iana","extensions":["plf"]},"application/vnd.powerbuilder6":{"source":"iana","extensions":["pbd"]},"application/vnd.powerbuilder6-s":{"source":"iana"},"application/vnd.powerbuilder7":{"source":"iana"},"application/vnd.powerbuilder7-s":{"source":"iana"},"application/vnd.powerbuilder75":{"source":"iana"},"application/vnd.powerbuilder75-s":{"source":"iana"},"application/vnd.preminet":{"source":"iana"},"application/vnd.previewsystems.box":{"source":"iana","extensions":["box"]},"application/vnd.proteus.magazine":{"source":"iana","extensions":["mgz"]},"application/vnd.publishare-delta-tree":{"source":"iana","extensions":["qps"]},"application/vnd.pvi.ptid1":{"source":"iana","extensions":["ptid"]},"application/vnd.pwg-multiplexed":{"source":"iana"},"application/vnd.pwg-xhtml-print+xml":{"source":"iana"},"application/vnd.qualcomm.brew-app-res":{"source":"iana"},"application/vnd.quarantainenet":{"source":"iana"},"application/vnd.quark.quarkxpress":{"source":"iana","extensions":["qxd","qxt","qwd","qwt","qxl","qxb"]},"application/vnd.quobject-quoxdocument":{"source":"iana"},"application/vnd.radisys.moml+xml":{"source":"iana"},"application/vnd.radisys.msml+xml":{"source":"iana"},"application/vnd.radisys.msml-audit+xml":{"source":"iana"},"application/vnd.radisys.msml-audit-conf+xml":{"source":"iana"},"application/vnd.radisys.msml-audit-conn+xml":{"source":"iana"},"application/vnd.radisys.msml-audit-dialog+xml":{"source":"iana"},"application/vnd.radisys.msml-audit-stream+xml":{"source":"iana"},"application/vnd.radisys.msml-conf+xml":{"source":"iana"},"application/vnd.radisys.msml-dialog+xml":{"source":"iana"},"application/vnd.radisys.msml-dialog-base+xml":{"source":"iana"},"application/vnd.radisys.msml-dialog-fax-detect+xml":{"source":"iana"},"application/vnd.radisys.msml-dialog-fax-sendrecv+xml":{"source":"iana"},"application/vnd.radisys.msml-dialog-group+xml":{"source":"iana"},"application/vnd.radisys.msml-dialog-speech+xml":{"source":"iana"},"application/vnd.radisys.msml-dialog-transform+xml":{"source":"iana"},"application/vnd.rainstor.data":{"source":"iana"},"application/vnd.rapid":{"source":"iana"},"application/vnd.rar":{"source":"iana"},"application/vnd.realvnc.bed":{"source":"iana","extensions":["bed"]},"application/vnd.recordare.musicxml":{"source":"iana","extensions":["mxl"]},"application/vnd.recordare.musicxml+xml":{"source":"iana","extensions":["musicxml"]},"application/vnd.renlearn.rlprint":{"source":"iana"},"application/vnd.rig.cryptonote":{"source":"iana","extensions":["cryptonote"]},"application/vnd.rim.cod":{"source":"apache","extensions":["cod"]},"application/vnd.rn-realmedia":{"source":"apache","extensions":["rm"]},"application/vnd.rn-realmedia-vbr":{"source":"apache","extensions":["rmvb"]},"application/vnd.route66.link66+xml":{"source":"iana","extensions":["link66"]},"application/vnd.rs-274x":{"source":"iana"},"application/vnd.ruckus.download":{"source":"iana"},"application/vnd.s3sms":{"source":"iana"},"application/vnd.sailingtracker.track":{"source":"iana","extensions":["st"]},"application/vnd.sbm.cid":{"source":"iana"},"application/vnd.sbm.mid2":{"source":"iana"},"application/vnd.scribus":{"source":"iana"},"application/vnd.sealed.3df":{"source":"iana"},"application/vnd.sealed.csf":{"source":"iana"},"application/vnd.sealed.doc":{"source":"iana"},"application/vnd.sealed.eml":{"source":"iana"},"application/vnd.sealed.mht":{"source":"iana"},"application/vnd.sealed.net":{"source":"iana"},"application/vnd.sealed.ppt":{"source":"iana"},"application/vnd.sealed.tiff":{"source":"iana"},"application/vnd.sealed.xls":{"source":"iana"},"application/vnd.sealedmedia.softseal.html":{"source":"iana"},"application/vnd.sealedmedia.softseal.pdf":{"source":"iana"},"application/vnd.seemail":{"source":"iana","extensions":["see"]},"application/vnd.sema":{"source":"iana","extensions":["sema"]},"application/vnd.semd":{"source":"iana","extensions":["semd"]},"application/vnd.semf":{"source":"iana","extensions":["semf"]},"application/vnd.shana.informed.formdata":{"source":"iana","extensions":["ifm"]},"application/vnd.shana.informed.formtemplate":{"source":"iana","extensions":["itp"]},"application/vnd.shana.informed.interchange":{"source":"iana","extensions":["iif"]},"application/vnd.shana.informed.package":{"source":"iana","extensions":["ipk"]},"application/vnd.sigrok.session":{"source":"iana"},"application/vnd.simtech-mindmapper":{"source":"iana","extensions":["twd","twds"]},"application/vnd.siren+json":{"source":"iana","compressible":true},"application/vnd.smaf":{"source":"iana","extensions":["mmf"]},"application/vnd.smart.notebook":{"source":"iana"},"application/vnd.smart.teacher":{"source":"iana","extensions":["teacher"]},"application/vnd.software602.filler.form+xml":{"source":"iana"},"application/vnd.software602.filler.form-xml-zip":{"source":"iana"},"application/vnd.solent.sdkm+xml":{"source":"iana","extensions":["sdkm","sdkd"]},"application/vnd.spotfire.dxp":{"source":"iana","extensions":["dxp"]},"application/vnd.spotfire.sfs":{"source":"iana","extensions":["sfs"]},"application/vnd.sss-cod":{"source":"iana"},"application/vnd.sss-dtf":{"source":"iana"},"application/vnd.sss-ntf":{"source":"iana"},"application/vnd.stardivision.calc":{"source":"apache","extensions":["sdc"]},"application/vnd.stardivision.draw":{"source":"apache","extensions":["sda"]},"application/vnd.stardivision.impress":{"source":"apache","extensions":["sdd"]},"application/vnd.stardivision.math":{"source":"apache","extensions":["smf"]},"application/vnd.stardivision.writer":{"source":"apache","extensions":["sdw","vor"]},"application/vnd.stardivision.writer-global":{"source":"apache","extensions":["sgl"]},"application/vnd.stepmania.package":{"source":"iana","extensions":["smzip"]},"application/vnd.stepmania.stepchart":{"source":"iana","extensions":["sm"]},"application/vnd.street-stream":{"source":"iana"},"application/vnd.sun.wadl+xml":{"source":"iana","compressible":true,"extensions":["wadl"]},"application/vnd.sun.xml.calc":{"source":"apache","extensions":["sxc"]},"application/vnd.sun.xml.calc.template":{"source":"apache","extensions":["stc"]},"application/vnd.sun.xml.draw":{"source":"apache","extensions":["sxd"]},"application/vnd.sun.xml.draw.template":{"source":"apache","extensions":["std"]},"application/vnd.sun.xml.impress":{"source":"apache","extensions":["sxi"]},"application/vnd.sun.xml.impress.template":{"source":"apache","extensions":["sti"]},"application/vnd.sun.xml.math":{"source":"apache","extensions":["sxm"]},"application/vnd.sun.xml.writer":{"source":"apache","extensions":["sxw"]},"application/vnd.sun.xml.writer.global":{"source":"apache","extensions":["sxg"]},"application/vnd.sun.xml.writer.template":{"source":"apache","extensions":["stw"]},"application/vnd.sus-calendar":{"source":"iana","extensions":["sus","susp"]},"application/vnd.svd":{"source":"iana","extensions":["svd"]},"application/vnd.swiftview-ics":{"source":"iana"},"application/vnd.symbian.install":{"source":"apache","extensions":["sis","sisx"]},"application/vnd.syncml+xml":{"source":"iana","extensions":["xsm"]},"application/vnd.syncml.dm+wbxml":{"source":"iana","extensions":["bdm"]},"application/vnd.syncml.dm+xml":{"source":"iana","extensions":["xdm"]},"application/vnd.syncml.dm.notification":{"source":"iana"},"application/vnd.syncml.dmddf+wbxml":{"source":"iana"},"application/vnd.syncml.dmddf+xml":{"source":"iana"},"application/vnd.syncml.dmtnds+wbxml":{"source":"iana"},"application/vnd.syncml.dmtnds+xml":{"source":"iana"},"application/vnd.syncml.ds.notification":{"source":"iana"},"application/vnd.tableschema+json":{"source":"iana","compressible":true},"application/vnd.tao.intent-module-archive":{"source":"iana","extensions":["tao"]},"application/vnd.tcpdump.pcap":{"source":"iana","extensions":["pcap","cap","dmp"]},"application/vnd.tmd.mediaflex.api+xml":{"source":"iana"},"application/vnd.tml":{"source":"iana"},"application/vnd.tmobile-livetv":{"source":"iana","extensions":["tmo"]},"application/vnd.tri.onesource":{"source":"iana"},"application/vnd.trid.tpt":{"source":"iana","extensions":["tpt"]},"application/vnd.triscape.mxs":{"source":"iana","extensions":["mxs"]},"application/vnd.trueapp":{"source":"iana","extensions":["tra"]},"application/vnd.truedoc":{"source":"iana"},"application/vnd.ubisoft.webplayer":{"source":"iana"},"application/vnd.ufdl":{"source":"iana","extensions":["ufd","ufdl"]},"application/vnd.uiq.theme":{"source":"iana","extensions":["utz"]},"application/vnd.umajin":{"source":"iana","extensions":["umj"]},"application/vnd.unity":{"source":"iana","extensions":["unityweb"]},"application/vnd.uoml+xml":{"source":"iana","extensions":["uoml"]},"application/vnd.uplanet.alert":{"source":"iana"},"application/vnd.uplanet.alert-wbxml":{"source":"iana"},"application/vnd.uplanet.bearer-choice":{"source":"iana"},"application/vnd.uplanet.bearer-choice-wbxml":{"source":"iana"},"application/vnd.uplanet.cacheop":{"source":"iana"},"application/vnd.uplanet.cacheop-wbxml":{"source":"iana"},"application/vnd.uplanet.channel":{"source":"iana"},"application/vnd.uplanet.channel-wbxml":{"source":"iana"},"application/vnd.uplanet.list":{"source":"iana"},"application/vnd.uplanet.list-wbxml":{"source":"iana"},"application/vnd.uplanet.listcmd":{"source":"iana"},"application/vnd.uplanet.listcmd-wbxml":{"source":"iana"},"application/vnd.uplanet.signal":{"source":"iana"},"application/vnd.uri-map":{"source":"iana"},"application/vnd.valve.source.material":{"source":"iana"},"application/vnd.vcx":{"source":"iana","extensions":["vcx"]},"application/vnd.vd-study":{"source":"iana"},"application/vnd.vectorworks":{"source":"iana"},"application/vnd.vel+json":{"source":"iana","compressible":true},"application/vnd.verimatrix.vcas":{"source":"iana"},"application/vnd.vidsoft.vidconference":{"source":"iana"},"application/vnd.visio":{"source":"iana","extensions":["vsd","vst","vss","vsw"]},"application/vnd.visionary":{"source":"iana","extensions":["vis"]},"application/vnd.vividence.scriptfile":{"source":"iana"},"application/vnd.vsf":{"source":"iana","extensions":["vsf"]},"application/vnd.wap.sic":{"source":"iana"},"application/vnd.wap.slc":{"source":"iana"},"application/vnd.wap.wbxml":{"source":"iana","extensions":["wbxml"]},"application/vnd.wap.wmlc":{"source":"iana","extensions":["wmlc"]},"application/vnd.wap.wmlscriptc":{"source":"iana","extensions":["wmlsc"]},"application/vnd.webturbo":{"source":"iana","extensions":["wtb"]},"application/vnd.wfa.p2p":{"source":"iana"},"application/vnd.wfa.wsc":{"source":"iana"},"application/vnd.windows.devicepairing":{"source":"iana"},"application/vnd.wmc":{"source":"iana"},"application/vnd.wmf.bootstrap":{"source":"iana"},"application/vnd.wolfram.mathematica":{"source":"iana"},"application/vnd.wolfram.mathematica.package":{"source":"iana"},"application/vnd.wolfram.player":{"source":"iana","extensions":["nbp"]},"application/vnd.wordperfect":{"source":"iana","extensions":["wpd"]},"application/vnd.wqd":{"source":"iana","extensions":["wqd"]},"application/vnd.wrq-hp3000-labelled":{"source":"iana"},"application/vnd.wt.stf":{"source":"iana","extensions":["stf"]},"application/vnd.wv.csp+wbxml":{"source":"iana"},"application/vnd.wv.csp+xml":{"source":"iana"},"application/vnd.wv.ssp+xml":{"source":"iana"},"application/vnd.xacml+json":{"source":"iana","compressible":true},"application/vnd.xara":{"source":"iana","extensions":["xar"]},"application/vnd.xfdl":{"source":"iana","extensions":["xfdl"]},"application/vnd.xfdl.webform":{"source":"iana"},"application/vnd.xmi+xml":{"source":"iana"},"application/vnd.xmpie.cpkg":{"source":"iana"},"application/vnd.xmpie.dpkg":{"source":"iana"},"application/vnd.xmpie.plan":{"source":"iana"},"application/vnd.xmpie.ppkg":{"source":"iana"},"application/vnd.xmpie.xlim":{"source":"iana"},"application/vnd.yamaha.hv-dic":{"source":"iana","extensions":["hvd"]},"application/vnd.yamaha.hv-script":{"source":"iana","extensions":["hvs"]},"application/vnd.yamaha.hv-voice":{"source":"iana","extensions":["hvp"]},"application/vnd.yamaha.openscoreformat":{"source":"iana","extensions":["osf"]},"application/vnd.yamaha.openscoreformat.osfpvg+xml":{"source":"iana","extensions":["osfpvg"]},"application/vnd.yamaha.remote-setup":{"source":"iana"},"application/vnd.yamaha.smaf-audio":{"source":"iana","extensions":["saf"]},"application/vnd.yamaha.smaf-phrase":{"source":"iana","extensions":["spf"]},"application/vnd.yamaha.through-ngn":{"source":"iana"},"application/vnd.yamaha.tunnel-udpencap":{"source":"iana"},"application/vnd.yaoweme":{"source":"iana"},"application/vnd.yellowriver-custom-menu":{"source":"iana","extensions":["cmp"]},"application/vnd.zul":{"source":"iana","extensions":["zir","zirz"]},"application/vnd.zzazz.deck+xml":{"source":"iana","extensions":["zaz"]},"application/voicexml+xml":{"source":"iana","extensions":["vxml"]},"application/vq-rtcpxr":{"source":"iana"},"application/watcherinfo+xml":{"source":"iana"},"application/whoispp-query":{"source":"iana"},"application/whoispp-response":{"source":"iana"},"application/widget":{"source":"iana","extensions":["wgt"]},"application/winhlp":{"source":"apache","extensions":["hlp"]},"application/wita":{"source":"iana"},"application/wordperfect5.1":{"source":"iana"},"application/wsdl+xml":{"source":"iana","extensions":["wsdl"]},"application/wspolicy+xml":{"source":"iana","extensions":["wspolicy"]},"application/x-7z-compressed":{"source":"apache","compressible":false,"extensions":["7z"]},"application/x-abiword":{"source":"apache","extensions":["abw"]},"application/x-ace-compressed":{"source":"apache","extensions":["ace"]},"application/x-amf":{"source":"apache"},"application/x-apple-diskimage":{"source":"apache","extensions":["dmg"]},"application/x-arj":{"compressible":false,"extensions":["arj"]},"application/x-authorware-bin":{"source":"apache","extensions":["aab","x32","u32","vox"]},"application/x-authorware-map":{"source":"apache","extensions":["aam"]},"application/x-authorware-seg":{"source":"apache","extensions":["aas"]},"application/x-bcpio":{"source":"apache","extensions":["bcpio"]},"application/x-bdoc":{"compressible":false,"extensions":["bdoc"]},"application/x-bittorrent":{"source":"apache","extensions":["torrent"]},"application/x-blorb":{"source":"apache","extensions":["blb","blorb"]},"application/x-bzip":{"source":"apache","compressible":false,"extensions":["bz"]},"application/x-bzip2":{"source":"apache","compressible":false,"extensions":["bz2","boz"]},"application/x-cbr":{"source":"apache","extensions":["cbr","cba","cbt","cbz","cb7"]},"application/x-cdlink":{"source":"apache","extensions":["vcd"]},"application/x-cfs-compressed":{"source":"apache","extensions":["cfs"]},"application/x-chat":{"source":"apache","extensions":["chat"]},"application/x-chess-pgn":{"source":"apache","extensions":["pgn"]},"application/x-chrome-extension":{"extensions":["crx"]},"application/x-cocoa":{"source":"nginx","extensions":["cco"]},"application/x-compress":{"source":"apache"},"application/x-conference":{"source":"apache","extensions":["nsc"]},"application/x-cpio":{"source":"apache","extensions":["cpio"]},"application/x-csh":{"source":"apache","extensions":["csh"]},"application/x-deb":{"compressible":false},"application/x-debian-package":{"source":"apache","extensions":["deb","udeb"]},"application/x-dgc-compressed":{"source":"apache","extensions":["dgc"]},"application/x-director":{"source":"apache","extensions":["dir","dcr","dxr","cst","cct","cxt","w3d","fgd","swa"]},"application/x-doom":{"source":"apache","extensions":["wad"]},"application/x-dtbncx+xml":{"source":"apache","extensions":["ncx"]},"application/x-dtbook+xml":{"source":"apache","extensions":["dtb"]},"application/x-dtbresource+xml":{"source":"apache","extensions":["res"]},"application/x-dvi":{"source":"apache","compressible":false,"extensions":["dvi"]},"application/x-envoy":{"source":"apache","extensions":["evy"]},"application/x-eva":{"source":"apache","extensions":["eva"]},"application/x-font-bdf":{"source":"apache","extensions":["bdf"]},"application/x-font-dos":{"source":"apache"},"application/x-font-framemaker":{"source":"apache"},"application/x-font-ghostscript":{"source":"apache","extensions":["gsf"]},"application/x-font-libgrx":{"source":"apache"},"application/x-font-linux-psf":{"source":"apache","extensions":["psf"]},"application/x-font-otf":{"source":"apache","compressible":true,"extensions":["otf"]},"application/x-font-pcf":{"source":"apache","extensions":["pcf"]},"application/x-font-snf":{"source":"apache","extensions":["snf"]},"application/x-font-speedo":{"source":"apache"},"application/x-font-sunos-news":{"source":"apache"},"application/x-font-ttf":{"source":"apache","compressible":true,"extensions":["ttf","ttc"]},"application/x-font-type1":{"source":"apache","extensions":["pfa","pfb","pfm","afm"]},"application/x-font-vfont":{"source":"apache"},"application/x-freearc":{"source":"apache","extensions":["arc"]},"application/x-futuresplash":{"source":"apache","extensions":["spl"]},"application/x-gca-compressed":{"source":"apache","extensions":["gca"]},"application/x-glulx":{"source":"apache","extensions":["ulx"]},"application/x-gnumeric":{"source":"apache","extensions":["gnumeric"]},"application/x-gramps-xml":{"source":"apache","extensions":["gramps"]},"application/x-gtar":{"source":"apache","extensions":["gtar"]},"application/x-gzip":{"source":"apache"},"application/x-hdf":{"source":"apache","extensions":["hdf"]},"application/x-httpd-php":{"compressible":true,"extensions":["php"]},"application/x-install-instructions":{"source":"apache","extensions":["install"]},"application/x-iso9660-image":{"source":"apache","extensions":["iso"]},"application/x-java-archive-diff":{"source":"nginx","extensions":["jardiff"]},"application/x-java-jnlp-file":{"source":"apache","compressible":false,"extensions":["jnlp"]},"application/x-javascript":{"compressible":true},"application/x-latex":{"source":"apache","compressible":false,"extensions":["latex"]},"application/x-lua-bytecode":{"extensions":["luac"]},"application/x-lzh-compressed":{"source":"apache","extensions":["lzh","lha"]},"application/x-makeself":{"source":"nginx","extensions":["run"]},"application/x-mie":{"source":"apache","extensions":["mie"]},"application/x-mobipocket-ebook":{"source":"apache","extensions":["prc","mobi"]},"application/x-mpegurl":{"compressible":false},"application/x-ms-application":{"source":"apache","extensions":["application"]},"application/x-ms-shortcut":{"source":"apache","extensions":["lnk"]},"application/x-ms-wmd":{"source":"apache","extensions":["wmd"]},"application/x-ms-wmz":{"source":"apache","extensions":["wmz"]},"application/x-ms-xbap":{"source":"apache","extensions":["xbap"]},"application/x-msaccess":{"source":"apache","extensions":["mdb"]},"application/x-msbinder":{"source":"apache","extensions":["obd"]},"application/x-mscardfile":{"source":"apache","extensions":["crd"]},"application/x-msclip":{"source":"apache","extensions":["clp"]},"application/x-msdos-program":{"extensions":["exe"]},"application/x-msdownload":{"source":"apache","extensions":["exe","dll","com","bat","msi"]},"application/x-msmediaview":{"source":"apache","extensions":["mvb","m13","m14"]},"application/x-msmetafile":{"source":"apache","extensions":["wmf","wmz","emf","emz"]},"application/x-msmoney":{"source":"apache","extensions":["mny"]},"application/x-mspublisher":{"source":"apache","extensions":["pub"]},"application/x-msschedule":{"source":"apache","extensions":["scd"]},"application/x-msterminal":{"source":"apache","extensions":["trm"]},"application/x-mswrite":{"source":"apache","extensions":["wri"]},"application/x-netcdf":{"source":"apache","extensions":["nc","cdf"]},"application/x-ns-proxy-autoconfig":{"compressible":true,"extensions":["pac"]},"application/x-nzb":{"source":"apache","extensions":["nzb"]},"application/x-perl":{"source":"nginx","extensions":["pl","pm"]},"application/x-pilot":{"source":"nginx","extensions":["prc","pdb"]},"application/x-pkcs12":{"source":"apache","compressible":false,"extensions":["p12","pfx"]},"application/x-pkcs7-certificates":{"source":"apache","extensions":["p7b","spc"]},"application/x-pkcs7-certreqresp":{"source":"apache","extensions":["p7r"]},"application/x-rar-compressed":{"source":"apache","compressible":false,"extensions":["rar"]},"application/x-redhat-package-manager":{"source":"nginx","extensions":["rpm"]},"application/x-research-info-systems":{"source":"apache","extensions":["ris"]},"application/x-sea":{"source":"nginx","extensions":["sea"]},"application/x-sh":{"source":"apache","compressible":true,"extensions":["sh"]},"application/x-shar":{"source":"apache","extensions":["shar"]},"application/x-shockwave-flash":{"source":"apache","compressible":false,"extensions":["swf"]},"application/x-silverlight-app":{"source":"apache","extensions":["xap"]},"application/x-sql":{"source":"apache","extensions":["sql"]},"application/x-stuffit":{"source":"apache","compressible":false,"extensions":["sit"]},"application/x-stuffitx":{"source":"apache","extensions":["sitx"]},"application/x-subrip":{"source":"apache","extensions":["srt"]},"application/x-sv4cpio":{"source":"apache","extensions":["sv4cpio"]},"application/x-sv4crc":{"source":"apache","extensions":["sv4crc"]},"application/x-t3vm-image":{"source":"apache","extensions":["t3"]},"application/x-tads":{"source":"apache","extensions":["gam"]},"application/x-tar":{"source":"apache","compressible":true,"extensions":["tar"]},"application/x-tcl":{"source":"apache","extensions":["tcl","tk"]},"application/x-tex":{"source":"apache","extensions":["tex"]},"application/x-tex-tfm":{"source":"apache","extensions":["tfm"]},"application/x-texinfo":{"source":"apache","extensions":["texinfo","texi"]},"application/x-tgif":{"source":"apache","extensions":["obj"]},"application/x-ustar":{"source":"apache","extensions":["ustar"]},"application/x-virtualbox-hdd":{"compressible":true,"extensions":["hdd"]},"application/x-virtualbox-ova":{"compressible":true,"extensions":["ova"]},"application/x-virtualbox-ovf":{"compressible":true,"extensions":["ovf"]},"application/x-virtualbox-vbox":{"compressible":true,"extensions":["vbox"]},"application/x-virtualbox-vbox-extpack":{"compressible":false,"extensions":["vbox-extpack"]},"application/x-virtualbox-vdi":{"compressible":true,"extensions":["vdi"]},"application/x-virtualbox-vhd":{"compressible":true,"extensions":["vhd"]},"application/x-virtualbox-vmdk":{"compressible":true,"extensions":["vmdk"]},"application/x-wais-source":{"source":"apache","extensions":["src"]},"application/x-web-app-manifest+json":{"compressible":true,"extensions":["webapp"]},"application/x-www-form-urlencoded":{"source":"iana","compressible":true},"application/x-x509-ca-cert":{"source":"apache","extensions":["der","crt","pem"]},"application/x-xfig":{"source":"apache","extensions":["fig"]},"application/x-xliff+xml":{"source":"apache","extensions":["xlf"]},"application/x-xpinstall":{"source":"apache","compressible":false,"extensions":["xpi"]},"application/x-xz":{"source":"apache","extensions":["xz"]},"application/x-zmachine":{"source":"apache","extensions":["z1","z2","z3","z4","z5","z6","z7","z8"]},"application/x400-bp":{"source":"iana"},"application/xacml+xml":{"source":"iana"},"application/xaml+xml":{"source":"apache","extensions":["xaml"]},"application/xcap-att+xml":{"source":"iana"},"application/xcap-caps+xml":{"source":"iana"},"application/xcap-diff+xml":{"source":"iana","extensions":["xdf"]},"application/xcap-el+xml":{"source":"iana"},"application/xcap-error+xml":{"source":"iana"},"application/xcap-ns+xml":{"source":"iana"},"application/xcon-conference-info+xml":{"source":"iana"},"application/xcon-conference-info-diff+xml":{"source":"iana"},"application/xenc+xml":{"source":"iana","extensions":["xenc"]},"application/xhtml+xml":{"source":"iana","compressible":true,"extensions":["xhtml","xht"]},"application/xhtml-voice+xml":{"source":"apache"},"application/xml":{"source":"iana","compressible":true,"extensions":["xml","xsl","xsd","rng"]},"application/xml-dtd":{"source":"iana","compressible":true,"extensions":["dtd"]},"application/xml-external-parsed-entity":{"source":"iana"},"application/xml-patch+xml":{"source":"iana"},"application/xmpp+xml":{"source":"iana"},"application/xop+xml":{"source":"iana","compressible":true,"extensions":["xop"]},"application/xproc+xml":{"source":"apache","extensions":["xpl"]},"application/xslt+xml":{"source":"iana","extensions":["xslt"]},"application/xspf+xml":{"source":"apache","extensions":["xspf"]},"application/xv+xml":{"source":"iana","extensions":["mxml","xhvml","xvml","xvm"]},"application/yang":{"source":"iana","extensions":["yang"]},"application/yang-data+json":{"source":"iana","compressible":true},"application/yang-data+xml":{"source":"iana"},"application/yang-patch+json":{"source":"iana","compressible":true},"application/yang-patch+xml":{"source":"iana"},"application/yin+xml":{"source":"iana","extensions":["yin"]},"application/zip":{"source":"iana","compressible":false,"extensions":["zip"]},"application/zlib":{"source":"iana"},"audio/1d-interleaved-parityfec":{"source":"iana"},"audio/32kadpcm":{"source":"iana"},"audio/3gpp":{"source":"iana","compressible":false,"extensions":["3gpp"]},"audio/3gpp2":{"source":"iana"},"audio/ac3":{"source":"iana"},"audio/adpcm":{"source":"apache","extensions":["adp"]},"audio/amr":{"source":"iana"},"audio/amr-wb":{"source":"iana"},"audio/amr-wb+":{"source":"iana"},"audio/aptx":{"source":"iana"},"audio/asc":{"source":"iana"},"audio/atrac-advanced-lossless":{"source":"iana"},"audio/atrac-x":{"source":"iana"},"audio/atrac3":{"source":"iana"},"audio/basic":{"source":"iana","compressible":false,"extensions":["au","snd"]},"audio/bv16":{"source":"iana"},"audio/bv32":{"source":"iana"},"audio/clearmode":{"source":"iana"},"audio/cn":{"source":"iana"},"audio/dat12":{"source":"iana"},"audio/dls":{"source":"iana"},"audio/dsr-es201108":{"source":"iana"},"audio/dsr-es202050":{"source":"iana"},"audio/dsr-es202211":{"source":"iana"},"audio/dsr-es202212":{"source":"iana"},"audio/dv":{"source":"iana"},"audio/dvi4":{"source":"iana"},"audio/eac3":{"source":"iana"},"audio/encaprtp":{"source":"iana"},"audio/evrc":{"source":"iana"},"audio/evrc-qcp":{"source":"iana"},"audio/evrc0":{"source":"iana"},"audio/evrc1":{"source":"iana"},"audio/evrcb":{"source":"iana"},"audio/evrcb0":{"source":"iana"},"audio/evrcb1":{"source":"iana"},"audio/evrcnw":{"source":"iana"},"audio/evrcnw0":{"source":"iana"},"audio/evrcnw1":{"source":"iana"},"audio/evrcwb":{"source":"iana"},"audio/evrcwb0":{"source":"iana"},"audio/evrcwb1":{"source":"iana"},"audio/evs":{"source":"iana"},"audio/fwdred":{"source":"iana"},"audio/g711-0":{"source":"iana"},"audio/g719":{"source":"iana"},"audio/g722":{"source":"iana"},"audio/g7221":{"source":"iana"},"audio/g723":{"source":"iana"},"audio/g726-16":{"source":"iana"},"audio/g726-24":{"source":"iana"},"audio/g726-32":{"source":"iana"},"audio/g726-40":{"source":"iana"},"audio/g728":{"source":"iana"},"audio/g729":{"source":"iana"},"audio/g7291":{"source":"iana"},"audio/g729d":{"source":"iana"},"audio/g729e":{"source":"iana"},"audio/gsm":{"source":"iana"},"audio/gsm-efr":{"source":"iana"},"audio/gsm-hr-08":{"source":"iana"},"audio/ilbc":{"source":"iana"},"audio/ip-mr_v2.5":{"source":"iana"},"audio/isac":{"source":"apache"},"audio/l16":{"source":"iana"},"audio/l20":{"source":"iana"},"audio/l24":{"source":"iana","compressible":false},"audio/l8":{"source":"iana"},"audio/lpc":{"source":"iana"},"audio/melp":{"source":"iana"},"audio/melp1200":{"source":"iana"},"audio/melp2400":{"source":"iana"},"audio/melp600":{"source":"iana"},"audio/midi":{"source":"apache","extensions":["mid","midi","kar","rmi"]},"audio/mobile-xmf":{"source":"iana"},"audio/mp3":{"compressible":false,"extensions":["mp3"]},"audio/mp4":{"source":"iana","compressible":false,"extensions":["m4a","mp4a"]},"audio/mp4a-latm":{"source":"iana"},"audio/mpa":{"source":"iana"},"audio/mpa-robust":{"source":"iana"},"audio/mpeg":{"source":"iana","compressible":false,"extensions":["mpga","mp2","mp2a","mp3","m2a","m3a"]},"audio/mpeg4-generic":{"source":"iana"},"audio/musepack":{"source":"apache"},"audio/ogg":{"source":"iana","compressible":false,"extensions":["oga","ogg","spx"]},"audio/opus":{"source":"iana"},"audio/parityfec":{"source":"iana"},"audio/pcma":{"source":"iana"},"audio/pcma-wb":{"source":"iana"},"audio/pcmu":{"source":"iana"},"audio/pcmu-wb":{"source":"iana"},"audio/prs.sid":{"source":"iana"},"audio/qcelp":{"source":"iana"},"audio/raptorfec":{"source":"iana"},"audio/red":{"source":"iana"},"audio/rtp-enc-aescm128":{"source":"iana"},"audio/rtp-midi":{"source":"iana"},"audio/rtploopback":{"source":"iana"},"audio/rtx":{"source":"iana"},"audio/s3m":{"source":"apache","extensions":["s3m"]},"audio/silk":{"source":"apache","extensions":["sil"]},"audio/smv":{"source":"iana"},"audio/smv-qcp":{"source":"iana"},"audio/smv0":{"source":"iana"},"audio/sp-midi":{"source":"iana"},"audio/speex":{"source":"iana"},"audio/t140c":{"source":"iana"},"audio/t38":{"source":"iana"},"audio/telephone-event":{"source":"iana"},"audio/tone":{"source":"iana"},"audio/uemclip":{"source":"iana"},"audio/ulpfec":{"source":"iana"},"audio/vdvi":{"source":"iana"},"audio/vmr-wb":{"source":"iana"},"audio/vnd.3gpp.iufp":{"source":"iana"},"audio/vnd.4sb":{"source":"iana"},"audio/vnd.audiokoz":{"source":"iana"},"audio/vnd.celp":{"source":"iana"},"audio/vnd.cisco.nse":{"source":"iana"},"audio/vnd.cmles.radio-events":{"source":"iana"},"audio/vnd.cns.anp1":{"source":"iana"},"audio/vnd.cns.inf1":{"source":"iana"},"audio/vnd.dece.audio":{"source":"iana","extensions":["uva","uvva"]},"audio/vnd.digital-winds":{"source":"iana","extensions":["eol"]},"audio/vnd.dlna.adts":{"source":"iana"},"audio/vnd.dolby.heaac.1":{"source":"iana"},"audio/vnd.dolby.heaac.2":{"source":"iana"},"audio/vnd.dolby.mlp":{"source":"iana"},"audio/vnd.dolby.mps":{"source":"iana"},"audio/vnd.dolby.pl2":{"source":"iana"},"audio/vnd.dolby.pl2x":{"source":"iana"},"audio/vnd.dolby.pl2z":{"source":"iana"},"audio/vnd.dolby.pulse.1":{"source":"iana"},"audio/vnd.dra":{"source":"iana","extensions":["dra"]},"audio/vnd.dts":{"source":"iana","extensions":["dts"]},"audio/vnd.dts.hd":{"source":"iana","extensions":["dtshd"]},"audio/vnd.dvb.file":{"source":"iana"},"audio/vnd.everad.plj":{"source":"iana"},"audio/vnd.hns.audio":{"source":"iana"},"audio/vnd.lucent.voice":{"source":"iana","extensions":["lvp"]},"audio/vnd.ms-playready.media.pya":{"source":"iana","extensions":["pya"]},"audio/vnd.nokia.mobile-xmf":{"source":"iana"},"audio/vnd.nortel.vbk":{"source":"iana"},"audio/vnd.nuera.ecelp4800":{"source":"iana","extensions":["ecelp4800"]},"audio/vnd.nuera.ecelp7470":{"source":"iana","extensions":["ecelp7470"]},"audio/vnd.nuera.ecelp9600":{"source":"iana","extensions":["ecelp9600"]},"audio/vnd.octel.sbc":{"source":"iana"},"audio/vnd.presonus.multitrack":{"source":"iana"},"audio/vnd.qcelp":{"source":"iana"},"audio/vnd.rhetorex.32kadpcm":{"source":"iana"},"audio/vnd.rip":{"source":"iana","extensions":["rip"]},"audio/vnd.rn-realaudio":{"compressible":false},"audio/vnd.sealedmedia.softseal.mpeg":{"source":"iana"},"audio/vnd.vmx.cvsd":{"source":"iana"},"audio/vnd.wave":{"compressible":false},"audio/vorbis":{"source":"iana","compressible":false},"audio/vorbis-config":{"source":"iana"},"audio/wav":{"compressible":false,"extensions":["wav"]},"audio/wave":{"compressible":false,"extensions":["wav"]},"audio/webm":{"source":"apache","compressible":false,"extensions":["weba"]},"audio/x-aac":{"source":"apache","compressible":false,"extensions":["aac"]},"audio/x-aiff":{"source":"apache","extensions":["aif","aiff","aifc"]},"audio/x-caf":{"source":"apache","compressible":false,"extensions":["caf"]},"audio/x-flac":{"source":"apache","extensions":["flac"]},"audio/x-m4a":{"source":"nginx","extensions":["m4a"]},"audio/x-matroska":{"source":"apache","extensions":["mka"]},"audio/x-mpegurl":{"source":"apache","extensions":["m3u"]},"audio/x-ms-wax":{"source":"apache","extensions":["wax"]},"audio/x-ms-wma":{"source":"apache","extensions":["wma"]},"audio/x-pn-realaudio":{"source":"apache","extensions":["ram","ra"]},"audio/x-pn-realaudio-plugin":{"source":"apache","extensions":["rmp"]},"audio/x-realaudio":{"source":"nginx","extensions":["ra"]},"audio/x-tta":{"source":"apache"},"audio/x-wav":{"source":"apache","extensions":["wav"]},"audio/xm":{"source":"apache","extensions":["xm"]},"chemical/x-cdx":{"source":"apache","extensions":["cdx"]},"chemical/x-cif":{"source":"apache","extensions":["cif"]},"chemical/x-cmdf":{"source":"apache","extensions":["cmdf"]},"chemical/x-cml":{"source":"apache","extensions":["cml"]},"chemical/x-csml":{"source":"apache","extensions":["csml"]},"chemical/x-pdb":{"source":"apache"},"chemical/x-xyz":{"source":"apache","extensions":["xyz"]},"font/otf":{"compressible":true,"extensions":["otf"]},"image/apng":{"compressible":false,"extensions":["apng"]},"image/bmp":{"source":"iana","compressible":true,"extensions":["bmp"]},"image/cgm":{"source":"iana","extensions":["cgm"]},"image/dicom-rle":{"source":"iana"},"image/emf":{"source":"iana"},"image/fits":{"source":"iana"},"image/g3fax":{"source":"iana","extensions":["g3"]},"image/gif":{"source":"iana","compressible":false,"extensions":["gif"]},"image/ief":{"source":"iana","extensions":["ief"]},"image/jls":{"source":"iana"},"image/jp2":{"source":"iana"},"image/jpeg":{"source":"iana","compressible":false,"extensions":["jpeg","jpg","jpe"]},"image/jpm":{"source":"iana"},"image/jpx":{"source":"iana"},"image/ktx":{"source":"iana","extensions":["ktx"]},"image/naplps":{"source":"iana"},"image/pjpeg":{"compressible":false},"image/png":{"source":"iana","compressible":false,"extensions":["png"]},"image/prs.btif":{"source":"iana","extensions":["btif"]},"image/prs.pti":{"source":"iana"},"image/pwg-raster":{"source":"iana"},"image/sgi":{"source":"apache","extensions":["sgi"]},"image/svg+xml":{"source":"iana","compressible":true,"extensions":["svg","svgz"]},"image/t38":{"source":"iana"},"image/tiff":{"source":"iana","compressible":false,"extensions":["tiff","tif"]},"image/tiff-fx":{"source":"iana"},"image/vnd.adobe.photoshop":{"source":"iana","compressible":true,"extensions":["psd"]},"image/vnd.airzip.accelerator.azv":{"source":"iana"},"image/vnd.cns.inf2":{"source":"iana"},"image/vnd.dece.graphic":{"source":"iana","extensions":["uvi","uvvi","uvg","uvvg"]},"image/vnd.djvu":{"source":"iana","extensions":["djvu","djv"]},"image/vnd.dvb.subtitle":{"source":"iana","extensions":["sub"]},"image/vnd.dwg":{"source":"iana","extensions":["dwg"]},"image/vnd.dxf":{"source":"iana","extensions":["dxf"]},"image/vnd.fastbidsheet":{"source":"iana","extensions":["fbs"]},"image/vnd.fpx":{"source":"iana","extensions":["fpx"]},"image/vnd.fst":{"source":"iana","extensions":["fst"]},"image/vnd.fujixerox.edmics-mmr":{"source":"iana","extensions":["mmr"]},"image/vnd.fujixerox.edmics-rlc":{"source":"iana","extensions":["rlc"]},"image/vnd.globalgraphics.pgb":{"source":"iana"},"image/vnd.microsoft.icon":{"source":"iana"},"image/vnd.mix":{"source":"iana"},"image/vnd.mozilla.apng":{"source":"iana"},"image/vnd.ms-modi":{"source":"iana","extensions":["mdi"]},"image/vnd.ms-photo":{"source":"apache","extensions":["wdp"]},"image/vnd.net-fpx":{"source":"iana","extensions":["npx"]},"image/vnd.radiance":{"source":"iana"},"image/vnd.sealed.png":{"source":"iana"},"image/vnd.sealedmedia.softseal.gif":{"source":"iana"},"image/vnd.sealedmedia.softseal.jpg":{"source":"iana"},"image/vnd.svf":{"source":"iana"},"image/vnd.tencent.tap":{"source":"iana"},"image/vnd.valve.source.texture":{"source":"iana"},"image/vnd.wap.wbmp":{"source":"iana","extensions":["wbmp"]},"image/vnd.xiff":{"source":"iana","extensions":["xif"]},"image/vnd.zbrush.pcx":{"source":"iana"},"image/webp":{"source":"apache","extensions":["webp"]},"image/wmf":{"source":"iana"},"image/x-3ds":{"source":"apache","extensions":["3ds"]},"image/x-cmu-raster":{"source":"apache","extensions":["ras"]},"image/x-cmx":{"source":"apache","extensions":["cmx"]},"image/x-freehand":{"source":"apache","extensions":["fh","fhc","fh4","fh5","fh7"]},"image/x-icon":{"source":"apache","compressible":true,"extensions":["ico"]},"image/x-jng":{"source":"nginx","extensions":["jng"]},"image/x-mrsid-image":{"source":"apache","extensions":["sid"]},"image/x-ms-bmp":{"source":"nginx","compressible":true,"extensions":["bmp"]},"image/x-pcx":{"source":"apache","extensions":["pcx"]},"image/x-pict":{"source":"apache","extensions":["pic","pct"]},"image/x-portable-anymap":{"source":"apache","extensions":["pnm"]},"image/x-portable-bitmap":{"source":"apache","extensions":["pbm"]},"image/x-portable-graymap":{"source":"apache","extensions":["pgm"]},"image/x-portable-pixmap":{"source":"apache","extensions":["ppm"]},"image/x-rgb":{"source":"apache","extensions":["rgb"]},"image/x-tga":{"source":"apache","extensions":["tga"]},"image/x-xbitmap":{"source":"apache","extensions":["xbm"]},"image/x-xcf":{"compressible":false},"image/x-xpixmap":{"source":"apache","extensions":["xpm"]},"image/x-xwindowdump":{"source":"apache","extensions":["xwd"]},"message/cpim":{"source":"iana"},"message/delivery-status":{"source":"iana"},"message/disposition-notification":{"source":"iana"},"message/external-body":{"source":"iana"},"message/feedback-report":{"source":"iana"},"message/global":{"source":"iana"},"message/global-delivery-status":{"source":"iana"},"message/global-disposition-notification":{"source":"iana"},"message/global-headers":{"source":"iana"},"message/http":{"source":"iana","compressible":false},"message/imdn+xml":{"source":"iana","compressible":true},"message/news":{"source":"iana"},"message/partial":{"source":"iana","compressible":false},"message/rfc822":{"source":"iana","compressible":true,"extensions":["eml","mime"]},"message/s-http":{"source":"iana"},"message/sip":{"source":"iana"},"message/sipfrag":{"source":"iana"},"message/tracking-status":{"source":"iana"},"message/vnd.si.simp":{"source":"iana"},"message/vnd.wfa.wsc":{"source":"iana"},"model/3mf":{"source":"iana"},"model/gltf+json":{"source":"iana","compressible":true,"extensions":["gltf"]},"model/gltf-binary":{"compressible":true,"extensions":["glb"]},"model/iges":{"source":"iana","compressible":false,"extensions":["igs","iges"]},"model/mesh":{"source":"iana","compressible":false,"extensions":["msh","mesh","silo"]},"model/vnd.collada+xml":{"source":"iana","extensions":["dae"]},"model/vnd.dwf":{"source":"iana","extensions":["dwf"]},"model/vnd.flatland.3dml":{"source":"iana"},"model/vnd.gdl":{"source":"iana","extensions":["gdl"]},"model/vnd.gs-gdl":{"source":"apache"},"model/vnd.gs.gdl":{"source":"iana"},"model/vnd.gtw":{"source":"iana","extensions":["gtw"]},"model/vnd.moml+xml":{"source":"iana"},"model/vnd.mts":{"source":"iana","extensions":["mts"]},"model/vnd.opengex":{"source":"iana"},"model/vnd.parasolid.transmit.binary":{"source":"iana"},"model/vnd.parasolid.transmit.text":{"source":"iana"},"model/vnd.rosette.annotated-data-model":{"source":"iana"},"model/vnd.valve.source.compiled-map":{"source":"iana"},"model/vnd.vtu":{"source":"iana","extensions":["vtu"]},"model/vrml":{"source":"iana","compressible":false,"extensions":["wrl","vrml"]},"model/x3d+binary":{"source":"apache","compressible":false,"extensions":["x3db","x3dbz"]},"model/x3d+fastinfoset":{"source":"iana"},"model/x3d+vrml":{"source":"apache","compressible":false,"extensions":["x3dv","x3dvz"]},"model/x3d+xml":{"source":"iana","compressible":true,"extensions":["x3d","x3dz"]},"model/x3d-vrml":{"source":"iana"},"multipart/alternative":{"source":"iana","compressible":false},"multipart/appledouble":{"source":"iana"},"multipart/byteranges":{"source":"iana"},"multipart/digest":{"source":"iana"},"multipart/encrypted":{"source":"iana","compressible":false},"multipart/form-data":{"source":"iana","compressible":false},"multipart/header-set":{"source":"iana"},"multipart/mixed":{"source":"iana","compressible":false},"multipart/parallel":{"source":"iana"},"multipart/related":{"source":"iana","compressible":false},"multipart/report":{"source":"iana"},"multipart/signed":{"source":"iana","compressible":false},"multipart/vnd.bint.med-plus":{"source":"iana"},"multipart/voice-message":{"source":"iana"},"multipart/x-mixed-replace":{"source":"iana"},"text/1d-interleaved-parityfec":{"source":"iana"},"text/cache-manifest":{"source":"iana","compressible":true,"extensions":["appcache","manifest"]},"text/calendar":{"source":"iana","extensions":["ics","ifb"]},"text/calender":{"compressible":true},"text/cmd":{"compressible":true},"text/coffeescript":{"extensions":["coffee","litcoffee"]},"text/css":{"source":"iana","charset":"UTF-8","compressible":true,"extensions":["css"]},"text/csv":{"source":"iana","compressible":true,"extensions":["csv"]},"text/csv-schema":{"source":"iana"},"text/directory":{"source":"iana"},"text/dns":{"source":"iana"},"text/ecmascript":{"source":"iana"},"text/encaprtp":{"source":"iana"},"text/enriched":{"source":"iana"},"text/fwdred":{"source":"iana"},"text/grammar-ref-list":{"source":"iana"},"text/hjson":{"extensions":["hjson"]},"text/html":{"source":"iana","compressible":true,"extensions":["html","htm","shtml"]},"text/jade":{"extensions":["jade"]},"text/javascript":{"source":"iana","compressible":true},"text/jcr-cnd":{"source":"iana"},"text/jsx":{"compressible":true,"extensions":["jsx"]},"text/less":{"extensions":["less"]},"text/markdown":{"source":"iana","compressible":true,"extensions":["markdown","md"]},"text/mathml":{"source":"nginx","extensions":["mml"]},"text/mizar":{"source":"iana"},"text/n3":{"source":"iana","compressible":true,"extensions":["n3"]},"text/parameters":{"source":"iana"},"text/parityfec":{"source":"iana"},"text/plain":{"source":"iana","compressible":true,"extensions":["txt","text","conf","def","list","log","in","ini"]},"text/provenance-notation":{"source":"iana"},"text/prs.fallenstein.rst":{"source":"iana"},"text/prs.lines.tag":{"source":"iana","extensions":["dsc"]},"text/prs.prop.logic":{"source":"iana"},"text/raptorfec":{"source":"iana"},"text/red":{"source":"iana"},"text/rfc822-headers":{"source":"iana"},"text/richtext":{"source":"iana","compressible":true,"extensions":["rtx"]},"text/rtf":{"source":"iana","compressible":true,"extensions":["rtf"]},"text/rtp-enc-aescm128":{"source":"iana"},"text/rtploopback":{"source":"iana"},"text/rtx":{"source":"iana"},"text/sgml":{"source":"iana","extensions":["sgml","sgm"]},"text/slim":{"extensions":["slim","slm"]},"text/strings":{"source":"iana"},"text/stylus":{"extensions":["stylus","styl"]},"text/t140":{"source":"iana"},"text/tab-separated-values":{"source":"iana","compressible":true,"extensions":["tsv"]},"text/troff":{"source":"iana","extensions":["t","tr","roff","man","me","ms"]},"text/turtle":{"source":"iana","extensions":["ttl"]},"text/ulpfec":{"source":"iana"},"text/uri-list":{"source":"iana","compressible":true,"extensions":["uri","uris","urls"]},"text/vcard":{"source":"iana","compressible":true,"extensions":["vcard"]},"text/vnd.a":{"source":"iana"},"text/vnd.abc":{"source":"iana"},"text/vnd.ascii-art":{"source":"iana"},"text/vnd.curl":{"source":"iana","extensions":["curl"]},"text/vnd.curl.dcurl":{"source":"apache","extensions":["dcurl"]},"text/vnd.curl.mcurl":{"source":"apache","extensions":["mcurl"]},"text/vnd.curl.scurl":{"source":"apache","extensions":["scurl"]},"text/vnd.debian.copyright":{"source":"iana"},"text/vnd.dmclientscript":{"source":"iana"},"text/vnd.dvb.subtitle":{"source":"iana","extensions":["sub"]},"text/vnd.esmertec.theme-descriptor":{"source":"iana"},"text/vnd.fly":{"source":"iana","extensions":["fly"]},"text/vnd.fmi.flexstor":{"source":"iana","extensions":["flx"]},"text/vnd.graphviz":{"source":"iana","extensions":["gv"]},"text/vnd.in3d.3dml":{"source":"iana","extensions":["3dml"]},"text/vnd.in3d.spot":{"source":"iana","extensions":["spot"]},"text/vnd.iptc.newsml":{"source":"iana"},"text/vnd.iptc.nitf":{"source":"iana"},"text/vnd.latex-z":{"source":"iana"},"text/vnd.motorola.reflex":{"source":"iana"},"text/vnd.ms-mediapackage":{"source":"iana"},"text/vnd.net2phone.commcenter.command":{"source":"iana"},"text/vnd.radisys.msml-basic-layout":{"source":"iana"},"text/vnd.si.uricatalogue":{"source":"iana"},"text/vnd.sun.j2me.app-descriptor":{"source":"iana","extensions":["jad"]},"text/vnd.trolltech.linguist":{"source":"iana"},"text/vnd.wap.si":{"source":"iana"},"text/vnd.wap.sl":{"source":"iana"},"text/vnd.wap.wml":{"source":"iana","extensions":["wml"]},"text/vnd.wap.wmlscript":{"source":"iana","extensions":["wmls"]},"text/vtt":{"charset":"UTF-8","compressible":true,"extensions":["vtt"]},"text/x-asm":{"source":"apache","extensions":["s","asm"]},"text/x-c":{"source":"apache","extensions":["c","cc","cxx","cpp","h","hh","dic"]},"text/x-component":{"source":"nginx","extensions":["htc"]},"text/x-fortran":{"source":"apache","extensions":["f","for","f77","f90"]},"text/x-gwt-rpc":{"compressible":true},"text/x-handlebars-template":{"extensions":["hbs"]},"text/x-java-source":{"source":"apache","extensions":["java"]},"text/x-jquery-tmpl":{"compressible":true},"text/x-lua":{"extensions":["lua"]},"text/x-markdown":{"compressible":true,"extensions":["mkd"]},"text/x-nfo":{"source":"apache","extensions":["nfo"]},"text/x-opml":{"source":"apache","extensions":["opml"]},"text/x-org":{"compressible":true,"extensions":["org"]},"text/x-pascal":{"source":"apache","extensions":["p","pas"]},"text/x-processing":{"compressible":true,"extensions":["pde"]},"text/x-sass":{"extensions":["sass"]},"text/x-scss":{"extensions":["scss"]},"text/x-setext":{"source":"apache","extensions":["etx"]},"text/x-sfv":{"source":"apache","extensions":["sfv"]},"text/x-suse-ymp":{"compressible":true,"extensions":["ymp"]},"text/x-uuencode":{"source":"apache","extensions":["uu"]},"text/x-vcalendar":{"source":"apache","extensions":["vcs"]},"text/x-vcard":{"source":"apache","extensions":["vcf"]},"text/xml":{"source":"iana","compressible":true,"extensions":["xml"]},"text/xml-external-parsed-entity":{"source":"iana"},"text/yaml":{"extensions":["yaml","yml"]},"video/1d-interleaved-parityfec":{"source":"iana"},"video/3gpp":{"source":"iana","extensions":["3gp","3gpp"]},"video/3gpp-tt":{"source":"iana"},"video/3gpp2":{"source":"iana","extensions":["3g2"]},"video/bmpeg":{"source":"iana"},"video/bt656":{"source":"iana"},"video/celb":{"source":"iana"},"video/dv":{"source":"iana"},"video/encaprtp":{"source":"iana"},"video/h261":{"source":"iana","extensions":["h261"]},"video/h263":{"source":"iana","extensions":["h263"]},"video/h263-1998":{"source":"iana"},"video/h263-2000":{"source":"iana"},"video/h264":{"source":"iana","extensions":["h264"]},"video/h264-rcdo":{"source":"iana"},"video/h264-svc":{"source":"iana"},"video/h265":{"source":"iana"},"video/iso.segment":{"source":"iana"},"video/jpeg":{"source":"iana","extensions":["jpgv"]},"video/jpeg2000":{"source":"iana"},"video/jpm":{"source":"apache","extensions":["jpm","jpgm"]},"video/mj2":{"source":"iana","extensions":["mj2","mjp2"]},"video/mp1s":{"source":"iana"},"video/mp2p":{"source":"iana"},"video/mp2t":{"source":"iana","extensions":["ts"]},"video/mp4":{"source":"iana","compressible":false,"extensions":["mp4","mp4v","mpg4"]},"video/mp4v-es":{"source":"iana"},"video/mpeg":{"source":"iana","compressible":false,"extensions":["mpeg","mpg","mpe","m1v","m2v"]},"video/mpeg4-generic":{"source":"iana"},"video/mpv":{"source":"iana"},"video/nv":{"source":"iana"},"video/ogg":{"source":"iana","compressible":false,"extensions":["ogv"]},"video/parityfec":{"source":"iana"},"video/pointer":{"source":"iana"},"video/quicktime":{"source":"iana","compressible":false,"extensions":["qt","mov"]},"video/raptorfec":{"source":"iana"},"video/raw":{"source":"iana"},"video/rtp-enc-aescm128":{"source":"iana"},"video/rtploopback":{"source":"iana"},"video/rtx":{"source":"iana"},"video/smpte292m":{"source":"iana"},"video/ulpfec":{"source":"iana"},"video/vc1":{"source":"iana"},"video/vnd.cctv":{"source":"iana"},"video/vnd.dece.hd":{"source":"iana","extensions":["uvh","uvvh"]},"video/vnd.dece.mobile":{"source":"iana","extensions":["uvm","uvvm"]},"video/vnd.dece.mp4":{"source":"iana"},"video/vnd.dece.pd":{"source":"iana","extensions":["uvp","uvvp"]},"video/vnd.dece.sd":{"source":"iana","extensions":["uvs","uvvs"]},"video/vnd.dece.video":{"source":"iana","extensions":["uvv","uvvv"]},"video/vnd.directv.mpeg":{"source":"iana"},"video/vnd.directv.mpeg-tts":{"source":"iana"},"video/vnd.dlna.mpeg-tts":{"source":"iana"},"video/vnd.dvb.file":{"source":"iana","extensions":["dvb"]},"video/vnd.fvt":{"source":"iana","extensions":["fvt"]},"video/vnd.hns.video":{"source":"iana"},"video/vnd.iptvforum.1dparityfec-1010":{"source":"iana"},"video/vnd.iptvforum.1dparityfec-2005":{"source":"iana"},"video/vnd.iptvforum.2dparityfec-1010":{"source":"iana"},"video/vnd.iptvforum.2dparityfec-2005":{"source":"iana"},"video/vnd.iptvforum.ttsavc":{"source":"iana"},"video/vnd.iptvforum.ttsmpeg2":{"source":"iana"},"video/vnd.motorola.video":{"source":"iana"},"video/vnd.motorola.videop":{"source":"iana"},"video/vnd.mpegurl":{"source":"iana","extensions":["mxu","m4u"]},"video/vnd.ms-playready.media.pyv":{"source":"iana","extensions":["pyv"]},"video/vnd.nokia.interleaved-multimedia":{"source":"iana"},"video/vnd.nokia.videovoip":{"source":"iana"},"video/vnd.objectvideo":{"source":"iana"},"video/vnd.radgamettools.bink":{"source":"iana"},"video/vnd.radgamettools.smacker":{"source":"iana"},"video/vnd.sealed.mpeg1":{"source":"iana"},"video/vnd.sealed.mpeg4":{"source":"iana"},"video/vnd.sealed.swf":{"source":"iana"},"video/vnd.sealedmedia.softseal.mov":{"source":"iana"},"video/vnd.uvvu.mp4":{"source":"iana","extensions":["uvu","uvvu"]},"video/vnd.vivo":{"source":"iana","extensions":["viv"]},"video/vp8":{"source":"iana"},"video/webm":{"source":"apache","compressible":false,"extensions":["webm"]},"video/x-f4v":{"source":"apache","extensions":["f4v"]},"video/x-fli":{"source":"apache","extensions":["fli"]},"video/x-flv":{"source":"apache","compressible":false,"extensions":["flv"]},"video/x-m4v":{"source":"apache","extensions":["m4v"]},"video/x-matroska":{"source":"apache","compressible":false,"extensions":["mkv","mk3d","mks"]},"video/x-mng":{"source":"apache","extensions":["mng"]},"video/x-ms-asf":{"source":"apache","extensions":["asf","asx"]},"video/x-ms-vob":{"source":"apache","extensions":["vob"]},"video/x-ms-wm":{"source":"apache","extensions":["wm"]},"video/x-ms-wmv":{"source":"apache","compressible":false,"extensions":["wmv"]},"video/x-ms-wmx":{"source":"apache","extensions":["wmx"]},"video/x-ms-wvx":{"source":"apache","extensions":["wvx"]},"video/x-msvideo":{"source":"apache","extensions":["avi"]},"video/x-sgi-movie":{"source":"apache","extensions":["movie"]},"video/x-smv":{"source":"apache","extensions":["smv"]},"x-conference/x-cooltalk":{"source":"apache","extensions":["ice"]},"x-shader/x-fragment":{"compressible":true},"x-shader/x-vertex":{"compressible":true}} - -/***/ }), -/* 153 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// resolves . and .. elements in a path array with directory names there -// must be no slashes, empty elements, or device names (c:\) in the array -// (so also no leading and trailing slashes - it does not distinguish -// relative and absolute paths) -function normalizeArray(parts, allowAboveRoot) { - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up--; up) { - parts.unshift('..'); - } - } - - return parts; -} - -// Split a filename into [root, dir, basename, ext], unix version -// 'root' is just a slash, or nothing. -var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; -var splitPath = function(filename) { - return splitPathRe.exec(filename).slice(1); -}; - -// path.resolve([from ...], to) -// posix version -exports.resolve = function() { - var resolvedPath = '', - resolvedAbsolute = false; - - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) ? arguments[i] : process.cwd(); - - // Skip empty and invalid entries - if (typeof path !== 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); - } else if (!path) { - continue; - } - - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charAt(0) === '/'; - } - - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) - - // Normalize the path - resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { - return !!p; - }), !resolvedAbsolute).join('/'); - - return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; -}; - -// path.normalize(path) -// posix version -exports.normalize = function(path) { - var isAbsolute = exports.isAbsolute(path), - trailingSlash = substr(path, -1) === '/'; - - // Normalize the path - path = normalizeArray(filter(path.split('/'), function(p) { - return !!p; - }), !isAbsolute).join('/'); - - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; - } - - return (isAbsolute ? '/' : '') + path; -}; - -// posix version -exports.isAbsolute = function(path) { - return path.charAt(0) === '/'; -}; - -// posix version -exports.join = function() { - var paths = Array.prototype.slice.call(arguments, 0); - return exports.normalize(filter(paths, function(p, index) { - if (typeof p !== 'string') { - throw new TypeError('Arguments to path.join must be strings'); - } - return p; - }).join('/')); -}; - - -// path.relative(from, to) -// posix version -exports.relative = function(from, to) { - from = exports.resolve(from).substr(1); - to = exports.resolve(to).substr(1); - - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - - if (start > end) return []; - return arr.slice(start, end - start + 1); - } - - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); - - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - - return outputParts.join('/'); -}; - -exports.sep = '/'; -exports.delimiter = ':'; - -exports.dirname = function(path) { - var result = splitPath(path), - root = result[0], - dir = result[1]; - - if (!root && !dir) { - // No dirname whatsoever - return '.'; - } - - if (dir) { - // It has a dirname, strip trailing slash - dir = dir.substr(0, dir.length - 1); - } - - return root + dir; -}; - - -exports.basename = function(path, ext) { - var f = splitPath(path)[2]; - // TODO: make this comparison case-insensitive on windows? - if (ext && f.substr(-1 * ext.length) === ext) { - f = f.substr(0, f.length - ext.length); - } - return f; -}; - - -exports.extname = function(path) { - return splitPath(path)[3]; -}; - -function filter (xs, f) { - if (xs.filter) return xs.filter(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - if (f(xs[i], i, xs)) res.push(xs[i]); - } - return res; -} - -// String.prototype.substr - negative index don't work in IE8 -var substr = 'ab'.substr(-1) === 'b' - ? function (str, start, len) { return str.substr(start, len) } - : function (str, start, len) { - if (start < 0) start = str.length + start; - return str.substr(start, len); - } -; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(154))) - -/***/ }), -/* 154 */ -/***/ (function(module, exports) { - -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - - -/***/ }), -/* 155 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = (function (file, fileName) { - saveAs(file, fileName); -}); - -/***/ }), -/* 156 */ -/***/ (function(module, exports) { - -/** - * @module zrender/core/util - */ -// 用于处理merge时无法遍历Date等对象的问题 -var BUILTIN_OBJECT = { - '[object Function]': 1, - '[object RegExp]': 1, - '[object Date]': 1, - '[object Error]': 1, - '[object CanvasGradient]': 1, - '[object CanvasPattern]': 1, - // For node-canvas - '[object Image]': 1, - '[object Canvas]': 1 -}; -var TYPED_ARRAY = { - '[object Int8Array]': 1, - '[object Uint8Array]': 1, - '[object Uint8ClampedArray]': 1, - '[object Int16Array]': 1, - '[object Uint16Array]': 1, - '[object Int32Array]': 1, - '[object Uint32Array]': 1, - '[object Float32Array]': 1, - '[object Float64Array]': 1 -}; -var objToString = Object.prototype.toString; -var arrayProto = Array.prototype; -var nativeForEach = arrayProto.forEach; -var nativeFilter = arrayProto.filter; -var nativeSlice = arrayProto.slice; -var nativeMap = arrayProto.map; -var nativeReduce = arrayProto.reduce; -/** - * Those data types can be cloned: - * Plain object, Array, TypedArray, number, string, null, undefined. - * Those data types will be assgined using the orginal data: - * BUILTIN_OBJECT - * Instance of user defined class will be cloned to a plain object, without - * properties in prototype. - * Other data types is not supported (not sure what will happen). - * - * Caution: do not support clone Date, for performance consideration. - * (There might be a large number of date in `series.data`). - * So date should not be modified in and out of echarts. - * - * @param {*} source - * @return {*} new - */ - -function clone(source) { - if (source == null || typeof source != 'object') { - return source; - } - - var result = source; - var typeStr = objToString.call(source); - - if (typeStr === '[object Array]') { - result = []; - - for (var i = 0, len = source.length; i < len; i++) { - result[i] = clone(source[i]); - } - } else if (TYPED_ARRAY[typeStr]) { - var Ctor = source.constructor; - - if (source.constructor.from) { - result = Ctor.from(source); - } else { - result = new Ctor(source.length); - - for (var i = 0, len = source.length; i < len; i++) { - result[i] = clone(source[i]); - } - } - } else if (!BUILTIN_OBJECT[typeStr] && !isPrimitive(source) && !isDom(source)) { - result = {}; - - for (var key in source) { - if (source.hasOwnProperty(key)) { - result[key] = clone(source[key]); - } - } - } - - return result; -} -/** - * @memberOf module:zrender/core/util - * @param {*} target - * @param {*} source - * @param {boolean} [overwrite=false] - */ - - -function merge(target, source, overwrite) { - // We should escapse that source is string - // and enter for ... in ... - if (!isObject(source) || !isObject(target)) { - return overwrite ? clone(source) : target; - } - - for (var key in source) { - if (source.hasOwnProperty(key)) { - var targetProp = target[key]; - var sourceProp = source[key]; - - if (isObject(sourceProp) && isObject(targetProp) && !isArray(sourceProp) && !isArray(targetProp) && !isDom(sourceProp) && !isDom(targetProp) && !isBuiltInObject(sourceProp) && !isBuiltInObject(targetProp) && !isPrimitive(sourceProp) && !isPrimitive(targetProp)) { - // 如果需要递归覆盖,就递归调用merge - merge(targetProp, sourceProp, overwrite); - } else if (overwrite || !(key in target)) { - // 否则只处理overwrite为true,或者在目标对象中没有此属性的情况 - // NOTE,在 target[key] 不存在的时候也是直接覆盖 - target[key] = clone(source[key], true); - } - } - } - - return target; -} -/** - * @param {Array} targetAndSources The first item is target, and the rests are source. - * @param {boolean} [overwrite=false] - * @return {*} target - */ - - -function mergeAll(targetAndSources, overwrite) { - var result = targetAndSources[0]; - - for (var i = 1, len = targetAndSources.length; i < len; i++) { - result = merge(result, targetAndSources[i], overwrite); - } - - return result; -} -/** - * @param {*} target - * @param {*} source - * @memberOf module:zrender/core/util - */ - - -function extend(target, source) { - for (var key in source) { - if (source.hasOwnProperty(key)) { - target[key] = source[key]; - } - } - - return target; -} -/** - * @param {*} target - * @param {*} source - * @param {boolean} [overlay=false] - * @memberOf module:zrender/core/util - */ - - -function defaults(target, source, overlay) { - for (var key in source) { - if (source.hasOwnProperty(key) && (overlay ? source[key] != null : target[key] == null)) { - target[key] = source[key]; - } - } - - return target; -} - -var createCanvas = function () { - return document.createElement('canvas'); -}; // FIXME - - -var _ctx; - -function getContext() { - if (!_ctx) { - // Use util.createCanvas instead of createCanvas - // because createCanvas may be overwritten in different environment - _ctx = createCanvas().getContext('2d'); - } - - return _ctx; -} -/** - * 查询数组中元素的index - * @memberOf module:zrender/core/util - */ - - -function indexOf(array, value) { - if (array) { - if (array.indexOf) { - return array.indexOf(value); - } - - for (var i = 0, len = array.length; i < len; i++) { - if (array[i] === value) { - return i; - } - } - } - - return -1; -} -/** - * 构造类继承关系 - * - * @memberOf module:zrender/core/util - * @param {Function} clazz 源类 - * @param {Function} baseClazz 基类 - */ - - -function inherits(clazz, baseClazz) { - var clazzPrototype = clazz.prototype; - - function F() {} - - F.prototype = baseClazz.prototype; - clazz.prototype = new F(); - - for (var prop in clazzPrototype) { - clazz.prototype[prop] = clazzPrototype[prop]; - } - - clazz.prototype.constructor = clazz; - clazz.superClass = baseClazz; -} -/** - * @memberOf module:zrender/core/util - * @param {Object|Function} target - * @param {Object|Function} sorce - * @param {boolean} overlay - */ - - -function mixin(target, source, overlay) { - target = 'prototype' in target ? target.prototype : target; - source = 'prototype' in source ? source.prototype : source; - defaults(target, source, overlay); -} -/** - * Consider typed array. - * @param {Array|TypedArray} data - */ - - -function isArrayLike(data) { - if (!data) { - return; - } - - if (typeof data == 'string') { - return false; - } - - return typeof data.length == 'number'; -} -/** - * 数组或对象遍历 - * @memberOf module:zrender/core/util - * @param {Object|Array} obj - * @param {Function} cb - * @param {*} [context] - */ - - -function each(obj, cb, context) { - if (!(obj && cb)) { - return; - } - - if (obj.forEach && obj.forEach === nativeForEach) { - obj.forEach(cb, context); - } else if (obj.length === +obj.length) { - for (var i = 0, len = obj.length; i < len; i++) { - cb.call(context, obj[i], i, obj); - } - } else { - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - cb.call(context, obj[key], key, obj); - } - } - } -} -/** - * 数组映射 - * @memberOf module:zrender/core/util - * @param {Array} obj - * @param {Function} cb - * @param {*} [context] - * @return {Array} - */ - - -function map(obj, cb, context) { - if (!(obj && cb)) { - return; - } - - if (obj.map && obj.map === nativeMap) { - return obj.map(cb, context); - } else { - var result = []; - - for (var i = 0, len = obj.length; i < len; i++) { - result.push(cb.call(context, obj[i], i, obj)); - } - - return result; - } -} -/** - * @memberOf module:zrender/core/util - * @param {Array} obj - * @param {Function} cb - * @param {Object} [memo] - * @param {*} [context] - * @return {Array} - */ - - -function reduce(obj, cb, memo, context) { - if (!(obj && cb)) { - return; - } - - if (obj.reduce && obj.reduce === nativeReduce) { - return obj.reduce(cb, memo, context); - } else { - for (var i = 0, len = obj.length; i < len; i++) { - memo = cb.call(context, memo, obj[i], i, obj); - } - - return memo; - } -} -/** - * 数组过滤 - * @memberOf module:zrender/core/util - * @param {Array} obj - * @param {Function} cb - * @param {*} [context] - * @return {Array} - */ - - -function filter(obj, cb, context) { - if (!(obj && cb)) { - return; - } - - if (obj.filter && obj.filter === nativeFilter) { - return obj.filter(cb, context); - } else { - var result = []; - - for (var i = 0, len = obj.length; i < len; i++) { - if (cb.call(context, obj[i], i, obj)) { - result.push(obj[i]); - } - } - - return result; - } -} -/** - * 数组项查找 - * @memberOf module:zrender/core/util - * @param {Array} obj - * @param {Function} cb - * @param {*} [context] - * @return {*} - */ - - -function find(obj, cb, context) { - if (!(obj && cb)) { - return; - } - - for (var i = 0, len = obj.length; i < len; i++) { - if (cb.call(context, obj[i], i, obj)) { - return obj[i]; - } - } -} -/** - * @memberOf module:zrender/core/util - * @param {Function} func - * @param {*} context - * @return {Function} - */ - - -function bind(func, context) { - var args = nativeSlice.call(arguments, 2); - return function () { - return func.apply(context, args.concat(nativeSlice.call(arguments))); - }; -} -/** - * @memberOf module:zrender/core/util - * @param {Function} func - * @return {Function} - */ - - -function curry(func) { - var args = nativeSlice.call(arguments, 1); - return function () { - return func.apply(this, args.concat(nativeSlice.call(arguments))); - }; -} -/** - * @memberOf module:zrender/core/util - * @param {*} value - * @return {boolean} - */ - - -function isArray(value) { - return objToString.call(value) === '[object Array]'; -} -/** - * @memberOf module:zrender/core/util - * @param {*} value - * @return {boolean} - */ - - -function isFunction(value) { - return typeof value === 'function'; -} -/** - * @memberOf module:zrender/core/util - * @param {*} value - * @return {boolean} - */ - - -function isString(value) { - return objToString.call(value) === '[object String]'; -} -/** - * @memberOf module:zrender/core/util - * @param {*} value - * @return {boolean} - */ - - -function isObject(value) { - // Avoid a V8 JIT bug in Chrome 19-20. - // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. - var type = typeof value; - return type === 'function' || !!value && type == 'object'; -} -/** - * @memberOf module:zrender/core/util - * @param {*} value - * @return {boolean} - */ - - -function isBuiltInObject(value) { - return !!BUILTIN_OBJECT[objToString.call(value)]; -} -/** - * @memberOf module:zrender/core/util - * @param {*} value - * @return {boolean} - */ - - -function isDom(value) { - return typeof value === 'object' && typeof value.nodeType === 'number' && typeof value.ownerDocument === 'object'; -} -/** - * Whether is exactly NaN. Notice isNaN('a') returns true. - * @param {*} value - * @return {boolean} - */ - - -function eqNaN(value) { - return value !== value; -} -/** - * If value1 is not null, then return value1, otherwise judget rest of values. - * Low performance. - * @memberOf module:zrender/core/util - * @return {*} Final value - */ - - -function retrieve(values) { - for (var i = 0, len = arguments.length; i < len; i++) { - if (arguments[i] != null) { - return arguments[i]; - } - } -} - -function retrieve2(value0, value1) { - return value0 != null ? value0 : value1; -} - -function retrieve3(value0, value1, value2) { - return value0 != null ? value0 : value1 != null ? value1 : value2; -} -/** - * @memberOf module:zrender/core/util - * @param {Array} arr - * @param {number} startIndex - * @param {number} endIndex - * @return {Array} - */ - - -function slice() { - return Function.call.apply(nativeSlice, arguments); -} -/** - * Normalize css liked array configuration - * e.g. - * 3 => [3, 3, 3, 3] - * [4, 2] => [4, 2, 4, 2] - * [4, 3, 2] => [4, 3, 2, 3] - * @param {number|Array.} val - * @return {Array.} - */ - - -function normalizeCssArray(val) { - if (typeof val === 'number') { - return [val, val, val, val]; - } - - var len = val.length; - - if (len === 2) { - // vertical | horizontal - return [val[0], val[1], val[0], val[1]]; - } else if (len === 3) { - // top | horizontal | bottom - return [val[0], val[1], val[2], val[1]]; - } - - return val; -} -/** - * @memberOf module:zrender/core/util - * @param {boolean} condition - * @param {string} message - */ - - -function assert(condition, message) { - if (!condition) { - throw new Error(message); - } -} - -var primitiveKey = '__ec_primitive__'; -/** - * Set an object as primitive to be ignored traversing children in clone or merge - */ - -function setAsPrimitive(obj) { - obj[primitiveKey] = true; -} - -function isPrimitive(obj) { - return obj[primitiveKey]; -} -/** - * @constructor - * @param {Object} obj Only apply `ownProperty`. - */ - - -function HashMap(obj) { - obj && each(obj, function (value, key) { - this.set(key, value); - }, this); -} // Add prefix to avoid conflict with Object.prototype. - - -var HASH_MAP_PREFIX = '_ec_'; -var HASH_MAP_PREFIX_LENGTH = 4; -HashMap.prototype = { - constructor: HashMap, - // Do not provide `has` method to avoid defining what is `has`. - // (We usually treat `null` and `undefined` as the same, different - // from ES6 Map). - get: function (key) { - return this[HASH_MAP_PREFIX + key]; - }, - set: function (key, value) { - this[HASH_MAP_PREFIX + key] = value; // Comparing with invocation chaining, `return value` is more commonly - // used in this case: `var someVal = map.set('a', genVal());` - - return value; - }, - // Although util.each can be performed on this hashMap directly, user - // should not use the exposed keys, who are prefixed. - each: function (cb, context) { - context !== void 0 && (cb = bind(cb, context)); - - for (var prefixedKey in this) { - this.hasOwnProperty(prefixedKey) && cb(this[prefixedKey], prefixedKey.slice(HASH_MAP_PREFIX_LENGTH)); - } - }, - // Do not use this method if performance sensitive. - removeKey: function (key) { - delete this[HASH_MAP_PREFIX + key]; - } -}; - -function createHashMap(obj) { - return new HashMap(obj); -} - -function noop() {} - -var $inject = { - createCanvas: function (f) { - createCanvas = f; - exports.createCanvas = f; - } -}; -exports.clone = clone; -exports.merge = merge; -exports.mergeAll = mergeAll; -exports.extend = extend; -exports.defaults = defaults; -exports.createCanvas = createCanvas; -exports.getContext = getContext; -exports.indexOf = indexOf; -exports.inherits = inherits; -exports.mixin = mixin; -exports.isArrayLike = isArrayLike; -exports.each = each; -exports.map = map; -exports.reduce = reduce; -exports.filter = filter; -exports.find = find; -exports.bind = bind; -exports.curry = curry; -exports.isArray = isArray; -exports.isFunction = isFunction; -exports.isString = isString; -exports.isObject = isObject; -exports.isBuiltInObject = isBuiltInObject; -exports.isDom = isDom; -exports.eqNaN = eqNaN; -exports.retrieve = retrieve; -exports.retrieve2 = retrieve2; -exports.retrieve3 = retrieve3; -exports.slice = slice; -exports.normalizeCssArray = normalizeCssArray; -exports.assert = assert; -exports.setAsPrimitive = setAsPrimitive; -exports.isPrimitive = isPrimitive; -exports.createHashMap = createHashMap; -exports.noop = noop; -exports.$inject = $inject; - -/***/ }), -/* 157 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -function TextureUI(parent, object, key, params) { - ControlKit.ObjectComponent.apply(this, arguments); - - this._object = object; - this._key = key; - - this._onChange = params.onChange || function () {}; - this._getFileNameByURL = params.getFileName || function (url) { return url; }; - - var self = this; - - var wrap = this._wrapNode; - wrap.setStyleClass('texture-wrap'); - - var img = document.createElement('img'); - var deleteEl = document.createElement('div'); - deleteEl.className = 'texture-delete button'; - var uploadEl = document.createElement('div'); - uploadEl.className = 'texture-upload button'; - - this._img = img; - this._uploadEl = uploadEl; - - wrap.getElement().appendChild(img); - wrap.getElement().appendChild(uploadEl); - wrap.getElement().appendChild(deleteEl); - - this.update(); - - var liEl = this._wrapNode.getParent().getElement(); - - function uploadFiles(files) { - var imgFile = files.filter(function (file) { - return file.type.match(/image/); - })[0]; - - if (imgFile) { - object[key] = URL.createObjectURL(imgFile); - - self._onChange(imgFile, object[key]); - - self.update(); - } - } - FileAPI.event.dnd(liEl, function (over) { - over ? liEl.classList.add('drag-hover') - : liEl.classList.remove('drag-hover'); - }, function (files) { - uploadFiles(files); - }); - - // Clear - deleteEl.addEventListener('click', function () { - object[key] = 'none'; - self.update(); - self._onChange(null, 'none'); - }); - uploadEl.addEventListener('click', function () { - var el = document.createElement('input'); - el.type = 'file'; - el.onchange = function (e) { - uploadFiles(Array.prototype.slice.call(el.files)); - }; - el.click(); - }); -} - -TextureUI.prototype = Object.create(ControlKit.ObjectComponent.prototype); -TextureUI.prototype.constructor = TextureUI; - -TextureUI.prototype.update = function () { - var value = this._object[this._key]; - this._img.src = value && value.toLowerCase() !== 'none' ? value : './img/chessboard.jpg'; - this._img.style.opacity = (value && value != 'none') ? 1 : 0.5; - - var text = this._getFileNameByURL(value) || value || 'none';; - this._uploadEl.innerHTML = text; - this._uploadEl.title = text; -}; - - -/* harmony default export */ __webpack_exports__["a"] = (TextureUI); - -/***/ }), -/* 158 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_claygl_src_Texture2D__ = __webpack_require__(5); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1_claygl_src_Texture__ = __webpack_require__(3); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2_claygl_src_compositor_Pass__ = __webpack_require__(13); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_3_claygl_src_Shader__ = __webpack_require__(4); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_4_claygl_src_FrameBuffer__ = __webpack_require__(11); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_5_claygl_src_Material__ = __webpack_require__(10); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__edge_glsl_js__ = __webpack_require__(159); - - - - - - - - -__WEBPACK_IMPORTED_MODULE_3_claygl_src_Shader__["a" /* default */]['import'](__WEBPACK_IMPORTED_MODULE_6__edge_glsl_js__["a" /* default */]); - -var texture = new __WEBPACK_IMPORTED_MODULE_0_claygl_src_Texture2D__["a" /* default */](); -var framebuffer = new __WEBPACK_IMPORTED_MODULE_4_claygl_src_FrameBuffer__["a" /* default */](); -framebuffer.attach(texture); - -var edgePass = new __WEBPACK_IMPORTED_MODULE_2_claygl_src_compositor_Pass__["a" /* default */]({ - fragment: __WEBPACK_IMPORTED_MODULE_3_claygl_src_Shader__["a" /* default */].source('qmv.editor.edge') -}); - -var outlineBasicMaterial = new __WEBPACK_IMPORTED_MODULE_5_claygl_src_Material__["a" /* default */]({ - shader: new __WEBPACK_IMPORTED_MODULE_3_claygl_src_Shader__["a" /* default */](__WEBPACK_IMPORTED_MODULE_3_claygl_src_Shader__["a" /* default */].source('clay.basic.vertex'), __WEBPACK_IMPORTED_MODULE_3_claygl_src_Shader__["a" /* default */].source('clay.basic.fragment')) -}); - -/* harmony default export */ __webpack_exports__["a"] = (function (viewer, meshes, camera) { - var renderer = viewer.getRenderer(); - texture.width = renderer.getWidth(); - texture.height = renderer.getHeight(); - - framebuffer.bind(renderer); - renderer.gl.clearColor(0, 0, 0, 0); - renderer.gl.clear(renderer.gl.COLOR_BUFFER_BIT | renderer.gl.DEPTH_BUFFER_BIT); - camera.update(); - renderer.renderPass(meshes, camera, { - getMaterial: function () { - return outlineBasicMaterial; - } - }); - framebuffer.unbind(renderer); - - edgePass.setUniform('edgeWidth', 1.5); - edgePass.setUniform('edgeColor', [1, 1, 0, 1]); - edgePass.setUniform('texture', texture); - edgePass.setUniform('textureSize', [texture.width, texture.height]); - edgePass.render(renderer); -}); - -/***/ }), -/* 159 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = ("@export qmv.editor.edge\n\nuniform sampler2D texture;\n\nuniform vec2 textureSize;\n\nuniform vec4 edgeColor: [0,0,0,1.0];\nuniform float edgeWidth: 1;\n\nvarying vec2 v_Texcoord;\n\nfloat getCol(vec2 coord) {\n return texture2D(texture, coord).a;\n}\n\nvoid main() {\n vec2 cc = v_Texcoord;\n float center = getCol(cc);\n\n float dx = edgeWidth / textureSize.x;\n float dy = edgeWidth / textureSize.y;\n\n vec2 coord;\n float topLeft = getCol(cc+vec2(-dx, -dy));\n float top = getCol(cc+vec2(0.0, -dy));\n float topRight = getCol(cc+vec2(dx, -dy));\n float left = getCol(cc+vec2(-dx, 0.0));\n float right = getCol(cc+vec2(dx, 0.0));\n float bottomLeft = getCol(cc+vec2(-dx, dy));\n float bottom = getCol(cc+vec2(0.0, dy));\n float bottomRight = getCol(cc+vec2(dx, dy));\n\n float v = -topLeft-2.0*top-topRight+bottomLeft+2.0*bottom+bottomRight;\n float h = -bottomLeft-2.0*left-topLeft+bottomRight+2.0*right+topRight;\n\n float edge = sqrt(h * h + v * v);\n\n edge = smoothstep(0.9, 1.0, edge);\n if (edge < 0.5) {\n discard;\n }\n\n gl_FragColor = edgeColor;\n}\n@end"); - - -/***/ }), -/* 160 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -/* harmony default export */ __webpack_exports__["a"] = (function (url) { - window.open(url); -}); - -/***/ }) -/******/ ]); \ No newline at end of file +e.exports=n(152)},function(e,t){e.exports={"application/1d-interleaved-parityfec":{source:"iana"},"application/3gpdash-qoe-report+xml":{source:"iana"},"application/3gpp-ims+xml":{source:"iana"},"application/a2l":{source:"iana"},"application/activemessage":{source:"iana"},"application/alto-costmap+json":{source:"iana",compressible:!0},"application/alto-costmapfilter+json":{source:"iana",compressible:!0},"application/alto-directory+json":{source:"iana",compressible:!0},"application/alto-endpointcost+json":{source:"iana",compressible:!0},"application/alto-endpointcostparams+json":{source:"iana",compressible:!0},"application/alto-endpointprop+json":{source:"iana",compressible:!0},"application/alto-endpointpropparams+json":{source:"iana",compressible:!0},"application/alto-error+json":{source:"iana",compressible:!0},"application/alto-networkmap+json":{source:"iana",compressible:!0},"application/alto-networkmapfilter+json":{source:"iana",compressible:!0},"application/aml":{source:"iana"},"application/andrew-inset":{source:"iana",extensions:["ez"]},"application/applefile":{source:"iana"},"application/applixware":{source:"apache",extensions:["aw"]},"application/atf":{source:"iana"},"application/atfx":{source:"iana"},"application/atom+xml":{source:"iana",compressible:!0,extensions:["atom"]},"application/atomcat+xml":{source:"iana",extensions:["atomcat"]},"application/atomdeleted+xml":{source:"iana"},"application/atomicmail":{source:"iana"},"application/atomsvc+xml":{source:"iana",extensions:["atomsvc"]},"application/atxml":{source:"iana"},"application/auth-policy+xml":{source:"iana"},"application/bacnet-xdd+zip":{source:"iana"},"application/batch-smtp":{source:"iana"},"application/bdoc":{compressible:!1,extensions:["bdoc"]},"application/beep+xml":{source:"iana"},"application/calendar+json":{source:"iana",compressible:!0},"application/calendar+xml":{source:"iana"},"application/call-completion":{source:"iana"},"application/cals-1840":{source:"iana"},"application/cbor":{source:"iana"},"application/cccex":{source:"iana"},"application/ccmp+xml":{source:"iana"},"application/ccxml+xml":{source:"iana",extensions:["ccxml"]},"application/cdfx+xml":{source:"iana"},"application/cdmi-capability":{source:"iana",extensions:["cdmia"]},"application/cdmi-container":{source:"iana",extensions:["cdmic"]},"application/cdmi-domain":{source:"iana",extensions:["cdmid"]},"application/cdmi-object":{source:"iana",extensions:["cdmio"]},"application/cdmi-queue":{source:"iana",extensions:["cdmiq"]},"application/cdni":{source:"iana"},"application/cea":{source:"iana"},"application/cea-2018+xml":{source:"iana"},"application/cellml+xml":{source:"iana"},"application/cfw":{source:"iana"},"application/clue_info+xml":{source:"iana"},"application/cms":{source:"iana"},"application/cnrp+xml":{source:"iana"},"application/coap-group+json":{source:"iana",compressible:!0},"application/coap-payload":{source:"iana"},"application/commonground":{source:"iana"},"application/conference-info+xml":{source:"iana"},"application/cose":{source:"iana"},"application/cose-key":{source:"iana"},"application/cose-key-set":{source:"iana"},"application/cpl+xml":{source:"iana"},"application/csrattrs":{source:"iana"},"application/csta+xml":{source:"iana"},"application/cstadata+xml":{source:"iana"},"application/csvm+json":{source:"iana",compressible:!0},"application/cu-seeme":{source:"apache",extensions:["cu"]},"application/cybercash":{source:"iana"},"application/dart":{compressible:!0},"application/dash+xml":{source:"iana",extensions:["mpd"]},"application/dashdelta":{source:"iana"},"application/davmount+xml":{source:"iana",extensions:["davmount"]},"application/dca-rft":{source:"iana"},"application/dcd":{source:"iana"},"application/dec-dx":{source:"iana"},"application/dialog-info+xml":{source:"iana"},"application/dicom":{source:"iana"},"application/dicom+json":{source:"iana",compressible:!0},"application/dicom+xml":{source:"iana"},"application/dii":{source:"iana"},"application/dit":{source:"iana"},"application/dns":{source:"iana"},"application/docbook+xml":{source:"apache",extensions:["dbk"]},"application/dskpp+xml":{source:"iana"},"application/dssc+der":{source:"iana",extensions:["dssc"]},"application/dssc+xml":{source:"iana",extensions:["xdssc"]},"application/dvcs":{source:"iana"},"application/ecmascript":{source:"iana",compressible:!0,extensions:["ecma"]},"application/edi-consent":{source:"iana"},"application/edi-x12":{source:"iana",compressible:!1},"application/edifact":{source:"iana",compressible:!1},"application/efi":{source:"iana"},"application/emergencycalldata.comment+xml":{source:"iana"},"application/emergencycalldata.control+xml":{source:"iana"},"application/emergencycalldata.deviceinfo+xml":{source:"iana"},"application/emergencycalldata.ecall.msd":{source:"iana"},"application/emergencycalldata.providerinfo+xml":{source:"iana"},"application/emergencycalldata.serviceinfo+xml":{source:"iana"},"application/emergencycalldata.subscriberinfo+xml":{source:"iana"},"application/emergencycalldata.veds+xml":{source:"iana"},"application/emma+xml":{source:"iana",extensions:["emma"]},"application/emotionml+xml":{source:"iana"},"application/encaprtp":{source:"iana"},"application/epp+xml":{source:"iana"},"application/epub+zip":{source:"iana",extensions:["epub"]},"application/eshop":{source:"iana"},"application/exi":{source:"iana",extensions:["exi"]},"application/fastinfoset":{source:"iana"},"application/fastsoap":{source:"iana"},"application/fdt+xml":{source:"iana"},"application/fido.trusted-apps+json":{compressible:!0},"application/fits":{source:"iana"},"application/font-sfnt":{source:"iana"},"application/font-tdpfr":{source:"iana",extensions:["pfr"]},"application/font-woff":{source:"iana",compressible:!1,extensions:["woff"]},"application/font-woff2":{compressible:!1,extensions:["woff2"]},"application/framework-attributes+xml":{source:"iana"},"application/geo+json":{source:"iana",compressible:!0,extensions:["geojson"]},"application/geo+json-seq":{source:"iana"},"application/geoxacml+xml":{source:"iana"},"application/gml+xml":{source:"iana",extensions:["gml"]},"application/gpx+xml":{source:"apache",extensions:["gpx"]},"application/gxf":{source:"apache",extensions:["gxf"]},"application/gzip":{source:"iana",compressible:!1,extensions:["gz"]},"application/h224":{source:"iana"},"application/held+xml":{source:"iana"},"application/http":{source:"iana"},"application/hyperstudio":{source:"iana",extensions:["stk"]},"application/ibe-key-request+xml":{source:"iana"},"application/ibe-pkg-reply+xml":{source:"iana"},"application/ibe-pp-data":{source:"iana"},"application/iges":{source:"iana"},"application/im-iscomposing+xml":{source:"iana"},"application/index":{source:"iana"},"application/index.cmd":{source:"iana"},"application/index.obj":{source:"iana"},"application/index.response":{source:"iana"},"application/index.vnd":{source:"iana"},"application/inkml+xml":{source:"iana",extensions:["ink","inkml"]},"application/iotp":{source:"iana"},"application/ipfix":{source:"iana",extensions:["ipfix"]},"application/ipp":{source:"iana"},"application/isup":{source:"iana"},"application/its+xml":{source:"iana"},"application/java-archive":{source:"apache",compressible:!1,extensions:["jar","war","ear"]},"application/java-serialized-object":{source:"apache",compressible:!1,extensions:["ser"]},"application/java-vm":{source:"apache",compressible:!1,extensions:["class"]},"application/javascript":{source:"iana",charset:"UTF-8",compressible:!0,extensions:["js","mjs"]},"application/jf2feed+json":{source:"iana",compressible:!0},"application/jose":{source:"iana"},"application/jose+json":{source:"iana",compressible:!0},"application/jrd+json":{source:"iana",compressible:!0},"application/json":{source:"iana",charset:"UTF-8",compressible:!0,extensions:["json","map"]},"application/json-patch+json":{source:"iana",compressible:!0},"application/json-seq":{source:"iana"},"application/json5":{extensions:["json5"]},"application/jsonml+json":{source:"apache",compressible:!0,extensions:["jsonml"]},"application/jwk+json":{source:"iana",compressible:!0},"application/jwk-set+json":{source:"iana",compressible:!0},"application/jwt":{source:"iana"},"application/kpml-request+xml":{source:"iana"},"application/kpml-response+xml":{source:"iana"},"application/ld+json":{source:"iana",compressible:!0,extensions:["jsonld"]},"application/lgr+xml":{source:"iana"},"application/link-format":{source:"iana"},"application/load-control+xml":{source:"iana"},"application/lost+xml":{source:"iana",extensions:["lostxml"]},"application/lostsync+xml":{source:"iana"},"application/lxf":{source:"iana"},"application/mac-binhex40":{source:"iana",extensions:["hqx"]},"application/mac-compactpro":{source:"apache",extensions:["cpt"]},"application/macwriteii":{source:"iana"},"application/mads+xml":{source:"iana",extensions:["mads"]},"application/manifest+json":{charset:"UTF-8",compressible:!0,extensions:["webmanifest"]},"application/marc":{source:"iana",extensions:["mrc"]},"application/marcxml+xml":{source:"iana",extensions:["mrcx"]},"application/mathematica":{source:"iana",extensions:["ma","nb","mb"]},"application/mathml+xml":{source:"iana",extensions:["mathml"]},"application/mathml-content+xml":{source:"iana"},"application/mathml-presentation+xml":{source:"iana"},"application/mbms-associated-procedure-description+xml":{source:"iana"},"application/mbms-deregister+xml":{source:"iana"},"application/mbms-envelope+xml":{source:"iana"},"application/mbms-msk+xml":{source:"iana"},"application/mbms-msk-response+xml":{source:"iana"},"application/mbms-protection-description+xml":{source:"iana"},"application/mbms-reception-report+xml":{source:"iana"},"application/mbms-register+xml":{source:"iana"},"application/mbms-register-response+xml":{source:"iana"},"application/mbms-schedule+xml":{source:"iana"},"application/mbms-user-service-description+xml":{source:"iana"},"application/mbox":{source:"iana",extensions:["mbox"]},"application/media-policy-dataset+xml":{source:"iana"},"application/media_control+xml":{source:"iana"},"application/mediaservercontrol+xml":{source:"iana",extensions:["mscml"]},"application/merge-patch+json":{source:"iana",compressible:!0},"application/metalink+xml":{source:"apache",extensions:["metalink"]},"application/metalink4+xml":{source:"iana",extensions:["meta4"]},"application/mets+xml":{source:"iana",extensions:["mets"]},"application/mf4":{source:"iana"},"application/mikey":{source:"iana"},"application/mmt-usd+xml":{source:"iana"},"application/mods+xml":{source:"iana",extensions:["mods"]},"application/moss-keys":{source:"iana"},"application/moss-signature":{source:"iana"},"application/mosskey-data":{source:"iana"},"application/mosskey-request":{source:"iana"},"application/mp21":{source:"iana",extensions:["m21","mp21"]},"application/mp4":{source:"iana",extensions:["mp4s","m4p"]},"application/mpeg4-generic":{source:"iana"},"application/mpeg4-iod":{source:"iana"},"application/mpeg4-iod-xmt":{source:"iana"},"application/mrb-consumer+xml":{source:"iana"},"application/mrb-publish+xml":{source:"iana"},"application/msc-ivr+xml":{source:"iana"},"application/msc-mixer+xml":{source:"iana"},"application/msword":{source:"iana",compressible:!1,extensions:["doc","dot"]},"application/mud+json":{source:"iana",compressible:!0},"application/mxf":{source:"iana",extensions:["mxf"]},"application/n-quads":{source:"iana"},"application/n-triples":{source:"iana"},"application/nasdata":{source:"iana"},"application/news-checkgroups":{source:"iana"},"application/news-groupinfo":{source:"iana"},"application/news-transmission":{source:"iana"},"application/nlsml+xml":{source:"iana"},"application/nss":{source:"iana"},"application/ocsp-request":{source:"iana"},"application/ocsp-response":{source:"iana"},"application/octet-stream":{source:"iana",compressible:!1,extensions:["bin","dms","lrf","mar","so","dist","distz","pkg","bpk","dump","elc","deploy","exe","dll","deb","dmg","iso","img","msi","msp","msm","buffer"]},"application/oda":{source:"iana",extensions:["oda"]},"application/odx":{source:"iana"},"application/oebps-package+xml":{source:"iana",extensions:["opf"]},"application/ogg":{source:"iana",compressible:!1,extensions:["ogx"]},"application/omdoc+xml":{source:"apache",extensions:["omdoc"]},"application/onenote":{source:"apache",extensions:["onetoc","onetoc2","onetmp","onepkg"]},"application/oxps":{source:"iana",extensions:["oxps"]},"application/p2p-overlay+xml":{source:"iana"},"application/parityfec":{source:"iana"},"application/passport":{source:"iana"},"application/patch-ops-error+xml":{source:"iana",extensions:["xer"]},"application/pdf":{source:"iana",compressible:!1,extensions:["pdf"]},"application/pdx":{source:"iana"},"application/pgp-encrypted":{source:"iana",compressible:!1,extensions:["pgp"]},"application/pgp-keys":{source:"iana"},"application/pgp-signature":{source:"iana",extensions:["asc","sig"]},"application/pics-rules":{source:"apache",extensions:["prf"]},"application/pidf+xml":{source:"iana"},"application/pidf-diff+xml":{source:"iana"},"application/pkcs10":{source:"iana",extensions:["p10"]},"application/pkcs12":{source:"iana"},"application/pkcs7-mime":{source:"iana",extensions:["p7m","p7c"]},"application/pkcs7-signature":{source:"iana",extensions:["p7s"]},"application/pkcs8":{source:"iana",extensions:["p8"]},"application/pkix-attr-cert":{source:"iana",extensions:["ac"]},"application/pkix-cert":{source:"iana",extensions:["cer"]},"application/pkix-crl":{source:"iana",extensions:["crl"]},"application/pkix-pkipath":{source:"iana",extensions:["pkipath"]},"application/pkixcmp":{source:"iana",extensions:["pki"]},"application/pls+xml":{source:"iana",extensions:["pls"]},"application/poc-settings+xml":{source:"iana"},"application/postscript":{source:"iana",compressible:!0,extensions:["ai","eps","ps"]},"application/ppsp-tracker+json":{source:"iana",compressible:!0},"application/problem+json":{source:"iana",compressible:!0},"application/problem+xml":{source:"iana"},"application/provenance+xml":{source:"iana"},"application/prs.alvestrand.titrax-sheet":{source:"iana"},"application/prs.cww":{source:"iana",extensions:["cww"]},"application/prs.hpub+zip":{source:"iana"},"application/prs.nprend":{source:"iana"},"application/prs.plucker":{source:"iana"},"application/prs.rdf-xml-crypt":{source:"iana"},"application/prs.xsf+xml":{source:"iana"},"application/pskc+xml":{source:"iana",extensions:["pskcxml"]},"application/qsig":{source:"iana"},"application/raptorfec":{source:"iana"},"application/rdap+json":{source:"iana",compressible:!0},"application/rdf+xml":{source:"iana",compressible:!0,extensions:["rdf"]},"application/reginfo+xml":{source:"iana",extensions:["rif"]},"application/relax-ng-compact-syntax":{source:"iana",extensions:["rnc"]},"application/remote-printing":{source:"iana"},"application/reputon+json":{source:"iana",compressible:!0},"application/resource-lists+xml":{source:"iana",extensions:["rl"]},"application/resource-lists-diff+xml":{source:"iana",extensions:["rld"]},"application/rfc+xml":{source:"iana"},"application/riscos":{source:"iana"},"application/rlmi+xml":{source:"iana"},"application/rls-services+xml":{source:"iana",extensions:["rs"]},"application/route-apd+xml":{source:"iana"},"application/route-s-tsid+xml":{source:"iana"},"application/route-usd+xml":{source:"iana"},"application/rpki-ghostbusters":{source:"iana",extensions:["gbr"]},"application/rpki-manifest":{source:"iana",extensions:["mft"]},"application/rpki-publication":{source:"iana"},"application/rpki-roa":{source:"iana",extensions:["roa"]},"application/rpki-updown":{source:"iana"},"application/rsd+xml":{source:"apache",extensions:["rsd"]},"application/rss+xml":{source:"apache",compressible:!0,extensions:["rss"]},"application/rtf":{source:"iana",compressible:!0,extensions:["rtf"]},"application/rtploopback":{source:"iana"},"application/rtx":{source:"iana"},"application/samlassertion+xml":{source:"iana"},"application/samlmetadata+xml":{source:"iana"},"application/sbml+xml":{source:"iana",extensions:["sbml"]},"application/scaip+xml":{source:"iana"},"application/scim+json":{source:"iana",compressible:!0},"application/scvp-cv-request":{source:"iana",extensions:["scq"]},"application/scvp-cv-response":{source:"iana",extensions:["scs"]},"application/scvp-vp-request":{source:"iana",extensions:["spq"]},"application/scvp-vp-response":{source:"iana",extensions:["spp"]},"application/sdp":{source:"iana",extensions:["sdp"]},"application/sep+xml":{source:"iana"},"application/sep-exi":{source:"iana"},"application/session-info":{source:"iana"},"application/set-payment":{source:"iana"},"application/set-payment-initiation":{source:"iana",extensions:["setpay"]},"application/set-registration":{source:"iana"},"application/set-registration-initiation":{source:"iana",extensions:["setreg"]},"application/sgml":{source:"iana"},"application/sgml-open-catalog":{source:"iana"},"application/shf+xml":{source:"iana",extensions:["shf"]},"application/sieve":{source:"iana"},"application/simple-filter+xml":{source:"iana"},"application/simple-message-summary":{source:"iana"},"application/simplesymbolcontainer":{source:"iana"},"application/slate":{source:"iana"},"application/smil":{source:"iana"},"application/smil+xml":{source:"iana",extensions:["smi","smil"]},"application/smpte336m":{source:"iana"},"application/soap+fastinfoset":{source:"iana"},"application/soap+xml":{source:"iana",compressible:!0},"application/sparql-query":{source:"iana",extensions:["rq"]},"application/sparql-results+xml":{source:"iana",extensions:["srx"]},"application/spirits-event+xml":{source:"iana"},"application/sql":{source:"iana"},"application/srgs":{source:"iana",extensions:["gram"]},"application/srgs+xml":{source:"iana",extensions:["grxml"]},"application/sru+xml":{source:"iana",extensions:["sru"]},"application/ssdl+xml":{source:"apache",extensions:["ssdl"]},"application/ssml+xml":{source:"iana",extensions:["ssml"]},"application/tamp-apex-update":{source:"iana"},"application/tamp-apex-update-confirm":{source:"iana"},"application/tamp-community-update":{source:"iana"},"application/tamp-community-update-confirm":{source:"iana"},"application/tamp-error":{source:"iana"},"application/tamp-sequence-adjust":{source:"iana"},"application/tamp-sequence-adjust-confirm":{source:"iana"},"application/tamp-status-query":{source:"iana"},"application/tamp-status-response":{source:"iana"},"application/tamp-update":{source:"iana"},"application/tamp-update-confirm":{source:"iana"},"application/tar":{compressible:!0},"application/tei+xml":{source:"iana",extensions:["tei","teicorpus"]},"application/thraud+xml":{source:"iana",extensions:["tfi"]},"application/timestamp-query":{source:"iana"},"application/timestamp-reply":{source:"iana"},"application/timestamped-data":{source:"iana",extensions:["tsd"]},"application/trig":{source:"iana"},"application/ttml+xml":{source:"iana"},"application/tve-trigger":{source:"iana"},"application/ulpfec":{source:"iana"},"application/urc-grpsheet+xml":{source:"iana"},"application/urc-ressheet+xml":{source:"iana"},"application/urc-targetdesc+xml":{source:"iana"},"application/urc-uisocketdesc+xml":{source:"iana"},"application/vcard+json":{source:"iana",compressible:!0},"application/vcard+xml":{source:"iana"},"application/vemmi":{source:"iana"},"application/vividence.scriptfile":{source:"apache"},"application/vnd.1000minds.decision-model+xml":{source:"iana"},"application/vnd.3gpp-prose+xml":{source:"iana"},"application/vnd.3gpp-prose-pc3ch+xml":{source:"iana"},"application/vnd.3gpp.access-transfer-events+xml":{source:"iana"},"application/vnd.3gpp.bsf+xml":{source:"iana"},"application/vnd.3gpp.gmop+xml":{source:"iana"},"application/vnd.3gpp.mcptt-info+xml":{source:"iana"},"application/vnd.3gpp.mcptt-mbms-usage-info+xml":{source:"iana"},"application/vnd.3gpp.mid-call+xml":{source:"iana"},"application/vnd.3gpp.pic-bw-large":{source:"iana",extensions:["plb"]},"application/vnd.3gpp.pic-bw-small":{source:"iana",extensions:["psb"]},"application/vnd.3gpp.pic-bw-var":{source:"iana",extensions:["pvb"]},"application/vnd.3gpp.sms":{source:"iana"},"application/vnd.3gpp.sms+xml":{source:"iana"},"application/vnd.3gpp.srvcc-ext+xml":{source:"iana"},"application/vnd.3gpp.srvcc-info+xml":{source:"iana"},"application/vnd.3gpp.state-and-event-info+xml":{source:"iana"},"application/vnd.3gpp.ussd+xml":{source:"iana"},"application/vnd.3gpp2.bcmcsinfo+xml":{source:"iana"},"application/vnd.3gpp2.sms":{source:"iana"},"application/vnd.3gpp2.tcap":{source:"iana",extensions:["tcap"]},"application/vnd.3lightssoftware.imagescal":{source:"iana"},"application/vnd.3m.post-it-notes":{source:"iana",extensions:["pwn"]},"application/vnd.accpac.simply.aso":{source:"iana",extensions:["aso"]},"application/vnd.accpac.simply.imp":{source:"iana",extensions:["imp"]},"application/vnd.acucobol":{source:"iana",extensions:["acu"]},"application/vnd.acucorp":{source:"iana",extensions:["atc","acutc"]},"application/vnd.adobe.air-application-installer-package+zip":{source:"apache",extensions:["air"]},"application/vnd.adobe.flash.movie":{source:"iana"},"application/vnd.adobe.formscentral.fcdt":{source:"iana",extensions:["fcdt"]},"application/vnd.adobe.fxp":{source:"iana",extensions:["fxp","fxpl"]},"application/vnd.adobe.partial-upload":{source:"iana"},"application/vnd.adobe.xdp+xml":{source:"iana",extensions:["xdp"]},"application/vnd.adobe.xfdf":{source:"iana",extensions:["xfdf"]},"application/vnd.aether.imp":{source:"iana"},"application/vnd.ah-barcode":{source:"iana"},"application/vnd.ahead.space":{source:"iana",extensions:["ahead"]},"application/vnd.airzip.filesecure.azf":{source:"iana",extensions:["azf"]},"application/vnd.airzip.filesecure.azs":{source:"iana",extensions:["azs"]},"application/vnd.amazon.ebook":{source:"apache",extensions:["azw"]},"application/vnd.amazon.mobi8-ebook":{source:"iana"},"application/vnd.americandynamics.acc":{source:"iana",extensions:["acc"]},"application/vnd.amiga.ami":{source:"iana",extensions:["ami"]},"application/vnd.amundsen.maze+xml":{source:"iana"},"application/vnd.android.package-archive":{source:"apache",compressible:!1,extensions:["apk"]},"application/vnd.anki":{source:"iana"},"application/vnd.anser-web-certificate-issue-initiation":{source:"iana",extensions:["cii"]},"application/vnd.anser-web-funds-transfer-initiation":{source:"apache",extensions:["fti"]},"application/vnd.antix.game-component":{source:"iana",extensions:["atx"]},"application/vnd.apache.thrift.binary":{source:"iana"},"application/vnd.apache.thrift.compact":{source:"iana"},"application/vnd.apache.thrift.json":{source:"iana"},"application/vnd.api+json":{source:"iana",compressible:!0},"application/vnd.apothekende.reservation+json":{source:"iana",compressible:!0},"application/vnd.apple.installer+xml":{source:"iana",extensions:["mpkg"]},"application/vnd.apple.mpegurl":{source:"iana",extensions:["m3u8"]},"application/vnd.apple.pkpass":{compressible:!1,extensions:["pkpass"]},"application/vnd.arastra.swi":{source:"iana"},"application/vnd.aristanetworks.swi":{source:"iana",extensions:["swi"]},"application/vnd.artsquare":{source:"iana"},"application/vnd.astraea-software.iota":{source:"iana",extensions:["iota"]},"application/vnd.audiograph":{source:"iana",extensions:["aep"]},"application/vnd.autopackage":{source:"iana"},"application/vnd.avistar+xml":{source:"iana"},"application/vnd.balsamiq.bmml+xml":{source:"iana"},"application/vnd.balsamiq.bmpr":{source:"iana"},"application/vnd.bekitzur-stech+json":{source:"iana",compressible:!0},"application/vnd.bint.med-content":{source:"iana"},"application/vnd.biopax.rdf+xml":{source:"iana"},"application/vnd.blink-idb-value-wrapper":{source:"iana"},"application/vnd.blueice.multipass":{source:"iana",extensions:["mpm"]},"application/vnd.bluetooth.ep.oob":{source:"iana"},"application/vnd.bluetooth.le.oob":{source:"iana"},"application/vnd.bmi":{source:"iana",extensions:["bmi"]},"application/vnd.businessobjects":{source:"iana",extensions:["rep"]},"application/vnd.cab-jscript":{source:"iana"},"application/vnd.canon-cpdl":{source:"iana"},"application/vnd.canon-lips":{source:"iana"},"application/vnd.capasystems-pg+json":{source:"iana",compressible:!0},"application/vnd.cendio.thinlinc.clientconf":{source:"iana"},"application/vnd.century-systems.tcp_stream":{source:"iana"},"application/vnd.chemdraw+xml":{source:"iana",extensions:["cdxml"]},"application/vnd.chess-pgn":{source:"iana"},"application/vnd.chipnuts.karaoke-mmd":{source:"iana",extensions:["mmd"]},"application/vnd.cinderella":{source:"iana",extensions:["cdy"]},"application/vnd.cirpack.isdn-ext":{source:"iana"},"application/vnd.citationstyles.style+xml":{source:"iana"},"application/vnd.claymore":{source:"iana",extensions:["cla"]},"application/vnd.cloanto.rp9":{source:"iana",extensions:["rp9"]},"application/vnd.clonk.c4group":{source:"iana",extensions:["c4g","c4d","c4f","c4p","c4u"]},"application/vnd.cluetrust.cartomobile-config":{source:"iana",extensions:["c11amc"]},"application/vnd.cluetrust.cartomobile-config-pkg":{source:"iana",extensions:["c11amz"]},"application/vnd.coffeescript":{source:"iana"},"application/vnd.collection+json":{source:"iana",compressible:!0},"application/vnd.collection.doc+json":{source:"iana",compressible:!0},"application/vnd.collection.next+json":{source:"iana",compressible:!0},"application/vnd.comicbook+zip":{source:"iana"},"application/vnd.commerce-battelle":{source:"iana"},"application/vnd.commonspace":{source:"iana",extensions:["csp"]},"application/vnd.contact.cmsg":{source:"iana",extensions:["cdbcmsg"]},"application/vnd.coreos.ignition+json":{source:"iana",compressible:!0},"application/vnd.cosmocaller":{source:"iana",extensions:["cmc"]},"application/vnd.crick.clicker":{source:"iana",extensions:["clkx"]},"application/vnd.crick.clicker.keyboard":{source:"iana",extensions:["clkk"]},"application/vnd.crick.clicker.palette":{source:"iana",extensions:["clkp"]},"application/vnd.crick.clicker.template":{source:"iana",extensions:["clkt"]},"application/vnd.crick.clicker.wordbank":{source:"iana",extensions:["clkw"]},"application/vnd.criticaltools.wbs+xml":{source:"iana",extensions:["wbs"]},"application/vnd.ctc-posml":{source:"iana",extensions:["pml"]},"application/vnd.ctct.ws+xml":{source:"iana"},"application/vnd.cups-pdf":{source:"iana"},"application/vnd.cups-postscript":{source:"iana"},"application/vnd.cups-ppd":{source:"iana",extensions:["ppd"]},"application/vnd.cups-raster":{source:"iana"},"application/vnd.cups-raw":{source:"iana"},"application/vnd.curl":{source:"iana"},"application/vnd.curl.car":{source:"apache",extensions:["car"]},"application/vnd.curl.pcurl":{source:"apache",extensions:["pcurl"]},"application/vnd.cyan.dean.root+xml":{source:"iana"},"application/vnd.cybank":{source:"iana"},"application/vnd.d2l.coursepackage1p0+zip":{source:"iana"},"application/vnd.dart":{source:"iana",compressible:!0,extensions:["dart"]},"application/vnd.data-vision.rdz":{source:"iana",extensions:["rdz"]},"application/vnd.datapackage+json":{source:"iana",compressible:!0},"application/vnd.dataresource+json":{source:"iana",compressible:!0},"application/vnd.debian.binary-package":{source:"iana"},"application/vnd.dece.data":{source:"iana",extensions:["uvf","uvvf","uvd","uvvd"]},"application/vnd.dece.ttml+xml":{source:"iana",extensions:["uvt","uvvt"]},"application/vnd.dece.unspecified":{source:"iana",extensions:["uvx","uvvx"]},"application/vnd.dece.zip":{source:"iana",extensions:["uvz","uvvz"]},"application/vnd.denovo.fcselayout-link":{source:"iana",extensions:["fe_launch"]},"application/vnd.desmume-movie":{source:"iana"},"application/vnd.desmume.movie":{source:"apache"},"application/vnd.dir-bi.plate-dl-nosuffix":{source:"iana"},"application/vnd.dm.delegation+xml":{source:"iana"},"application/vnd.dna":{source:"iana",extensions:["dna"]},"application/vnd.document+json":{source:"iana",compressible:!0},"application/vnd.dolby.mlp":{source:"apache",extensions:["mlp"]},"application/vnd.dolby.mobile.1":{source:"iana"},"application/vnd.dolby.mobile.2":{source:"iana"},"application/vnd.doremir.scorecloud-binary-document":{source:"iana"},"application/vnd.dpgraph":{source:"iana",extensions:["dpg"]},"application/vnd.dreamfactory":{source:"iana",extensions:["dfac"]},"application/vnd.drive+json":{source:"iana",compressible:!0},"application/vnd.ds-keypoint":{source:"apache",extensions:["kpxx"]},"application/vnd.dtg.local":{source:"iana"},"application/vnd.dtg.local.flash":{source:"iana"},"application/vnd.dtg.local.html":{source:"iana"},"application/vnd.dvb.ait":{source:"iana",extensions:["ait"]},"application/vnd.dvb.dvbj":{source:"iana"},"application/vnd.dvb.esgcontainer":{source:"iana"},"application/vnd.dvb.ipdcdftnotifaccess":{source:"iana"},"application/vnd.dvb.ipdcesgaccess":{source:"iana"},"application/vnd.dvb.ipdcesgaccess2":{source:"iana"},"application/vnd.dvb.ipdcesgpdd":{source:"iana"},"application/vnd.dvb.ipdcroaming":{source:"iana"},"application/vnd.dvb.iptv.alfec-base":{source:"iana"},"application/vnd.dvb.iptv.alfec-enhancement":{source:"iana"},"application/vnd.dvb.notif-aggregate-root+xml":{source:"iana"},"application/vnd.dvb.notif-container+xml":{source:"iana"},"application/vnd.dvb.notif-generic+xml":{source:"iana"},"application/vnd.dvb.notif-ia-msglist+xml":{source:"iana"},"application/vnd.dvb.notif-ia-registration-request+xml":{source:"iana"},"application/vnd.dvb.notif-ia-registration-response+xml":{source:"iana"},"application/vnd.dvb.notif-init+xml":{source:"iana"},"application/vnd.dvb.pfr":{source:"iana"},"application/vnd.dvb.service":{source:"iana",extensions:["svc"]},"application/vnd.dxr":{source:"iana"},"application/vnd.dynageo":{source:"iana",extensions:["geo"]},"application/vnd.dzr":{source:"iana"},"application/vnd.easykaraoke.cdgdownload":{source:"iana"},"application/vnd.ecdis-update":{source:"iana"},"application/vnd.ecowin.chart":{source:"iana",extensions:["mag"]},"application/vnd.ecowin.filerequest":{source:"iana"},"application/vnd.ecowin.fileupdate":{source:"iana"},"application/vnd.ecowin.series":{source:"iana"},"application/vnd.ecowin.seriesrequest":{source:"iana"},"application/vnd.ecowin.seriesupdate":{source:"iana"},"application/vnd.efi.img":{source:"iana"},"application/vnd.efi.iso":{source:"iana"},"application/vnd.emclient.accessrequest+xml":{source:"iana"},"application/vnd.enliven":{source:"iana",extensions:["nml"]},"application/vnd.enphase.envoy":{source:"iana"},"application/vnd.eprints.data+xml":{source:"iana"},"application/vnd.epson.esf":{source:"iana",extensions:["esf"]},"application/vnd.epson.msf":{source:"iana",extensions:["msf"]},"application/vnd.epson.quickanime":{source:"iana",extensions:["qam"]},"application/vnd.epson.salt":{source:"iana",extensions:["slt"]},"application/vnd.epson.ssf":{source:"iana",extensions:["ssf"]},"application/vnd.ericsson.quickcall":{source:"iana"},"application/vnd.espass-espass+zip":{source:"iana"},"application/vnd.eszigno3+xml":{source:"iana",extensions:["es3","et3"]},"application/vnd.etsi.aoc+xml":{source:"iana"},"application/vnd.etsi.asic-e+zip":{source:"iana"},"application/vnd.etsi.asic-s+zip":{source:"iana"},"application/vnd.etsi.cug+xml":{source:"iana"},"application/vnd.etsi.iptvcommand+xml":{source:"iana"},"application/vnd.etsi.iptvdiscovery+xml":{source:"iana"},"application/vnd.etsi.iptvprofile+xml":{source:"iana"},"application/vnd.etsi.iptvsad-bc+xml":{source:"iana"},"application/vnd.etsi.iptvsad-cod+xml":{source:"iana"},"application/vnd.etsi.iptvsad-npvr+xml":{source:"iana"},"application/vnd.etsi.iptvservice+xml":{source:"iana"},"application/vnd.etsi.iptvsync+xml":{source:"iana"},"application/vnd.etsi.iptvueprofile+xml":{source:"iana"},"application/vnd.etsi.mcid+xml":{source:"iana"},"application/vnd.etsi.mheg5":{source:"iana"},"application/vnd.etsi.overload-control-policy-dataset+xml":{source:"iana"},"application/vnd.etsi.pstn+xml":{source:"iana"},"application/vnd.etsi.sci+xml":{source:"iana"},"application/vnd.etsi.simservs+xml":{source:"iana"},"application/vnd.etsi.timestamp-token":{source:"iana"},"application/vnd.etsi.tsl+xml":{source:"iana"},"application/vnd.etsi.tsl.der":{source:"iana"},"application/vnd.eudora.data":{source:"iana"},"application/vnd.evolv.ecig.profile":{source:"iana"},"application/vnd.evolv.ecig.settings":{source:"iana"},"application/vnd.evolv.ecig.theme":{source:"iana"},"application/vnd.ezpix-album":{source:"iana",extensions:["ez2"]},"application/vnd.ezpix-package":{source:"iana",extensions:["ez3"]},"application/vnd.f-secure.mobile":{source:"iana"},"application/vnd.fastcopy-disk-image":{source:"iana"},"application/vnd.fdf":{source:"iana",extensions:["fdf"]},"application/vnd.fdsn.mseed":{source:"iana",extensions:["mseed"]},"application/vnd.fdsn.seed":{source:"iana",extensions:["seed","dataless"]},"application/vnd.ffsns":{source:"iana"},"application/vnd.filmit.zfc":{source:"iana"},"application/vnd.fints":{source:"iana"},"application/vnd.firemonkeys.cloudcell":{source:"iana"},"application/vnd.flographit":{source:"iana",extensions:["gph"]},"application/vnd.fluxtime.clip":{source:"iana",extensions:["ftc"]},"application/vnd.font-fontforge-sfd":{source:"iana"},"application/vnd.framemaker":{source:"iana",extensions:["fm","frame","maker","book"]},"application/vnd.frogans.fnc":{source:"iana",extensions:["fnc"]},"application/vnd.frogans.ltf":{source:"iana",extensions:["ltf"]},"application/vnd.fsc.weblaunch":{source:"iana",extensions:["fsc"]},"application/vnd.fujitsu.oasys":{source:"iana",extensions:["oas"]},"application/vnd.fujitsu.oasys2":{source:"iana",extensions:["oa2"]},"application/vnd.fujitsu.oasys3":{source:"iana",extensions:["oa3"]},"application/vnd.fujitsu.oasysgp":{source:"iana",extensions:["fg5"]},"application/vnd.fujitsu.oasysprs":{source:"iana",extensions:["bh2"]},"application/vnd.fujixerox.art-ex":{source:"iana"},"application/vnd.fujixerox.art4":{source:"iana"},"application/vnd.fujixerox.ddd":{source:"iana",extensions:["ddd"]},"application/vnd.fujixerox.docuworks":{source:"iana",extensions:["xdw"]},"application/vnd.fujixerox.docuworks.binder":{source:"iana",extensions:["xbd"]},"application/vnd.fujixerox.docuworks.container":{source:"iana"},"application/vnd.fujixerox.hbpl":{source:"iana"},"application/vnd.fut-misnet":{source:"iana"},"application/vnd.fuzzysheet":{source:"iana",extensions:["fzs"]},"application/vnd.genomatix.tuxedo":{source:"iana",extensions:["txd"]},"application/vnd.geo+json":{source:"iana",compressible:!0},"application/vnd.geocube+xml":{source:"iana"},"application/vnd.geogebra.file":{source:"iana",extensions:["ggb"]},"application/vnd.geogebra.tool":{source:"iana",extensions:["ggt"]},"application/vnd.geometry-explorer":{source:"iana",extensions:["gex","gre"]},"application/vnd.geonext":{source:"iana",extensions:["gxt"]},"application/vnd.geoplan":{source:"iana",extensions:["g2w"]},"application/vnd.geospace":{source:"iana",extensions:["g3w"]},"application/vnd.gerber":{source:"iana"},"application/vnd.globalplatform.card-content-mgt":{source:"iana"},"application/vnd.globalplatform.card-content-mgt-response":{source:"iana"},"application/vnd.gmx":{source:"iana",extensions:["gmx"]},"application/vnd.google-apps.document":{compressible:!1,extensions:["gdoc"]},"application/vnd.google-apps.presentation":{compressible:!1,extensions:["gslides"]},"application/vnd.google-apps.spreadsheet":{compressible:!1,extensions:["gsheet"]},"application/vnd.google-earth.kml+xml":{source:"iana",compressible:!0,extensions:["kml"]},"application/vnd.google-earth.kmz":{source:"iana",compressible:!1,extensions:["kmz"]},"application/vnd.gov.sk.e-form+xml":{source:"iana"},"application/vnd.gov.sk.e-form+zip":{source:"iana"},"application/vnd.gov.sk.xmldatacontainer+xml":{source:"iana"},"application/vnd.grafeq":{source:"iana",extensions:["gqf","gqs"]},"application/vnd.gridmp":{source:"iana"},"application/vnd.groove-account":{source:"iana",extensions:["gac"]},"application/vnd.groove-help":{source:"iana",extensions:["ghf"]},"application/vnd.groove-identity-message":{source:"iana",extensions:["gim"]},"application/vnd.groove-injector":{source:"iana",extensions:["grv"]},"application/vnd.groove-tool-message":{source:"iana",extensions:["gtm"]},"application/vnd.groove-tool-template":{source:"iana",extensions:["tpl"]},"application/vnd.groove-vcard":{source:"iana",extensions:["vcg"]},"application/vnd.hal+json":{source:"iana",compressible:!0},"application/vnd.hal+xml":{source:"iana",extensions:["hal"]},"application/vnd.handheld-entertainment+xml":{source:"iana",extensions:["zmm"]},"application/vnd.hbci":{source:"iana",extensions:["hbci"]},"application/vnd.hc+json":{source:"iana",compressible:!0},"application/vnd.hcl-bireports":{source:"iana"},"application/vnd.hdt":{source:"iana"},"application/vnd.heroku+json":{source:"iana",compressible:!0},"application/vnd.hhe.lesson-player":{source:"iana",extensions:["les"]},"application/vnd.hp-hpgl":{source:"iana",extensions:["hpgl"]},"application/vnd.hp-hpid":{source:"iana",extensions:["hpid"]},"application/vnd.hp-hps":{source:"iana",extensions:["hps"]},"application/vnd.hp-jlyt":{source:"iana",extensions:["jlt"]},"application/vnd.hp-pcl":{source:"iana",extensions:["pcl"]},"application/vnd.hp-pclxl":{source:"iana",extensions:["pclxl"]},"application/vnd.httphone":{source:"iana"},"application/vnd.hydrostatix.sof-data":{source:"iana",extensions:["sfd-hdstx"]},"application/vnd.hyper-item+json":{source:"iana",compressible:!0},"application/vnd.hyperdrive+json":{source:"iana",compressible:!0},"application/vnd.hzn-3d-crossword":{source:"iana"},"application/vnd.ibm.afplinedata":{source:"iana"},"application/vnd.ibm.electronic-media":{source:"iana"},"application/vnd.ibm.minipay":{source:"iana",extensions:["mpy"]},"application/vnd.ibm.modcap":{source:"iana",extensions:["afp","listafp","list3820"]},"application/vnd.ibm.rights-management":{source:"iana",extensions:["irm"]},"application/vnd.ibm.secure-container":{source:"iana",extensions:["sc"]},"application/vnd.iccprofile":{source:"iana",extensions:["icc","icm"]},"application/vnd.ieee.1905":{source:"iana"},"application/vnd.igloader":{source:"iana",extensions:["igl"]},"application/vnd.imagemeter.folder+zip":{source:"iana"},"application/vnd.imagemeter.image+zip":{source:"iana"},"application/vnd.immervision-ivp":{source:"iana",extensions:["ivp"]},"application/vnd.immervision-ivu":{source:"iana",extensions:["ivu"]},"application/vnd.ims.imsccv1p1":{source:"iana"},"application/vnd.ims.imsccv1p2":{source:"iana"},"application/vnd.ims.imsccv1p3":{source:"iana"},"application/vnd.ims.lis.v2.result+json":{source:"iana",compressible:!0},"application/vnd.ims.lti.v2.toolconsumerprofile+json":{source:"iana",compressible:!0},"application/vnd.ims.lti.v2.toolproxy+json":{source:"iana",compressible:!0},"application/vnd.ims.lti.v2.toolproxy.id+json":{source:"iana",compressible:!0},"application/vnd.ims.lti.v2.toolsettings+json":{source:"iana",compressible:!0},"application/vnd.ims.lti.v2.toolsettings.simple+json":{source:"iana",compressible:!0},"application/vnd.informedcontrol.rms+xml":{source:"iana"},"application/vnd.informix-visionary":{source:"iana"},"application/vnd.infotech.project":{source:"iana"},"application/vnd.infotech.project+xml":{source:"iana"},"application/vnd.innopath.wamp.notification":{source:"iana"},"application/vnd.insors.igm":{source:"iana",extensions:["igm"]},"application/vnd.intercon.formnet":{source:"iana",extensions:["xpw","xpx"]},"application/vnd.intergeo":{source:"iana",extensions:["i2g"]},"application/vnd.intertrust.digibox":{source:"iana"},"application/vnd.intertrust.nncp":{source:"iana"},"application/vnd.intu.qbo":{source:"iana",extensions:["qbo"]},"application/vnd.intu.qfx":{source:"iana",extensions:["qfx"]},"application/vnd.iptc.g2.catalogitem+xml":{source:"iana"},"application/vnd.iptc.g2.conceptitem+xml":{source:"iana"},"application/vnd.iptc.g2.knowledgeitem+xml":{source:"iana"},"application/vnd.iptc.g2.newsitem+xml":{source:"iana"},"application/vnd.iptc.g2.newsmessage+xml":{source:"iana"},"application/vnd.iptc.g2.packageitem+xml":{source:"iana"},"application/vnd.iptc.g2.planningitem+xml":{source:"iana"},"application/vnd.ipunplugged.rcprofile":{source:"iana",extensions:["rcprofile"]},"application/vnd.irepository.package+xml":{source:"iana",extensions:["irp"]},"application/vnd.is-xpr":{source:"iana",extensions:["xpr"]},"application/vnd.isac.fcs":{source:"iana",extensions:["fcs"]},"application/vnd.jam":{source:"iana",extensions:["jam"]},"application/vnd.japannet-directory-service":{source:"iana"},"application/vnd.japannet-jpnstore-wakeup":{source:"iana"},"application/vnd.japannet-payment-wakeup":{source:"iana"},"application/vnd.japannet-registration":{source:"iana"},"application/vnd.japannet-registration-wakeup":{source:"iana"},"application/vnd.japannet-setstore-wakeup":{source:"iana"},"application/vnd.japannet-verification":{source:"iana"},"application/vnd.japannet-verification-wakeup":{source:"iana"},"application/vnd.jcp.javame.midlet-rms":{source:"iana",extensions:["rms"]},"application/vnd.jisp":{source:"iana",extensions:["jisp"]},"application/vnd.joost.joda-archive":{source:"iana",extensions:["joda"]},"application/vnd.jsk.isdn-ngn":{source:"iana"},"application/vnd.kahootz":{source:"iana",extensions:["ktz","ktr"]},"application/vnd.kde.karbon":{source:"iana",extensions:["karbon"]},"application/vnd.kde.kchart":{source:"iana",extensions:["chrt"]},"application/vnd.kde.kformula":{source:"iana",extensions:["kfo"]},"application/vnd.kde.kivio":{source:"iana",extensions:["flw"]},"application/vnd.kde.kontour":{source:"iana",extensions:["kon"]},"application/vnd.kde.kpresenter":{source:"iana",extensions:["kpr","kpt"]},"application/vnd.kde.kspread":{source:"iana",extensions:["ksp"]},"application/vnd.kde.kword":{source:"iana",extensions:["kwd","kwt"]},"application/vnd.kenameaapp":{source:"iana",extensions:["htke"]},"application/vnd.kidspiration":{source:"iana",extensions:["kia"]},"application/vnd.kinar":{source:"iana",extensions:["kne","knp"]},"application/vnd.koan":{source:"iana",extensions:["skp","skd","skt","skm"]},"application/vnd.kodak-descriptor":{source:"iana",extensions:["sse"]},"application/vnd.las.las+json":{source:"iana",compressible:!0},"application/vnd.las.las+xml":{source:"iana",extensions:["lasxml"]},"application/vnd.liberty-request+xml":{source:"iana"},"application/vnd.llamagraphics.life-balance.desktop":{source:"iana",extensions:["lbd"]},"application/vnd.llamagraphics.life-balance.exchange+xml":{source:"iana",extensions:["lbe"]},"application/vnd.lotus-1-2-3":{source:"iana",extensions:["123"]},"application/vnd.lotus-approach":{source:"iana",extensions:["apr"]},"application/vnd.lotus-freelance":{source:"iana",extensions:["pre"]},"application/vnd.lotus-notes":{source:"iana",extensions:["nsf"]},"application/vnd.lotus-organizer":{source:"iana",extensions:["org"]},"application/vnd.lotus-screencam":{source:"iana",extensions:["scm"]},"application/vnd.lotus-wordpro":{source:"iana",extensions:["lwp"]},"application/vnd.macports.portpkg":{source:"iana",extensions:["portpkg"]},"application/vnd.mapbox-vector-tile":{source:"iana"},"application/vnd.marlin.drm.actiontoken+xml":{source:"iana"},"application/vnd.marlin.drm.conftoken+xml":{source:"iana"},"application/vnd.marlin.drm.license+xml":{source:"iana"},"application/vnd.marlin.drm.mdcf":{source:"iana"},"application/vnd.mason+json":{source:"iana",compressible:!0},"application/vnd.maxmind.maxmind-db":{source:"iana"},"application/vnd.mcd":{source:"iana",extensions:["mcd"]},"application/vnd.medcalcdata":{source:"iana",extensions:["mc1"]},"application/vnd.mediastation.cdkey":{source:"iana",extensions:["cdkey"]},"application/vnd.meridian-slingshot":{source:"iana"},"application/vnd.mfer":{source:"iana",extensions:["mwf"]},"application/vnd.mfmp":{source:"iana",extensions:["mfm"]},"application/vnd.micro+json":{source:"iana",compressible:!0},"application/vnd.micrografx.flo":{source:"iana",extensions:["flo"]},"application/vnd.micrografx.igx":{source:"iana",extensions:["igx"]},"application/vnd.microsoft.portable-executable":{source:"iana"},"application/vnd.microsoft.windows.thumbnail-cache":{source:"iana"},"application/vnd.miele+json":{source:"iana",compressible:!0},"application/vnd.mif":{source:"iana",extensions:["mif"]},"application/vnd.minisoft-hp3000-save":{source:"iana"},"application/vnd.mitsubishi.misty-guard.trustweb":{source:"iana"},"application/vnd.mobius.daf":{source:"iana",extensions:["daf"]},"application/vnd.mobius.dis":{source:"iana",extensions:["dis"]},"application/vnd.mobius.mbk":{source:"iana",extensions:["mbk"]},"application/vnd.mobius.mqy":{source:"iana",extensions:["mqy"]},"application/vnd.mobius.msl":{source:"iana",extensions:["msl"]},"application/vnd.mobius.plc":{source:"iana",extensions:["plc"]},"application/vnd.mobius.txf":{source:"iana",extensions:["txf"]},"application/vnd.mophun.application":{source:"iana",extensions:["mpn"]},"application/vnd.mophun.certificate":{source:"iana",extensions:["mpc"]},"application/vnd.motorola.flexsuite":{source:"iana"},"application/vnd.motorola.flexsuite.adsi":{source:"iana"},"application/vnd.motorola.flexsuite.fis":{source:"iana"},"application/vnd.motorola.flexsuite.gotap":{source:"iana"},"application/vnd.motorola.flexsuite.kmr":{source:"iana"},"application/vnd.motorola.flexsuite.ttc":{source:"iana"},"application/vnd.motorola.flexsuite.wem":{source:"iana"},"application/vnd.motorola.iprm":{source:"iana"},"application/vnd.mozilla.xul+xml":{source:"iana",compressible:!0,extensions:["xul"]},"application/vnd.ms-3mfdocument":{source:"iana"},"application/vnd.ms-artgalry":{source:"iana",extensions:["cil"]},"application/vnd.ms-asf":{source:"iana"},"application/vnd.ms-cab-compressed":{source:"iana",extensions:["cab"]},"application/vnd.ms-color.iccprofile":{source:"apache"},"application/vnd.ms-excel":{source:"iana",compressible:!1,extensions:["xls","xlm","xla","xlc","xlt","xlw"]},"application/vnd.ms-excel.addin.macroenabled.12":{source:"iana",extensions:["xlam"]},"application/vnd.ms-excel.sheet.binary.macroenabled.12":{source:"iana",extensions:["xlsb"]},"application/vnd.ms-excel.sheet.macroenabled.12":{source:"iana",extensions:["xlsm"]},"application/vnd.ms-excel.template.macroenabled.12":{source:"iana",extensions:["xltm"]},"application/vnd.ms-fontobject":{source:"iana",compressible:!0,extensions:["eot"]},"application/vnd.ms-htmlhelp":{source:"iana",extensions:["chm"]},"application/vnd.ms-ims":{source:"iana",extensions:["ims"]},"application/vnd.ms-lrm":{source:"iana",extensions:["lrm"]},"application/vnd.ms-office.activex+xml":{source:"iana"},"application/vnd.ms-officetheme":{source:"iana",extensions:["thmx"]},"application/vnd.ms-opentype":{source:"apache",compressible:!0},"application/vnd.ms-outlook":{compressible:!1,extensions:["msg"]},"application/vnd.ms-package.obfuscated-opentype":{source:"apache"},"application/vnd.ms-pki.seccat":{source:"apache",extensions:["cat"]},"application/vnd.ms-pki.stl":{source:"apache",extensions:["stl"]},"application/vnd.ms-playready.initiator+xml":{source:"iana"},"application/vnd.ms-powerpoint":{source:"iana",compressible:!1,extensions:["ppt","pps","pot"]},"application/vnd.ms-powerpoint.addin.macroenabled.12":{source:"iana",extensions:["ppam"]},"application/vnd.ms-powerpoint.presentation.macroenabled.12":{source:"iana",extensions:["pptm"]},"application/vnd.ms-powerpoint.slide.macroenabled.12":{source:"iana",extensions:["sldm"]},"application/vnd.ms-powerpoint.slideshow.macroenabled.12":{source:"iana",extensions:["ppsm"]},"application/vnd.ms-powerpoint.template.macroenabled.12":{source:"iana",extensions:["potm"]},"application/vnd.ms-printdevicecapabilities+xml":{source:"iana"},"application/vnd.ms-printing.printticket+xml":{source:"apache"},"application/vnd.ms-printschematicket+xml":{source:"iana"},"application/vnd.ms-project":{source:"iana",extensions:["mpp","mpt"]},"application/vnd.ms-tnef":{source:"iana"},"application/vnd.ms-windows.devicepairing":{source:"iana"},"application/vnd.ms-windows.nwprinting.oob":{source:"iana"},"application/vnd.ms-windows.printerpairing":{source:"iana"},"application/vnd.ms-windows.wsd.oob":{source:"iana"},"application/vnd.ms-wmdrm.lic-chlg-req":{source:"iana"},"application/vnd.ms-wmdrm.lic-resp":{source:"iana"},"application/vnd.ms-wmdrm.meter-chlg-req":{source:"iana"},"application/vnd.ms-wmdrm.meter-resp":{source:"iana"},"application/vnd.ms-word.document.macroenabled.12":{source:"iana",extensions:["docm"]},"application/vnd.ms-word.template.macroenabled.12":{source:"iana",extensions:["dotm"]},"application/vnd.ms-works":{source:"iana",extensions:["wps","wks","wcm","wdb"]},"application/vnd.ms-wpl":{source:"iana",extensions:["wpl"]},"application/vnd.ms-xpsdocument":{source:"iana",compressible:!1,extensions:["xps"]},"application/vnd.msa-disk-image":{source:"iana"},"application/vnd.mseq":{source:"iana",extensions:["mseq"]},"application/vnd.msign":{source:"iana"},"application/vnd.multiad.creator":{source:"iana"},"application/vnd.multiad.creator.cif":{source:"iana"},"application/vnd.music-niff":{source:"iana"},"application/vnd.musician":{source:"iana",extensions:["mus"]},"application/vnd.muvee.style":{source:"iana",extensions:["msty"]},"application/vnd.mynfc":{source:"iana",extensions:["taglet"]},"application/vnd.ncd.control":{source:"iana"},"application/vnd.ncd.reference":{source:"iana"},"application/vnd.nearst.inv+json":{source:"iana",compressible:!0},"application/vnd.nervana":{source:"iana"},"application/vnd.netfpx":{source:"iana"},"application/vnd.neurolanguage.nlu":{source:"iana",extensions:["nlu"]},"application/vnd.nintendo.nitro.rom":{source:"iana"},"application/vnd.nintendo.snes.rom":{source:"iana"},"application/vnd.nitf":{source:"iana",extensions:["ntf","nitf"]},"application/vnd.noblenet-directory":{source:"iana",extensions:["nnd"]},"application/vnd.noblenet-sealer":{source:"iana",extensions:["nns"]},"application/vnd.noblenet-web":{source:"iana",extensions:["nnw"]},"application/vnd.nokia.catalogs":{source:"iana"},"application/vnd.nokia.conml+wbxml":{source:"iana"},"application/vnd.nokia.conml+xml":{source:"iana"},"application/vnd.nokia.iptv.config+xml":{source:"iana"},"application/vnd.nokia.isds-radio-presets":{source:"iana"},"application/vnd.nokia.landmark+wbxml":{source:"iana"},"application/vnd.nokia.landmark+xml":{source:"iana"},"application/vnd.nokia.landmarkcollection+xml":{source:"iana"},"application/vnd.nokia.n-gage.ac+xml":{source:"iana"},"application/vnd.nokia.n-gage.data":{source:"iana",extensions:["ngdat"]},"application/vnd.nokia.n-gage.symbian.install":{source:"iana",extensions:["n-gage"]},"application/vnd.nokia.ncd":{source:"iana"},"application/vnd.nokia.pcd+wbxml":{source:"iana"},"application/vnd.nokia.pcd+xml":{source:"iana"},"application/vnd.nokia.radio-preset":{source:"iana",extensions:["rpst"]},"application/vnd.nokia.radio-presets":{source:"iana",extensions:["rpss"]},"application/vnd.novadigm.edm":{source:"iana",extensions:["edm"]},"application/vnd.novadigm.edx":{source:"iana",extensions:["edx"]},"application/vnd.novadigm.ext":{source:"iana",extensions:["ext"]},"application/vnd.ntt-local.content-share":{source:"iana"},"application/vnd.ntt-local.file-transfer":{source:"iana"},"application/vnd.ntt-local.ogw_remote-access":{source:"iana"},"application/vnd.ntt-local.sip-ta_remote":{source:"iana"},"application/vnd.ntt-local.sip-ta_tcp_stream":{source:"iana"},"application/vnd.oasis.opendocument.chart":{source:"iana",extensions:["odc"]},"application/vnd.oasis.opendocument.chart-template":{source:"iana",extensions:["otc"]},"application/vnd.oasis.opendocument.database":{source:"iana",extensions:["odb"]},"application/vnd.oasis.opendocument.formula":{source:"iana",extensions:["odf"]},"application/vnd.oasis.opendocument.formula-template":{source:"iana",extensions:["odft"]},"application/vnd.oasis.opendocument.graphics":{source:"iana",compressible:!1,extensions:["odg"]},"application/vnd.oasis.opendocument.graphics-template":{source:"iana",extensions:["otg"]},"application/vnd.oasis.opendocument.image":{source:"iana",extensions:["odi"]},"application/vnd.oasis.opendocument.image-template":{source:"iana",extensions:["oti"]},"application/vnd.oasis.opendocument.presentation":{source:"iana",compressible:!1,extensions:["odp"]},"application/vnd.oasis.opendocument.presentation-template":{source:"iana",extensions:["otp"]},"application/vnd.oasis.opendocument.spreadsheet":{source:"iana",compressible:!1,extensions:["ods"]},"application/vnd.oasis.opendocument.spreadsheet-template":{source:"iana",extensions:["ots"]},"application/vnd.oasis.opendocument.text":{source:"iana",compressible:!1,extensions:["odt"]},"application/vnd.oasis.opendocument.text-master":{source:"iana",extensions:["odm"]},"application/vnd.oasis.opendocument.text-template":{source:"iana",extensions:["ott"]},"application/vnd.oasis.opendocument.text-web":{source:"iana",extensions:["oth"]},"application/vnd.obn":{source:"iana"},"application/vnd.ocf+cbor":{source:"iana"},"application/vnd.oftn.l10n+json":{source:"iana",compressible:!0},"application/vnd.oipf.contentaccessdownload+xml":{source:"iana"},"application/vnd.oipf.contentaccessstreaming+xml":{source:"iana"},"application/vnd.oipf.cspg-hexbinary":{source:"iana"},"application/vnd.oipf.dae.svg+xml":{source:"iana"},"application/vnd.oipf.dae.xhtml+xml":{source:"iana"},"application/vnd.oipf.mippvcontrolmessage+xml":{source:"iana"},"application/vnd.oipf.pae.gem":{source:"iana"},"application/vnd.oipf.spdiscovery+xml":{source:"iana"},"application/vnd.oipf.spdlist+xml":{source:"iana"},"application/vnd.oipf.ueprofile+xml":{source:"iana"},"application/vnd.oipf.userprofile+xml":{source:"iana"},"application/vnd.olpc-sugar":{source:"iana",extensions:["xo"]},"application/vnd.oma-scws-config":{source:"iana"},"application/vnd.oma-scws-http-request":{source:"iana"},"application/vnd.oma-scws-http-response":{source:"iana"},"application/vnd.oma.bcast.associated-procedure-parameter+xml":{source:"iana"},"application/vnd.oma.bcast.drm-trigger+xml":{source:"iana"},"application/vnd.oma.bcast.imd+xml":{source:"iana"},"application/vnd.oma.bcast.ltkm":{source:"iana"},"application/vnd.oma.bcast.notification+xml":{source:"iana"},"application/vnd.oma.bcast.provisioningtrigger":{source:"iana"},"application/vnd.oma.bcast.sgboot":{source:"iana"},"application/vnd.oma.bcast.sgdd+xml":{source:"iana"},"application/vnd.oma.bcast.sgdu":{source:"iana"},"application/vnd.oma.bcast.simple-symbol-container":{source:"iana"},"application/vnd.oma.bcast.smartcard-trigger+xml":{source:"iana"},"application/vnd.oma.bcast.sprov+xml":{source:"iana"},"application/vnd.oma.bcast.stkm":{source:"iana"},"application/vnd.oma.cab-address-book+xml":{source:"iana"},"application/vnd.oma.cab-feature-handler+xml":{source:"iana"},"application/vnd.oma.cab-pcc+xml":{source:"iana"},"application/vnd.oma.cab-subs-invite+xml":{source:"iana"},"application/vnd.oma.cab-user-prefs+xml":{source:"iana"},"application/vnd.oma.dcd":{source:"iana"},"application/vnd.oma.dcdc":{source:"iana"},"application/vnd.oma.dd2+xml":{source:"iana",extensions:["dd2"]},"application/vnd.oma.drm.risd+xml":{source:"iana"},"application/vnd.oma.group-usage-list+xml":{source:"iana"},"application/vnd.oma.lwm2m+json":{source:"iana",compressible:!0},"application/vnd.oma.lwm2m+tlv":{source:"iana"},"application/vnd.oma.pal+xml":{source:"iana"},"application/vnd.oma.poc.detailed-progress-report+xml":{source:"iana"},"application/vnd.oma.poc.final-report+xml":{source:"iana"},"application/vnd.oma.poc.groups+xml":{source:"iana"},"application/vnd.oma.poc.invocation-descriptor+xml":{source:"iana"},"application/vnd.oma.poc.optimized-progress-report+xml":{source:"iana"},"application/vnd.oma.push":{source:"iana"},"application/vnd.oma.scidm.messages+xml":{source:"iana"},"application/vnd.oma.xcap-directory+xml":{source:"iana"},"application/vnd.omads-email+xml":{source:"iana"},"application/vnd.omads-file+xml":{source:"iana"},"application/vnd.omads-folder+xml":{source:"iana"},"application/vnd.omaloc-supl-init":{source:"iana"},"application/vnd.onepager":{source:"iana"},"application/vnd.onepagertamp":{source:"iana"},"application/vnd.onepagertamx":{source:"iana"},"application/vnd.onepagertat":{source:"iana"},"application/vnd.onepagertatp":{source:"iana"},"application/vnd.onepagertatx":{source:"iana"},"application/vnd.openblox.game+xml":{source:"iana"},"application/vnd.openblox.game-binary":{source:"iana"},"application/vnd.openeye.oeb":{source:"iana"},"application/vnd.openofficeorg.extension":{source:"apache",extensions:["oxt"]},"application/vnd.openstreetmap.data+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.custom-properties+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.customxmlproperties+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.drawing+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.drawingml.chart+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.drawingml.diagramcolors+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.drawingml.diagramdata+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.drawingml.diagramlayout+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.drawingml.diagramstyle+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.extended-properties+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml-template":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.commentauthors+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.comments+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.handoutmaster+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.notesmaster+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.notesslide+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.presentation":{source:"iana",compressible:!1,extensions:["pptx"]},"application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.presprops+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.slide":{source:"iana",extensions:["sldx"]},"application/vnd.openxmlformats-officedocument.presentationml.slide+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.slidelayout+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.slidemaster+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.slideshow":{source:"iana",extensions:["ppsx"]},"application/vnd.openxmlformats-officedocument.presentationml.slideshow.main+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.slideupdateinfo+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.tablestyles+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.tags+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.template":{source:"apache",extensions:["potx"]},"application/vnd.openxmlformats-officedocument.presentationml.template.main+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.presentationml.viewprops+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml-template":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.calcchain+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.externallink+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcachedefinition+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotcacherecords+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.pivottable+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.querytable+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionheaders+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionlog+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedstrings+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":{source:"iana",compressible:!1,extensions:["xlsx"]},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetmetadata+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.tablesinglecells+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.template":{source:"apache",extensions:["xltx"]},"application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.usernames+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.volatiledependencies+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.theme+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.themeoverride+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.vmldrawing":{source:"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml-template":{source:"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.document":{source:"iana",compressible:!1,extensions:["docx"]},"application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.fonttable+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.template":{source:"apache",extensions:["dotx"]},"application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml":{source:"iana"},"application/vnd.openxmlformats-officedocument.wordprocessingml.websettings+xml":{source:"iana"},"application/vnd.openxmlformats-package.core-properties+xml":{source:"iana"},"application/vnd.openxmlformats-package.digital-signature-xmlsignature+xml":{source:"iana"},"application/vnd.openxmlformats-package.relationships+xml":{source:"iana"},"application/vnd.oracle.resource+json":{source:"iana",compressible:!0},"application/vnd.orange.indata":{source:"iana"},"application/vnd.osa.netdeploy":{source:"iana"},"application/vnd.osgeo.mapguide.package":{source:"iana",extensions:["mgp"]},"application/vnd.osgi.bundle":{source:"iana"},"application/vnd.osgi.dp":{source:"iana",extensions:["dp"]},"application/vnd.osgi.subsystem":{source:"iana",extensions:["esa"]},"application/vnd.otps.ct-kip+xml":{source:"iana"},"application/vnd.oxli.countgraph":{source:"iana"},"application/vnd.pagerduty+json":{source:"iana",compressible:!0},"application/vnd.palm":{source:"iana",extensions:["pdb","pqa","oprc"]},"application/vnd.panoply":{source:"iana"},"application/vnd.paos+xml":{source:"iana"},"application/vnd.paos.xml":{source:"apache"},"application/vnd.pawaafile":{source:"iana",extensions:["paw"]},"application/vnd.pcos":{source:"iana"},"application/vnd.pg.format":{source:"iana",extensions:["str"]},"application/vnd.pg.osasli":{source:"iana",extensions:["ei6"]},"application/vnd.piaccess.application-licence":{source:"iana"},"application/vnd.picsel":{source:"iana",extensions:["efif"]},"application/vnd.pmi.widget":{source:"iana",extensions:["wg"]},"application/vnd.poc.group-advertisement+xml":{source:"iana"},"application/vnd.pocketlearn":{source:"iana",extensions:["plf"]},"application/vnd.powerbuilder6":{source:"iana",extensions:["pbd"]},"application/vnd.powerbuilder6-s":{source:"iana"},"application/vnd.powerbuilder7":{source:"iana"},"application/vnd.powerbuilder7-s":{source:"iana"},"application/vnd.powerbuilder75":{source:"iana"},"application/vnd.powerbuilder75-s":{source:"iana"},"application/vnd.preminet":{source:"iana"},"application/vnd.previewsystems.box":{source:"iana",extensions:["box"]},"application/vnd.proteus.magazine":{source:"iana",extensions:["mgz"]},"application/vnd.publishare-delta-tree":{source:"iana",extensions:["qps"]},"application/vnd.pvi.ptid1":{source:"iana",extensions:["ptid"]},"application/vnd.pwg-multiplexed":{source:"iana"},"application/vnd.pwg-xhtml-print+xml":{source:"iana"},"application/vnd.qualcomm.brew-app-res":{source:"iana"},"application/vnd.quarantainenet":{source:"iana"},"application/vnd.quark.quarkxpress":{source:"iana",extensions:["qxd","qxt","qwd","qwt","qxl","qxb"]},"application/vnd.quobject-quoxdocument":{source:"iana"},"application/vnd.radisys.moml+xml":{source:"iana"},"application/vnd.radisys.msml+xml":{source:"iana"},"application/vnd.radisys.msml-audit+xml":{source:"iana"},"application/vnd.radisys.msml-audit-conf+xml":{source:"iana"},"application/vnd.radisys.msml-audit-conn+xml":{source:"iana"},"application/vnd.radisys.msml-audit-dialog+xml":{source:"iana"},"application/vnd.radisys.msml-audit-stream+xml":{source:"iana"},"application/vnd.radisys.msml-conf+xml":{source:"iana"},"application/vnd.radisys.msml-dialog+xml":{source:"iana"},"application/vnd.radisys.msml-dialog-base+xml":{source:"iana"},"application/vnd.radisys.msml-dialog-fax-detect+xml":{source:"iana"},"application/vnd.radisys.msml-dialog-fax-sendrecv+xml":{source:"iana"},"application/vnd.radisys.msml-dialog-group+xml":{source:"iana"},"application/vnd.radisys.msml-dialog-speech+xml":{source:"iana"},"application/vnd.radisys.msml-dialog-transform+xml":{source:"iana"},"application/vnd.rainstor.data":{source:"iana"},"application/vnd.rapid":{source:"iana"},"application/vnd.rar":{source:"iana"},"application/vnd.realvnc.bed":{source:"iana",extensions:["bed"]},"application/vnd.recordare.musicxml":{source:"iana",extensions:["mxl"]},"application/vnd.recordare.musicxml+xml":{source:"iana",extensions:["musicxml"]},"application/vnd.renlearn.rlprint":{source:"iana"},"application/vnd.rig.cryptonote":{source:"iana",extensions:["cryptonote"]},"application/vnd.rim.cod":{source:"apache",extensions:["cod"]},"application/vnd.rn-realmedia":{source:"apache",extensions:["rm"]},"application/vnd.rn-realmedia-vbr":{source:"apache",extensions:["rmvb"]},"application/vnd.route66.link66+xml":{source:"iana",extensions:["link66"]},"application/vnd.rs-274x":{source:"iana"},"application/vnd.ruckus.download":{source:"iana"},"application/vnd.s3sms":{source:"iana"},"application/vnd.sailingtracker.track":{source:"iana",extensions:["st"]},"application/vnd.sbm.cid":{source:"iana"},"application/vnd.sbm.mid2":{source:"iana"},"application/vnd.scribus":{source:"iana"},"application/vnd.sealed.3df":{source:"iana"},"application/vnd.sealed.csf":{source:"iana"},"application/vnd.sealed.doc":{source:"iana"},"application/vnd.sealed.eml":{source:"iana"},"application/vnd.sealed.mht":{source:"iana"},"application/vnd.sealed.net":{source:"iana"},"application/vnd.sealed.ppt":{source:"iana"},"application/vnd.sealed.tiff":{source:"iana"},"application/vnd.sealed.xls":{source:"iana"},"application/vnd.sealedmedia.softseal.html":{source:"iana"},"application/vnd.sealedmedia.softseal.pdf":{source:"iana"},"application/vnd.seemail":{source:"iana",extensions:["see"]},"application/vnd.sema":{source:"iana",extensions:["sema"]},"application/vnd.semd":{source:"iana",extensions:["semd"]},"application/vnd.semf":{source:"iana",extensions:["semf"]},"application/vnd.shana.informed.formdata":{source:"iana",extensions:["ifm"]},"application/vnd.shana.informed.formtemplate":{source:"iana",extensions:["itp"]},"application/vnd.shana.informed.interchange":{source:"iana",extensions:["iif"]},"application/vnd.shana.informed.package":{source:"iana",extensions:["ipk"]},"application/vnd.sigrok.session":{source:"iana"},"application/vnd.simtech-mindmapper":{source:"iana",extensions:["twd","twds"]},"application/vnd.siren+json":{source:"iana",compressible:!0},"application/vnd.smaf":{source:"iana",extensions:["mmf"]},"application/vnd.smart.notebook":{source:"iana"},"application/vnd.smart.teacher":{source:"iana",extensions:["teacher"]},"application/vnd.software602.filler.form+xml":{source:"iana"},"application/vnd.software602.filler.form-xml-zip":{source:"iana"},"application/vnd.solent.sdkm+xml":{source:"iana",extensions:["sdkm","sdkd"]},"application/vnd.spotfire.dxp":{source:"iana",extensions:["dxp"]},"application/vnd.spotfire.sfs":{source:"iana",extensions:["sfs"]},"application/vnd.sss-cod":{source:"iana"},"application/vnd.sss-dtf":{source:"iana"},"application/vnd.sss-ntf":{source:"iana"},"application/vnd.stardivision.calc":{source:"apache",extensions:["sdc"]},"application/vnd.stardivision.draw":{source:"apache",extensions:["sda"]},"application/vnd.stardivision.impress":{source:"apache",extensions:["sdd"]},"application/vnd.stardivision.math":{source:"apache",extensions:["smf"]},"application/vnd.stardivision.writer":{source:"apache",extensions:["sdw","vor"]},"application/vnd.stardivision.writer-global":{source:"apache",extensions:["sgl"]},"application/vnd.stepmania.package":{source:"iana",extensions:["smzip"]},"application/vnd.stepmania.stepchart":{source:"iana",extensions:["sm"]},"application/vnd.street-stream":{source:"iana"},"application/vnd.sun.wadl+xml":{source:"iana",compressible:!0,extensions:["wadl"]},"application/vnd.sun.xml.calc":{source:"apache",extensions:["sxc"]},"application/vnd.sun.xml.calc.template":{source:"apache",extensions:["stc"]},"application/vnd.sun.xml.draw":{source:"apache",extensions:["sxd"]},"application/vnd.sun.xml.draw.template":{source:"apache",extensions:["std"]},"application/vnd.sun.xml.impress":{source:"apache",extensions:["sxi"]},"application/vnd.sun.xml.impress.template":{source:"apache",extensions:["sti"]},"application/vnd.sun.xml.math":{source:"apache",extensions:["sxm"]},"application/vnd.sun.xml.writer":{source:"apache",extensions:["sxw"]},"application/vnd.sun.xml.writer.global":{source:"apache",extensions:["sxg"]},"application/vnd.sun.xml.writer.template":{source:"apache",extensions:["stw"]},"application/vnd.sus-calendar":{source:"iana",extensions:["sus","susp"]},"application/vnd.svd":{source:"iana",extensions:["svd"]},"application/vnd.swiftview-ics":{source:"iana"},"application/vnd.symbian.install":{source:"apache",extensions:["sis","sisx"]},"application/vnd.syncml+xml":{source:"iana",extensions:["xsm"]},"application/vnd.syncml.dm+wbxml":{source:"iana",extensions:["bdm"]},"application/vnd.syncml.dm+xml":{source:"iana",extensions:["xdm"]},"application/vnd.syncml.dm.notification":{source:"iana"},"application/vnd.syncml.dmddf+wbxml":{source:"iana"},"application/vnd.syncml.dmddf+xml":{source:"iana"},"application/vnd.syncml.dmtnds+wbxml":{source:"iana"},"application/vnd.syncml.dmtnds+xml":{source:"iana"},"application/vnd.syncml.ds.notification":{source:"iana"},"application/vnd.tableschema+json":{source:"iana",compressible:!0},"application/vnd.tao.intent-module-archive":{source:"iana",extensions:["tao"]},"application/vnd.tcpdump.pcap":{source:"iana",extensions:["pcap","cap","dmp"]},"application/vnd.tmd.mediaflex.api+xml":{source:"iana"},"application/vnd.tml":{source:"iana"},"application/vnd.tmobile-livetv":{source:"iana",extensions:["tmo"]},"application/vnd.tri.onesource":{source:"iana"},"application/vnd.trid.tpt":{source:"iana",extensions:["tpt"]},"application/vnd.triscape.mxs":{source:"iana",extensions:["mxs"]},"application/vnd.trueapp":{source:"iana",extensions:["tra"]},"application/vnd.truedoc":{source:"iana"},"application/vnd.ubisoft.webplayer":{source:"iana"},"application/vnd.ufdl":{source:"iana",extensions:["ufd","ufdl"]},"application/vnd.uiq.theme":{source:"iana",extensions:["utz"]},"application/vnd.umajin":{source:"iana",extensions:["umj"]},"application/vnd.unity":{source:"iana",extensions:["unityweb"]},"application/vnd.uoml+xml":{source:"iana",extensions:["uoml"]},"application/vnd.uplanet.alert":{source:"iana"},"application/vnd.uplanet.alert-wbxml":{source:"iana"},"application/vnd.uplanet.bearer-choice":{source:"iana"},"application/vnd.uplanet.bearer-choice-wbxml":{source:"iana"},"application/vnd.uplanet.cacheop":{source:"iana"},"application/vnd.uplanet.cacheop-wbxml":{source:"iana"},"application/vnd.uplanet.channel":{source:"iana"},"application/vnd.uplanet.channel-wbxml":{source:"iana"},"application/vnd.uplanet.list":{source:"iana"},"application/vnd.uplanet.list-wbxml":{source:"iana"},"application/vnd.uplanet.listcmd":{source:"iana"},"application/vnd.uplanet.listcmd-wbxml":{source:"iana"},"application/vnd.uplanet.signal":{source:"iana"},"application/vnd.uri-map":{source:"iana"},"application/vnd.valve.source.material":{source:"iana"},"application/vnd.vcx":{source:"iana",extensions:["vcx"]},"application/vnd.vd-study":{source:"iana"},"application/vnd.vectorworks":{source:"iana"},"application/vnd.vel+json":{source:"iana",compressible:!0},"application/vnd.verimatrix.vcas":{source:"iana"},"application/vnd.vidsoft.vidconference":{source:"iana"},"application/vnd.visio":{source:"iana",extensions:["vsd","vst","vss","vsw"]},"application/vnd.visionary":{source:"iana",extensions:["vis"]},"application/vnd.vividence.scriptfile":{source:"iana"},"application/vnd.vsf":{source:"iana",extensions:["vsf"]},"application/vnd.wap.sic":{source:"iana"},"application/vnd.wap.slc":{source:"iana"},"application/vnd.wap.wbxml":{source:"iana",extensions:["wbxml"]},"application/vnd.wap.wmlc":{source:"iana",extensions:["wmlc"]},"application/vnd.wap.wmlscriptc":{source:"iana",extensions:["wmlsc"]},"application/vnd.webturbo":{source:"iana",extensions:["wtb"]},"application/vnd.wfa.p2p":{source:"iana"},"application/vnd.wfa.wsc":{source:"iana"},"application/vnd.windows.devicepairing":{source:"iana"},"application/vnd.wmc":{source:"iana"},"application/vnd.wmf.bootstrap":{source:"iana"},"application/vnd.wolfram.mathematica":{source:"iana"},"application/vnd.wolfram.mathematica.package":{source:"iana"},"application/vnd.wolfram.player":{source:"iana",extensions:["nbp"]},"application/vnd.wordperfect":{source:"iana",extensions:["wpd"]},"application/vnd.wqd":{source:"iana",extensions:["wqd"]},"application/vnd.wrq-hp3000-labelled":{source:"iana"},"application/vnd.wt.stf":{source:"iana",extensions:["stf"]},"application/vnd.wv.csp+wbxml":{source:"iana"},"application/vnd.wv.csp+xml":{source:"iana"},"application/vnd.wv.ssp+xml":{source:"iana"},"application/vnd.xacml+json":{source:"iana",compressible:!0},"application/vnd.xara":{source:"iana",extensions:["xar"]},"application/vnd.xfdl":{source:"iana",extensions:["xfdl"]},"application/vnd.xfdl.webform":{source:"iana"},"application/vnd.xmi+xml":{source:"iana"},"application/vnd.xmpie.cpkg":{source:"iana"},"application/vnd.xmpie.dpkg":{source:"iana"},"application/vnd.xmpie.plan":{source:"iana"},"application/vnd.xmpie.ppkg":{source:"iana"},"application/vnd.xmpie.xlim":{source:"iana"},"application/vnd.yamaha.hv-dic":{source:"iana",extensions:["hvd"]},"application/vnd.yamaha.hv-script":{source:"iana",extensions:["hvs"]},"application/vnd.yamaha.hv-voice":{source:"iana",extensions:["hvp"]},"application/vnd.yamaha.openscoreformat":{source:"iana",extensions:["osf"]},"application/vnd.yamaha.openscoreformat.osfpvg+xml":{source:"iana",extensions:["osfpvg"]},"application/vnd.yamaha.remote-setup":{source:"iana"},"application/vnd.yamaha.smaf-audio":{source:"iana",extensions:["saf"]},"application/vnd.yamaha.smaf-phrase":{source:"iana",extensions:["spf"]},"application/vnd.yamaha.through-ngn":{source:"iana"},"application/vnd.yamaha.tunnel-udpencap":{source:"iana"},"application/vnd.yaoweme":{source:"iana"},"application/vnd.yellowriver-custom-menu":{source:"iana",extensions:["cmp"]},"application/vnd.zul":{source:"iana",extensions:["zir","zirz"]},"application/vnd.zzazz.deck+xml":{source:"iana",extensions:["zaz"]},"application/voicexml+xml":{source:"iana",extensions:["vxml"]},"application/vq-rtcpxr":{source:"iana"},"application/watcherinfo+xml":{source:"iana"},"application/whoispp-query":{source:"iana"},"application/whoispp-response":{source:"iana"},"application/widget":{source:"iana",extensions:["wgt"]},"application/winhlp":{source:"apache",extensions:["hlp"]},"application/wita":{source:"iana"},"application/wordperfect5.1":{source:"iana"},"application/wsdl+xml":{source:"iana",extensions:["wsdl"]},"application/wspolicy+xml":{source:"iana",extensions:["wspolicy"]},"application/x-7z-compressed":{source:"apache",compressible:!1,extensions:["7z"]},"application/x-abiword":{source:"apache",extensions:["abw"]},"application/x-ace-compressed":{source:"apache",extensions:["ace"]},"application/x-amf":{source:"apache"},"application/x-apple-diskimage":{source:"apache",extensions:["dmg"]},"application/x-arj":{compressible:!1,extensions:["arj"]},"application/x-authorware-bin":{source:"apache",extensions:["aab","x32","u32","vox"]},"application/x-authorware-map":{source:"apache",extensions:["aam"]},"application/x-authorware-seg":{source:"apache",extensions:["aas"]},"application/x-bcpio":{source:"apache",extensions:["bcpio"]},"application/x-bdoc":{compressible:!1,extensions:["bdoc"]},"application/x-bittorrent":{source:"apache",extensions:["torrent"]},"application/x-blorb":{source:"apache",extensions:["blb","blorb"]},"application/x-bzip":{source:"apache",compressible:!1,extensions:["bz"]},"application/x-bzip2":{source:"apache",compressible:!1,extensions:["bz2","boz"]},"application/x-cbr":{source:"apache",extensions:["cbr","cba","cbt","cbz","cb7"]},"application/x-cdlink":{source:"apache",extensions:["vcd"]},"application/x-cfs-compressed":{source:"apache",extensions:["cfs"]},"application/x-chat":{source:"apache",extensions:["chat"]},"application/x-chess-pgn":{source:"apache",extensions:["pgn"]},"application/x-chrome-extension":{extensions:["crx"]},"application/x-cocoa":{source:"nginx",extensions:["cco"]},"application/x-compress":{source:"apache"},"application/x-conference":{source:"apache",extensions:["nsc"]},"application/x-cpio":{source:"apache",extensions:["cpio"]},"application/x-csh":{source:"apache",extensions:["csh"]},"application/x-deb":{compressible:!1},"application/x-debian-package":{source:"apache",extensions:["deb","udeb"]},"application/x-dgc-compressed":{source:"apache",extensions:["dgc"]},"application/x-director":{source:"apache",extensions:["dir","dcr","dxr","cst","cct","cxt","w3d","fgd","swa"]},"application/x-doom":{source:"apache",extensions:["wad"]},"application/x-dtbncx+xml":{source:"apache",extensions:["ncx"]},"application/x-dtbook+xml":{source:"apache",extensions:["dtb"]},"application/x-dtbresource+xml":{source:"apache",extensions:["res"]},"application/x-dvi":{source:"apache",compressible:!1,extensions:["dvi"]},"application/x-envoy":{source:"apache",extensions:["evy"]},"application/x-eva":{source:"apache",extensions:["eva"]},"application/x-font-bdf":{source:"apache",extensions:["bdf"]},"application/x-font-dos":{source:"apache"},"application/x-font-framemaker":{source:"apache"},"application/x-font-ghostscript":{source:"apache",extensions:["gsf"]},"application/x-font-libgrx":{source:"apache"},"application/x-font-linux-psf":{source:"apache",extensions:["psf"]},"application/x-font-otf":{source:"apache",compressible:!0,extensions:["otf"]},"application/x-font-pcf":{source:"apache",extensions:["pcf"]},"application/x-font-snf":{source:"apache",extensions:["snf"]},"application/x-font-speedo":{source:"apache"},"application/x-font-sunos-news":{source:"apache"},"application/x-font-ttf":{source:"apache",compressible:!0,extensions:["ttf","ttc"]},"application/x-font-type1":{source:"apache",extensions:["pfa","pfb","pfm","afm"]},"application/x-font-vfont":{source:"apache"},"application/x-freearc":{source:"apache",extensions:["arc"]},"application/x-futuresplash":{source:"apache",extensions:["spl"]},"application/x-gca-compressed":{source:"apache",extensions:["gca"]},"application/x-glulx":{source:"apache",extensions:["ulx"]},"application/x-gnumeric":{source:"apache",extensions:["gnumeric"]},"application/x-gramps-xml":{source:"apache",extensions:["gramps"]},"application/x-gtar":{source:"apache",extensions:["gtar"]},"application/x-gzip":{source:"apache"},"application/x-hdf":{source:"apache",extensions:["hdf"]},"application/x-httpd-php":{compressible:!0,extensions:["php"]},"application/x-install-instructions":{source:"apache",extensions:["install"]},"application/x-iso9660-image":{source:"apache",extensions:["iso"]},"application/x-java-archive-diff":{source:"nginx",extensions:["jardiff"]},"application/x-java-jnlp-file":{source:"apache",compressible:!1,extensions:["jnlp"]},"application/x-javascript":{compressible:!0},"application/x-latex":{source:"apache",compressible:!1,extensions:["latex"]},"application/x-lua-bytecode":{extensions:["luac"]},"application/x-lzh-compressed":{source:"apache",extensions:["lzh","lha"]},"application/x-makeself":{source:"nginx",extensions:["run"]},"application/x-mie":{source:"apache",extensions:["mie"]},"application/x-mobipocket-ebook":{source:"apache",extensions:["prc","mobi"]},"application/x-mpegurl":{compressible:!1},"application/x-ms-application":{source:"apache",extensions:["application"]},"application/x-ms-shortcut":{source:"apache",extensions:["lnk"]},"application/x-ms-wmd":{source:"apache",extensions:["wmd"]},"application/x-ms-wmz":{source:"apache",extensions:["wmz"]},"application/x-ms-xbap":{source:"apache",extensions:["xbap"]},"application/x-msaccess":{source:"apache",extensions:["mdb"]},"application/x-msbinder":{source:"apache",extensions:["obd"]},"application/x-mscardfile":{source:"apache",extensions:["crd"]},"application/x-msclip":{source:"apache",extensions:["clp"]},"application/x-msdos-program":{extensions:["exe"]},"application/x-msdownload":{source:"apache",extensions:["exe","dll","com","bat","msi"]},"application/x-msmediaview":{source:"apache",extensions:["mvb","m13","m14"]},"application/x-msmetafile":{source:"apache",extensions:["wmf","wmz","emf","emz"]},"application/x-msmoney":{source:"apache",extensions:["mny"]},"application/x-mspublisher":{source:"apache",extensions:["pub"]},"application/x-msschedule":{source:"apache",extensions:["scd"]},"application/x-msterminal":{source:"apache",extensions:["trm"]},"application/x-mswrite":{source:"apache",extensions:["wri"]},"application/x-netcdf":{source:"apache",extensions:["nc","cdf"]},"application/x-ns-proxy-autoconfig":{compressible:!0,extensions:["pac"]},"application/x-nzb":{source:"apache",extensions:["nzb"]},"application/x-perl":{source:"nginx",extensions:["pl","pm"]},"application/x-pilot":{source:"nginx",extensions:["prc","pdb"]},"application/x-pkcs12":{source:"apache",compressible:!1,extensions:["p12","pfx"]},"application/x-pkcs7-certificates":{source:"apache",extensions:["p7b","spc"]},"application/x-pkcs7-certreqresp":{source:"apache",extensions:["p7r"]},"application/x-rar-compressed":{source:"apache",compressible:!1,extensions:["rar"]},"application/x-redhat-package-manager":{source:"nginx",extensions:["rpm"]},"application/x-research-info-systems":{source:"apache",extensions:["ris"]},"application/x-sea":{source:"nginx",extensions:["sea"]},"application/x-sh":{source:"apache",compressible:!0,extensions:["sh"]},"application/x-shar":{source:"apache",extensions:["shar"]},"application/x-shockwave-flash":{source:"apache",compressible:!1,extensions:["swf"]},"application/x-silverlight-app":{source:"apache",extensions:["xap"]},"application/x-sql":{source:"apache",extensions:["sql"]},"application/x-stuffit":{source:"apache",compressible:!1,extensions:["sit"]},"application/x-stuffitx":{source:"apache",extensions:["sitx"]},"application/x-subrip":{source:"apache",extensions:["srt"]},"application/x-sv4cpio":{source:"apache",extensions:["sv4cpio"]},"application/x-sv4crc":{source:"apache",extensions:["sv4crc"]},"application/x-t3vm-image":{source:"apache",extensions:["t3"]},"application/x-tads":{source:"apache",extensions:["gam"]},"application/x-tar":{source:"apache",compressible:!0,extensions:["tar"]},"application/x-tcl":{source:"apache",extensions:["tcl","tk"]},"application/x-tex":{source:"apache",extensions:["tex"]},"application/x-tex-tfm":{source:"apache",extensions:["tfm"]},"application/x-texinfo":{source:"apache",extensions:["texinfo","texi"]},"application/x-tgif":{source:"apache",extensions:["obj"]},"application/x-ustar":{source:"apache",extensions:["ustar"]},"application/x-virtualbox-hdd":{compressible:!0,extensions:["hdd"]},"application/x-virtualbox-ova":{compressible:!0,extensions:["ova"]},"application/x-virtualbox-ovf":{compressible:!0,extensions:["ovf"]},"application/x-virtualbox-vbox":{compressible:!0,extensions:["vbox"]},"application/x-virtualbox-vbox-extpack":{compressible:!1,extensions:["vbox-extpack"]},"application/x-virtualbox-vdi":{compressible:!0,extensions:["vdi"]},"application/x-virtualbox-vhd":{compressible:!0,extensions:["vhd"]},"application/x-virtualbox-vmdk":{compressible:!0,extensions:["vmdk"]},"application/x-wais-source":{source:"apache",extensions:["src"]},"application/x-web-app-manifest+json":{compressible:!0,extensions:["webapp"]},"application/x-www-form-urlencoded":{source:"iana",compressible:!0},"application/x-x509-ca-cert":{source:"apache",extensions:["der","crt","pem"]},"application/x-xfig":{source:"apache",extensions:["fig"]},"application/x-xliff+xml":{source:"apache",extensions:["xlf"]},"application/x-xpinstall":{source:"apache",compressible:!1,extensions:["xpi"]},"application/x-xz":{source:"apache",extensions:["xz"]},"application/x-zmachine":{source:"apache",extensions:["z1","z2","z3","z4","z5","z6","z7","z8"]},"application/x400-bp":{source:"iana"},"application/xacml+xml":{source:"iana"},"application/xaml+xml":{source:"apache",extensions:["xaml"]},"application/xcap-att+xml":{source:"iana"},"application/xcap-caps+xml":{source:"iana"},"application/xcap-diff+xml":{source:"iana",extensions:["xdf"]},"application/xcap-el+xml":{source:"iana"},"application/xcap-error+xml":{source:"iana"},"application/xcap-ns+xml":{source:"iana"},"application/xcon-conference-info+xml":{source:"iana"},"application/xcon-conference-info-diff+xml":{source:"iana"},"application/xenc+xml":{source:"iana",extensions:["xenc"]},"application/xhtml+xml":{source:"iana",compressible:!0,extensions:["xhtml","xht"]},"application/xhtml-voice+xml":{source:"apache"},"application/xml":{source:"iana",compressible:!0,extensions:["xml","xsl","xsd","rng"]},"application/xml-dtd":{source:"iana",compressible:!0,extensions:["dtd"]},"application/xml-external-parsed-entity":{source:"iana"},"application/xml-patch+xml":{source:"iana"},"application/xmpp+xml":{source:"iana"},"application/xop+xml":{source:"iana",compressible:!0,extensions:["xop"]},"application/xproc+xml":{source:"apache",extensions:["xpl"]},"application/xslt+xml":{source:"iana",extensions:["xslt"]},"application/xspf+xml":{source:"apache",extensions:["xspf"]},"application/xv+xml":{source:"iana",extensions:["mxml","xhvml","xvml","xvm"]},"application/yang":{source:"iana",extensions:["yang"]},"application/yang-data+json":{source:"iana",compressible:!0},"application/yang-data+xml":{source:"iana"},"application/yang-patch+json":{source:"iana",compressible:!0},"application/yang-patch+xml":{source:"iana"},"application/yin+xml":{source:"iana",extensions:["yin"]},"application/zip":{source:"iana",compressible:!1,extensions:["zip"]},"application/zlib":{source:"iana"},"audio/1d-interleaved-parityfec":{source:"iana"},"audio/32kadpcm":{source:"iana"},"audio/3gpp":{source:"iana",compressible:!1,extensions:["3gpp"]},"audio/3gpp2":{source:"iana"},"audio/ac3":{source:"iana"},"audio/adpcm":{source:"apache",extensions:["adp"]},"audio/amr":{source:"iana"},"audio/amr-wb":{source:"iana"},"audio/amr-wb+":{source:"iana"},"audio/aptx":{source:"iana"},"audio/asc":{source:"iana"},"audio/atrac-advanced-lossless":{source:"iana"},"audio/atrac-x":{source:"iana"},"audio/atrac3":{source:"iana"},"audio/basic":{source:"iana",compressible:!1,extensions:["au","snd"]},"audio/bv16":{source:"iana"},"audio/bv32":{source:"iana"},"audio/clearmode":{source:"iana"},"audio/cn":{source:"iana"},"audio/dat12":{source:"iana"},"audio/dls":{source:"iana"},"audio/dsr-es201108":{source:"iana"},"audio/dsr-es202050":{source:"iana"},"audio/dsr-es202211":{source:"iana"},"audio/dsr-es202212":{source:"iana"},"audio/dv":{source:"iana"},"audio/dvi4":{source:"iana"},"audio/eac3":{source:"iana"},"audio/encaprtp":{source:"iana"},"audio/evrc":{source:"iana"},"audio/evrc-qcp":{source:"iana"},"audio/evrc0":{source:"iana"},"audio/evrc1":{source:"iana"},"audio/evrcb":{source:"iana"},"audio/evrcb0":{source:"iana"},"audio/evrcb1":{source:"iana"},"audio/evrcnw":{source:"iana"},"audio/evrcnw0":{source:"iana"},"audio/evrcnw1":{source:"iana"},"audio/evrcwb":{source:"iana"},"audio/evrcwb0":{source:"iana"},"audio/evrcwb1":{source:"iana"},"audio/evs":{source:"iana"},"audio/fwdred":{source:"iana"},"audio/g711-0":{source:"iana"},"audio/g719":{source:"iana"},"audio/g722":{source:"iana"},"audio/g7221":{source:"iana"},"audio/g723":{source:"iana"},"audio/g726-16":{source:"iana"},"audio/g726-24":{source:"iana"},"audio/g726-32":{source:"iana"},"audio/g726-40":{source:"iana"},"audio/g728":{source:"iana"},"audio/g729":{source:"iana"},"audio/g7291":{source:"iana"},"audio/g729d":{source:"iana"},"audio/g729e":{source:"iana"},"audio/gsm":{source:"iana"},"audio/gsm-efr":{source:"iana"},"audio/gsm-hr-08":{source:"iana"},"audio/ilbc":{source:"iana"},"audio/ip-mr_v2.5":{source:"iana"},"audio/isac":{source:"apache"},"audio/l16":{source:"iana"},"audio/l20":{source:"iana"},"audio/l24":{source:"iana",compressible:!1},"audio/l8":{source:"iana"},"audio/lpc":{source:"iana"},"audio/melp":{source:"iana"},"audio/melp1200":{source:"iana"},"audio/melp2400":{source:"iana"},"audio/melp600":{source:"iana"},"audio/midi":{source:"apache",extensions:["mid","midi","kar","rmi"]},"audio/mobile-xmf":{source:"iana"},"audio/mp3":{compressible:!1,extensions:["mp3"]},"audio/mp4":{source:"iana",compressible:!1,extensions:["m4a","mp4a"]},"audio/mp4a-latm":{source:"iana"},"audio/mpa":{source:"iana"},"audio/mpa-robust":{source:"iana"},"audio/mpeg":{source:"iana",compressible:!1,extensions:["mpga","mp2","mp2a","mp3","m2a","m3a"]},"audio/mpeg4-generic":{source:"iana"},"audio/musepack":{source:"apache"},"audio/ogg":{source:"iana",compressible:!1,extensions:["oga","ogg","spx"]},"audio/opus":{source:"iana"},"audio/parityfec":{source:"iana"},"audio/pcma":{source:"iana"},"audio/pcma-wb":{source:"iana"},"audio/pcmu":{source:"iana"},"audio/pcmu-wb":{source:"iana"},"audio/prs.sid":{source:"iana"},"audio/qcelp":{source:"iana"},"audio/raptorfec":{source:"iana"},"audio/red":{source:"iana"},"audio/rtp-enc-aescm128":{source:"iana"},"audio/rtp-midi":{source:"iana"},"audio/rtploopback":{source:"iana"},"audio/rtx":{source:"iana"},"audio/s3m":{source:"apache",extensions:["s3m"]},"audio/silk":{source:"apache",extensions:["sil"]},"audio/smv":{source:"iana"},"audio/smv-qcp":{source:"iana"},"audio/smv0":{source:"iana"},"audio/sp-midi":{source:"iana"},"audio/speex":{source:"iana"},"audio/t140c":{source:"iana"},"audio/t38":{source:"iana"},"audio/telephone-event":{source:"iana"},"audio/tone":{source:"iana"},"audio/uemclip":{source:"iana"},"audio/ulpfec":{source:"iana"},"audio/vdvi":{source:"iana"},"audio/vmr-wb":{source:"iana"},"audio/vnd.3gpp.iufp":{source:"iana"},"audio/vnd.4sb":{source:"iana"},"audio/vnd.audiokoz":{source:"iana"},"audio/vnd.celp":{source:"iana"},"audio/vnd.cisco.nse":{source:"iana"},"audio/vnd.cmles.radio-events":{source:"iana"},"audio/vnd.cns.anp1":{source:"iana"},"audio/vnd.cns.inf1":{source:"iana"},"audio/vnd.dece.audio":{source:"iana",extensions:["uva","uvva"]},"audio/vnd.digital-winds":{source:"iana",extensions:["eol"]},"audio/vnd.dlna.adts":{source:"iana"},"audio/vnd.dolby.heaac.1":{source:"iana"},"audio/vnd.dolby.heaac.2":{source:"iana"},"audio/vnd.dolby.mlp":{source:"iana"},"audio/vnd.dolby.mps":{source:"iana"},"audio/vnd.dolby.pl2":{source:"iana"},"audio/vnd.dolby.pl2x":{source:"iana"},"audio/vnd.dolby.pl2z":{source:"iana"},"audio/vnd.dolby.pulse.1":{source:"iana"},"audio/vnd.dra":{source:"iana",extensions:["dra"]},"audio/vnd.dts":{source:"iana",extensions:["dts"]},"audio/vnd.dts.hd":{source:"iana",extensions:["dtshd"]},"audio/vnd.dvb.file":{source:"iana"},"audio/vnd.everad.plj":{source:"iana"},"audio/vnd.hns.audio":{source:"iana"},"audio/vnd.lucent.voice":{source:"iana",extensions:["lvp"]},"audio/vnd.ms-playready.media.pya":{source:"iana",extensions:["pya"]},"audio/vnd.nokia.mobile-xmf":{source:"iana"},"audio/vnd.nortel.vbk":{source:"iana"},"audio/vnd.nuera.ecelp4800":{source:"iana",extensions:["ecelp4800"]},"audio/vnd.nuera.ecelp7470":{source:"iana",extensions:["ecelp7470"]},"audio/vnd.nuera.ecelp9600":{source:"iana",extensions:["ecelp9600"]},"audio/vnd.octel.sbc":{source:"iana"},"audio/vnd.presonus.multitrack":{source:"iana"},"audio/vnd.qcelp":{source:"iana"},"audio/vnd.rhetorex.32kadpcm":{source:"iana"},"audio/vnd.rip":{source:"iana",extensions:["rip"]},"audio/vnd.rn-realaudio":{compressible:!1},"audio/vnd.sealedmedia.softseal.mpeg":{source:"iana"},"audio/vnd.vmx.cvsd":{source:"iana"},"audio/vnd.wave":{compressible:!1},"audio/vorbis":{source:"iana",compressible:!1},"audio/vorbis-config":{source:"iana"},"audio/wav":{compressible:!1,extensions:["wav"]},"audio/wave":{compressible:!1,extensions:["wav"]},"audio/webm":{source:"apache",compressible:!1,extensions:["weba"]},"audio/x-aac":{source:"apache",compressible:!1,extensions:["aac"]},"audio/x-aiff":{source:"apache",extensions:["aif","aiff","aifc"]},"audio/x-caf":{source:"apache",compressible:!1,extensions:["caf"]},"audio/x-flac":{source:"apache",extensions:["flac"]},"audio/x-m4a":{source:"nginx",extensions:["m4a"]},"audio/x-matroska":{source:"apache",extensions:["mka"]},"audio/x-mpegurl":{source:"apache",extensions:["m3u"]},"audio/x-ms-wax":{source:"apache",extensions:["wax"]},"audio/x-ms-wma":{source:"apache",extensions:["wma"]},"audio/x-pn-realaudio":{source:"apache",extensions:["ram","ra"]},"audio/x-pn-realaudio-plugin":{source:"apache",extensions:["rmp"]},"audio/x-realaudio":{source:"nginx",extensions:["ra"]},"audio/x-tta":{source:"apache"},"audio/x-wav":{source:"apache",extensions:["wav"]},"audio/xm":{source:"apache",extensions:["xm"]},"chemical/x-cdx":{source:"apache",extensions:["cdx"]},"chemical/x-cif":{source:"apache",extensions:["cif"]},"chemical/x-cmdf":{source:"apache",extensions:["cmdf"]},"chemical/x-cml":{source:"apache",extensions:["cml"]},"chemical/x-csml":{source:"apache",extensions:["csml"]},"chemical/x-pdb":{source:"apache"},"chemical/x-xyz":{source:"apache",extensions:["xyz"]},"font/otf":{compressible:!0,extensions:["otf"]},"image/apng":{compressible:!1,extensions:["apng"]},"image/bmp":{source:"iana",compressible:!0,extensions:["bmp"]},"image/cgm":{source:"iana",extensions:["cgm"]},"image/dicom-rle":{source:"iana"},"image/emf":{source:"iana"},"image/fits":{source:"iana"},"image/g3fax":{source:"iana",extensions:["g3"]},"image/gif":{source:"iana",compressible:!1,extensions:["gif"]},"image/ief":{source:"iana",extensions:["ief"]},"image/jls":{source:"iana"},"image/jp2":{source:"iana"},"image/jpeg":{source:"iana",compressible:!1,extensions:["jpeg","jpg","jpe"]},"image/jpm":{source:"iana"},"image/jpx":{source:"iana"},"image/ktx":{source:"iana",extensions:["ktx"]},"image/naplps":{source:"iana"},"image/pjpeg":{compressible:!1},"image/png":{source:"iana",compressible:!1,extensions:["png"]},"image/prs.btif":{source:"iana",extensions:["btif"]},"image/prs.pti":{source:"iana"},"image/pwg-raster":{source:"iana"},"image/sgi":{source:"apache",extensions:["sgi"]},"image/svg+xml":{source:"iana",compressible:!0,extensions:["svg","svgz"]},"image/t38":{source:"iana"},"image/tiff":{source:"iana",compressible:!1,extensions:["tiff","tif"]},"image/tiff-fx":{source:"iana"},"image/vnd.adobe.photoshop":{source:"iana",compressible:!0,extensions:["psd"]},"image/vnd.airzip.accelerator.azv":{source:"iana"},"image/vnd.cns.inf2":{source:"iana"},"image/vnd.dece.graphic":{source:"iana",extensions:["uvi","uvvi","uvg","uvvg"]},"image/vnd.djvu":{source:"iana",extensions:["djvu","djv"]},"image/vnd.dvb.subtitle":{source:"iana",extensions:["sub"]},"image/vnd.dwg":{source:"iana",extensions:["dwg"]},"image/vnd.dxf":{source:"iana",extensions:["dxf"]},"image/vnd.fastbidsheet":{source:"iana",extensions:["fbs"]},"image/vnd.fpx":{source:"iana",extensions:["fpx"]},"image/vnd.fst":{source:"iana",extensions:["fst"]},"image/vnd.fujixerox.edmics-mmr":{source:"iana",extensions:["mmr"]},"image/vnd.fujixerox.edmics-rlc":{source:"iana",extensions:["rlc"]},"image/vnd.globalgraphics.pgb":{source:"iana"},"image/vnd.microsoft.icon":{source:"iana"},"image/vnd.mix":{source:"iana"},"image/vnd.mozilla.apng":{source:"iana"},"image/vnd.ms-modi":{source:"iana",extensions:["mdi"]},"image/vnd.ms-photo":{source:"apache",extensions:["wdp"]},"image/vnd.net-fpx":{source:"iana",extensions:["npx"]},"image/vnd.radiance":{source:"iana"},"image/vnd.sealed.png":{source:"iana"},"image/vnd.sealedmedia.softseal.gif":{source:"iana"},"image/vnd.sealedmedia.softseal.jpg":{source:"iana"},"image/vnd.svf":{source:"iana"},"image/vnd.tencent.tap":{source:"iana"},"image/vnd.valve.source.texture":{source:"iana"},"image/vnd.wap.wbmp":{source:"iana",extensions:["wbmp"]},"image/vnd.xiff":{source:"iana",extensions:["xif"]},"image/vnd.zbrush.pcx":{source:"iana"},"image/webp":{source:"apache",extensions:["webp"]},"image/wmf":{source:"iana"},"image/x-3ds":{source:"apache",extensions:["3ds"]},"image/x-cmu-raster":{source:"apache",extensions:["ras"]},"image/x-cmx":{source:"apache",extensions:["cmx"]},"image/x-freehand":{source:"apache",extensions:["fh","fhc","fh4","fh5","fh7"]},"image/x-icon":{source:"apache",compressible:!0,extensions:["ico"]},"image/x-jng":{source:"nginx",extensions:["jng"]},"image/x-mrsid-image":{source:"apache",extensions:["sid"]},"image/x-ms-bmp":{source:"nginx",compressible:!0,extensions:["bmp"]},"image/x-pcx":{source:"apache",extensions:["pcx"]},"image/x-pict":{source:"apache",extensions:["pic","pct"]},"image/x-portable-anymap":{source:"apache",extensions:["pnm"]},"image/x-portable-bitmap":{source:"apache",extensions:["pbm"]},"image/x-portable-graymap":{source:"apache",extensions:["pgm"]},"image/x-portable-pixmap":{source:"apache",extensions:["ppm"]},"image/x-rgb":{source:"apache",extensions:["rgb"]},"image/x-tga":{source:"apache",extensions:["tga"]},"image/x-xbitmap":{source:"apache",extensions:["xbm"]},"image/x-xcf":{compressible:!1},"image/x-xpixmap":{source:"apache",extensions:["xpm"]},"image/x-xwindowdump":{source:"apache",extensions:["xwd"]},"message/cpim":{source:"iana"},"message/delivery-status":{source:"iana"},"message/disposition-notification":{source:"iana"},"message/external-body":{source:"iana"},"message/feedback-report":{source:"iana"},"message/global":{source:"iana"},"message/global-delivery-status":{source:"iana"},"message/global-disposition-notification":{source:"iana"},"message/global-headers":{source:"iana"},"message/http":{source:"iana",compressible:!1},"message/imdn+xml":{source:"iana",compressible:!0},"message/news":{source:"iana"},"message/partial":{source:"iana",compressible:!1},"message/rfc822":{source:"iana",compressible:!0,extensions:["eml","mime"]},"message/s-http":{source:"iana"},"message/sip":{source:"iana"},"message/sipfrag":{source:"iana"},"message/tracking-status":{source:"iana"},"message/vnd.si.simp":{source:"iana"},"message/vnd.wfa.wsc":{source:"iana"},"model/3mf":{source:"iana"},"model/gltf+json":{source:"iana",compressible:!0,extensions:["gltf"]},"model/gltf-binary":{compressible:!0,extensions:["glb"]},"model/iges":{source:"iana",compressible:!1,extensions:["igs","iges"]},"model/mesh":{source:"iana",compressible:!1,extensions:["msh","mesh","silo"]},"model/vnd.collada+xml":{source:"iana",extensions:["dae"]},"model/vnd.dwf":{source:"iana",extensions:["dwf"]},"model/vnd.flatland.3dml":{source:"iana"},"model/vnd.gdl":{source:"iana",extensions:["gdl"]},"model/vnd.gs-gdl":{source:"apache"},"model/vnd.gs.gdl":{source:"iana"},"model/vnd.gtw":{source:"iana",extensions:["gtw"]},"model/vnd.moml+xml":{source:"iana"},"model/vnd.mts":{source:"iana",extensions:["mts"]},"model/vnd.opengex":{source:"iana"},"model/vnd.parasolid.transmit.binary":{source:"iana"},"model/vnd.parasolid.transmit.text":{source:"iana"},"model/vnd.rosette.annotated-data-model":{source:"iana"},"model/vnd.valve.source.compiled-map":{source:"iana"},"model/vnd.vtu":{source:"iana",extensions:["vtu"]},"model/vrml":{source:"iana",compressible:!1,extensions:["wrl","vrml"]},"model/x3d+binary":{source:"apache",compressible:!1,extensions:["x3db","x3dbz"]},"model/x3d+fastinfoset":{source:"iana"},"model/x3d+vrml":{source:"apache",compressible:!1,extensions:["x3dv","x3dvz"]},"model/x3d+xml":{source:"iana",compressible:!0,extensions:["x3d","x3dz"]},"model/x3d-vrml":{source:"iana"},"multipart/alternative":{source:"iana",compressible:!1},"multipart/appledouble":{source:"iana"},"multipart/byteranges":{source:"iana"},"multipart/digest":{source:"iana"},"multipart/encrypted":{source:"iana",compressible:!1},"multipart/form-data":{source:"iana",compressible:!1},"multipart/header-set":{source:"iana"},"multipart/mixed":{source:"iana",compressible:!1},"multipart/parallel":{source:"iana"},"multipart/related":{source:"iana",compressible:!1},"multipart/report":{source:"iana"},"multipart/signed":{source:"iana",compressible:!1},"multipart/vnd.bint.med-plus":{source:"iana"},"multipart/voice-message":{source:"iana"},"multipart/x-mixed-replace":{source:"iana"},"text/1d-interleaved-parityfec":{source:"iana"},"text/cache-manifest":{source:"iana",compressible:!0,extensions:["appcache","manifest"]},"text/calendar":{source:"iana",extensions:["ics","ifb"]},"text/calender":{compressible:!0},"text/cmd":{compressible:!0},"text/coffeescript":{extensions:["coffee","litcoffee"]},"text/css":{source:"iana",charset:"UTF-8",compressible:!0,extensions:["css"]},"text/csv":{source:"iana",compressible:!0,extensions:["csv"]},"text/csv-schema":{source:"iana"},"text/directory":{source:"iana"},"text/dns":{source:"iana"},"text/ecmascript":{source:"iana"},"text/encaprtp":{source:"iana"},"text/enriched":{source:"iana"},"text/fwdred":{source:"iana"},"text/grammar-ref-list":{source:"iana"},"text/hjson":{extensions:["hjson"]},"text/html":{source:"iana",compressible:!0,extensions:["html","htm","shtml"]},"text/jade":{extensions:["jade"]},"text/javascript":{source:"iana",compressible:!0},"text/jcr-cnd":{source:"iana"},"text/jsx":{compressible:!0,extensions:["jsx"]},"text/less":{extensions:["less"]},"text/markdown":{source:"iana",compressible:!0,extensions:["markdown","md"]},"text/mathml":{source:"nginx",extensions:["mml"]},"text/mizar":{source:"iana"},"text/n3":{source:"iana",compressible:!0,extensions:["n3"]},"text/parameters":{source:"iana"},"text/parityfec":{source:"iana"},"text/plain":{source:"iana",compressible:!0,extensions:["txt","text","conf","def","list","log","in","ini"]},"text/provenance-notation":{source:"iana"},"text/prs.fallenstein.rst":{source:"iana"},"text/prs.lines.tag":{source:"iana",extensions:["dsc"]},"text/prs.prop.logic":{source:"iana"},"text/raptorfec":{source:"iana"},"text/red":{source:"iana"},"text/rfc822-headers":{source:"iana"},"text/richtext":{source:"iana",compressible:!0,extensions:["rtx"]},"text/rtf":{source:"iana",compressible:!0,extensions:["rtf"]},"text/rtp-enc-aescm128":{source:"iana"},"text/rtploopback":{source:"iana"},"text/rtx":{source:"iana"},"text/sgml":{source:"iana",extensions:["sgml","sgm"]},"text/slim":{extensions:["slim","slm"]},"text/strings":{source:"iana"},"text/stylus":{extensions:["stylus","styl"]},"text/t140":{source:"iana"},"text/tab-separated-values":{source:"iana",compressible:!0,extensions:["tsv"]},"text/troff":{source:"iana",extensions:["t","tr","roff","man","me","ms"]},"text/turtle":{source:"iana",extensions:["ttl"]},"text/ulpfec":{source:"iana"},"text/uri-list":{source:"iana",compressible:!0,extensions:["uri","uris","urls"]},"text/vcard":{source:"iana",compressible:!0,extensions:["vcard"]},"text/vnd.a":{source:"iana"},"text/vnd.abc":{source:"iana"},"text/vnd.ascii-art":{source:"iana"},"text/vnd.curl":{source:"iana",extensions:["curl"]},"text/vnd.curl.dcurl":{source:"apache",extensions:["dcurl"]},"text/vnd.curl.mcurl":{source:"apache",extensions:["mcurl"]},"text/vnd.curl.scurl":{source:"apache",extensions:["scurl"]},"text/vnd.debian.copyright":{source:"iana"},"text/vnd.dmclientscript":{source:"iana"},"text/vnd.dvb.subtitle":{source:"iana",extensions:["sub"]},"text/vnd.esmertec.theme-descriptor":{source:"iana"},"text/vnd.fly":{source:"iana",extensions:["fly"]},"text/vnd.fmi.flexstor":{source:"iana",extensions:["flx"]},"text/vnd.graphviz":{source:"iana",extensions:["gv"]},"text/vnd.in3d.3dml":{source:"iana",extensions:["3dml"]},"text/vnd.in3d.spot":{source:"iana",extensions:["spot"]},"text/vnd.iptc.newsml":{source:"iana"},"text/vnd.iptc.nitf":{source:"iana"},"text/vnd.latex-z":{source:"iana"},"text/vnd.motorola.reflex":{source:"iana"},"text/vnd.ms-mediapackage":{source:"iana"},"text/vnd.net2phone.commcenter.command":{source:"iana"},"text/vnd.radisys.msml-basic-layout":{source:"iana"},"text/vnd.si.uricatalogue":{source:"iana"},"text/vnd.sun.j2me.app-descriptor":{source:"iana",extensions:["jad"]},"text/vnd.trolltech.linguist":{source:"iana"},"text/vnd.wap.si":{source:"iana"},"text/vnd.wap.sl":{source:"iana"},"text/vnd.wap.wml":{source:"iana",extensions:["wml"]},"text/vnd.wap.wmlscript":{source:"iana",extensions:["wmls"]},"text/vtt":{charset:"UTF-8",compressible:!0,extensions:["vtt"]},"text/x-asm":{source:"apache",extensions:["s","asm"]},"text/x-c":{source:"apache",extensions:["c","cc","cxx","cpp","h","hh","dic"]},"text/x-component":{source:"nginx",extensions:["htc"]},"text/x-fortran":{source:"apache",extensions:["f","for","f77","f90"]},"text/x-gwt-rpc":{compressible:!0},"text/x-handlebars-template":{extensions:["hbs"]},"text/x-java-source":{source:"apache",extensions:["java"]},"text/x-jquery-tmpl":{compressible:!0},"text/x-lua":{extensions:["lua"]},"text/x-markdown":{compressible:!0,extensions:["mkd"]},"text/x-nfo":{source:"apache",extensions:["nfo"]},"text/x-opml":{source:"apache",extensions:["opml"]},"text/x-org":{compressible:!0,extensions:["org"]},"text/x-pascal":{source:"apache",extensions:["p","pas"]},"text/x-processing":{compressible:!0,extensions:["pde"]},"text/x-sass":{extensions:["sass"]},"text/x-scss":{extensions:["scss"]},"text/x-setext":{source:"apache",extensions:["etx"]},"text/x-sfv":{source:"apache",extensions:["sfv"]},"text/x-suse-ymp":{compressible:!0,extensions:["ymp"]},"text/x-uuencode":{source:"apache",extensions:["uu"]},"text/x-vcalendar":{source:"apache",extensions:["vcs"]},"text/x-vcard":{source:"apache",extensions:["vcf"]},"text/xml":{source:"iana",compressible:!0,extensions:["xml"]},"text/xml-external-parsed-entity":{source:"iana"},"text/yaml":{extensions:["yaml","yml"]},"video/1d-interleaved-parityfec":{source:"iana"},"video/3gpp":{source:"iana",extensions:["3gp","3gpp"]},"video/3gpp-tt":{source:"iana"},"video/3gpp2":{source:"iana",extensions:["3g2"]},"video/bmpeg":{source:"iana"},"video/bt656":{source:"iana"},"video/celb":{source:"iana"},"video/dv":{source:"iana"},"video/encaprtp":{source:"iana"},"video/h261":{source:"iana",extensions:["h261"]},"video/h263":{source:"iana",extensions:["h263"]},"video/h263-1998":{source:"iana"},"video/h263-2000":{source:"iana"},"video/h264":{source:"iana",extensions:["h264"]},"video/h264-rcdo":{source:"iana"},"video/h264-svc":{source:"iana"},"video/h265":{source:"iana"},"video/iso.segment":{source:"iana"},"video/jpeg":{source:"iana",extensions:["jpgv"]},"video/jpeg2000":{source:"iana"},"video/jpm":{source:"apache",extensions:["jpm","jpgm"]},"video/mj2":{source:"iana",extensions:["mj2","mjp2"]},"video/mp1s":{source:"iana"},"video/mp2p":{source:"iana"},"video/mp2t":{source:"iana",extensions:["ts"]},"video/mp4":{source:"iana",compressible:!1,extensions:["mp4","mp4v","mpg4"]},"video/mp4v-es":{source:"iana"},"video/mpeg":{source:"iana",compressible:!1,extensions:["mpeg","mpg","mpe","m1v","m2v"]},"video/mpeg4-generic":{source:"iana"},"video/mpv":{source:"iana"},"video/nv":{source:"iana"},"video/ogg":{source:"iana",compressible:!1,extensions:["ogv"]},"video/parityfec":{source:"iana"},"video/pointer":{source:"iana"},"video/quicktime":{source:"iana",compressible:!1,extensions:["qt","mov"]},"video/raptorfec":{source:"iana"},"video/raw":{source:"iana"},"video/rtp-enc-aescm128":{source:"iana"},"video/rtploopback":{source:"iana"},"video/rtx":{source:"iana"},"video/smpte292m":{source:"iana"},"video/ulpfec":{source:"iana"},"video/vc1":{source:"iana"},"video/vnd.cctv":{source:"iana"},"video/vnd.dece.hd":{source:"iana",extensions:["uvh","uvvh"]},"video/vnd.dece.mobile":{source:"iana",extensions:["uvm","uvvm"]},"video/vnd.dece.mp4":{source:"iana"},"video/vnd.dece.pd":{source:"iana",extensions:["uvp","uvvp"]},"video/vnd.dece.sd":{source:"iana",extensions:["uvs","uvvs"]},"video/vnd.dece.video":{source:"iana",extensions:["uvv","uvvv"]},"video/vnd.directv.mpeg":{source:"iana"},"video/vnd.directv.mpeg-tts":{source:"iana"},"video/vnd.dlna.mpeg-tts":{source:"iana"},"video/vnd.dvb.file":{source:"iana",extensions:["dvb"]},"video/vnd.fvt":{source:"iana",extensions:["fvt"]},"video/vnd.hns.video":{source:"iana"},"video/vnd.iptvforum.1dparityfec-1010":{source:"iana"},"video/vnd.iptvforum.1dparityfec-2005":{source:"iana"},"video/vnd.iptvforum.2dparityfec-1010":{source:"iana"},"video/vnd.iptvforum.2dparityfec-2005":{source:"iana"},"video/vnd.iptvforum.ttsavc":{source:"iana"},"video/vnd.iptvforum.ttsmpeg2":{source:"iana"},"video/vnd.motorola.video":{source:"iana"},"video/vnd.motorola.videop":{source:"iana"},"video/vnd.mpegurl":{source:"iana",extensions:["mxu","m4u"]},"video/vnd.ms-playready.media.pyv":{source:"iana",extensions:["pyv"]},"video/vnd.nokia.interleaved-multimedia":{source:"iana"},"video/vnd.nokia.videovoip":{source:"iana"},"video/vnd.objectvideo":{source:"iana"},"video/vnd.radgamettools.bink":{source:"iana"},"video/vnd.radgamettools.smacker":{source:"iana"},"video/vnd.sealed.mpeg1":{source:"iana"},"video/vnd.sealed.mpeg4":{source:"iana"},"video/vnd.sealed.swf":{source:"iana"},"video/vnd.sealedmedia.softseal.mov":{source:"iana"},"video/vnd.uvvu.mp4":{source:"iana",extensions:["uvu","uvvu"]},"video/vnd.vivo":{source:"iana",extensions:["viv"]},"video/vp8":{source:"iana"},"video/webm":{source:"apache",compressible:!1,extensions:["webm"]},"video/x-f4v":{source:"apache",extensions:["f4v"]},"video/x-fli":{source:"apache",extensions:["fli"]},"video/x-flv":{source:"apache",compressible:!1,extensions:["flv"]},"video/x-m4v":{source:"apache",extensions:["m4v"]},"video/x-matroska":{source:"apache",compressible:!1,extensions:["mkv","mk3d","mks"]},"video/x-mng":{source:"apache",extensions:["mng"]},"video/x-ms-asf":{source:"apache",extensions:["asf","asx"]},"video/x-ms-vob":{source:"apache",extensions:["vob"]},"video/x-ms-wm":{source:"apache",extensions:["wm"]},"video/x-ms-wmv":{source:"apache",compressible:!1,extensions:["wmv"]},"video/x-ms-wmx":{source:"apache",extensions:["wmx"]},"video/x-ms-wvx":{source:"apache",extensions:["wvx"]},"video/x-msvideo":{source:"apache",extensions:["avi"]},"video/x-sgi-movie":{source:"apache",extensions:["movie"]},"video/x-smv":{source:"apache",extensions:["smv"]},"x-conference/x-cooltalk":{source:"apache",extensions:["ice"]},"x-shader/x-fragment":{compressible:!0},"x-shader/x-vertex":{compressible:!0}}},function(e,t,n){(function(e){function n(e,t){for(var n=0,a=e.length-1;a>=0;a--){var i=e[a];"."===i?e.splice(a,1):".."===i?(e.splice(a,1),n++):n&&(e.splice(a,1),n--)}if(t)for(;n--;n)e.unshift("..");return e}function a(e,t){if(e.filter)return e.filter(t);for(var n=[],a=0;a=-1&&!i;r--){var o=r>=0?arguments[r]:e.cwd();if("string"!=typeof o)throw new TypeError("Arguments to path.resolve must be strings");o&&(t=o+"/"+t,i="/"===o.charAt(0))}return t=n(a(t.split("/"),function(e){return!!e}),!i).join("/"),(i?"/":"")+t||"."},t.normalize=function(e){var i=t.isAbsolute(e),r="/"===o(e,-1);return e=n(a(e.split("/"),function(e){return!!e}),!i).join("/"),e||i||(e="."),e&&r&&(e+="/"),(i?"/":"")+e},t.isAbsolute=function(e){return"/"===e.charAt(0)},t.join=function(){var e=Array.prototype.slice.call(arguments,0);return t.normalize(a(e,function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e}).join("/"))},t.relative=function(e,n){function a(e){for(var t=0;t=0&&""===e[n];n--);return t>n?[]:e.slice(t,n-t+1)}e=t.resolve(e).substr(1),n=t.resolve(n).substr(1);for(var i=a(e.split("/")),r=a(n.split("/")),o=Math.min(i.length,r.length),s=o,c=0;c1)for(var n=1;n0?a():i(),!(l<=0)){var t=document.getElementById("timeline-pause-resume");t.removeEventListener("click",d),t.addEventListener("click",d=function(){f?c():s(n)}),m=0,h=0,o();var n=Math.random();p=n,l>0?s(n):c();var r=null;if(!$("#timeline-progress input").data("ionRangeSlider")){$("#timeline-progress input").ionRangeSlider({from_shadow:!0,force_edges:!0,onChange:function(e){h=e.from,u.setPose(h),null==r&&(r=f),c()},onFinish:function(){r&&s(n),r=null}}),$("#timeline-range input").ionRangeSlider({from_shadow:!0,force_edges:!0,type:"double",drag_interval:!0,grid:!0,grid_num:10,onChange:function(e){l=e.to-e.from,m=e.from,h=Math.min(Math.max(e.from,h),e.to),u.setPose(h),v.update({from_min:e.from,from_max:e.to})}});var v=$("#timeline-progress input").data("ionRangeSlider"),g=$("#timeline-range input").data("ionRangeSlider");v.update({min:0,max:l,from:h,from_min:0,from_max:l}),g.update({min:0,max:l,from:0,to:l})}}}function o(){var e=$("#timeline-progress input").data("ionRangeSlider");e&&e.update({from:h})}function s(e){function t(){if(f&&e===p){u.setPose(h);var a=Math.min(Date.now()-n,20);n=Date.now(),o(),h+=a,h>m+l&&(h=m),requestAnimationFrame(t)}}if(!f){f=!0;var n=Date.now(),a=document.getElementById("timeline-pause-resume");a.classList.remove("icon-resume"),a.classList.add("icon-pause"),requestAnimationFrame(t)}}function c(){if(f){f=!1;var e=document.getElementById("timeline-pause-resume");e.classList.remove("icon-pause"),e.classList.add("icon-resume")}}n.d(t,"b",function(){return r}),n.d(t,"a",function(){return i});var l,u,p,d,f=!1,h=0,m=0},function(e,t,n){"use strict";var a=n(5),i=(n(3),n(13)),r=n(2),o=n(11),s=n(10),c=n(160);r.a.import(c.a);var l=new a.a,u=new o.a;u.attach(l);var p=new i.a({fragment:r.a.source("qmv.editor.edge")}),d=new s.a({shader:new r.a(r.a.source("clay.basic.vertex"),r.a.source("clay.basic.fragment"))});t.a=function(e,t,n){var a=e.getRenderer();l.width=a.getWidth(),l.height=a.getHeight(),u.bind(a),a.gl.clearColor(0,0,0,0),a.gl.clear(a.gl.COLOR_BUFFER_BIT|a.gl.DEPTH_BUFFER_BIT),n.update(),a.renderPass(t,n,{getMaterial:function(){return d}}),u.unbind(a),p.setUniform("edgeWidth",1.5),p.setUniform("edgeColor",[1,1,0,1]),p.setUniform("texture",l),p.setUniform("textureSize",[l.width,l.height]),p.render(a)}},function(e,t,n){"use strict";t.a="@export qmv.editor.edge\n\nuniform sampler2D texture;\n\nuniform vec2 textureSize;\n\nuniform vec4 edgeColor: [0,0,0,1.0];\nuniform float edgeWidth: 1;\n\nvarying vec2 v_Texcoord;\n\nfloat getCol(vec2 coord) {\n return texture2D(texture, coord).a;\n}\n\nvoid main() {\n vec2 cc = v_Texcoord;\n float center = getCol(cc);\n\n float dx = edgeWidth / textureSize.x;\n float dy = edgeWidth / textureSize.y;\n\n vec2 coord;\n float topLeft = getCol(cc+vec2(-dx, -dy));\n float top = getCol(cc+vec2(0.0, -dy));\n float topRight = getCol(cc+vec2(dx, -dy));\n float left = getCol(cc+vec2(-dx, 0.0));\n float right = getCol(cc+vec2(dx, 0.0));\n float bottomLeft = getCol(cc+vec2(-dx, dy));\n float bottom = getCol(cc+vec2(0.0, dy));\n float bottomRight = getCol(cc+vec2(dx, dy));\n\n float v = -topLeft-2.0*top-topRight+bottomLeft+2.0*bottom+bottomRight;\n float h = -bottomLeft-2.0*left-topLeft+bottomRight+2.0*right+topRight;\n\n float edge = sqrt(h * h + v * v);\n\n edge = smoothstep(0.9, 1.0, edge);\n if (edge < 0.5) {\n discard;\n }\n\n gl_FragColor = edgeColor;\n}\n@end"},function(e,t,n){"use strict";t.a=function(e){window.open(e)}}]); \ No newline at end of file diff --git a/package.json b/package.json index b17af32..d6c10ed 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "clay-viewer", - "version": "0.1.2", + "version": "0.2.0", "description": "Clay Viewer is built on top of WebGL, Supported FBX, DAE, OBJ, glTF2.0 model formats.", "main": "dist/clay-viewer.js", "dependencies": { - "claygl": "^1.0.0", - "zrender": "^3.7.2" + "claygl": "^1.1.0", + "zrender": "^4.0.0" }, "devDependencies": { "case-sensitive-paths-webpack-plugin": "^2.0.0",