@doegis/core
Version:
DOE GIS API
3 lines (1 loc) • 9.12 kB
JavaScript
import{_ as e}from"../../../../chunks/tslib.es6.js";import t from"../../../../core/Accessor.js";import s from"../../../../core/Evented.js";import{someMap as r}from"../../../../core/MapUtils.js";import{nextHighestPowerOfTwo as i}from"../../../../core/mathUtils.js";import{disposeMaybe as a,isSome as n,removeMaybe as o,isNone as h}from"../../../../core/maybe.js";import{generateUID as l}from"../../../../core/uid.js";import{property as d}from"../../../../core/accessorSupport/decorators/property.js";import"../../../../core/accessorSupport/ensureType.js";import"../../../../core/arrayUtils.js";import{subclass as c}from"../../../../core/accessorSupport/decorators/subclass.js";import{s as m}from"../../../../chunks/vec4.js";import{c as _}from"../../../../chunks/vec4f64.js";import{ContentObjectType as g}from"./ContentObjectType.js";import{textTextureAtlas as u}from"./testUtils.js";import{VertexAttribute as p}from"./VertexAttribute.js";import{TaskPriority as x,Task as T,noBudget as f}from"../../../support/Scheduler.js";import{TextureType as A,PixelFormat as v,PixelType as R,TextureWrapMode as y,TextureSamplingMode as w}from"../../../webgl/enums.js";import{Texture as z}from"../../../webgl/Texture.js";const b=512,j=4096,O=.85,E=.95;class U{constructor(){this.offset={x:0,y:0},this.uvMinMax=_()}}class k{constructor(e,t){this.textId=e,this.textRenderer=t,this.placement=new U,this.rendered=!1}}let M=class extends t{constructor(e){super(e),this.type=g.Texture,this.id=l(),this.events=new s,this._glTexture=null,this._needsClear=!1,this._elementsToAddOrUpdate=new Map,this._elementsToRemove=new Map,this._elementsToRender=new Map,this._elements=new Map,this._stageObjects=new Map,this.updating=!1}initialize(){this._stage=this.view._stage,this._canvas=this._create2DCanvas(),this._ctx=this._canvas.getContext("2d"),this._stage.add(this);const e=this._computeAtlasResolution(this.view.width,this.view.height);this._createAtlasRegion(e),this._update2DCanvasSize(),this._resetAtlasCursor()}unload(){this._glTexture=a(this._glTexture),this.updating=!1,this.events.emit("unloaded")}get width(){return this._atlas.size.width}get height(){return this._atlas.size.height}get requiresFrameUpdates(){return!1}_createDescriptor(e){return{target:A.TEXTURE_2D,pixelFormat:v.RGBA,dataType:R.UNSIGNED_BYTE,wrapMode:y.CLAMP_TO_EDGE,flipped:!0,samplingMode:w.LINEAR_MIPMAP_LINEAR,hasMipmap:!0,preMultiplyAlpha:!0,maxAnisotropy:e.parameters.maxMaxAnisotropy}}get glTexture(){return this._glTexture}load(e){return n(this._glTexture)||(this._glTexture=new z(e,this._createDescriptor(e),this._canvas),this._frameWorker=this.view.resourceController.scheduler.registerTask(x.TEXT_TEXTURE_ATLAS,this),this.setDirty()),this._glTexture}dispose(){this._elements=null,this._elementsToAddOrUpdate=null,this._elementsToRemove=null,this._elementsToRender=null,this._frameWorker=o(this._frameWorker),this._glTexture&&(this._stage.remove(this),this._glTexture=a(this._glTexture)),this._canvas.width=0,this._canvas.height=0,this._canvas=null,this._ctx=null}_create2DCanvas(){const e=document.createElement("canvas");return e.setAttribute("id","canvas2d"),e.setAttribute("style","display:none"),e.setAttribute("width",b.toString()),e.setAttribute("height",b.toString()),e}_update2DCanvasSize(){this._canvas.setAttribute("width",this._atlas.size.width.toString()),this._canvas.setAttribute("height",this._atlas.size.height.toString())}_createAtlasRegion(e=b){this._atlas={size:{width:e,height:e},cursor:{x:0,y:0},lineHeight:0}}_computeAtlasResolution(e,t){let s=Math.max(e,t);return s+=256,s=i(s),s=Math.min(s,j),s}_resizeAtlas(e,t){t=t||e;const s=this._atlas;s.size.width=e,s.size.height=t,n(this._glTexture)&&this._glTexture.resize(e,t),this._update2DCanvasSize()}_resetAtlasCursor(){const e=this._atlas;e.cursor.x=S,e.cursor.y=S+C,e.lineHeight=0,this._needsClear=!0}_getAtlasUsage(){const e=this._atlas;return(e.cursor.x+e.cursor.y*e.size.width)/(e.size.width*e.size.height)}_getExpectedAtlasUsage(){const e=this._elementsToRemove.size,t=this._elementsToAddOrUpdate.size,s=this._elements.size;return this._getAtlasUsage()/s*(s+t-e)}_addAtlasElement(e,t,s,r){const i=this._atlas,{renderedWidth:a,renderedHeight:n}=e.textRenderer;e.placement.offset.x=i.cursor.x,e.placement.offset.y=i.cursor.y,m(e.placement.uvMinMax,e.placement.offset.x/i.size.width,1-(e.placement.offset.y+n)/i.size.height,(e.placement.offset.x+a)/i.size.width,1-e.placement.offset.y/i.size.height),i.cursor.x+=s,i.lineHeight=Math.max(i.lineHeight,r),this._elements.set(t,e)}_removeAtlasElement(e){if(e&&this._elements.has(e.textId)){const t=e.placement.offset;this._ctx.clearRect(t.x,t.y,e.textRenderer.renderedWidth,e.textRenderer.renderedHeight),this._elements.delete(e.textId)}}_ensureStageObjects(e){const t=this._stageObjects.get(e);if(t)return t;const s=new Set;return this._stageObjects.set(e,s),s}_addStageObject(e,t){this._ensureStageObjects(e).add(t)}_removeStageObject(e,t){const s=this._stageObjects.get(e);s&&s.delete(t)&&(t.geometries[0].vertexAttributes.get(p.SIZE).data=[0,0],t.geometryVertexAttrsUpdated(t.geometries[0]))}_processAddition(e,t){const s=this._atlas,r=e.textId,i=e.textRenderer.renderedWidth,a=e.textRenderer.renderedHeight,n=i+S,o=a+S+C;if(s.cursor.x+n<s.size.width&&s.cursor.y+o<s.size.height)this._addAtlasElement(e,r,n,o),this._elementsToRender.set(r,e),this._elementsToAddOrUpdate.delete(r);else{if(!(s.cursor.y+o+s.lineHeight<s.size.height)){const e=this._getExpectedAtlasUsage(),r=e>O&&s.size.width<j;return r&&this._resizeAtlas(2*s.size.width,2*s.size.height),!t||!r&&e>E&&s.size.width===j?(this._processRemovals(),D.OK):(this._repack(),D.REPACK)}s.cursor.x=S,s.cursor.y+=s.lineHeight,s.lineHeight=0,this._addAtlasElement(e,r,n,o),this._elementsToRender.set(r,e),this._elementsToAddOrUpdate.delete(r)}return D.OK}_processRemovals(){this._elementsToRemove.forEach(((e,t)=>{const s=this._stageObjects.get(t);s&&0!==s.size||this._removeAtlasElement(e),s&&0===s.size&&this._stageObjects.delete(t)})),this._elementsToRemove.clear()}_repack(){this._processRemovals(),this._elements.forEach(((e,t)=>{e.rendered=!1,this._elementsToAddOrUpdate.set(t,e)})),this._elements.clear(),this._resetAtlasCursor(),this._elementsToRender.clear()}_processRenderingRequest(e){this._ctx.clearRect(e.placement.offset.x,e.placement.offset.y,e.textRenderer.renderedWidth,e.textRenderer.renderedHeight),e.textRenderer.render(this._ctx,e.placement.offset.x,e.placement.offset.y);const t=this._stageObjects.get(e.textId);t&&t.forEach((t=>{t.geometries[0].vertexAttributes.get(p.UV0).data=new Float32Array(e.placement.uvMinMax),t.geometries[0].vertexAttributes.get(p.SIZE).data=[e.textRenderer.displayWidth,e.textRenderer.displayHeight],t.geometryVertexAttrsUpdated(t.geometries[0])})),e.rendered=!0}get running(){return this.updating}runTask(e,t=!0){if(h(this._glTexture))return T.YIELD;let s=!1;if(r(this._elementsToAddOrUpdate,((r,i)=>{const a=this._elements.get(i);if(a&&a.rendered){const t=this._stageObjects.get(i);return t&&t.forEach((e=>{const t=e.geometries[0].vertexAttributes,s=this._elements.get(i);t.get(p.UV0).data=s.placement.uvMinMax,t.get(p.SIZE).data=[s.textRenderer.displayWidth,s.textRenderer.displayHeight],e.geometryVertexAttrsUpdated(e.geometries[0])})),this._elementsToAddOrUpdate.delete(i),e.madeProgress(),!1}return this._processAddition(this._elementsToAddOrUpdate.get(i),t)===D.REPACK&&(s=!0,!0)})),s)return this.runTask(f,!1),void e.madeProgress();let i=!1;this._elementsToRender.size>0&&this._needsClear&&(this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height),this._needsClear=!1),r(this._elementsToRender,((t,s)=>(this._processRenderingRequest(t),this._elementsToRender.delete(s),i=!0,e.madeProgress(),e.done))),i&&this._glTexture.setData(this._canvas),this.updating=this._elementsToRender.size>0,!this.updating&&u.orderedRepackingEnabled&&(this.repackOrdered(),e.madeProgress())}addTextTexture(e,t){const s=e.key;this._elementsToAddOrUpdate.has(s)||this._elementsToAddOrUpdate.set(s,new k(s,e)),this._addStageObject(s,t),this._elementsToRemove.delete(s),this.setDirty()}removeTextTexture(e,t){const s=e.key;this._elementsToRemove.set(s,this._elements.get(s)),this._removeStageObject(s,t)}setDirty(){this._glTexture&&(this.updating=!0)}repackOrdered(){if(0===this._elements.size)return;const e=[];this._elements.forEach(((t,s)=>e.push({element:t,key:s})));let t=!0;for(let s=0;s<e.length-1;s++)if(e[s].key.localeCompare(e[s+1].key)>0){t=!1;break}if(!t||this._elementsToRemove.size){e.sort(((e,t)=>e.key.localeCompare(t.key))),this._elements.clear();for(const{element:t,key:s}of e)this._elements.set(s,t);this._repack(),this.setDirty()}}get test(){const{_elements:e,_stageObjects:t,_elementsToRemove:s,_atlas:r}=this,i=this;return{elements:e,stageObjects:t,elementsToRemove:s,atlas:r,resizeAtlas:(e,t)=>i._resizeAtlas(e,t),run:(e,t)=>i.runTask(e,t)}}};e([d({constructOnly:!0})],M.prototype,"view",void 0),e([d({type:Boolean})],M.prototype,"updating",void 0),M=e([c("esri.views.3d.webgl-engine.lib.TextTextureAtlas")],M);const S=2,C=2;var D;!function(e){e[e.OK=0]="OK",e[e.REPACK=1]="REPACK"}(D||(D={}));export{M as TextTextureAtlas};