UNPKG

@animech-public/playcanvas

Version:
2 lines (1 loc) 11.2 kB
import{CoreExporter as e}from"./core-exporter.js";import{CULLFACE_NONE as t,SEMANTIC_POSITION as r,INDEXFORMAT_UINT32 as s,INDEXFORMAT_UINT16 as n,INDEXFORMAT_UINT8 as a,TYPE_FLOAT32 as i,TYPE_UINT32 as o,TYPE_INT32 as c,TYPE_UINT16 as u,TYPE_INT16 as f,TYPE_UINT8 as l,TYPE_INT8 as m,SEMANTIC_TEXCOORD7 as h,SEMANTIC_TEXCOORD6 as p,SEMANTIC_TEXCOORD5 as d,SEMANTIC_TEXCOORD4 as x,SEMANTIC_TEXCOORD3 as b,SEMANTIC_TEXCOORD2 as g,SEMANTIC_TEXCOORD1 as w,SEMANTIC_TEXCOORD0 as y,SEMANTIC_BLENDWEIGHT as T,SEMANTIC_BLENDINDICES as M,SEMANTIC_COLOR as O,SEMANTIC_TANGENT as R,SEMANTIC_NORMAL as E,FILTER_LINEAR_MIPMAP_LINEAR as v,FILTER_NEAREST_MIPMAP_LINEAR as V,FILTER_LINEAR_MIPMAP_NEAREST as C,FILTER_NEAREST_MIPMAP_NEAREST as _,FILTER_LINEAR as B,FILTER_NEAREST as L,ADDRESS_REPEAT as I,ADDRESS_MIRRORED_REPEAT as A,ADDRESS_CLAMP_TO_EDGE as U}from"../../platform/graphics/constants.js";import{math as j}from"../../core/math/math.js";import{Vec2 as q}from"../../core/math/vec2.js";import{Vec3 as S}from"../../core/math/vec3.js";import{Quat as N}from"../../core/math/quat.js";import{Color as P}from"../../core/math/color.js";import{BoundingBox as z}from"../../core/shape/bounding-box.js";import{IndexBuffer as D}from"../../platform/graphics/index-buffer.js";import{VertexBuffer as F}from"../../platform/graphics/vertex-buffer.js";import{StandardMaterial as H}from"../../scene/materials/standard-material.js";import{BasicMaterial as K}from"../../scene/materials/basic-material.js";import{PROJECTION_ORTHOGRAPHIC as X,BLEND_NORMAL as G,BLEND_NONE as J}from"../../scene/constants.js";const $=34962,k=e=>{switch(e){case a:return 5121;case n:return 5123;case s:return 5125}return 0},W=e=>{switch(e){case m:return 5120;case l:return 5121;case f:return 5122;case u:return 5123;case c:return 5124;case o:return 5125;case i:return 5126}return 0},Z=e=>{switch(e){case 1:return"SCALAR";case 2:return"VEC2";case 3:return"VEC3";case 4:return"VEC4"}return 0},Y=function(e){switch(e){case L:return 9728;case B:return 9729;case _:return 9984;case C:return 9985;case V:return 9986;case v:return 9987}return 0},Q=function(e){switch(e){case U:return 33071;case A:return 33648;case I:return 10497}return 0};function ee(e){const t=e.getContext("2d").getImageData(0,0,e.width,e.height).data;for(let e=3;e<t.length;e+=4)if(t[e]<255)return!0;return!1}const te=["diffuseMap","colorMap","normalMap","metalnessMap","emissiveMap"];class re extends e{collectResources(e){const t={buffers:[],cameras:[],entities:[],materials:[],textures:[],entityMeshInstances:[],bufferViewMap:new Map,compressableTexture:new Set},{materials:r,buffers:s,entityMeshInstances:n,textures:a}=t;e.forEach((e=>{t.entities.push(e)}));const i=e=>{e.forEach((e=>{const i=e.material;r.indexOf(i)<0&&(t.materials.push(i),te.forEach((e=>{const r=i[e];r&&a.indexOf(r)<0&&("normalMap"!==e&&t.compressableTexture.add(r),a.push(r))})));const o=e.node;let c=n.find((e=>e.node===o));c||(c={node:o,meshInstances:[]},n.push(c)),c.meshInstances.push(e);const u=e.mesh,f=u.vertexBuffer;s.indexOf(f)<0&&s.unshift(f);const l=u.indexBuffer[0];s.indexOf(l)<0&&s.push(l)}))};return t.entities.forEach((e=>{e.camera&&t.cameras.push(e.camera),e.render&&e.render.enabled&&i(e.render.meshInstances),e.model&&e.model.enabled&&e.model.meshInstances&&i(e.model.meshInstances)})),t}writeBufferViews(e,t){t.bufferViews=[];for(const r of e.buffers)re.writeBufferView(e,t,r)}static writeBufferView(e,t,r){var s,n;t.buffers=null!=(s=t.buffers)?s:[],t.buffers[0]=null!=(n=t.buffers[0])?n:{byteLength:0};const a=t.buffers[0];a.byteLength=j.roundUp(a.byteLength,4);const i=a.byteLength,o=(e,r,s,n)=>{const a={target:e,buffer:0,byteLength:r,byteOffset:s,byteStride:n};return t.bufferViews.push(a)-1};let c;if(r instanceof F){c=r.lock();const t=r.getFormat();if(t.interleaved){const s=o($,c.byteLength,i,t.size);e.bufferViewMap.set(r,[s])}else{const s=[];for(const e of t.elements){const r=o($,e.size*t.vertexCount,i+e.offset,e.size);s.push(r)}e.bufferViewMap.set(r,s)}}else if(r instanceof D){c=r.lock();const t=o($,c.byteLength,i);e.bufferViewMap.set(r,[t])}else{c=r;const t=o(34963,c.byteLength,i);e.bufferViewMap.set(r,[t])}a.byteLength+=c.byteLength}writeCameras(e,t){e.cameras.length>0&&(t.cameras=e.cameras.map((e=>{const t=e.projection,r=e.nearClip,s=e.farClip,n={};if(t===X)n.type="orthographic",n.orthographic={xmag:1,ymag:1,znear:r,zfar:s};else{const t=e.fov;n.type="perspective",n.perspective={yfov:t*Math.PI/180,znear:r,zfar:s}}return n})))}attachTexture(e,t,r,s,n,a){const i=t[n];if(i){const u=e.textures.indexOf(i);u<0&&console.warn(`Texture ${i.name} wasn't collected.`),r[s]={index:u};const f=t[`${n}Tiling`],l=t[`${n}Offset`],m=t[`${n}Rotation`];var o,c;if(f&&!f.equals(q.ONE)||l&&!l.equals(q.ZERO)||0!==m)r[s].extensions={KHR_texture_transform:{}},a.extensionsUsed=null!=(o=a.extensionsUsed)?o:[],a.extensionsUsed.indexOf("KHR_texture_transform")<0&&a.extensionsUsed.push("KHR_texture_transform"),a.extensionsRequired=null!=(c=a.extensionsRequired)?c:[],a.extensionsRequired.indexOf("KHR_texture_transform")<0&&a.extensionsRequired.push("KHR_texture_transform"),f&&!f.equals(q.ONE)&&(r[s].extensions.KHR_texture_transform.scale=[f.x,f.y]),l&&!l.equals(q.ZERO)&&(r[s].extensions.KHR_texture_transform.offset=[l.x,l.y-1+f.y]),0!==m&&(r[s].extensions.KHR_texture_transform.rotation=m*j.DEG_TO_RAD)}}writeStandardMaterial(e,t,r,s){const{diffuse:n,emissive:a,opacity:i,metalness:o,gloss:c,glossInvert:u}=t,f=r.pbrMetallicRoughness;n.equals(P.WHITE)&&1===i||(f.baseColorFactor=[n.r,n.g,n.b,i]),1!==o&&(f.metallicFactor=o);const l=u?c:1-c;1!==l&&(f.roughnessFactor=l),this.attachTexture(e,t,f,"baseColorTexture","diffuseMap",s),this.attachTexture(e,t,f,"metallicRoughnessTexture","metalnessMap",s),a.equals(P.BLACK)||(r.emissiveFactor=[a.r,a.g,a.b])}writeBasicMaterial(e,t,r,s){const{color:n}=t,a=r.pbrMetallicRoughness;n.equals(P.WHITE)||(a.baseColorFactor=[n.r,n.g,n.b,n]),this.attachTexture(e,t,a,"baseColorTexture","colorMap",s)}writeMaterials(e,r){e.materials.length>0&&(r.materials=e.materials.map((s=>{const{name:n,blendType:a,cull:i,alphaTest:o}=s,c={pbrMetallicRoughness:{}};return n&&n.length>0&&(c.name=n),s instanceof H&&this.writeStandardMaterial(e,s,c,r),s instanceof K&&this.writeBasicMaterial(e,s,c,r),a===G?c.alphaMode="BLEND":a===J&&0!==o&&(c.alphaMode="MASK",c.alphaCutoff=o),i===t&&(c.doubleSided=!0),this.attachTexture(e,s,c,"normalTexture","normalMap",r),this.attachTexture(e,s,c,"occlusionTexture","aoMap",r),this.attachTexture(e,s,c,"emissiveTexture","emissiveMap",r),c})))}writeNodes(e,t){e.entities.length>0&&(t.nodes=e.entities.map((t=>{const r=t.name,s=t.getLocalPosition(),n=t.getLocalRotation(),a=t.getLocalScale(),i={};r&&r.length>0&&(i.name=r),s.equals(S.ZERO)||(i.translation=[s.x,s.y,s.z]),n.equals(N.IDENTITY)||(i.rotation=[n.x,n.y,n.z,n.w]),a.equals(S.ONE)||(i.scale=[a.x,a.y,a.z]),t.camera&&t.camera.enabled&&(i.camera=e.cameras.indexOf(t.camera));const o=e.entityMeshInstances.find((e=>e.node===t));return o&&(i.mesh=e.entityMeshInstances.indexOf(o)),t.children.length>0&&(i.children=[],t.children.forEach((t=>{i.children.push(e.entities.indexOf(t))}))),i})))}writeMeshes(e,t){e.entityMeshInstances.length>0&&(t.accessors=[],t.meshes=[],e.entityMeshInstances.forEach((r=>{const s={primitives:[]};r.meshInstances.forEach((r=>{const n=re.createPrimitive(e,t,r.mesh);n.material=e.materials.indexOf(r.material),s.primitives.push(n)})),t.meshes.push(s)})))}static createPrimitive(e,t,s){const n={attributes:{}},{vertexBuffer:a}=s,{format:i}=a,{interleaved:o,elements:c}=i,u=a.getNumVertices();c.forEach(((i,c)=>{let f=e.bufferViewMap.get(a);f||(re.writeBufferView(e,t,a),e.buffers.push(a),f=e.bufferViewMap.get(a));const l={bufferView:f[o?0:c],byteOffset:o?i.offset:0,componentType:W(i.dataType),type:Z(i.numComponents),count:u},m=t.accessors.push(l)-1;if(n.attributes[(e=>{switch(e){case r:return"POSITION";case E:return"NORMAL";case R:return"TANGENT";case O:return"COLOR_0";case M:return"JOINTS_0";case T:return"WEIGHTS_0";case y:return"TEXCOORD_0";case w:return"TEXCOORD_1";case g:return"TEXCOORD_2";case b:return"TEXCOORD_3";case x:return"TEXCOORD_4";case d:return"TEXCOORD_5";case p:return"TEXCOORD_6";case h:return"TEXCOORD_7"}return""})(i.name)]=m,i.name===r){const e=[];s.getPositions(e);const t=new S,r=new S;z.computeMinMax(e,t,r),l.min=[t.x,t.y,t.z],l.max=[r.x,r.y,r.z]}}));const f=s.indexBuffer[0];if(f){let r=e.bufferViewMap.get(f);r||(re.writeBufferView(e,t,f),e.buffers.push(f),r=e.bufferViewMap.get(f));const s={bufferView:r[0],componentType:k(f.getFormat()),count:f.getNumIndices(),type:"SCALAR"},a=t.accessors.push(s)-1;n.indices=a}return n}convertTextures(e,t){const r={maxTextureSize:t.maxTextureSize},s=[];return e.forEach((e=>{const t=this.textureToCanvas(e,r);t.then((e=>new Promise((t=>t(e))))),s.push(t)})),s}writeTextures(e,t,r,s){const n=e.textures,a=[];for(let s=0;s<t.length;s++){const i=n[s],o=t[s],c=ee(o)||!e.compressableTexture.has(i)?"image/png":"image/jpeg";a.push(this.getBlob(o,c).then((e=>{const t=new FileReader;return t.readAsArrayBuffer(e),new Promise((e=>{t.onloadend=()=>{e(t)}}))})).then((t=>{const n=this.getPaddedArrayBuffer(t.result);re.writeBufferView(e,r,n),e.buffers.push(n);const a=e.bufferViewMap.get(n);r.images[s]={mimeType:c,bufferView:a[0]},r.samplers[s]={minFilter:Y(i.minFilter),magFilter:Y(i.magFilter),wrapS:Q(i.addressU),wrapT:Q(i.addressV)},r.textures[s]={sampler:s,source:s}})))}return Promise.all(a)}getBlob(e,t){if(void 0!==e.toBlob)return new Promise((r=>{e.toBlob(r,t)}));let r=1;return"image/jpeg"===t&&(r=.92),e.convertToBlob({type:t,quality:r})}getPaddedArrayBuffer(e,t=0){const r=j.roundUp(e.byteLength,4);if(r!==e.byteLength){const s=new Uint8Array(r);if(s.set(new Uint8Array(e)),0!==t)for(let n=e.byteLength;n<r;n++)s[n]=t;return s.buffer}return e}buildJson(e,t){var r=this;const s=this.convertTextures(e.textures,t);return Promise.all(s).then((async function(s){const n={asset:{version:"2.0",generator:"PlayCanvas GltfExporter"},scenes:[{nodes:[0]}],images:[],samplers:[],textures:[],scene:0};return r.writeBufferViews(e,n),r.writeCameras(e,n),r.writeMeshes(e,n),r.writeMaterials(e,n),r.writeNodes(e,n,t),await r.writeTextures(e,s,n,t),n.images.length||delete n.images,n.samplers.length||delete n.samplers,n.textures.length||delete n.textures,n}))}build(e,t={}){const r=this.collectResources(e);return this.buildJson(r,t).then((e=>{const t=(new TextEncoder).encode(JSON.stringify(e)),s=t.length,n=4-(3&s)&3,a=e.buffers.reduce(((e,t)=>j.roundUp(e+t.byteLength,4)),0);let i=20+s+n;a>0&&(i+=8+a);const o=new ArrayBuffer(i),c=new DataView(o);c.setUint32(0,1179937895,!0),c.setUint32(4,2,!0),c.setUint32(8,i,!0),c.setUint32(12,s+n,!0),c.setUint32(16,1313821514,!0);let u=20;new Uint8Array(o,u,s).set(t),u+=s;for(let e=0;e<n;e++)c.setUint8(u+e,32);return u+=n,a>0&&(c.setUint32(u,a,!0),c.setUint32(u+4,5130562,!0),u+=8,r.buffers.forEach((t=>{let s;const n=r.bufferViewMap.get(t)[0],a=e.bufferViews[n].byteOffset;if(t instanceof ArrayBuffer)s=new Uint8Array(t);else{const e=t.lock();s=e instanceof ArrayBuffer?new Uint8Array(e):new Uint8Array(e.buffer,e.byteOffset,e.byteLength)}new Uint8Array(o,u+a,s.byteLength).set(s)}))),Promise.resolve(o)}))}}export{re as GltfExporter};