@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
6 lines (5 loc) • 12 kB
JavaScript
/*
All material copyright ESRI, All Rights Reserved, unless otherwise specified.
See https://js.arcgis.com/4.32/esri/copyright.txt for details.
*/
import{_ as e}from"../../../../../chunks/tslib.es6.js";import{removeUnordered as t,filterInPlace as r}from"../../../../../core/arrayUtils.js";import"../../../../../core/has.js";import{nextHighestPowerOfTwo as i}from"../../../../../core/mathUtils.js";import{disposeMaybe as s}from"../../../../../core/maybe.js";import{NestedMap as a}from"../../../../../core/NestedMap.js";import o from"../../../../../core/PooledArray.js";import{addMany as n}from"../../../../../core/SetUtils.js";import{property as l}from"../../../../../core/accessorSupport/decorators/property.js";import"../../../../../core/Logger.js";import{subclass as h}from"../../../../../core/accessorSupport/decorators/subclass.js";import{copy as u,invert as c,transpose as f}from"../../../../../core/libs/gl-matrix-2/math/mat4.js";import{create as d}from"../../../../../core/libs/gl-matrix-2/factories/mat4f64.js";import{glLayout as m}from"../../../support/buffer/glUtil.js";import{ShaderOutput as g}from"../../core/shaderLibrary/ShaderOutput.js";import{SyncRenderPlugin as p}from"../../effects/RenderPlugin.js";import{GLMaterials as y}from"../../lib/GLMaterials.js";import{DirtyState as _}from"../../lib/ModelDirtyTypes.js";import{RenderSlot as b}from"../../lib/RenderSlot.js";import{assert as w}from"../../lib/Util.js";import{DrawParameters as v}from"../DrawParameters.js";import{BufferRange as O,mergeAdjacentRanges as C}from"./BufferRange.js";import{Instance as E}from"./Instance.js";import{PerBufferData as A,hasVao as B}from"./PerBufferData.js";import{PerOriginData as M}from"./PerOriginData.js";import{defaultHighlightName as S}from"../../../../support/HighlightDefaults.js";let D=class extends p{get _hasHighlights(){return this._highlightNames.size>0}hasHighlightOptions(e){return this._highlightNames.has(e)}constructor(e){super(e),this._dataByOrigin=new Map,this._drawParameters=new v,this._highlightNames=new Set,this.drapedPriority=0,this._produces=new Map,this._hasOccludees=!1}destroy(){this._glMaterials=s(this._glMaterials),this._dataByOrigin.forEach((e=>e.dispose())),this._dataByOrigin.clear(),this._vaoCache=null}initialize(){this._updateProduces()}_updateProduces(){this.material.produces.forEach(((e,t)=>{this._produces.set(t,(t=>!(0===this._dataByOrigin.size||!(t!==g.Highlight&&t!==g.ShadowHighlight||this._hasHighlights))&&e(t)))}))}initializeRenderContext(e,t){this._glMaterials=new y(this.material,t??e.materials),this._bufferWriter=this.material.createBufferWriter(),this._vaoCache=e.renderContext.rctx.getVaoCache(this.material.vertexAttributeLocations,m(this._bufferWriter.vertexBufferLayout))}uninitializeRenderContext(){}get produces(){return this._produces}get hasOccludees(){return this._hasOccludees}get hasEmissions(){return this.material.hasEmissions}get isDecoration(){return this.material.parameters.isDecoration}queryRenderOccludedState(e){return this.material.queryRenderOccludedState(e)}get numGeometries(){let e=0;return this._dataByOrigin.forEach((t=>e+=t.buffers.reduce(((e,t)=>e+t.instances.size),0))),e}get usedMemory(){let e=0;return this._dataByOrigin.forEach((t=>e+=t.buffers.reduce(((e,t)=>e+t.vao.cachedMemory),0))),e}forEachGeometry(e){this._dataByOrigin.forEach((t=>t.buffers.forEach((t=>t.instances.forEach((({geometry:t})=>e(t)))))))}modify(e){this._updateGeometries(e.updates),this._addAndRemoveGeometries(e.adds,e.removes),this._updateDrawCommands()}updateHighlights(e){this.highlightOrderMap=e,this._highlightNames.clear(),this._dataByOrigin.forEach((t=>{t.buffers.forEach((t=>{t.updateHighlights(e),t.highlightNames.forEach((e=>this._highlightNames.add(e)))}))})),this._updateProduces()}_updateGeometries(e){const t=this._bufferWriter;if(null==t)return;const r=t.vertexBufferLayout.stride/4;for(const i of e){const e=i.renderGeometry,s=this._dataByOrigin.get(e.localOrigin.id),a=s?.findBuffer(e.id);if(null==a)return;const o=a.instances.get(e.id);if(i.updateType&(_.GEOMETRY|_.TRANSFORMATION)){const i=z(t.elementCount(o.geometry.geometry.attributes)*r),s=t.vertexBufferLayout.createView(i.buffer);this._writeGeometry(e,s,0),a.vao.vertexBuffers.get("geometry").setSubData(i,o.from*r,0,o.numElements*r)}i.updateType&(_.HIGHLIGHT|_.OCCLUDEE|_.VISIBILITY)&&(a.drawCommandsDirty=!0)}}_computeDeltas(e,t){const r=new a;for(const i of e){const e=i.localOrigin;if(null==e)continue;let t=r.get(e.id,null);null==t&&(t=new H(e.vec3),r.set(e.id,null,t)),t.changes.push(i)}for(const i of t){const e=i.localOrigin;if(null==e)continue;const t=this._dataByOrigin.get(e.id),s=t?.findBuffer(i.id);if(null==s)continue;let a=r.get(e.id,s);null==a&&(a=new H(e.vec3),r.set(e.id,s,a)),a.changes.push(i)}return r}_addAndRemoveGeometries(e,r){if(null==this._bufferWriter||null==this._vaoCache)return;const{_bufferWriter:i,_dataByOrigin:s}=this,a=i.vertexBufferLayout.stride/4,o=this._computeDeltas(e,r);o.forEach(((e,r)=>{const n=e.get(null),l=n?.changes??[];o.delete(r,null);let h=s.get(r);if(e.forEach(((e,n)=>{if(o.delete(r,n),null==n)return void w(!1,"No VAO for removed geometries");if(n.instances.size===e.changes.length)return this._vaoCache.deleteVao(n.vao),t(h.buffers,n),void(0===h.buffers.length&&0===l.length&&s.delete(r));const u=n.numElements,c=n.vao.byteSize/4,f=l.reduce(((e,t)=>e+i.elementCount(t.geometry.attributes)),0),d=e.changes.reduce(((e,t)=>e+i.elementCount(t.geometry.attributes)),0),m=Math.min((u+f-d)*a,G),g=m>c;m>N&&m<c/2?(e.changes.forEach((({id:e})=>n.deleteInstance(e))),n.instances.forEach((({geometry:e})=>l.push(e))),this._vaoCache.deleteVao(n.vao),t(h.buffers,n)):g?this._applyAndRebuild(n,l,e):this._applyRemoves(n,e)})),l.length>0)for(null==h&&(h=new M(n.origin),s.set(r,h)),h.buffers.forEach((e=>this._applyAdds(e,l)));l.length>0;)h.buffers.push(this._applyAndRebuild(new A,l,null))}))}_updateDrawCommands(){this._highlightNames.clear(),this._hasOccludees=!1,this._dataByOrigin.forEach((e=>{e.buffers.forEach((e=>{e.updateIfDrawCommandsDirty(this.highlightOrderMap,this._bufferWriter.vertexBufferLayout.stride),e.hasHighlights&&n(this._highlightNames,e.highlightNames),this._hasOccludees=this._hasOccludees||e.hasOccludees}))}))}_applyAndRebuild(e,t,r){if(r)for(const d of r.changes)e.deleteInstance(d.id);const i=this._bufferWriter,s=i.vertexBufferLayout.stride,a=s/4,o=Math.floor(G/a);let n=e.numElements;for(;t.length>0;){const r=t.pop(),s=i.elementCount(r.geometry.attributes);if(n+s>o&&n>0){t.push(r);break}n+=s;const a=new E(r,0,0,this.highlightOrderMap);w(null==e.instances.get(r.id)),e.addInstance(r.id,a)}const l=n*a,h=z(l),u=i.vertexBufferLayout.createView(h.buffer);let c=0;e.resetInstanceSummary(),e.instances.forEach(((t,r)=>{this._writeGeometry(t.geometry,u,c);const s=c;c+=i.elementCount(t.geometry.geometry.attributes),e.updateInstance(r,s,c),e.updateDrawState(t)})),this._vaoCache.deleteVao(e.vao),e.vao=this._vaoCache.newVao(V(l)),e.vao.vertexBuffers.get("geometry").setSubData(h,0,0,c*a),e.holes.clear();const f=e.holes.pushNew();return f.from=c,f.to=Math.floor(e.vao.byteSize/s),e.updateDrawCommands(this.highlightOrderMap,s),e}_applyRemoves(e,t){if(0===t.changes.length||null==this._bufferWriter)return;for(const o of t.changes){const t=o.id,r=e.instances.get(t);if(!r)continue;e.deleteInstance(t);const i=L.back();if(i){if(i.to===r.from){i.to=r.to;continue}if(i.from===r.to){i.from=r.from;continue}}const s=L.pushNew();s.from=r.from,s.to=r.to}C(L);const r=this._bufferWriter.vertexBufferLayout.stride/4,i=L.reduce(((e,t)=>Math.max(e,t.numElements)),0)*r,s=z(i);s.fill(0,0,i);const a=e.vao.vertexBuffers.get("geometry");L.forAll((e=>a.setSubData(s,e.from*r,0,e.numElements*r))),e.holes.pushArray(L.data,L.length),L.forAll(((e,t)=>L.data[t]=null)),L.clear(),e.drawCommandsDirty=!0}_applyAdds(e,t){if(0===t.length||null==this._bufferWriter)return;if(!B(e))return void this._applyAndRebuild(e,t,null);const i=this._bufferWriter,s=i.vertexBufferLayout.stride/4,a=e.numElements,o=t.reduce(((e,t)=>e+i.elementCount(t.geometry.attributes)),0),n=Math.min((a+o)*s,G),l=4*n;if(e.vao.byteSize<V(G-N)&&l>e.vao.byteSize)return void this._applyAndRebuild(e,t,null);C(e.holes);const h=new Array;for(const r of t){const t=i.elementCount(r.geometry.attributes),s=x(e.holes,t);h.push(s)}const u=e.vao.vertexBuffers.get("geometry");let c=0,f=0,d=0;const m=z(n),g=i.vertexBufferLayout.createView(m.buffer);t.forEach(((t,r)=>{const a=h[r];if(null==a)return;if(!(d===a)){const e=d-f;e>0&&u.setSubData(m,f*s,0,e*s),f=a,c=0}const o=i.elementCount(t.geometry.attributes);this._writeGeometry(t,g,c),c+=o,d=a+o;const n=new E(t,a,a+o,this.highlightOrderMap);w(null==e.instances.get(t.id)),e.addInstance(t.id,n),e.drawCommandsDirty=!0}));const p=d-f;p>0&&u.setSubData(m,f*s,0,p*s),r(t,((e,t)=>null==h[t]))}_writeGeometry(e,t,r){null!=this._bufferWriter&&(u(R,e.transformation),R[12]-=e.localOrigin.vec3[0],R[13]-=e.localOrigin.vec3[1],R[14]-=e.localOrigin.vec3[2],c(j,R),f(j,j),this._bufferWriter.write(R,j,e.geometry.attributes,e.geometry.objectAndLayerIdColor,t,r))}updateAnimation(e){return this.material.update(e)}acquireTechniques(e){if(!this.material.shouldRender(e))return null;const{output:t,bind:r}=e,i=this.material.produces.get(r.slot);if(!i?.(t))return null;const{highlight:s,slot:a}=r,o=t===g.ShadowHighlight,n=t===g.Highlight,l=n||o,h=s?.name;if(l&&(0===this._highlightNames.size||n&&h&&!this._highlightNames.has(h)))return null;const u=e=>n&&!!h&&!e.has(h),c=t===g.ShadowExcludeHighlight,f=!(l||c);for(const{buffers:d}of this._dataByOrigin.values())for(const i of d){if(u(i.highlightNames))continue;const s=o?i.drawCommandsHighlights.get(S):l?h?i.drawCommandsHighlights.get(h):i.drawCommandsHighlights.size>0:((c&&i.needsMultipleCommands()?i.drawCommandsShadowHighlightRest:i.drawCommandsDefault)||null)?.length??!1,n=f&&i.drawCommandsOccludees||null;if(s||n?.length){const i=this._glMaterials.load(e.rctx,a,t),s=i?.beginSlot(r);if(s)return s}}return null}render(e,t){const{output:r,bind:i}=e,{slot:s,highlight:a}=i,n=r===g.Highlight,l=a?.name??"";if(n&&!a)return;const h=r===g.ShadowHighlight,u=n||h,c=r===g.ShadowExcludeHighlight,f=!(u||c),d=s===b.OCCLUDER_MATERIAL||s===b.TRANSPARENT_OCCLUDER_MATERIAL?s:null,{rctx:m}=e;m.runAppleAmdDriverHelper();const p=m.bindTechnique(t,i,this.material.parameters);for(const g of this._dataByOrigin.values())for(const e of g.buffers){if(n&&(!e.hasHighlights||!e.drawCommandsHighlights.has(l)))continue;if(h&&(!e.hasHighlights||!e.drawCommandsHighlights.has(S)))continue;const r=()=>{const t=[],r=e.drawCommandsHighlights.get(S)??new o;return r&&t.push(r),t},s=u&&!h?e.drawCommandsHighlights.get(l)??null:null,a=h?r():u?s?[s]:U:c&&e.needsMultipleCommands()?[e.drawCommandsShadowHighlightRest]:[e.drawCommandsDefault],y=a.some((e=>e.length>0)),_=f&&e.drawCommandsOccludees||null;if(y||_?.length){if(this._drawParameters.origin=g.origin,p.bindDraw(i,this.material.parameters,this._drawParameters),t.ensureAttributeLocations(e.vao),m.bindVAO(e.vao),y)for(const e of a)m.setPipelineState(t.getPipeline(!1,d)),e.forAll((e=>m.drawArrays(t.primitiveType,e.first,e.count)));_?.length&&(m.setPipelineState(t.getPipeline(!0,d)),_.forAll((e=>m.drawArrays(t.primitiveType,e.first,e.count))))}}}static prune(){W=new Float32Array(N)}get test(){}};e([l({constructOnly:!0})],D.prototype,"material",void 0),e([l({})],D.prototype,"highlightOrderMap",void 0),D=e([h("esri.views.3d.webgl-engine.materials.renderers.MergedRenderer")],D);class H{constructor(e){this.origin=e,this.changes=new Array}}function x(e,t){const r=e.find((e=>e.numElements>=t));if(null==r)return null;const i=r.from;return r.from+=t,r.from>=r.to&&e.removeUnordered(r),i}const R=d(),j=d(),L=new o({allocator:e=>e||new O,deallocator:null}),N=65536,I=4*N,P=1024,T=16777216,G=T/4;let W=new Float32Array(N);function z(e){return W.length<e&&(W=new Float32Array(e)),W}function V(e){const t=4*e;return t<=P?P:t<I?i(t):Math.max(Math.min(Math.ceil(1.5*t/I)*I,T),t)}const U=[];export{D as MergedRenderer,V as sizeForVao};