@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
3 lines (2 loc) • 8.65 kB
JavaScript
/* COPYRIGHT Esri - https://js.arcgis.com/5.0.8/LICENSE.txt */
import"../../../../../../core/has.js";import{isPowerOfTwo as e,nextPowerOfTwo as t}from"../../../../../../core/mathUtils.js";import{disposeMaybe as r}from"../../../../../../core/maybe.js";import{simplePipelineState as s}from"../utils.js";import{Technique as u}from"./Technique.js";import{TextureStatisticsDiffShader as o}from"./shaders/TextureStatisticsDiffShader.js";import{TextureStatisticsMinMaxSumShader as i}from"./shaders/TextureStatisticsMinMaxSumShader.js";import{TextureStatisticsStdDevShader as a}from"./shaders/TextureStatisticsStdDevShader.js";import{TextureStatisticsSumOfSquaredDiffShader as f}from"./shaders/TextureStatisticsSumOfSquaredDiffShader.js";import{getWebGLCapabilities as n}from"../../../../../webgl/capabilities.js";import{ColorAttachment2 as l,ColorAttachment3 as h,ColorAttachment0 as m,ColorAttachment1 as x,SizedPixelFormat as c,PixelType as T}from"../../../../../webgl/enums.js";import{FramebufferObject as d}from"../../../../../webgl/FramebufferObject.js";import p from"../../../../../webgl/Texture.js";import{TextureDescriptor as b}from"../../../../../webgl/TextureDescriptor.js";const _=1048576;class F extends u{constructor(){super(...arguments),this.type=33,this._width=0,this._height=0,this._framebuffers=null,this._minTexture=null,this._maxTexture=null,this._sumTexture=null,this._numOfNoDataTexture=null,this._resultsFramebuffer=null,this._startFramebuffer=null,this._diffFramebuffer=null,this._scaleFbo=null,this.shaders={textureStatisticsMinMaxSum:new i,textureStatisticsSum:new f,textureStatisticsDiff:new o,textureStatisticsStdDev:new a}}dispose(){this.shaders.textureStatisticsMinMaxSum=null,this._framebuffers&&(this._framebuffers.forEach(e=>r(e)),this._framebuffers=null),r(this._resultsFramebuffer),r(this._startFramebuffer),r(this._diffFramebuffer),r(this._scaleFbo),r(this._minTexture),r(this._maxTexture),r(this._sumTexture),r(this._numOfNoDataTexture)}get minValuesTexture(){return this._minTexture||null}get maxValuesTexture(){return this._maxTexture||null}get meanValuesTexture(){return this._resultsFramebuffer?.getColorTexture(l)||null}get stdDevValuesTexture(){return this._resultsFramebuffer?.getColorTexture(h)||null}get statsFbo(){return this._resultsFramebuffer}render(t,r){const{context:u,painter:o}=t;let i=r.fbo.width,a=r.fbo.height,f=r.fbo;const n=u.gl,l=u.getBoundFramebufferObject();if(i*a>_||!e(i)||!e(a)){const t=i/a;if(i*a>_){const e=Math.max(Math.floor(Math.sqrt(_/t)),1);i=Math.max(Math.floor(t*e),1),a=e}if(e(i)||(i=S(i)),e(a)||(a=S(a)),this._scaleFbo)this._scaleFbo.resize(i,a);else{const{dataType:e,internalFormat:t}=r.fbo.getColorTexture(m).descriptor,s=t??c.RGBA8;this._scaleFbo=w(u,i,a,e,s)}u.bindFramebuffer(this._scaleFbo),u.setViewport(0,0,i,a),o.blitTexture(u,f.getColorTexture(m),9728),f=this._scaleFbo}this._updateResources(t,f),o.setPipelineState({...s,color:{write:[!0,!0,!0,!0],blendMode:"none"}});const h=this._applyReductionPass(t);n.readBuffer(n.COLOR_ATTACHMENT3),h.copyToTexture(0,0,1,1,0,0,this._numOfNoDataTexture),n.readBuffer(n.COLOR_ATTACHMENT2),h.copyToTexture(0,0,1,1,0,0,this._sumTexture),n.readBuffer(n.COLOR_ATTACHMENT1),h.copyToTexture(0,0,1,1,0,0,this._maxTexture),n.readBuffer(n.COLOR_ATTACHMENT0),h.copyToTexture(0,0,1,1,0,0,this._minTexture);const x=r.fbo.getColorTexture(m);if(!x)throw new Error("Start buffer color texture is not available, cannot compute diff.");this._computeDiff(t,x,this._sumTexture,this._numOfNoDataTexture,i,a);const T=this._applySecondReductionPass(t,i,a).getColorTexture(m);this._computeSdtDev(t,this._minTexture,this._maxTexture,this._sumTexture,this._numOfNoDataTexture,T,i,a),u.bindFramebuffer(l),u.setViewport(0,0,r.fbo.width,r.fbo.height),u.setDrawBuffers([m]),o.setPipelineState(s)}_applyReductionPass(e){const{context:t,painter:r}=e,s=this.shaders.textureStatisticsMinMaxSum,u=this._framebuffers;if(null===u)throw new Error("Framebuffers are not initialized, cannot apply reduction pass.");t.setDrawBuffers([m,x,l]);const o=this._startFramebuffer;let i=o.getColorTexture(m),a=o.getColorTexture(x),f=o.getColorTexture(l),n=o.getColorTexture(h);const c=u;let T=0;for(const d of c){t.setViewport(0,0,d.width,d.height),t.bindFramebuffer(d),t.setClearColor(0,0,0,0),t.clear(16384);const e={shader:s,uniforms:{config:{minTexture:{texture:i,unit:1},maxTexture:{texture:a,unit:2},sumTexture:{texture:f,unit:3},numOfNoDataTexture:{texture:n,unit:4},width:d.width,height:d.height,isFirstPass:0===T?1:0}},defines:null,optionalAttributes:null,useComputeBuffer:!1};r.submitDrawMesh(t,e,r.quadMesh),i=d.getColorTexture(m),a=d.getColorTexture(x),f=d.getColorTexture(l),n=d.getColorTexture(h),T++}return u.at(-1)}_applySecondReductionPass(e,t,r){const{context:s,painter:u}=e,o=this.shaders.textureStatisticsSum,i=this._framebuffers;if(null===i||null==this._diffFramebuffer)throw new Error("Framebuffers are not initialized, cannot apply reduction pass.");s.setDrawBuffers([m]);let a=this._diffFramebuffer.getColorTexture(m);const f=i;for(const n of f){s.setViewport(0,0,n.width,n.height),s.bindFramebuffer(n),s.setClearColor(0,0,0,0),s.clear(16384);const e={shader:o,uniforms:{config:{sumTexture:{texture:a,unit:2},width:n.width,height:n.height}},defines:null,optionalAttributes:null,useComputeBuffer:!1};u.submitDrawMesh(s,e,u.quadMesh),a=n.getColorTexture(m)}return i.at(-1)}_updateResources(e,t){const{context:r}=e,s=t.width,u=t.height;if(null===this._startFramebuffer){if(!n().supportsColorBufferFloat)throw new Error("WebGL does not support color buffer float, cannot compute texture statistics.");const e=t.getColorTexture(m);if(!e)throw new Error("Input FBO does not have a color attachment 0, cannot compute texture statistics.");const o=e.descriptor,{dataType:i,internalFormat:a}=o,f=w(r,s,u,i,a??c.RGBA8,4),d=f.getColorTexture(m),p=f.getColorTexture(x),b=f.getColorTexture(l),_=f.getColorTexture(h);t.copyToTexture(0,0,s,u,0,0,d),t.copyToTexture(0,0,s,u,0,0,p),t.copyToTexture(0,0,s,u,0,0,b),t.copyToTexture(0,0,s,u,0,0,_),this._startFramebuffer=f,this._diffFramebuffer=w(r,s,u,T.FLOAT,c.RGBA32F),this._resultsFramebuffer=w(r,1,1,T.FLOAT,c.RGBA32F,4),this._minTexture=C(r,1,1,T.FLOAT,c.RGBA32F),this._maxTexture=C(r,1,1,T.FLOAT,c.RGBA32F),this._sumTexture=C(r,1,1,T.FLOAT,c.RGBA32F),this._numOfNoDataTexture=C(r,1,1,T.FLOAT,c.R32F)}else{const e=this._startFramebuffer;e.resize(s,u);const r=e.getColorTexture(m),o=e.getColorTexture(x),i=e.getColorTexture(l),a=e.getColorTexture(h);t.copyToTexture(0,0,s,u,0,0,r),t.copyToTexture(0,0,s,u,0,0,o),t.copyToTexture(0,0,s,u,0,0,i),t.copyToTexture(0,0,s,u,0,0,a),this._diffFramebuffer.resize(s,u)}if(this._width===s&&this._height===u&&null!==this._framebuffers)return;const o=(this._framebuffers||[]).reverse();this._framebuffers=null,this._width=s,this._height=u,this._framebuffers=this._updateFramebuffers(r,s,u,o,4)}_updateFramebuffers(e,t,s,u,o=1){const i=[];let a=t,f=s;for(;a>1||f>1;){const t=Math.max(1,Math.floor(a/2)),r=Math.max(1,Math.floor(f/2)),s=g(e,t,r,u,o);i.push(s),a=t,f=r}return i.at(-1),u.forEach(e=>r(e)),u.length=0,i}_computeDiff(e,t,r,s,u,o){const{context:i,painter:a}=e;i.bindFramebuffer(this._diffFramebuffer),i.setDrawBuffers([m]),i.setViewport(0,0,u,o),i.setClearColor(0,0,0,0),i.clear(16384);const f={shader:this.shaders.textureStatisticsDiff,uniforms:{config:{inputTexture:{texture:t,unit:1},sumTexture:{texture:r,unit:2},numOfNoDataTexture:{texture:s,unit:3},numTexels:u*o}},defines:null,optionalAttributes:null,useComputeBuffer:!1};a.submitDrawMesh(i,f,a.quadMesh)}_computeSdtDev(e,t,r,s,u,o,i,a){const{context:f,painter:n}=e;f.bindFramebuffer(this._resultsFramebuffer),f.setDrawBuffers([m,x,l,h]),f.setViewport(0,0,1,1),f.setClearColor(0,0,0,0),f.clear(16384);const c={shader:this.shaders.textureStatisticsStdDev,uniforms:{config:{minTexture:{texture:t,unit:1},maxTexture:{texture:r,unit:2},sumTexture:{texture:s,unit:3},numOfNoDataTexture:{texture:u,unit:4},diffSqTexture:{texture:o,unit:5},numTexels:i*a}},defines:null,optionalAttributes:null,useComputeBuffer:!1};n.submitDrawMesh(f,c,n.quadMesh)}}function g(e,t,r,s,u=1){let o=s.pop();return void 0!==o?o.resize(t,r):o=w(e,t,r,T.FLOAT,c.RGBA32F,u),o}function w(e,t,r,s,u,o=1){if(o<1||o>4)throw new Error("Number of color attachments must be between 1 and 4.");const i=new d(e,C(e,t,r,s,u));for(let a=1;a<o;a++){const o=C(e,t,r,s,u);i.attachColorTexture(o,m+a)}return i}function C(e,t,r,s,u){const o=new b(t,r);return o.samplingMode=9728,o.wrapMode=33071,o.pixelFormat=6408,o.dataType=s,o.internalFormat=u,new p(e,o)}function S(e){const r=t(e),s=r/2;return Math.abs(r-e)<Math.abs(s-e)?r:s}export{F as TextureStatisticsTechnique};