@doegis/core
Version:
DOE GIS API
3 lines (1 loc) • 7.29 kB
JavaScript
import t from"../../../../core/Error.js";import has from"../../../../core/has.js";import e from"../../../../core/Logger.js";import{isNone as i,mapMany as s,isSome as r,applySome as a,unwrap as d,forEachSome as h,mapOr as n,unwrapOr as o}from"../../../../core/maybe.js";import{createResolver as u}from"../../../../core/promiseUtils.js";import{ATTRIBUTE_DATA_VV as l,TEXTURE_BINDING_ATTRIBUTE_DATA_0 as p,TEXTURE_BINDING_ATTRIBUTE_DATA_1 as x,TEXTURE_BINDING_ATTRIBUTE_DATA_2 as _,TEXTURE_BINDING_ATTRIBUTE_DATA_3 as g,TEXTURE_BINDING_ATTRIBUTE_DATA_4 as c,TEXTURE_BINDING_ATTRIBUTE_DATA_5 as T,TEXTURE_BINDING_GPGPU as f,ATTRIBUTE_DATA_FILTER_FLAGS as b,ATTRIBUTE_DATA_GPGPU as m,ATTRIBUTE_DATA_ANIMATION as y,ATTRIBUTE_DATA_DD1 as w}from"./definitions.js";import{getDisplayIdTexel as z}from"./DisplayId.js";import{getPixelArrayCtor as E,getPixelBytes as U}from"./Utils.js";import{createDebugLogger as D,DEBUG_ATTR_UPDATES as S}from"./util/debug.js";import{TextureWrapMode as A,PixelFormat as j,PixelType as k,TextureSamplingMode as M,TextureType as N,TargetType as O,DepthStencilTargetType as F}from"../../../webgl/enums.js";import{FramebufferObject as R}from"../../../webgl/FramebufferObject.js";import{Texture as v}from"../../../webgl/Texture.js";const B=e.getLogger("esri.views.2d.engine.webgl.AttributeStoreView"),V=D(S,B);class L{constructor(t,e,i){this._texture=null,this._lastTexture=null,this._fbos={},this.texelSize=4;const{buffer:s,pixelType:r,textureOnly:a}=t,h=E(r);this.shared=i,this.pixelType=r,this.size=e,this.textureOnly=a,a||(this.data=new h(d(s))),this._resetRange()}destroy(){a(this._texture,(t=>t.dispose()));for(const t in this._fbos)a(this._fbos[t],(e=>{"0"===t&&e.detachColorTexture(),e.dispose()})),this._fbos[t]=null;this._texture=null}get _textureDesc(){return{target:N.TEXTURE_2D,wrapMode:A.CLAMP_TO_EDGE,pixelFormat:j.RGBA,dataType:this.pixelType,samplingMode:M.NEAREST,width:this.size,height:this.size}}setData(t,e,i){const s=z(t),r=d(this.data),a=s*this.texelSize+e;!r||a>=r.length||(r[a]=i,this.dirtyStart=Math.min(this.dirtyStart,s),this.dirtyEnd=Math.max(this.dirtyEnd,s))}getData(t,e){if(i(this.data))return null;const s=z(t)*this.texelSize+e;return!this.data||s>=this.data.length?null:this.data[s]}getTexture(t){return o(this._texture,(()=>this._initTexture(t)))}getFBO(t,e=0){if(i(this._fbos[e])){const i={colorTarget:O.TEXTURE,depthStencilTarget:F.NONE},s=0===e?this.getTexture(t):this._textureDesc;this._fbos[e]=new R(t,i,s)}return this._fbos[e]}get locked(){return!(this.pixelType!==k.UNSIGNED_BYTE||!this.shared||this.textureOnly||!has("esri-atomics")||!this.data)&&1===Atomics.load(this.data,0)}get hasDirty(){const t=this.dirtyStart;return this.dirtyEnd>=t}updateTexture(e,i){if(!this.locked){try{const i=this.dirtyStart,s=this.dirtyEnd;if(!this.hasDirty)return;this._resetRange();const r=d(this.data).buffer,a=this.getTexture(e),h=4,n=(i-i%this.size)/this.size,o=(s-s%this.size)/this.size,u=n,l=this.size,p=o,x=n*this.size*h,_=(l+p*this.size)*h-x,g=E(this.pixelType),c=new g(r,x*g.BYTES_PER_ELEMENT,_),T=this.size,f=p-u+1;if(f>this.size)return void B.error(new t("mapview-webgl","Out-of-bounds index when updating AttributeData"));a.updateData(0,0,u,T,f,c)}catch(s){}i()}}update(t){const{data:e,start:i,end:s}=t;if(r(e)&&r(this.data)){const s=this.data,r=i*this.texelSize;for(let i=0;i<e.length;i++){const a=1<<i%this.texelSize;t.layout&a&&(s[r+i]=e[i])}}this.dirtyStart=Math.min(this.dirtyStart,i),this.dirtyEnd=Math.max(this.dirtyEnd,s)}resize(t,e){const i=this.size;if(this.size=e,this.textureOnly)return void(i!==this.size&&(this._lastTexture=this._texture,this._texture=null));const s=E(this.pixelType);this.destroy(),this.data=new s(d(t.buffer))}_resetRange(){this.dirtyStart=2147483647,this.dirtyEnd=0}_initTexture(t){const e=new v(t,this._textureDesc,o(this.data,void 0));if(r(this._lastTexture)&&this._fbos[0]){const i=this._lastTexture.descriptor.width,s=this._lastTexture.descriptor.height,r=this._lastTexture.descriptor.dataType,a=this._lastTexture.descriptor.pixelFormat,d=this.getFBO(t),h=U(r),n=new(E(r))(new ArrayBuffer(i*s*h*this.texelSize)),o=t.getBoundFramebufferObject(),{x:u,y:l,width:p,height:x}=t.getViewport();t.bindFramebuffer(d),d.readPixels(0,0,i,s,a,r,n),e.updateData(0,0,0,2*i,s/2,n),t.setViewport(u,l,p,x),t.bindFramebuffer(o)}return this.destroy(),this._texture=e,this._texture}}class G{constructor(t){this._onUpdate=t,this._initialized=!1,this._forceNextUpload=!1,this._locked=!1}initialize(t){const{blocks:e,shared:a,size:d}=t;if(this.shared=a,this.size=d,V("Initializing AttributeStoreView",t),i(this._data))this._data=s(e,(t=>new L(t,d,a)));else for(let s=0;s<this._data.length;s++){const t=this._data[s],h=e[s];r(h)&&(i(t)?this._data[s]=new L(h,d,a):t.resize(h,d))}this._initialized=!0}destroy(){a(this._data,(t=>s(t,(t=>t.destroy())))),a(this._defaultTexture,(t=>t.dispose()))}isEmpty(){const t=this._data;return i(t)}isUpdating(){const t=r(this._pendingAttributeUpdate),e=t;return has("esri-2d-log-updating")&&console.log(`Updating AttributeStoreView ${e}\n -> hasPendingUpdate ${t}`),e}getBlock(t){if(i(this._data))return null;return this._data[t]}setLabelMinZoom(t,e){this.setData(t,0,1,e)}getLabelMinZoom(t){return this.getData(t,0,1,255)}getFilterFlags(t){return this.getData(t,0,0,0)}getVVSize(t){return this.getData(t,l,0,0)}getData(t,e,s,a){if(!this._data)return 0;const h=d(this._data)[e];if(i(h))return 0;const n=h.getData(t,s);return r(n)?n:a}setData(t,e,i,s){const r=d(this._data)[e];d(r).setData(t,i,s)}lockTextureUpload(){this._locked=!0}unlockTextureUpload(){this._locked=!1}forceTextureUpload(){this._forceNextUpload=!0}async requestUpdate(e){if(this._pendingAttributeUpdate)return void B.error(new t("mapview-webgl","Tried to update attribute data with a pending update"));const i=u();return V("AttributeStoreView Update Requested",e),this._pendingAttributeUpdate={data:e,resolver:i},this._onUpdate(),i.promise}update(){if(this._initialized&&r(this._pendingAttributeUpdate)){has("esri-2d-update-debug")&&console.debug("AttributeStoreView::update");const{data:t,resolver:e}=this._pendingAttributeUpdate,i=d(this._data);for(let s=0;s<t.blocks.length;s++){const e=t.blocks[s],r=i[s];a(r,(t=>a(e,(e=>{V(`Updating block ${s}`,e),t.update(e)}))))}this._pendingAttributeUpdate=null,e(),this._onUpdate()}}bindTextures(t,e=!0){const i=this._getDefaultTexture(t);if(!this._initialized)return t.bindTexture(i,p),void(e&&(t.bindTexture(i,x),t.bindTexture(i,_),t.bindTexture(i,g),t.bindTexture(i,c),t.bindTexture(i,T),t.bindTexture(i,f)));const s=d(this._data);this._locked&&!this._forceNextUpload||(h(s,(e=>e.updateTexture(t,(()=>this._onUpdate())))),this._forceNextUpload=!1),t.bindTexture(n(s[b],i,(e=>e.getTexture(t))),p),e&&(t.bindTexture(n(s[m],i,(e=>e.getTexture(t))),f),t.bindTexture(n(s[y],i,(e=>e.getTexture(t))),x),t.bindTexture(n(s[l],i,(e=>e.getTexture(t))),_),t.bindTexture(n(s[w],i,(e=>e.getTexture(t))),g),t.bindTexture(n(s[c],i,(e=>e.getTexture(t))),c),t.bindTexture(n(s[T],i,(e=>e.getTexture(t))),T))}_getDefaultTexture(t){if(i(this._defaultTexture)){const e={wrapMode:A.CLAMP_TO_EDGE,pixelFormat:j.RGBA,dataType:k.UNSIGNED_BYTE,samplingMode:M.NEAREST,width:1,height:1};this._defaultTexture=new v(t,e,new Uint8Array(4))}return this._defaultTexture}}export{G as AttributeStoreView};