@doegis/core
Version:
DOE GIS API
3 lines (1 loc) • 9.38 kB
JavaScript
import{removeUnordered as e,filterInPlace as t}from"../../../../../core/arrayUtils.js";import{someMap as r}from"../../../../../core/MapUtils.js";import{isNone as s,isSome as i}from"../../../../../core/maybe.js";import{NestedMap as a}from"../../../../../core/NestedMap.js";import o from"../../../../../core/PooledArray.js";import{m as n,a as l,t as h}from"../../../../../chunks/mat4.js";import{c as u}from"../../../../../chunks/mat4f64.js";import{glLayout as f}from"../../../support/buffer/glUtil.js";import{ShaderOutput as c}from"../../core/shaderLibrary/ShaderOutput.js";import{AppleAmdDriverHelper as d}from"../../lib/AppleAmdDriverHelper.js";import{GLMaterials as m}from"../../lib/GLMaterials.js";import{RenderOccludedFlag as g}from"../../lib/Material.js";import{DirtyState as p}from"../../lib/ModelDirtyTypes.js";import{assert as y,setMatrixTranslation3 as _}from"../../lib/Util.js";import{DrawParameters as v}from"../DrawParameters.js";import{WaterMaterial as w}from"../WaterMaterial.js";import{BufferRange as b,mergeAdjacentRanges as O}from"./BufferRange.js";import{Instance as A}from"./Instance.js";import{PerBufferData as B,hasVao as C}from"./PerBufferData.js";import{PerOriginData as E}from"./PerOriginData.js";import{VaoCache as D}from"./VaoCache.js";class H{constructor(e,t,r){this._rctx=e,this._materialRepository=t,this.material=r,this._dataByOrigin=new Map,this._appleAmdDriverHelper=null,this._hasHighlights=!1,this._hasOccludees=!1,this._glMaterials=new m(this.material,this._materialRepository),this._bufferWriter=r.createBufferWriter(),this._vaoCache=new D(e,r.vertexAttributeLocations,f(this._bufferWriter.vertexBufferLayout)),this._rctx.driverTest.drawArraysRequiresIndicesTypeReset.result&&(this._appleAmdDriverHelper=new d(this._rctx))}dispose(){this._glMaterials.destroy(),this._dataByOrigin.forEach((e=>e.dispose())),this._dataByOrigin.clear(),this._vaoCache.dispose(),this._appleAmdDriverHelper?.dispose()}get isEmpty(){return 0===this._dataByOrigin.size}get hasHighlights(){return this._hasHighlights}get hasOccludees(){return this._hasOccludees}get hasWater(){return!this.isEmpty&&this.material instanceof w}get rendersOccluded(){return!this.isEmpty&&this.material.renderOccluded!==g.Occlude}get numGeometries(){let e=0;return this._dataByOrigin.forEach((t=>e+=t.buffers.reduce(((e,t)=>e+t.instances.size),0))),e}forEachGeometry(e){this._dataByOrigin.forEach((t=>t.buffers.forEach((t=>t.instances.forEach((t=>e(t.geometry)))))))}modify(e){this._updateGeometries(e.updates),this._addAndRemoveGeometries(e.adds,e.removes),this._updateDrawCommands()}_updateGeometries(e){const t=this._bufferWriter,r=t.vertexBufferLayout.stride/4;for(const i of e){const e=i.renderGeometry,a=this._dataByOrigin.get(e.localOrigin.id)?.findBuffer(e.id);if(s(a))return;const o=a.instances.get(e.id);if(i.updateType&(p.GEOMETRY|p.TRANSFORMATION)){const s=z(t.elementCount(o.geometry.geometry)*r),i=t.vertexBufferLayout.createView(s.buffer);this._writeGeometry(e,i,0),a.vao.vertexBuffers.geometry.setSubData(s,o.from*r,0,o.numElements*r)}i.updateType&(p.HIGHLIGHT|p.OCCLUDEE|p.VISIBILITY)&&(a.drawCommandsDirty=!0)}}_computeDeltas(e,t){const r=new a;for(const i of e){const e=i.localOrigin;if(s(e))continue;let t=r.get(e.id,null);s(t)&&(t=new x(e.vec3),r.set(e.id,null,t)),t.changes.push(i)}for(const i of t){const e=i.localOrigin;if(s(e))continue;const t=this._dataByOrigin.get(e.id)?.findBuffer(i.id);if(s(t))continue;let a=r.get(e.id,t);s(a)&&(a=new x(e.vec3),r.set(e.id,t,a)),a.changes.push(i)}return r}_addAndRemoveGeometries(t,r){const{_bufferWriter:a,_dataByOrigin:o}=this,n=a.vertexBufferLayout.stride/4,l=this._computeDeltas(t,r);l.forEach(((t,r)=>{const h=t.get(null),u=i(h)?h.changes:[];l.delete(r,null);let f=o.get(r);if(t.forEach(((t,i)=>{if(l.delete(r,i),s(i))return void y(!1,"No VAO for removed geometries");if(i.instances.size===t.changes.length)return this._vaoCache.deleteVao(i.vao),e(f.buffers,i),void(0===f.buffers.length&&0===u.length&&o.delete(r));const h=i.numElements,c=i.vao.size/4,d=u.reduce(((e,t)=>e+a.elementCount(t.geometry)),0),m=t.changes.reduce(((e,t)=>e+a.elementCount(t.geometry)),0),g=Math.min((h+d-m)*n,W),p=g>c;g>L&&g<c/2?(t.changes.forEach((({id:e})=>i.deleteInstance(e))),i.instances.forEach((({geometry:e})=>u.push(e))),this._vaoCache.deleteVao(i.vao),e(f.buffers,i)):p?this._applyAndRebuild(i,u,t):this._applyRemoves(i,t)})),u.length>0)for(s(f)&&(f=new E(h.origin),o.set(r,f)),f.buffers.forEach((e=>this._applyAdds(e,u)));u.length>0;)f.buffers.push(this._applyAndRebuild(new B,u,null))}))}_updateDrawCommands(){this._hasHighlights=!1,this._hasOccludees=!1,this._dataByOrigin.forEach((e=>{e.buffers.forEach((e=>{e.drawCommandsDirty&&(e.hasHiddenInstances=!1,e.hasHighlights=!1,e.hasOccludees=!1,r(e.instances,(t=>(e.updateDrawState(t),e.hasHiddenInstances&&e.hasHighlights&&e.hasOccludees))),e.updateDrawCommands(this._bufferWriter.vertexBufferLayout.stride)),this._hasHighlights=this._hasHighlights||e.hasHighlights,this._hasOccludees=this._hasOccludees||e.hasOccludees}))}))}_applyAndRebuild(e,t,r){if(i(r))for(const i of r.changes)e.deleteInstance(i.id);const s=this._bufferWriter,a=s.vertexBufferLayout.stride,o=a/4,n=Math.floor(W/o);let l=e.numElements;for(;t.length>0;){const r=t.pop(),i=s.elementCount(r.geometry);if(l+i>n&&l>0){t.push(r);break}l+=i;const a=new A(r,0,0);y(null==e.instances.get(r.id)),e.addInstance(r.id,a)}const h=l*o,u=z(h),f=s.vertexBufferLayout.createView(u.buffer);let c=0;e.hasHiddenInstances=!1,e.hasHighlights=!1,e.hasOccludees=!1,e.instances.forEach(((t,r)=>{this._writeGeometry(t.geometry,f,c);const i=c;c+=s.elementCount(t.geometry.geometry),e.updateInstance(r,i,c),e.updateDrawState(t)})),this._vaoCache.deleteVao(e.vao),e.vao=this._vaoCache.newVao(N(h)),e.vao.vertexBuffers.geometry.setSubData(u,0,0,c*o),e.holes.clear();const d=e.holes.pushNew();return d.from=c,d.to=Math.floor(e.vao.size/a),e.updateDrawCommands(a),e}_applyRemoves(e,t){if(0===t.changes.length)return;for(const o of t.changes){const t=o.id,r=e.instances.get(t);if(!r)continue;e.deleteInstance(t);const s=R.back();if(s){if(s.to===r.from){s.to=r.to;continue}if(s.from===r.to){s.from=r.from;continue}}const i=R.pushNew();i.from=r.from,i.to=r.to}O(R);const r=this._bufferWriter.vertexBufferLayout.stride/4,s=R.reduce(((e,t)=>Math.max(e,t.numElements)),0)*r,i=z(s);i.fill(0,0,s);const a=e.vao.vertexBuffers.geometry;R.forAll((e=>a.setSubData(i,e.from*r,0,e.numElements*r))),e.holes.pushArray(R.data,R.length),R.forAll(((e,t)=>R.data[t]=null)),R.clear(),e.drawCommandsDirty=!0}_applyAdds(e,r){if(0===r.length)return;if(!C(e))return void this._applyAndRebuild(e,r,null);const i=this._bufferWriter,a=i.vertexBufferLayout.stride/4,o=e.numElements,n=r.reduce(((e,t)=>e+i.elementCount(t.geometry)),0),l=Math.min((o+n)*a,W),h=4*l;if(e.vao.size<N(W-L)&&h>e.vao.size)return void this._applyAndRebuild(e,r,null);O(e.holes);const u=new Array;for(const t of r){const r=i.elementCount(t.geometry),s=M(e.holes,r);u.push(s)}const f=e.vao.vertexBuffers.geometry;let c=0,d=0,m=0;const g=z(l),p=i.vertexBufferLayout.createView(g.buffer);r.forEach(((t,r)=>{const o=u[r];if(s(o))return;if(!(m===o)){const e=m-d;e>0&&f.setSubData(g,d*a,0,e*a),d=o,c=0}const n=i.elementCount(t.geometry);this._writeGeometry(t,p,c),c+=n,m=o+n;const l=new A(t,o,o+n);y(null==e.instances.get(t.id)),e.addInstance(t.id,l),e.drawCommandsDirty=!0}));const _=m-d;_>0&&f.setSubData(g,d*a,0,_*a),t(r,((e,t)=>s(u[t])))}_writeGeometry(e,t,r){const s=e.localOrigin.vec3;_(j,-s[0],-s[1],-s[2]);const i=n(I,j,e.transformation);l(S,i),h(S,S),this._bufferWriter.write(i,S,e.geometry,t,r)}updateAnimation(e){return this.material.update(e)}requiresSlot(e,t){return this.material.requiresSlot(e,t)}render(e,t){if(!this.requiresSlot(t.slot,e))return!1;const r=e===c.Highlight||e===c.ShadowHighlight;if(r&&!this._hasHighlights)return!1;const a=e===c.ShadowExcludeHighlight,o=!(r||a),n=this._rctx;let l;const h=()=>{if(i(l))return l;const r=this._glMaterials.load(n,t.slot,e);return s(r)?null:(l=r.beginSlot(t),s(l)?null:(n.bindTechnique(l,this.material.parameters,t),l))};this._appleAmdDriverHelper?.resetIndicesType();for(const i of this._dataByOrigin.values())for(const e of i.buffers){if(r&&!e.hasHighlights)continue;const l=(r?e.drawCommandsHighlight:a&&e.needsMultipleCommands()?e.drawCommandsShadowHighlightRest:e.drawCommandsDefault)||null,u=o&&e.drawCommandsOccludees||null;if(l?.length||u?.length){const r=h();if(s(r))return!1;r.program.bindDraw(new v(i.origin),t,this.material.parameters),r.ensureAttributeLocations(e.vao),n.bindVAO(e.vao),l?.length&&(r.bindPipelineState(n,t.slot,!1),l.forAll((e=>n.drawArrays(r.primitiveType,e.first,e.count)))),u?.length&&(r.bindPipelineState(n,t.slot,!0),u.forAll((e=>n.drawArrays(r.primitiveType,e.first,e.count))))}}return i(l)}get test(){return{material:this.material,glMaterials:this._glMaterials,dataByOrigin:this._dataByOrigin}}}class x{constructor(e){this.origin=e,this.changes=new Array}}function M(e,t){let r;if(!e.some((e=>!(e.numElements<t)&&(r=e,!0))))return null;const s=r.from;return r.from+=t,r.from>=r.to&&e.removeUnordered(r),s}const j=u(),I=u(),S=u(),R=new o({allocator:e=>e||new b,deallocator:null}),L=65536,G=4*L,T=16777216,W=T/4;let V=new Float32Array(L);function z(e){return V.length<e&&(V=new Float32Array(e)),V}function N(e){const t=4*e;return t<G?G:Math.max(Math.min(Math.ceil(1.5*t/G)*G,T),t)}export{H as MergedRenderer};