UNPKG

@doegis/core

Version:

DOE GIS API

3 lines (1 loc) 15 kB
import e from"../../../../core/Error.js";import t from"../../../../core/Logger.js";import{getOrCreateMapValue as r}from"../../../../core/MapUtils.js";import{eachAlwaysValues as o}from"../../../../core/promiseUtils.js";import{isDataProtocol as n,dataComponents as s,dataToArrayBuffer as a,makeAbsolute as i}from"../../../../core/urlUtils.js";import{Version as u}from"../../../../core/Version.js";import{A as f,m as c,w as d,e as l,k as p}from"../../../../chunks/mat4.js";import{c as h,b as m}from"../../../../chunks/mat4f64.js";import{g as w}from"../../../../chunks/quat.js";import{a as y}from"../../../../chunks/quatf64.js";import{BufferViewUint32 as T,BufferViewUint16 as b,BufferViewUint8 as _,BufferViewVec3f as g,BufferViewVec4f as x,BufferViewVec2f as O,BufferViewVec4u8 as N,BufferViewVec4u16 as S,BufferViewVec3u8 as C,BufferViewVec3u16 as A,BufferViewVec2u32 as L,BufferViewVec2u16 as E,BufferViewVec2i16 as I,BufferViewVec2u8 as R,BufferViewVec2i8 as B}from"../../../../geometry/support/buffer/BufferView.js";import{m as v}from"../../../../chunks/scalar.js";import{BinaryStreamReader as U}from"./BinaryStreamReader.js";import{AttributeType as D}from"./enums.js";import{material as G,textureSampler as j}from"./fillDefaults.js";import{splitURI as M}from"./pathUtils.js";import{jsonFromBinaryData as F,EncodedMeshTexture as H,imageFromBinaryData as P,isEncodedMeshTexture as V}from"./resourceUtils.js";import{DataType as k}from"../../../webgl/enums.js";const K={MAGIC:1179937895,CHUNK_TYPE_JSON:1313821514,CHUNK_TYPE_BIN:5130562,MIN_HEADER_LENGTH:20};class Y{constructor(t,r,o,n){if(this._context=t,this.uri=r,this.json=o,this._glbBuffer=n,this._bufferLoaders=new Map,this._textureLoaders=new Map,this._textureCache=new Map,this._materialCache=new Map,this._nodeParentMap=new Map,this._nodeTransformCache=new Map,this._supportedExtensions=["KHR_texture_basisu"],this._baseUri=M(this.uri).dirPart,this._checkVersionSupported(),this._checkRequiredExtensionsSupported(),null==o.scenes)throw new e("gltf-loader-unsupported-feature","Scenes must be defined.");if(null==o.meshes)throw new e("gltf-loader-unsupported-feature","Meshes must be defined");if(null==o.nodes)throw new e("gltf-loader-unsupported-feature","Nodes must be defined.");this._computeNodeParents()}static async load(e,t,r){if(n(t)){const r=s(t);if(r&&"model/gltf-binary"!==r.mediaType)try{const o=JSON.parse(r.isBase64?atob(r.data):r.data);return new Y(e,t,o)}catch{}const o=a(t);if(Y._isGLBData(o))return this._fromGLBData(e,t,o)}if(t.endsWith(".gltf")){const o=await e.loadJSON(t,r);return new Y(e,t,o)}const o=await e.loadBinary(t,r);if(Y._isGLBData(o))return this._fromGLBData(e,t,o);const i=await e.loadJSON(t,r);return new Y(e,t,i)}static _isGLBData(e){if(null==e)return!1;const t=new U(e);return t.remainingBytes()>=4&&t.readUint32()===K.MAGIC}static async _fromGLBData(e,t,r){const o=await Y._parseGLBData(r);return new Y(e,t,o.json,o.binaryData)}static async _parseGLBData(r){const o=new U(r);if(o.remainingBytes()<12)throw new e("gltf-loader-error","GLB binary data is insufficiently large.");const n=o.readUint32(),s=o.readUint32(),a=o.readUint32();if(n!==K.MAGIC)throw new e("gltf-loader-error","Magic first 4 bytes do not fit to expected GLB value.");if(r.byteLength<a)throw new e("gltf-loader-error","GLB binary data is smaller than header specifies.");if(2!==s)throw new e("gltf-loader-unsupported-feature","An unsupported GLB container version was detected. Only version 2 is supported.");let i,u,f=0;for(;o.remainingBytes()>=8;){const r=o.readUint32(),n=o.readUint32();if(0===f){if(n!==K.CHUNK_TYPE_JSON)throw new e("gltf-loader-error","First GLB chunk must be JSON.");if(r<0)throw new e("gltf-loader-error","No JSON data found.");i=await F(o.readUint8Array(r))}else if(1===f){if(n!==K.CHUNK_TYPE_BIN)throw new e("gltf-loader-unsupported-feature","Second GLB chunk expected to be BIN.");u=o.readUint8Array(r)}else t.getLogger("esri.views.3d.glTF").warn("[Unsupported Feature] More than 2 GLB chunks detected. Skipping.");f+=1}if(!i)throw new e("gltf-loader-error","No GLB JSON chunk detected.");return{json:i,binaryData:u}}async getBuffer(t,r){const o=this.json.buffers[t];if(null==o.uri){if(null==this._glbBuffer)throw new e("gltf-loader-error","GLB buffer not present");return this._glbBuffer}const n=await this._getBufferLoader(t,r);if(n.byteLength!==o.byteLength)throw new e("gltf-loader-error","Buffer byte lengths should match.");return n}async _getBufferLoader(e,t){const r=this._bufferLoaders.get(e);if(r)return r;const o=this.json.buffers[e].uri,n=this._context.loadBinary(this._resolveUri(o),t).then((e=>new Uint8Array(e)));return this._bufferLoaders.set(e,n),n}async getAccessor(t,r){if(!this.json.accessors)throw new e("gltf-loader-unsupported-feature","Accessors missing.");const o=this.json.accessors[t];if(null==o?.bufferView)throw new e("gltf-loader-unsupported-feature","Some accessor does not specify a bufferView.");if(o.type in[D.MAT2,D.MAT3,D.MAT4])throw new e("gltf-loader-unsupported-feature",`AttributeType ${o.type} is not supported`);const n=this.json.bufferViews[o.bufferView],s=await this.getBuffer(n.buffer,r),a=X[o.type],i=W[o.componentType],u=a*i,f=n.byteStride||u;return{raw:s.buffer,byteStride:f,byteOffset:s.byteOffset+(n.byteOffset||0)+(o.byteOffset||0),entryCount:o.count,isDenselyPacked:f===u,componentCount:a,componentByteSize:i,componentType:o.componentType,min:o.min,max:o.max,normalized:!!o.normalized}}async getIndexData(e,t){if(null==e.indices)return;const r=await this.getAccessor(e.indices,t);if(r.isDenselyPacked)switch(r.componentType){case k.UNSIGNED_BYTE:return new Uint8Array(r.raw,r.byteOffset,r.entryCount);case k.UNSIGNED_SHORT:return new Uint16Array(r.raw,r.byteOffset,r.entryCount);case k.UNSIGNED_INT:return new Uint32Array(r.raw,r.byteOffset,r.entryCount)}else switch(r.componentType){case k.UNSIGNED_BYTE:return v(this._wrapAccessor(_,r));case k.UNSIGNED_SHORT:return v(this._wrapAccessor(b,r));case k.UNSIGNED_INT:return v(this._wrapAccessor(T,r))}}async getPositionData(t,r){if(null==t.attributes.POSITION)throw new e("gltf-loader-unsupported-feature","No POSITION vertex data found.");const o=await this.getAccessor(t.attributes.POSITION,r);if(o.componentType!==k.FLOAT)throw new e("gltf-loader-unsupported-feature","Expected type FLOAT for POSITION vertex attribute, but found "+k[o.componentType]);if(3!==o.componentCount)throw new e("gltf-loader-unsupported-feature","POSITION vertex attribute must have 3 components, but found "+o.componentCount.toFixed());return this._wrapAccessor(g,o)}async getNormalData(t,r){if(null==t.attributes.NORMAL)throw new e("gltf-loader-error","No NORMAL vertex data found.");const o=await this.getAccessor(t.attributes.NORMAL,r);if(o.componentType!==k.FLOAT)throw new e("gltf-loader-unsupported-feature","Expected type FLOAT for NORMAL vertex attribute, but found "+k[o.componentType]);if(3!==o.componentCount)throw new e("gltf-loader-unsupported-feature","NORMAL vertex attribute must have 3 components, but found "+o.componentCount.toFixed());return this._wrapAccessor(g,o)}async getTangentData(t,r){if(null==t.attributes.TANGENT)throw new e("gltf-loader-error","No TANGENT vertex data found.");const o=await this.getAccessor(t.attributes.TANGENT,r);if(o.componentType!==k.FLOAT)throw new e("gltf-loader-unsupported-feature","Expected type FLOAT for TANGENT vertex attribute, but found "+k[o.componentType]);if(4!==o.componentCount)throw new e("gltf-loader-unsupported-feature","TANGENT vertex attribute must have 4 components, but found "+o.componentCount.toFixed());return new x(o.raw,o.byteOffset,o.byteStride,o.byteOffset+o.byteStride*o.entryCount)}async getTextureCoordinates(t,r){if(null==t.attributes.TEXCOORD_0)throw new e("gltf-loader-error","No TEXCOORD_0 vertex data found.");const o=await this.getAccessor(t.attributes.TEXCOORD_0,r);if(2!==o.componentCount)throw new e("gltf-loader-unsupported-feature","TEXCOORD_0 vertex attribute must have 2 components, but found "+o.componentCount.toFixed());if(o.componentType===k.FLOAT)return this._wrapAccessor(O,o);if(!o.normalized)throw new e("gltf-loader-unsupported-feature","Integer component types are only supported for a normalized accessor for TEXCOORD_0.");return $(o)}async getVertexColors(t,r){if(null==t.attributes.COLOR_0)throw new e("gltf-loader-error","No COLOR_0 vertex data found.");const o=await this.getAccessor(t.attributes.COLOR_0,r);if(4!==o.componentCount&&3!==o.componentCount)throw new e("gltf-loader-unsupported-feature","COLOR_0 attribute must have 3 or 4 components, but found "+o.componentCount.toFixed());if(4===o.componentCount){if(o.componentType===k.FLOAT)return this._wrapAccessor(x,o);if(o.componentType===k.UNSIGNED_BYTE)return this._wrapAccessor(N,o);if(o.componentType===k.UNSIGNED_SHORT)return this._wrapAccessor(S,o)}else if(3===o.componentCount){if(o.componentType===k.FLOAT)return this._wrapAccessor(g,o);if(o.componentType===k.UNSIGNED_BYTE)return this._wrapAccessor(C,o);if(o.componentType===k.UNSIGNED_SHORT)return this._wrapAccessor(A,o)}throw new e("gltf-loader-unsupported-feature","Unsupported component type for COLOR_0 attribute: "+k[o.componentType])}hasPositions(e){return void 0!==e.attributes.POSITION}hasNormals(e){return void 0!==e.attributes.NORMAL}hasVertexColors(e){return void 0!==e.attributes.COLOR_0}hasTextureCoordinates(e){return void 0!==e.attributes.TEXCOORD_0}hasTangents(e){return void 0!==e.attributes.TANGENT}async getMaterial(e,t,r){let o=e.material?this._materialCache.get(e.material):void 0;if(!o){const n=null!=e.material?G(this.json.materials[e.material]):G(),s=n.pbrMetallicRoughness,a=this.hasVertexColors(e),i=this.getTexture(s.baseColorTexture,t),u=this.getTexture(n.normalTexture,t),f=r?this.getTexture(n.occlusionTexture,t):void 0,c=r?this.getTexture(n.emissiveTexture,t):void 0,d=r?this.getTexture(s.metallicRoughnessTexture,t):void 0,l=null!=e.material?e.material:-1;o={alphaMode:n.alphaMode,alphaCutoff:n.alphaCutoff,color:s.baseColorFactor,doubleSided:!!n.doubleSided,colorTexture:await i,normalTexture:await u,name:n.name,id:l,occlusionTexture:await f,emissiveTexture:await c,emissiveFactor:n.emissiveFactor,metallicFactor:s.metallicFactor,roughnessFactor:s.roughnessFactor,metallicRoughnessTexture:await d,hasVertexColors:a,ESRI_externalColorMixMode:n.extras.ESRI_externalColorMixMode,colorTextureTransform:s?.baseColorTexture?.extensions?.KHR_texture_transform,normalTextureTransform:n.normalTexture?.extensions?.KHR_texture_transform,occlusionTextureTransform:n.occlusionTexture?.extensions?.KHR_texture_transform,emissiveTextureTransform:n.emissiveTexture?.extensions?.KHR_texture_transform,metallicRoughnessTextureTransform:s?.metallicRoughnessTexture?.extensions?.KHR_texture_transform}}return o}async getTexture(t,o){if(!t)return;if(0!==(t.texCoord||0))throw new e("gltf-loader-unsupported-feature","Only TEXCOORD with index 0 is supported.");const n=t.index,s=this.json.textures[n],a=j(null!=s.sampler?this.json.samplers[s.sampler]:{}),i=this._getTextureSourceId(s),u=this.json.images[i],f=await this._loadTextureImageData(n,s,o);return r(this._textureCache,n,(()=>{const t=e=>33071===e||33648===e||10497===e,r=t=>{throw new e("gltf-loader-error",`Unexpected TextureSampler WrapMode: ${t}`)};return{data:f,wrapS:t(a.wrapS)?a.wrapS:r(a.wrapS),wrapT:t(a.wrapT)?a.wrapT:r(a.wrapT),minFilter:a.minFilter,name:u.name,id:n}}))}getNodeTransform(e){if(void 0===e)return q;let t=this._nodeTransformCache.get(e);if(!t){const r=this.getNodeTransform(this._getNodeParent(e)),o=this.json.nodes[e];o.matrix?t=c(h(),r,o.matrix):o.translation||o.rotation||o.scale?(t=m(r),o.translation&&d(t,t,o.translation),o.rotation&&(z[3]=w(z,o.rotation),l(t,t,z[3],z)),o.scale&&p(t,t,o.scale)):t=m(r),this._nodeTransformCache.set(e,t)}return t}_wrapAccessor(e,t){return new e(t.raw,t.byteOffset,t.byteStride,t.byteOffset+t.byteStride*(t.entryCount-1)+t.componentByteSize*t.componentCount)}_resolveUri(e){return i(e,this._baseUri)}_getNodeParent(e){return this._nodeParentMap.get(e)}_checkVersionSupported(){const e=u.parse(this.json.asset.version,"glTF");J.validate(e)}_checkRequiredExtensionsSupported(){const t=this.json;if(t.extensionsRequired){if(!t.extensionsRequired.every((e=>this._supportedExtensions.includes(e))))throw new e("gltf-loader-unsupported-feature","gltf loader was not able to load unsupported feature. Required extensions: "+t.extensionsRequired.join(", "))}}_computeNodeParents(){this.json.nodes.forEach(((e,t)=>{e.children&&e.children.forEach((e=>{this._nodeParentMap.set(e,t)}))}))}async _loadTextureImageData(e,t,r){const o=this._textureLoaders.get(e);if(o)return o;const n=this._createTextureLoader(t,r);return this._textureLoaders.set(e,n),n}_getTextureSourceId(t){if(void 0!==t.extensions&&null!==t.extensions.KHR_texture_basisu)return t.extensions.KHR_texture_basisu.source;if(null!==t.source)return t.source;throw new e("gltf-loader-unsupported-feature","Source is expected to be defined for a texture. It can also be omitted in favour of an KHR_texture_basisu extension tag.")}async _createTextureLoader(t,r){const o=this._getTextureSourceId(t),n=this.json.images[o];if(n.uri){if(n.uri.endsWith(".ktx2")){const e=await this._context.loadBinary(this._resolveUri(n.uri),r);return new H(new Uint8Array(e))}return this._context.loadImage(this._resolveUri(n.uri),r)}if(null==n.bufferView)throw new e("gltf-loader-unsupported-feature","Image bufferView must be defined.");if(null==n.mimeType)throw new e("gltf-loader-unsupported-feature","Image mimeType must be defined.");const s=this.json.bufferViews[n.bufferView],a=await this.getBuffer(s.buffer,r);if(null!=s.byteStride)throw new e("gltf-loader-unsupported-feature","byteStride not supported for image buffer");const i=a.byteOffset+(s.byteOffset||0);return P(new Uint8Array(a.buffer,i,s.byteLength),n.mimeType)}async getLoadedBuffersSize(){if(this._glbBuffer)return this._glbBuffer.byteLength;const e=await o(Array.from(this._bufferLoaders.values())),t=await o(Array.from(this._textureLoaders.values()));return e.reduce(((e,t)=>e+(t?.byteLength??0)),0)+t.reduce(((e,t)=>e+(t?V(t)?t.data.byteLength:t.width*t.height*4:0)),0)}}const q=f(h(),Math.PI/2),J=new u(2,0,"glTF"),z=y(),X={SCALAR:1,VEC2:2,VEC3:3,VEC4:4},W={[k.BYTE]:1,[k.UNSIGNED_BYTE]:1,[k.SHORT]:2,[k.UNSIGNED_SHORT]:2,[k.FLOAT]:4,[k.UNSIGNED_INT]:4};function $(e){switch(e.componentType){case k.BYTE:return new B(e.raw,e.byteOffset,e.byteStride,e.byteOffset+e.byteStride*e.entryCount);case k.UNSIGNED_BYTE:return new R(e.raw,e.byteOffset,e.byteStride,e.byteOffset+e.byteStride*e.entryCount);case k.SHORT:return new I(e.raw,e.byteOffset,e.byteStride,e.byteOffset+e.byteStride*e.entryCount);case k.UNSIGNED_SHORT:return new E(e.raw,e.byteOffset,e.byteStride,e.byteOffset+e.byteStride*e.entryCount);case k.UNSIGNED_INT:return new L(e.raw,e.byteOffset,e.byteStride,e.byteOffset+e.byteStride*e.entryCount);case k.FLOAT:return new O(e.raw,e.byteOffset,e.byteStride,e.byteOffset+e.byteStride*e.entryCount)}}export{Y as GLTFResource,q as TRANSFORM_GLTF_TO_ENGINE};