@arcgis/core
Version:
ArcGIS Maps SDK for JavaScript: A complete 2D and 3D mapping and data visualization API
3 lines (2 loc) • 8.16 kB
JavaScript
/* COPYRIGHT Esri - https://js.arcgis.com/5.0.19/LICENSE.txt */
import e from"../../../../core/Error.js";import{assertIsSome as t}from"../../../../core/maybe.js";import{MinPriority as o}from"../../../../core/MemCache.js";import{throwIfAborted as r}from"../../../../core/promiseUtils.js";import{generateUUID as n}from"../../../../core/uuid.js";import{normalFromMat4 as s}from"../../../../core/libs/gl-matrix-2/math/mat3.js";import{create as i}from"../../../../core/libs/gl-matrix-2/factories/mat3f64.js";import{exactEquals as a}from"../../../../core/libs/gl-matrix-2/math/vec3.js";import{ONES as l}from"../../../../core/libs/gl-matrix-2/factories/vec3f64.js";import{projectBoundingSphere as c}from"../../../../geometry/projection/projectBoundingSphere.js";import{ensurePackedArray as d}from"../../../../geometry/support/DoubleArray.js";import{isRelativeVertexSpace as m}from"../../../../geometry/support/meshVertexSpaceUtils.js";import{Sphere as u}from"../../../../geometry/support/sphere.js";import{CachedMeshData as h}from"./CachedMeshData.js";import{convertMeshMaterialToPBRMaterial as f}from"./I3SClientMaterialUtil.js";class p{constructor(e,t,o,r,n,s){this.id=e,this.version=t,this.mbs=o,this.oid=r,this.componentNodeIds=n,this.unloadedMesh=s,this.type="mesh"}}class x{constructor(e,t,o){this.id=e,this.meshNodeInfo=t,this.componentIndex=o,this.type="mesh-component",this.textureData=new Map}get mbs(){return this.meshNodeInfo.mbs}}class y{constructor(e,t,o,r){this._uid=e,this._worker=r,this._id2Meta=new Map,this._oid2Meta=new Map,this._indexSR=t.indexSR,this._vertexSR=t.vertexSR,this._renderSR=t.renderSR,this._memCache=o.newCache(`sl-client-mesh-data-${this._uid}`)}get uid(){return this._uid}get worker(){return this._worker}get indexSR(){return this._indexSR}get renderSR(){return this._renderSR}createMeshNodeInfo(e,t){const o=`mesh${t}`,r=e.extent,n=r.spatialReference,s=this._indexSR,i=M(r,e.origin);c(i,n,i,s);const a=N(e);return new p(o,a,i,t,[],e)}addMeshNode(t,o){if(null!=this.getMeshNodeIndex(o.oid))throw new e("scenelayer",`I3SClientNodeLoader: client side mesh for feature oid=${o.oid} already exists`);o.nodeIndex=t,this._id2Meta.set(o.id,o),this._oid2Meta.set(o.oid,o)}getMeshNodeIndex(e){const t=this._oid2Meta.get(e);return null==t||"mesh"!==t.type?null:t.nodeIndex}getMeshNodeInfo(e){const t=this._oid2Meta.values();for(const o of t)if("mesh"===o.type&&o.id===e)return o;return null}removeNode(e){const t=this._id2Meta.get(e);null!=t&&(this._id2Meta.delete(e),"mesh"===t.type&&this._oid2Meta.delete(t.oid))}async loadNodeJSON(t){const o=this._id2Meta.get(t);if(null==o)throw new e("scenelayer",`I3SClientNodeLoader::loadNodeJSON unable to find node ${t}`);switch(o.type){case"mesh":return this._loadMeshNodeJSON(o);case"mesh-component":return g(o);default:throw new e("scenelayer",`I3SClientNodeLoader::loadNodeJSON unable to handle node ${t}`)}}async _loadMeshNodeJSON(e){const t=e.id,o=(await this._getMeshData(e)).loadedMesh;if(null==o.components||0===o.components.length)return{id:t,mbs:e.mbs.toVec4()};const r=new Array,n=o.components;for(let s=0;s<n.length;++s){const o=`${t}-component${s}`,n=new x(o,e,s);this._id2Meta.set(n.id,n),e.componentNodeIds.push(o),r.push({id:n.id,mbs:n.mbs.toVec4()})}return{id:t,mbs:e.mbs.toVec4(),children:r}}updateNodeIndex(e,t,o){const r=this._id2Meta.get(e);"mesh"===r?.type&&(r.nodeIndex=o)}async loadNodeData(o,n){const s=this._id2Meta.get(o);if(null==s||"mesh-component"!==s.type)throw new e("scenelayer",`Failed to load client node data for node ${o} (unexpected node info)`);const i=s.meshNodeInfo,a=await this._getMeshData(i),l=a.loadedMesh,c=i.oid;if(null==l.components)throw new e("scenelayer",`Failed to load client node data for node ${o} (unexpected null reference)`);const m=l.components[s.componentIndex],{material:u,requiredTextures:h,textureData:p}=await f(m.material);if(null!=p)for(const e of p)null!=e&&s.textureData.set(e.id,e);const{vertexSpace:x,origin:y,transform:g}=l,M=[y.x,y.y,y.z??0];a.projectionPromise||(t(this._worker,"SceneLayerWorker is needed to project mesh"),a.projectionPromise=this._worker.project({positions:l.vertexAttributes.position,localMatrix:g?.localMatrix,vertexSpace:x.toJSON(),origin:M,inSpatialReference:l.spatialReference.toJSON(),outSpatialReference:this._vertexSR.toJSON()},n));const{projected:_,original:N,projectedOrigin:b}=await a.projectionPromise,v=d(b);l.vertexAttributes.position=N;const{transformed:j,original:I}=await w(m,a,this._worker,n);l.vertexAttributes.normal=I,r(n);const{geometryBuffer:R,geometryDescriptor:A}=S(_,m.faces,j,l.vertexAttributes.uv,l.vertexAttributes.color,c);return{geometryData:{featureDataPosition:v,featureIds:[],geometries:[{params:{material:u},type:"ArrayBufferView"}]},attributeDataInfo:{attributeData:{},loadedAttributes:[]},geometryBuffer:R,geometryDescriptor:A,requiredTextures:h,textureData:p,normalReferenceFrame:this._vertexSR.isGeographic?"east-north-up":"vertex-reference-frame"}}async loadAttributes(e,t){const o=e.numFeatures,r={};for(const{field:{name:n}}of t)r[n]=new Array(o);return r}async loadTextures(e,t){const o=e.id,r=this._id2Meta.get(o);if(null==r||"mesh-component"!==r.type)throw new Error(`Failed to load textures for node ${e.id} (unexpected node info)`);const n=[];for(const s of t)n.push(r.textureData.get(s.id)||null);return n}async _getMeshData(e){const t=e.version,r=this._memCache.get(t);if(null==r){if(null!=e.loadMeshPromise)return e.loadMeshPromise;const r=async()=>{const r=e.unloadedMesh.clone();await r.load();const n=new h(r);return this._memCache.put(t,n,o),e.loadMeshPromise=null,n};return e.loadMeshPromise=r(),e.loadMeshPromise}return r}}async function g(e){return{id:e.id,version:e.meshNodeInfo.version,mbs:e.mbs.toVec4(),isEmpty:!1}}function M(e,t){const{spatialReference:o}=e,r=[1,-1],n=[.5*e.width,.5*e.height,e.hasZ?.5*(e.zmax-e.zmin):0],s=o.isGeographic?o.metersPerUnit:1,i=e.center;let a=0;if(e.hasZ)for(let l=0;l<2;++l)for(let e=0;e<2;++e)for(let o=0;o<2;++o){const c=(i.x+r[l]*n[0]-t.x)*s,d=(i.y+r[e]*n[1]-t.y)*s,m=i.z+r[o]*n[2]-t.z;a=Math.max(c*c+d*d+m*m,a)}else for(let l=0;l<2;++l)for(let e=0;e<2;++e){const o=(i.x+r[l]*n[0]-t.x)*s,c=(i.y+r[e]*n[1]-t.y)*s;a=Math.max(o*o+c*c,a)}return new u(t.x,t.y,t.z??0,Math.sqrt(a))}async function w(e,o,r,n){const{transform:c,vertexAttributes:d}=o.loadedMesh,m="source"===e.shading?d.normal:null;if(!(null!=m&&null!=c&&(0!==c.rotationAngle||!a(c.scale,l))))return{transformed:m,original:d.normal};if(!o.normalsTransformPromise){t(r,"SceneLayerWorker is needed to transform mesh normals");const e=i();s(e,c.localMatrix),o.normalsTransformPromise=r.transformNormals({normalMatrix:e,normals:m},n)}return o.normalsTransformPromise}function S(e,t,o,r,n,s){const i=1,a=(t?.length??0)/3,l=3*a;let c=b+b;const d=c;c+=3*l*v;const m=null!=o,u=c;m&&(c+=3*l*v);const h=null!=r,f=c;h&&(c+=2*l*v);const p=null!=n,x=c;p&&(c+=4*l*j);const y=c;c+=i*I;const g=c;c+=2*i*b;const M=new ArrayBuffer(c),w=new Uint8Array(M);_(w,0,l),_(w,b,i);const S=new Float32Array(M,d),N=null!=o?new Float32Array(M,u):null,R=null!=r?new Float32Array(M,f):null,A=null!=n?new Uint8Array(M,x):null;for(let _=0;_<a;++_){const s=3*_;for(let i=0;i<3;++i){const a=t[s+i],l=3*a,c=9*_+3*i;if(S[c]=e[l],S[c+1]=e[l+1],S[c+2]=e[l+2],N&&(N[c]=o[l],N[c+1]=o[l+1],N[c+2]=o[l+2]),R){const e=2*a,t=6*_+2*i;R[t]=r[e],R[t+1]=r[e+1]}if(A){const e=4*a,t=12*_+4*i;A[t]=n[e],A[t+1]=n[e+1],A[t+2]=n[e+2],A[t+3]=n[e+3]}}}_(w,y,s),_(w,y+b,s/2**32),_(w,g,0),_(w,g+b,a-1);return{geometryBuffer:M,geometryDescriptor:{isDraco:!1,isLegacy:!0,color:p,normal:m,uv0:h,uvRegion:!1,featureIndex:!0}}}function _(e,t,o){e[t]=255&o,e[t+1]=255&o>>8,e[t+2]=255&o>>16,e[t+3]=255&o>>24}function N(e){const t=e.metadata.displaySource?.source;if("service"!==t?.type)return n();return t.assets.reduce((e,t)=>e+t.makeHash(),"")+JSON.stringify(e.transform?.toJSON()??"")+(m(e.vertexSpace)?JSON.stringify(e.vertexSpace.origin):"")+JSON.stringify(e.spatialReference)}const b=4,v=4,j=1,I=8;export{x as ClientMeshComponentNodeInfo,p as ClientMeshNodeInfo,y as I3SClientNodeLoader,M as createSphereFromExtent,v as sizeOfFloat32,b as sizeOfInt32,I as sizeOfUInt64,j as sizeOfUInt8,w as transformNormals};