@doegis/core
Version:
DOE GIS API
3 lines (1 loc) • 13.4 kB
JavaScript
import{equals as e}from"../../../core/arrayUtils.js";import{isPowerOfTwo as t}from"../../../core/mathUtils.js";import{isSome as r,isNone as i,mapOr as s}from"../../../core/maybe.js";import{i as a,j as n,u as o,b as l,n as h,e as d,w as g,F as c}from"../../../chunks/vec3.js";import{c as u,a as m}from"../../../chunks/vec3f64.js";import{empty as p}from"../../../geometry/support/aaBoundingBox.js";import{containsXY as f}from"../../../geometry/support/aaBoundingRect.js";import{earth as y}from"../../../geometry/support/Ellipsoid.js";import{glLayout as _}from"../support/buffer/glUtil.js";import{GeometryState as x}from"./GeometryState.js";import{NeighborIndex as C}from"./interfaces.js";import{LayerClass as D}from"./LayerClass.js";import{PatchGeometry as v,releaseGeometry as S}from"./PatchGeometry.js";import{ENABLE_TERRAIN_INTERNAL_CHECKS as $,internalAssert as E,neighborEdgeIndices as b,oppositeEdge as T,neighborCornerIndices as j,v32s as A,lij2s as V}from"./terrainUtils.js";import{TextureFader as R,ActivationTime as w}from"./TextureFader.js";import{isEdgeNeighbor as L}from"./Tile.js";import P from"./TileOverlayData.js";import{fallsWithinLayer as N}from"./tileUtils.js";import{VertexArrayObject as I}from"../webgl-engine/lib/VertexArrayObject.js";import{terrainVertexAttributeLocations as G}from"../webgl-engine/shaders/TerrainTechnique.js";import{BufferObject as M}from"../../webgl/BufferObject.js";class O{constructor(){this.geometryInfo=new v,this.intersectionData=null,this.geometryState=null,this._textureRef=new R((()=>this.tile.surface.textureFadeDuration)),this.overlay=new P,this._geometryStateChangedSinceLastUpdate=!0,this._hasGeometry=!1,this._numVerticesPerSideChanged=!1,this._samplerDataChanged=!1,this._clippingAreaChanged=!1,this._wireframeChanged=!1,this._shadingChanged=!1,this._dirtyEdgeResolutions=15,this._dirtyEdges=15,this._dirtyCorners=15}get tile(){return this._tile}init(e){this.clear(),this._tile=e;const t=this.geometryInfo;t.indices=null,t.vertexAttributes=null,p(t.boundingBox),t.indexCount=0,t.numVerticesPerSide=0,this.intersectionData=null,this.geometryState=new x,this.localOrigin=null,this.overlay.clear()}clear(){this.releaseGeometry(),this.releaseTexture(),this._textureRef.clear(),this._tile=null,this.intersectionData=null,this.geometryState=null}updateGeometryIfNeeded(e){if((!this._vao||this._geometryStateChangedSinceLastUpdate||this._wireframeChanged||this._shadingChanged||this._clippingAreaChanged||this._samplerDataChanged||this._numVerticesPerSideChanged||this._dirtyCorners||this._dirtyEdgeResolutions||this._dirtyEdges)&&(this._updateGeometry(e),this._geometryStateChangedSinceLastUpdate=!1),$&&this.tile.intersectsClippingArea)for(let t=0;t<4;++t)E(this.geometryInfo.outerEdges[t].count===this.geometryState.neighborData.edgeResolutions[t]+1)}_calculateEdgeResolution(e,t){const s=this.tile,a=this.geometryState.numVerticesPerSide-1;if(!s.surface.isGlobal){const t=s.surface.extent;if(r(t)&&(0===e&&s.extent[3]>t[3]||1===e&&s.extent[2]>t[2]||2===e&&s.extent[1]<t[1]||3===e&&s.extent[0]<t[0]))return a}const n=s.level,o=b[e];if(!t)return E(i(s.surface?.rootTiles)||s.surface.updatingRootTiles||!s.shouldHaveNeighbor(o)),a;if(t.isLoaded){const r=t,i=r.renderData.geometryState,s=n-r.level;if(E(s>=0),0===s){const e=i.numVerticesPerSide-1;return Math.max(e,a)}const o=2**s,l=i.neighborData.edgeResolutions[(e+2)%4]/o;return Math.max(1,l)}E(!t.isLeaf);let l=a;return t.forAllSubtreeOnSide(T(o),(e=>e===s||(e.isLoaded?(l=Math.max(l,2**(e.level-n)),!0):(E(!e.isLeaf),!1)))),l}updateNeighborData(){const e=this.tile;if(!e.intersectsClippingArea)return;const r=e.renderData.geometryState.neighborData,i=t=>(t.isLoaded||t.level===e.level)&&t?.intersectsClippingArea,s=r.edgePeerNeighbors,a=r.edgePeerNeighborSamplerVersions;for(let o=0;o<4;++o){const n=e.findNeighborTile(b[o],i),l=z(e,n),h=l?.renderData?.geometryState.samplerDataVersion??-1,d=s[o],g=l!==z(e,d),c=a[o]!==h;s[o]=n,(g||c)&&(a[o]=h,this._markEdgeDirty(o));const u=r.edgeResolutions[o],m=this._calculateEdgeResolution(o,n);E(t(m)),E(m>=1),r.edgeResolutions[o]=m,u!==m&&this._markEdgeResolutionDirty(o)}const n=r.cornerPeerNeighbors;for(let t=0;t<4;++t){const a=e.findNeighborTile(j[t],i);n[t]=a;const o=z(e,s[t]),l=z(e,s[(t+1)%4]),h=z(e,a);q[t]=h,q[(t+1)%4]=l,q[(t+2)%4]=e,q[(t+3)%4]=o,E(q.some((t=>t?.isLoaded||t===e)));const d=q.reduce(((e,t)=>Math.min(e,t?.level??1/0)),1/0);q.forEach(((e,t)=>{e&&e?.level>d&&(q[t]=null)})),E(q.some((t=>t?.isLoaded||t===e)));const g=r.cornerNeighborData[t].cornerTiles,c=r.cornerNeighborData[t].cornerTileSamplerVersions;for(let e=0;e<4;++e){const r=q[e],i=r?.renderData.geometryState.samplerDataVersion??-1,s=g[e]!==r,a=!s&&c[e]!==i;(s||a)&&(g[e]=r,c[e]=i,this._markCornerDirty(t))}E(g.some((t=>t?.isLoaded||t===e)))}$&&E(this.geometryState.neighborData.edgeResolutions.every((e=>e>0)));for(let t=0;t<4;++t)q[t]=null}_updateGeometry(e){if(!this.tile.intersectsClippingArea)return;$&&E(!this.tile.intersectsClippingArea||this.geometryState.neighborData.edgeResolutions.every((e=>e>0))),this.intersectionData=null;const t=this.tile,r=this._vao,i=this.geometryInfo.vertexAttributes,s=!r||!i||this._wireframeChanged||this._shadingChanged||this._numVerticesPerSideChanged||this._samplerDataChanged||this._clippingAreaChanged||this._dirtyEdgeResolutions,a=!s&&(0!==this._dirtyEdges||0!==this._dirtyEdgeResolutions),n=!a&&0!==this._dirtyCorners;s?(this.releaseGeometry(),this._createGeometry(e)):a||n?t.updateEdgeElevations():n?t.updateCornerElevations():console.warn("Update for no reason?"),this._numVerticesPerSideChanged=!1,this._samplerDataChanged=!1,this._dirtyEdgeResolutions=0,this._dirtyEdges=0,this._dirtyCorners=0,this._clippingAreaChanged=!1,this._wireframeChanged=!1,this._shadingChanged=!1}get hasGeometry(){return this._hasGeometry}releaseGeometry(){return this._hasGeometry=!1,this.intersectionData=null,!!this._vao&&(this._vao.dispose(),this._vao=null,S(this.geometryInfo),!0)}ensureTexture(e,t){return r(this._texture)&&this._texture.descriptor.width!==e&&this.releaseTexture(),i(this._texture)&&(this._texture=t(),this.tile.setMemoryDirty()),this._texture}releaseTexture(){r(this._texture)&&(this._texture.release(),this._texture=null,this.tile.setMemoryDirty())}_markCornerDirty(e){const t=1<<e;this._dirtyCorners|=t}_markEdgeDirty(e){const t=1<<e;this._dirtyEdges|=t}_markEdgeResolutionDirty(e){const t=1<<e;this._dirtyEdgeResolutions|=t,this._dirtyEdges|=t}_markAllEdgesAndCornersDirty(){this._dirtyCorners=15,this._dirtyEdges=15,this._dirtyEdgeResolutions=15}updateGeometryState(){const t=this._getElevationInfo(),r=this.tile,i=t.samplerData?r.getElevationVerticesPerSide(t.maxTileLevel):r.getDefaultVerticesPerSide(),s=Math.max(i,5);let a=r.clippingArea;r.intersectsClippingArea&&!r.isWithinClippingArea||(a=null);const n=this.geometryState;let o=!1;n.numVerticesPerSide!==s&&(this._numVerticesPerSideChanged=!0,n.numVerticesPerSide=s,n.samplerDataVersion++,o=!0),t.changed&&(this._samplerDataChanged=!0,n.samplerData=t.samplerData,n.samplerDataVersion++,o=!0),e(n.clippingArea,a)||(this._clippingAreaChanged=!0,n.clippingArea=a,o=!0);const l=r.surface,h=l.wireframe;n.wireframe!==h&&(this._wireframeChanged=!0,n.wireframe=h,o=!0);const d=l.shading;return n.shading!==d&&(this._shadingChanged=d,n.shading=d,o=d),this._geometryStateChangedSinceLastUpdate||(this._geometryStateChangedSinceLastUpdate=o),o&&this._markAllEdgesAndCornersDirty(),this._hasGeometry=!0,this._geometryStateChangedSinceLastUpdate}_createGeometry(e){this.tile.createGeometry();const t=this.geometryInfo.vertexAttributes,r=this.geometryInfo.indices,i=e.gl;this._vao=new I(e,G,{geometry:_(t.layout)},{geometry:M.createVertex(e,i.STATIC_DRAW,t.buffer)},M.createIndex(e,i.STATIC_DRAW,r)),this._hasGeometry=!0}get vao(){return this._vao}setTextureReference(e,t=w.Immediate){r(e)&&e.texture!==this._texture&&this.releaseTexture(),this._textureRef.push(e,t)}get textureReference(){return this._textureRef.current}get nextTextureReference(){return this._textureRef.next}get textureFadeFactor(){return this._textureRef.fadeFactor}get textureIsFading(){return this._textureRef.isFading}_getElevationInfo(){const e=this.geometryState.samplerData,t=this.tile.layerInfo[D.ELEVATION],i=t.length,s=new Array(i);let a=0,n=0,o=!1;for(let d=0;d<i;d++){const i=t[d];if(r(i.upsampleInfo)){const t=i.upsampleInfo.tile,r=t.layerInfo[D.ELEVATION][d].data,l=r&&r.samplerData;e&&e[a]===l||(o=!0),s[a++]=l,n=Math.max(n,t.lij[0])}else if(i.data){const t=this.tile.surface.layerViewByIndex(d,D.ELEVATION);if(N(this.tile,t.layer,!1)){const t=i.data;e&&e[a]===t.samplerData||(o=!0),s[a++]=t.samplerData,n=this.tile.level}}}r(e)&&e.length!==a&&(o=!0);const l=a>0,h=l?s:null;return l&&(s.length=a),{changed:o,samplerData:h,maxTileLevel:n}}get estimatedGeometryMemoryUsage(){const e=s(this.intersectionData,0,(e=>e.estimatedMemoryUsage));return(this.geometryInfo.indices?.byteLength??0)+(this.geometryInfo.vertexAttributes?.byteLength??0)+e}get textureDescriptor(){return r(this._texture)?this._texture.descriptor:null}get test(){return{hasTexture:null!=this._texture}}checkGeometryWaterproofness(){if(!$)return;const e=this.tile;if(E(e?.isLoaded),!e.isLoaded||!e.intersectsClippingArea)return;const s=e.renderData;if(0===e.level)return;const p=e.surface.extent;if(r(p)&&!e.intersectsExtent(p))return;const _=b.map(((t,i)=>!!r(p)&&(i<2?-1:1)*(e.extent[3-i]-p[3-i])<0)),x=e.level;E(0===this._dirtyCorners),E(0===this._dirtyEdges),E(0===this._dirtyEdgeResolutions),E(!this._numVerticesPerSideChanged),E(!this._samplerDataChanged),E(!this._clippingAreaChanged),E(!this._wireframeChanged);const D=j.map((t=>e.findNeighborCornerTileExact(t,(t=>!t.intersectsClippingArea||t.isLoaded||t.level===e.level))??null)).map((e=>e?.intersectsClippingArea?e:null)),v=this.geometryState.neighborData;for(let t=0;t<4;++t){const r=v.cornerPeerNeighbors[t],i=D[t];E(i===r,`Tile[${e.lij}].corner[${t}] out of date: cur=[${r?.lij}] exp=[${i?.lij}]`)}b.forEach(((p,D)=>{if(_[D])return;const v=e.findNeighborTile(p,(e=>(e.level===x||e?.isLoaded)&&e?.intersectsClippingArea));if(!v){const t=!e.surface.updatingRootTiles&&r(e.surface.rootTiles)&&e.surface.rootTiles.length>0&&e.shouldHaveNeighbor(p);return void E(!t)}E(v.isLoaded||v.level===e.level),E(v===this.geometryState.neighborData.edgePeerNeighbors[D]);const S=x-v.level;if(!v.isLoaded)return E(!v.isLeaf),void E(0===S);const $=v.renderData;E(L(e,v,p)),E(S>=0);const b=2**S;if(S<0)return void E(!1);const T=s.geometryInfo,j=T.outerEdges[D],R=T.numVerticesPerSide-1,w=$.geometryInfo;if(!w)return void E(!1);{const e=this.geometryState.neighborData.edgePeerNeighbors[D];if(e?.isLoaded){const t=e.renderData;E(e==e),E(s.geometryState.neighborData.edgePeerNeighborSamplerVersions[D]===t.geometryState.samplerDataVersion),E(this.geometryState.neighborData.edgePeerNeighborSamplerVersions[D]===t.geometryState.samplerDataVersion)}}const P=(D+2)%4,N=w.outerEdges[P],I=j.count-1,G=N.count-1;E(I*b===G,`Tile[${e.lij}]:e${D},res=${I} edgeRes mismatch with Neighbor[${v.lij}]:e${P},res=${G} (expected:${I*b})`);const M=e.extent,O=p===C.NORTH||p===C.SOUTH,q=N.count-1,z=q/2**S,J=j.count-1;if(z<1)return void E(1===J);E(z===J),E(t(z));const K=w.numVerticesPerSide-1;E(S>0||z===Math.max(K,R));const Q=e.getNeighborEdgeStartVertexIndex(D,v);E(0<=Q&&Q<b);const Y=Q*z;E(0<=Y&&Y<=q-z);let Z=0,ee=Y;j.getVertexPos(U,0),j.getVertexPos(k,j.count-1);const te=a(U,k),re=Math.max(W,1e-4*te);for(let t=0;t<=z;++t){j.getVertexPos(U,Z),N.getVertexPos(k,ee);const a=t/z,_=O?M[0]+a*(M[2]-M[0]):p===C.WEST?M[0]:M[2],x=O?p===C.SOUTH?M[1]:M[3]:M[1]+a*(M[3]-M[1]),S=e.surface.extent;if(i(S)||f(S,_,x)){const t=n(U,k),i=o(U)-y.radius,a=o(k)-y.radius,p=t<re;if(!p){console.warn(`Tile edge vertex position mismatch: between [${e.lij}].edge${D}[${Z}/${j.count}] and [${v.lij}].edge${P}[${ee}/${N.count}]`),r(S)&&console.warn(" surface extent= ",S," x,y=",_,",",x);const n=u();l(n,s.localOrigin,$.localOrigin),o(n)>0&&console.warn(` localOrigins: ${s.localOrigin} vs ${$.localOrigin} d=${o(n)} [${n}]`);(()=>{const t=m(U),r=m(k);e.updateEdgeElevations(),v.updateEdgeElevations(),j.getVertexPos(U,Z),N.getVertexPos(k,ee);const i=u();g(i,U,t),o(i)>0&&console.warn(` XXX Tile[${e.lij}] edge out of date: ${t} vs ${U} d=${o(i)} [${i}]`),g(i,k,r),o(i)>0&&console.warn(` XXX Neighbor[${v.lij}] edge out of date: ${r} vs ${k} d=${o(i)} [${i}]`)})(),E(p,`Mismatch in tile [${e.lij}].edge[${D}][${Z}/${j.count}] vs neighbor [${v.lij}].edge[${P}][${ee}/${N.count}] ${A(U)} vs ${A(k)} dist=${t} h(t|n|d)=${i}|${a}|${a-i}`)}if(e.surface.shading){j.getNormal(F,Z),N.getNormal(B,ee),h(X,F),h(H,B);const t=d(X,H),r=1-t<.01||!1||e===v;if(!r){const i=u();g(i,F,B);const s=()=>`Mismatch in tile edge normal ${V(e.lij)} (${Z}/${j.count-1}) edge ${D} vs neighbor ${V(v.lij)} (${ee}/${N.count-1}) nedge ${P} :${A(F)} vs ${A(B)} dot = ${t} : ${A(i)}`;console.warn("Mismatch in tile edge normal: ",s());{e.updateEdgeElevations(),v.updateEdgeElevations();const t=u(),r=u();j.getNormal(t,Z),N.getNormal(r,ee),c(F,t)||console.warn("Missing update in tile normal: ",A(F)," => ",A(t)),c(B,r)||console.warn("Missing update in neighbor normal: ",A(B)," => ",A(r))}E(r,s())}}}Z+=1,ee+=1}}))}}const U=u(),k=u(),F=u(),B=u(),X=u(),H=u(),W=1,q=[null,null,null,null];function z(e,t){return t?.isLoaded||t===e?t:null}export{w as ActivationTime,O as PatchRenderData,z as neighborTileIfLoadedOrSelf};