@fonsecabarreto/genesis-gl-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -0
  3. package/dist/Camera-DY_8gx3C.d.ts +45 -0
  4. package/dist/Core/classes/Material.d.ts +3 -0
  5. package/dist/Core/classes/Material.js +9 -0
  6. package/dist/Core/classes/Material.js.map +1 -0
  7. package/dist/Core/classes/Model.d.ts +5 -0
  8. package/dist/Core/classes/Model.js +7 -0
  9. package/dist/Core/classes/Model.js.map +1 -0
  10. package/dist/Core/classes/Renderer.d.ts +30 -0
  11. package/dist/Core/classes/Renderer.js +11 -0
  12. package/dist/Core/classes/Renderer.js.map +1 -0
  13. package/dist/Core/classes/Scene.d.ts +37 -0
  14. package/dist/Core/classes/Scene.js +7 -0
  15. package/dist/Core/classes/Scene.js.map +1 -0
  16. package/dist/Core/classes/Viewport.d.ts +37 -0
  17. package/dist/Core/classes/Viewport.js +7 -0
  18. package/dist/Core/classes/Viewport.js.map +1 -0
  19. package/dist/Core/domain/interfaces/Vectors.d.ts +4 -0
  20. package/dist/Core/domain/interfaces/Vectors.js +1 -0
  21. package/dist/Core/domain/interfaces/Vectors.js.map +1 -0
  22. package/dist/Core/index.d.ts +10 -0
  23. package/dist/Core/index.js +51 -0
  24. package/dist/Core/index.js.map +1 -0
  25. package/dist/Core/utils/get-overlap.d.ts +3 -0
  26. package/dist/Core/utils/get-overlap.js +11 -0
  27. package/dist/Core/utils/get-overlap.js.map +1 -0
  28. package/dist/Core/utils/load-glb.d.ts +101 -0
  29. package/dist/Core/utils/load-glb.js +697 -0
  30. package/dist/Core/utils/load-glb.js.map +1 -0
  31. package/dist/Core/utils/parse-obj.d.ts +10 -0
  32. package/dist/Core/utils/parse-obj.js +183 -0
  33. package/dist/Core/utils/parse-obj.js.map +1 -0
  34. package/dist/Editor/index.d.ts +364 -0
  35. package/dist/Editor/index.js +1737 -0
  36. package/dist/Editor/index.js.map +1 -0
  37. package/dist/Game/controls/KeyboardInput.d.ts +8 -0
  38. package/dist/Game/controls/KeyboardInput.js +7 -0
  39. package/dist/Game/controls/KeyboardInput.js.map +1 -0
  40. package/dist/Game/index.d.ts +45 -0
  41. package/dist/Game/index.js +353 -0
  42. package/dist/Game/index.js.map +1 -0
  43. package/dist/KeyboardControl-5w7Vm0J0.d.ts +18 -0
  44. package/dist/KeyboardInput-DTsfj3tE.d.ts +166 -0
  45. package/dist/Material-BGLkldxv.d.ts +74 -0
  46. package/dist/Model-CQvDXd-b.d.ts +302 -0
  47. package/dist/WebGLCore-DR7ZHJB0.d.ts +22 -0
  48. package/dist/chunk-3ULETMWF.js +144 -0
  49. package/dist/chunk-3ULETMWF.js.map +1 -0
  50. package/dist/chunk-5TAAXI6S.js +330 -0
  51. package/dist/chunk-5TAAXI6S.js.map +1 -0
  52. package/dist/chunk-6LS6AO5H.js +296 -0
  53. package/dist/chunk-6LS6AO5H.js.map +1 -0
  54. package/dist/chunk-JK2HEZAT.js +317 -0
  55. package/dist/chunk-JK2HEZAT.js.map +1 -0
  56. package/dist/chunk-P7QOKDLY.js +57 -0
  57. package/dist/chunk-P7QOKDLY.js.map +1 -0
  58. package/dist/chunk-QCQVJCSR.js +968 -0
  59. package/dist/chunk-QCQVJCSR.js.map +1 -0
  60. package/dist/chunk-SUNYSY45.js +81 -0
  61. package/dist/chunk-SUNYSY45.js.map +1 -0
  62. package/package.json +83 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/Core/utils/load-glb.ts"],"sourcesContent":["import { mat4, quat, vec3 } from 'gl-matrix';\nimport { WebGLCore, Model, Mesh, Material } from '../classes';\nimport { GL_TRIANGLES } from '../classes/Mesh';\nimport { Skeleton, type Joint } from '../classes/Skeleton';\nimport {\n AnimationClip,\n type AnimationChannel,\n type AnimationSampler,\n type AnimationPath,\n type InterpolationMode,\n} from '../classes/AnimationClip';\nimport type {\n GltfJson,\n GltfAccessor,\n GltfBufferView,\n GltfNode,\n GltfPrimitive,\n GltfMaterial,\n GltfAccessorType,\n} from '../domain/interfaces/GltfTypes';\nimport { GltfComponentType } from '../domain/interfaces/GltfTypes';\n\n// ─── GLB binary constants ───────────────────────────────────────\nconst GLB_MAGIC = 0x46546c67; // \"glTF\"\nconst GLB_CHUNK_JSON = 0x4e4f534a; // \"JSON\"\nconst GLB_CHUNK_BIN = 0x004e4942; // \"BIN\\0\"\nconst GLB_HEADER_SIZE = 12; // magic(4) + version(4) + length(4)\nconst CHUNK_HEADER_SIZE = 8; // chunkLength(4) + chunkType(4)\n\n// ─── glTF accessor type → component count ───────────────────────\nconst COMPONENT_COUNT: Record<GltfAccessorType, number> = {\n SCALAR: 1,\n VEC2: 2,\n VEC3: 3,\n VEC4: 4,\n MAT2: 4,\n MAT3: 9,\n MAT4: 16,\n};\n\n// ─── Typed-array constructors keyed by glTF component type ──────\ntype TypedArray =\n | Float32Array\n | Int8Array\n | Uint8Array\n | Int16Array\n | Uint16Array\n | Uint32Array;\ntype TypedArrayConstructor =\n | Float32ArrayConstructor\n | Int8ArrayConstructor\n | Uint8ArrayConstructor\n | Int16ArrayConstructor\n | Uint16ArrayConstructor\n | Uint32ArrayConstructor;\n\nconst TYPED_ARRAY_CTOR: Record<number, TypedArrayConstructor> = {\n [GltfComponentType.BYTE]: Int8Array,\n [GltfComponentType.UNSIGNED_BYTE]: Uint8Array,\n [GltfComponentType.SHORT]: Int16Array,\n [GltfComponentType.UNSIGNED_SHORT]: Uint16Array,\n [GltfComponentType.UNSIGNED_INT]: Uint32Array,\n [GltfComponentType.FLOAT]: Float32Array,\n};\n\nconst COMPONENT_SIZES: Record<number, number> = {\n [GltfComponentType.BYTE]: 1,\n [GltfComponentType.UNSIGNED_BYTE]: 1,\n [GltfComponentType.SHORT]: 2,\n [GltfComponentType.UNSIGNED_SHORT]: 2,\n [GltfComponentType.UNSIGNED_INT]: 4,\n [GltfComponentType.FLOAT]: 4,\n};\n\n// ─── Result type ────────────────────────────────────────────────\n\n/** Everything parsed from a GLB file. */\nexport interface GLBLoadResult {\n /** The composed model with all meshes. */\n model: Model;\n /** Skeleton (if the GLB contains a skin). */\n skeleton: Skeleton | null;\n /** Named animation clips (if the GLB contains animations). */\n animations: Map<string, AnimationClip>;\n}\n\n// ─── GLBLoader ──────────────────────────────────────────────────\n\n/**\n * Professional GLB (binary glTF 2.0) loader for the GenesisGL engine.\n *\n * Handles:\n * - Strongly-typed glTF JSON parsing (no `any`)\n * - Full PBR material extraction (base colour, textures, alpha, double-sided)\n * - Embedded texture decoding from binary chunk\n * - Complete node hierarchy traversal\n * - Skeletal mesh data (JOINTS_0 / WEIGHTS_0)\n * - Skin parsing (inverse bind matrices + joint hierarchy)\n * - Animation parsing (TRS channels with LINEAR/STEP interpolation)\n *\n * @example\n * ```ts\n * const loader = new GLBLoader(core);\n * const { model, skeleton, animations } = await loader.load('/models/character.glb', 'hero');\n * if (skeleton) model.skeleton = skeleton;\n * for (const [name, clip] of animations) model.animations.set(name, clip);\n * scene.add(model);\n * ```\n */\nexport class GLBLoader {\n private gl: WebGLRenderingContext;\n private core: WebGLCore;\n\n constructor(core: WebGLCore) {\n this.gl = core.gl;\n this.core = core;\n }\n\n // ━━━ Public API ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n /**\n * Fetch and parse a `.glb` file.\n *\n * @param url - URL to the GLB resource.\n * @param name - Logical name assigned to the resulting {@link Model}.\n * @returns Parsed model, optional skeleton, and animation clips.\n */\n async load(url: string, name = 'model'): Promise<GLBLoadResult> {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(\n `[GLBLoader] Failed to fetch \"${url}\" (HTTP ${response.status})`,\n );\n }\n const arrayBuffer = await response.arrayBuffer();\n return this.parse(arrayBuffer, name);\n }\n\n /**\n * Parse a raw GLB `ArrayBuffer` that was already loaded (e.g. from drag-and-drop).\n */\n async parse(\n arrayBuffer: ArrayBuffer,\n name = 'model',\n ): Promise<GLBLoadResult> {\n const { gltf, binChunkData } = this.parseGlbHeader(arrayBuffer);\n const buffers: ArrayBuffer[] = [binChunkData];\n\n // ── Parse skeleton / skin FIRST ─────────────────────────────\n // Skin data is needed by parseMeshes to handle non-skinned mesh\n // nodes that are parented to bone joints (e.g. eyes / hair in the\n // Head bone's subtree).\n let skeleton: Skeleton | null = null;\n if (gltf.skins && gltf.skins.length > 0) {\n skeleton = this.parseSkin(gltf, buffers, 0);\n // Compute bind-pose joint matrices immediately so the model is\n // renderable from the very first frame (without waiting for an\n // animation update tick).\n skeleton.computeJointMatrices();\n }\n\n // ── Parse scene meshes ──────────────────────────────────────\n const meshes = await this.parseMeshes(gltf, buffers, skeleton);\n\n // ── Parse animations ────────────────────────────────────────\n const animations = new Map<string, AnimationClip>();\n if (gltf.animations && skeleton) {\n // Build node-index → joint-array-index mapping\n const nodeToJoint = new Map<number, number>();\n for (let ji = 0; ji < skeleton.joints.length; ji++) {\n nodeToJoint.set(skeleton.joints[ji].nodeIndex, ji);\n }\n\n // Load all animation clips — no artificial cap\n for (let ai = 0; ai < gltf.animations.length; ai++) {\n const clip = this.parseAnimation(gltf, buffers, ai, nodeToJoint);\n animations.set(clip.name, clip);\n }\n }\n\n // ── Compose model ───────────────────────────────────────────\n // Pass skeleton so the constructor's bbox computation includes rootTransform\n // (the non-joint ancestor transform from Blender/Sketchfab exports).\n const model = new Model(meshes, [0, 0, 0], [1, 1, 1], name, skeleton);\n\n // Centre the model's XZ around origin so it appears at the expected\n // position when the user calls setTranslation(). Many exported GLB\n // files (e.g. from Sketchfab / Blender) have vertex data offset from\n // the coordinate-system origin.\n // Centre the model's XZ — use setTranslation so the matrix is properly dirtied\n const center = model.getCenter();\n model.setTranslation(\n model.translation[0] - center[0],\n model.translation[1],\n model.translation[2] - center[2],\n );\n\n return { model, skeleton, animations };\n }\n\n // ━━━ GLB header parsing ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n private parseGlbHeader(arrayBuffer: ArrayBuffer): {\n gltf: GltfJson;\n binChunkData: ArrayBuffer;\n } {\n const view = new DataView(arrayBuffer);\n\n // Magic + version\n const magic = view.getUint32(0, true);\n if (magic !== GLB_MAGIC) {\n throw new Error(\n `[GLBLoader] Invalid GLB magic: 0x${magic.toString(16)} (expected 0x${GLB_MAGIC.toString(16)})`,\n );\n }\n const version = view.getUint32(4, true);\n if (version !== 2) {\n throw new Error(\n `[GLBLoader] Unsupported glTF version ${version} (only v2 is supported)`,\n );\n }\n\n // JSON chunk\n const jsonChunkLength = view.getUint32(GLB_HEADER_SIZE, true);\n const jsonChunkType = view.getUint32(GLB_HEADER_SIZE + 4, true);\n if (jsonChunkType !== GLB_CHUNK_JSON) {\n throw new Error('[GLBLoader] First chunk is not JSON');\n }\n\n const jsonStart = GLB_HEADER_SIZE + CHUNK_HEADER_SIZE;\n const jsonText = new TextDecoder().decode(\n new Uint8Array(arrayBuffer, jsonStart, jsonChunkLength),\n );\n const gltf: GltfJson = JSON.parse(jsonText) as GltfJson;\n\n // BIN chunk\n const binChunkOffset = jsonStart + jsonChunkLength;\n const binChunkLength = view.getUint32(binChunkOffset, true);\n const binChunkType = view.getUint32(binChunkOffset + 4, true);\n if (binChunkType !== GLB_CHUNK_BIN) {\n throw new Error('[GLBLoader] Second chunk is not BIN');\n }\n\n const binChunkData = arrayBuffer.slice(\n binChunkOffset + CHUNK_HEADER_SIZE,\n binChunkOffset + CHUNK_HEADER_SIZE + binChunkLength,\n );\n\n return { gltf, binChunkData };\n }\n\n // ━━━ Mesh parsing ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n /**\n * Walk the active scene's node tree and return all renderable meshes.\n *\n * Each scene node that references a mesh is visited in hierarchy order.\n * Non-skinned mesh nodes that are children of joint nodes (e.g. eyes /\n * hair parented to the Head bone in Blender) are automatically handled:\n * their vertex data is pre-transformed into skin-space and synthetic\n * single-joint weights are generated so they deform with the parent bone.\n *\n * @param skeleton – already-parsed skin for this model (or null).\n */\n private async parseMeshes(\n gltf: GltfJson,\n buffers: ArrayBuffer[],\n skeleton: Skeleton | null,\n ): Promise<Mesh[]> {\n if (!gltf.meshes || !gltf.nodes) return [];\n\n // ── Build nodeIndex → jointArrayIndex lookup from skeleton ──\n const nodeToJointIndex = new Map<number, number>();\n if (skeleton) {\n for (let ji = 0; ji < skeleton.joints.length; ji++) {\n nodeToJointIndex.set(skeleton.joints[ji].nodeIndex, ji);\n }\n }\n\n // ── Build child → parent map for the entire node tree ───────\n const nodeParentMap = new Map<number, number>();\n for (let ni = 0; ni < gltf.nodes.length; ni++) {\n const children = gltf.nodes[ni].children;\n if (children) {\n for (const ci of children) nodeParentMap.set(ci, ni);\n }\n }\n\n /**\n * Walk up from nodeIdx until we hit a joint node.\n * Returns the joint's index in skeleton.joints[], or null.\n */\n const findAncestorJoint = (nodeIdx: number): number | null => {\n let cur = nodeParentMap.get(nodeIdx);\n while (cur !== undefined) {\n const ji = nodeToJointIndex.get(cur);\n if (ji !== undefined) return ji;\n cur = nodeParentMap.get(cur);\n }\n return null;\n };\n\n // ── Collect mesh entries by walking the active scene graph ──\n interface MeshEntry {\n meshIdx: number;\n skinIdx: number | undefined;\n nodeIdx: number;\n }\n const entries: MeshEntry[] = [];\n const sceneNodes = gltf.scenes?.[gltf.scene ?? 0]?.nodes ?? [];\n\n const walk = (nodeIdx: number): void => {\n const node = gltf.nodes![nodeIdx];\n if (node.mesh !== undefined) {\n entries.push({ meshIdx: node.mesh, skinIdx: node.skin, nodeIdx });\n }\n node.children?.forEach((c) => walk(c));\n };\n for (const r of sceneNodes) walk(r);\n\n // ── Parse each entry into Mesh instances ────────────────────\n const meshes: Mesh[] = [];\n\n for (const { meshIdx, skinIdx, nodeIdx } of entries) {\n const meshDef = gltf.meshes[meshIdx];\n\n for (let pi = 0; pi < meshDef.primitives.length; pi++) {\n const prim = meshDef.primitives[pi];\n const mesh = await this.parsePrimitive(\n gltf,\n buffers,\n prim,\n meshDef.name ?? `mesh_${meshIdx}_${pi}`,\n );\n\n // ── Bone-parented non-skinned mesh support ───────────────\n // Blender sometimes exports mesh objects that are NOT weight-painted\n // but are instead parented to a bone (e.g. the face/hair/eyes mesh\n // sitting under the Head joint in the scene hierarchy). We detect\n // this pattern by checking whether the mesh node has no skin yet its\n // closest ancestor in the node tree is a joint. When detected we:\n // 1. Pre-transform the vertex positions and normals from the node's\n // local space into \"skin coordinate space\"\n // ( T = inv(IBM_parentJoint) * nodeLocalTransform ).\n // 2. Synthesise per-vertex joint weights (full weight = 1.0 to the\n // parent joint) so the mesh deforms correctly with the bone.\n if (!mesh.isSkinned && skeleton && skinIdx === undefined) {\n const ancestorJointIdx = findAncestorJoint(nodeIdx);\n if (ancestorJointIdx !== null) {\n this.applyBoneParenting(\n mesh,\n gltf.nodes![nodeIdx],\n ancestorJointIdx,\n skeleton.joints[ancestorJointIdx].inverseBindMatrix,\n );\n }\n }\n\n meshes.push(mesh);\n }\n }\n\n return meshes;\n }\n\n /**\n * Pre-transform a bone-parented non-skinned mesh into skin coordinate space\n * and synthesise single-joint weights so it deforms with its parent bone.\n *\n * The transform applied to each vertex is:\n * T = inv(IBM_parentJoint) × nodeLocalTransform\n *\n * After this call `mesh.isSkinned` returns `true`.\n */\n private applyBoneParenting(\n mesh: Mesh,\n node: GltfNode,\n jointIdx: number,\n ibm: mat4,\n ): void {\n // inv(IBM) == bind-pose global transform of the parent joint\n const bindGlobal = mat4.create();\n mat4.invert(bindGlobal, ibm);\n\n // preT = bindGlobal × nodeLocal\n const nodeLocal = this.getNodeLocalMatrix(node);\n const preT = mat4.create();\n mat4.multiply(preT, bindGlobal, nodeLocal);\n\n // Normal matrix = transpose(inv(preT))\n const normMat = mat4.create();\n mat4.invert(normMat, preT);\n mat4.transpose(normMat, normMat);\n\n // Pre-transform vertex positions (owned copy – never mutate the\n // original TypedArray view which may be shared with other accessors)\n const srcV = mesh.vertices;\n const v = new Float32Array(srcV.length);\n for (let i = 0; i < srcV.length; i += 3) {\n const x = srcV[i],\n y = srcV[i + 1],\n z = srcV[i + 2];\n v[i] = preT[0] * x + preT[4] * y + preT[8] * z + preT[12];\n v[i + 1] = preT[1] * x + preT[5] * y + preT[9] * z + preT[13];\n v[i + 2] = preT[2] * x + preT[6] * y + preT[10] * z + preT[14];\n }\n mesh.vertices = v;\n\n // Pre-transform normals (owned copy)\n const srcN = mesh.normals;\n if (srcN && srcN.length > 0) {\n const n = new Float32Array(srcN.length);\n for (let i = 0; i < srcN.length; i += 3) {\n const x = srcN[i],\n y = srcN[i + 1],\n z = srcN[i + 2];\n n[i] = normMat[0] * x + normMat[4] * y + normMat[8] * z;\n n[i + 1] = normMat[1] * x + normMat[5] * y + normMat[9] * z;\n n[i + 2] = normMat[2] * x + normMat[6] * y + normMat[10] * z;\n }\n mesh.normals = n;\n }\n\n // Synthesise per-vertex single-joint weights\n const vertexCount = mesh.vertices.length / 3;\n const ji = new Float32Array(vertexCount * 4); // [jointIdx, 0, 0, 0] × vtx\n const jw = new Float32Array(vertexCount * 4); // [1.0, 0.0, 0.0, 0.0] × vtx\n for (let i = 0; i < vertexCount; i++) {\n ji[i * 4] = jointIdx; // x component: parent joint\n jw[i * 4] = 1.0; // x component: full weight\n }\n mesh.jointIndices = ji;\n mesh.jointWeights = jw;\n }\n\n private async parsePrimitive(\n gltf: GltfJson,\n buffers: ArrayBuffer[],\n prim: GltfPrimitive,\n name: string,\n ): Promise<Mesh> {\n const accessors = gltf.accessors!;\n const bufferViews = gltf.bufferViews!;\n\n // ── Vertex attributes ───────────────────────────────────────\n const vertices = this.getAccessorData(\n accessors[prim.attributes.POSITION],\n bufferViews,\n buffers,\n ) as Float32Array;\n\n const normals =\n prim.attributes.NORMAL !== undefined\n ? (this.getAccessorData(\n accessors[prim.attributes.NORMAL],\n bufferViews,\n buffers,\n ) as Float32Array)\n : this.generateFlatNormals(vertices);\n\n const texCoords =\n prim.attributes.TEXCOORD_0 !== undefined\n ? (this.getAccessorData(\n accessors[prim.attributes.TEXCOORD_0],\n bufferViews,\n buffers,\n ) as Float32Array)\n : new Float32Array();\n\n const indices =\n prim.indices !== undefined\n ? (this.getAccessorData(\n accessors[prim.indices],\n bufferViews,\n buffers,\n ) as Uint16Array | Uint32Array)\n : null;\n\n // ── Material ────────────────────────────────────────────────\n const material = await this.parseMaterial(gltf, buffers, prim.material);\n\n const mesh = new Mesh(\n name,\n vertices,\n normals,\n material,\n texCoords,\n indices,\n );\n mesh.setMode(prim.mode ?? GL_TRIANGLES);\n\n // ── Skinning data ───────────────────────────────────────────\n if (\n prim.attributes.JOINTS_0 !== undefined &&\n prim.attributes.WEIGHTS_0 !== undefined\n ) {\n const rawJoints = this.getAccessorData(\n accessors[prim.attributes.JOINTS_0],\n bufferViews,\n buffers,\n );\n // JOINTS_0 may come as Uint8 or Uint16; we need Float32 for the shader attribute\n mesh.jointIndices = new Float32Array(rawJoints);\n\n mesh.jointWeights = this.getAccessorData(\n accessors[prim.attributes.WEIGHTS_0],\n bufferViews,\n buffers,\n ) as Float32Array;\n }\n\n return mesh;\n }\n\n // ━━━ Material parsing ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n private async parseMaterial(\n gltf: GltfJson,\n buffers: ArrayBuffer[],\n materialIndex?: number,\n ): Promise<Material> {\n const material = new Material(this.core, {});\n\n if (materialIndex === undefined || !gltf.materials) return material;\n const matDef: GltfMaterial = gltf.materials[materialIndex];\n if (!matDef) return material;\n\n // PBR metallic-roughness\n const pbr = matDef.pbrMetallicRoughness;\n if (pbr) {\n if (pbr.baseColorFactor) {\n const [r, g, b, a] = pbr.baseColorFactor;\n material.albedoColor = [r, g, b, a];\n material.diffuse = [r, g, b];\n material.dissolve = a;\n }\n\n // Base-colour texture (embedded in GLB binary chunk)\n if (pbr.baseColorTexture !== undefined) {\n const tex = await this.loadEmbeddedTexture(\n gltf,\n buffers,\n pbr.baseColorTexture.index,\n );\n if (tex) material.texture = tex;\n }\n\n // Derive specular from roughness — lower roughness = sharper specular\n const roughness = pbr.roughnessFactor ?? 1;\n material.shininess = Math.max(2, (1 - roughness) * 128);\n }\n\n // KHR_materials_pbrSpecularGlossiness extension fallback\n // Some models (e.g. Sketchfab exports) use this instead of standard PBR.\n const specGloss = (matDef as Record<string, unknown>).extensions as\n | Record<string, unknown>\n | undefined;\n const sg = specGloss?.['KHR_materials_pbrSpecularGlossiness'] as\n | Record<string, unknown>\n | undefined;\n if (sg) {\n // Diffuse factor (equivalent to baseColorFactor)\n if (sg.diffuseFactor && !material.texture) {\n const [r, g, b, a] = sg.diffuseFactor as number[];\n material.albedoColor = [r, g, b, a];\n material.diffuse = [r, g, b];\n material.dissolve = a;\n }\n\n // Diffuse texture (equivalent to baseColorTexture)\n if (sg.diffuseTexture && !material.texture) {\n const diffTex = sg.diffuseTexture as { index: number };\n const tex = await this.loadEmbeddedTexture(\n gltf,\n buffers,\n diffTex.index,\n );\n if (tex) material.texture = tex;\n }\n\n // Glossiness → shininess\n if (sg.glossinessFactor !== undefined) {\n material.shininess = Math.max(2, (sg.glossinessFactor as number) * 128);\n }\n }\n\n // Emissive (crude: add to ambient)\n if (matDef.emissiveFactor) {\n const [er, eg, eb] = matDef.emissiveFactor;\n material.ambientColor = [\n material.ambientColor[0] + er,\n material.ambientColor[1] + eg,\n material.ambientColor[2] + eb,\n ];\n }\n\n // Alpha mode\n if (matDef.alphaMode === 'BLEND') {\n material.dissolve = material.albedoColor[3];\n } else if (matDef.alphaMode === 'MASK') {\n // MASK = alpha cutout — treat as fully opaque at the material level;\n // the texture alpha channel is used for discard in the shader.\n material.dissolve = 1;\n } else {\n // OPAQUE (default) — ensure dissolve is set explicitly\n material.dissolve = 1;\n }\n\n // Double-sided\n if (matDef.doubleSided) {\n material.doubleSided = true;\n }\n\n return material;\n }\n\n // ━━━ Texture loading ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n /**\n * Decode a texture embedded in the GLB binary chunk and upload to GPU.\n */\n private async loadEmbeddedTexture(\n gltf: GltfJson,\n buffers: ArrayBuffer[],\n textureIndex: number,\n ): Promise<WebGLTexture | null> {\n const texDef = gltf.textures?.[textureIndex];\n if (!texDef || texDef.source === undefined) return null;\n\n const imageDef = gltf.images?.[texDef.source];\n if (!imageDef) return null;\n\n // Image stored as a bufferView reference inside the GLB\n if (imageDef.bufferView !== undefined) {\n const bv = gltf.bufferViews![imageDef.bufferView];\n const buffer = buffers[bv.buffer];\n const offset = bv.byteOffset ?? 0;\n const data = new Uint8Array(buffer, offset, bv.byteLength);\n\n const mimeType = imageDef.mimeType ?? 'image/png';\n const blob = new Blob([data], { type: mimeType });\n const url = URL.createObjectURL(blob);\n\n try {\n return await this.createTextureFromUrl(url);\n } finally {\n URL.revokeObjectURL(url);\n }\n }\n\n // External URI (not typical in .glb but allowed)\n if (imageDef.uri) {\n return this.createTextureFromUrl(imageDef.uri);\n }\n\n return null;\n }\n\n private createTextureFromUrl(url: string): Promise<WebGLTexture | null> {\n return new Promise((resolve) => {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.onload = () => {\n const gl = this.gl;\n const tex = gl.createTexture();\n if (!tex) {\n resolve(null);\n return;\n }\n gl.bindTexture(gl.TEXTURE_2D, tex);\n gl.texImage2D(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA,\n gl.RGBA,\n gl.UNSIGNED_BYTE,\n img,\n );\n\n // Check power-of-two for mipmaps\n if (isPowerOfTwo(img.width) && isPowerOfTwo(img.height)) {\n gl.generateMipmap(gl.TEXTURE_2D);\n } else {\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n }\n resolve(tex);\n };\n img.onerror = () => {\n console.warn(`[GLBLoader] Failed to load texture from \"${url}\"`);\n resolve(null);\n };\n img.src = url;\n });\n }\n\n // ━━━ Skin / Skeleton parsing ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n private parseSkin(\n gltf: GltfJson,\n buffers: ArrayBuffer[],\n skinIndex: number,\n ): Skeleton {\n const skinDef = gltf.skins![skinIndex];\n const nodes = gltf.nodes!;\n const accessors = gltf.accessors!;\n const bufferViews = gltf.bufferViews!;\n\n // Read inverse bind matrices (one mat4 per joint)\n let inverseBindMatrices: Float32Array | null = null;\n if (skinDef.inverseBindMatrices !== undefined) {\n inverseBindMatrices = this.getAccessorData(\n accessors[skinDef.inverseBindMatrices],\n bufferViews,\n buffers,\n ) as Float32Array;\n }\n\n // Build a fast lookup: node-index → joint-array-index\n const nodeToJointIndex = new Map<number, number>();\n for (let i = 0; i < skinDef.joints.length; i++) {\n nodeToJointIndex.set(skinDef.joints[i], i);\n }\n\n // Build joint array (topological order guaranteed by glTF spec: parent before child)\n const joints: Joint[] = [];\n for (let ji = 0; ji < skinDef.joints.length; ji++) {\n const nodeIdx = skinDef.joints[ji];\n const node = nodes[nodeIdx];\n\n // Find parent: walk all joints and check if this node is a child of another joint\n let parentIndex = -1;\n if (node) {\n for (let pji = 0; pji < skinDef.joints.length; pji++) {\n if (pji === ji) continue;\n const pNode = nodes[skinDef.joints[pji]];\n if (pNode.children?.includes(nodeIdx)) {\n parentIndex = pji;\n break;\n }\n }\n }\n\n const ibm = mat4.create();\n if (inverseBindMatrices) {\n for (let k = 0; k < 16; k++) {\n (ibm as unknown as Float32Array)[k] =\n inverseBindMatrices[ji * 16 + k];\n }\n }\n\n const t = node.translation\n ? vec3.fromValues(\n node.translation[0],\n node.translation[1],\n node.translation[2],\n )\n : vec3.create();\n const r = node.rotation\n ? quat.fromValues(\n node.rotation[0],\n node.rotation[1],\n node.rotation[2],\n node.rotation[3],\n )\n : quat.create();\n const s = node.scale\n ? vec3.fromValues(node.scale[0], node.scale[1], node.scale[2])\n : vec3.fromValues(1, 1, 1);\n\n joints.push({\n name: node.name ?? `joint_${ji}`,\n nodeIndex: nodeIdx,\n parentIndex,\n localTranslation: t,\n localRotation: r,\n localScale: s,\n inverseBindMatrix: ibm,\n });\n }\n\n // ── Compute skeleton root transform ─────────────────────────\n // Walk from the first root joint's parent up to the scene root,\n // accumulating non-joint ancestor transforms. Many exported models\n // (e.g. CS2, Sketchfab) place scale / rotation on a parent node that\n // is NOT a joint. The inverse-bind-matrices include that transform,\n // so we must include it in the global chain to get identity in bind pose.\n const skinRootTransform = this.computeSkinRootTransform(\n gltf,\n skinDef.joints,\n joints,\n );\n\n return new Skeleton(joints, skinRootTransform);\n }\n\n /**\n * Compute the accumulated global transform of all non-joint ancestor\n * nodes above the skeleton's root joint(s).\n */\n private computeSkinRootTransform(\n gltf: GltfJson,\n jointNodeIndices: number[],\n joints: Joint[],\n ): mat4 {\n const nodes = gltf.nodes!;\n\n // 1. Build a child → parent lookup for the entire node tree\n const nodeParentMap = new Map<number, number>();\n for (let ni = 0; ni < nodes.length; ni++) {\n const children = nodes[ni].children;\n if (children) {\n for (const ci of children) {\n nodeParentMap.set(ci, ni);\n }\n }\n }\n\n // 2. Find the first root joint (parentIndex === -1)\n const rootJoint = joints.find((j) => j.parentIndex === -1);\n if (!rootJoint) return mat4.create();\n\n // 3. Walk from the root joint's actual parent upward, accumulating\n // transforms until we reach a node with no parent (scene root).\n const skinRoot = mat4.create();\n let ancestor = nodeParentMap.get(rootJoint.nodeIndex);\n while (ancestor !== undefined) {\n const localMat = this.getNodeLocalMatrix(nodes[ancestor]);\n // Pre-multiply: skinRoot = localMat * skinRoot\n mat4.multiply(skinRoot, localMat, skinRoot);\n ancestor = nodeParentMap.get(ancestor);\n }\n\n return skinRoot;\n }\n\n // ━━━ Animation parsing ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n private parseAnimation(\n gltf: GltfJson,\n buffers: ArrayBuffer[],\n animIndex: number,\n nodeToJoint: Map<number, number>,\n ): AnimationClip {\n const animDef = gltf.animations![animIndex];\n const accessors = gltf.accessors!;\n const bufferViews = gltf.bufferViews!;\n\n const channels: AnimationChannel[] = [];\n let maxTime = 0;\n\n for (const chDef of animDef.channels) {\n const targetNode = chDef.target.node;\n if (targetNode === undefined) continue;\n\n const jointIndex = nodeToJoint.get(targetNode);\n if (jointIndex === undefined) continue; // node isn't a joint\n\n const path = chDef.target.path;\n if (path === 'weights') continue; // morph targets not supported yet\n\n const samplerDef = animDef.samplers[chDef.sampler];\n const times = this.getAccessorData(\n accessors[samplerDef.input],\n bufferViews,\n buffers,\n ) as Float32Array;\n const values = this.getAccessorData(\n accessors[samplerDef.output],\n bufferViews,\n buffers,\n ) as Float32Array;\n\n if (times.length > 0) {\n maxTime = Math.max(maxTime, times[times.length - 1]);\n }\n\n const sampler: AnimationSampler = {\n times,\n values,\n interpolation: (samplerDef.interpolation ??\n 'LINEAR') as InterpolationMode,\n };\n\n channels.push({\n jointIndex,\n path: path as AnimationPath,\n sampler,\n });\n }\n\n return new AnimationClip(\n animDef.name ?? `animation_${animIndex}`,\n channels,\n maxTime,\n );\n }\n\n // ━━━ Accessor data extraction ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n /**\n * Extract a typed array from a glTF accessor + bufferView.\n * Handles byte-stride (interleaved buffers) and all glTF component types.\n */\n private getAccessorData(\n accessor: GltfAccessor,\n bufferViews: GltfBufferView[],\n buffers: ArrayBuffer[],\n ): TypedArray {\n if (accessor.bufferView === undefined) {\n // Sparse or zero-filled accessor — return zero array\n const count = accessor.count * COMPONENT_COUNT[accessor.type];\n const Ctor = TYPED_ARRAY_CTOR[accessor.componentType] ?? Float32Array;\n return new Ctor(count);\n }\n\n const bv = bufferViews[accessor.bufferView];\n const buffer = buffers[bv.buffer];\n const numComponents = COMPONENT_COUNT[accessor.type];\n const componentSize = COMPONENT_SIZES[accessor.componentType] ?? 4;\n const byteOffset = (bv.byteOffset ?? 0) + (accessor.byteOffset ?? 0);\n const count = accessor.count;\n const Ctor = TYPED_ARRAY_CTOR[accessor.componentType];\n\n if (!Ctor) {\n throw new Error(\n `[GLBLoader] Unsupported componentType: ${accessor.componentType}`,\n );\n }\n\n const stride = bv.byteStride ?? 0;\n const tightStride = numComponents * componentSize;\n\n if (stride === 0 || stride === tightStride) {\n // Tightly packed — fast path: create typed view directly\n return new Ctor(buffer, byteOffset, count * numComponents);\n }\n\n // Interleaved — de-interleave into a contiguous typed array\n const out = new Ctor(count * numComponents);\n const src = new DataView(buffer);\n\n for (let i = 0; i < count; i++) {\n const base = byteOffset + i * stride;\n for (let c = 0; c < numComponents; c++) {\n const off = base + c * componentSize;\n out[i * numComponents + c] = readComponent(\n src,\n off,\n accessor.componentType,\n );\n }\n }\n return out;\n }\n\n // ━━━ Node-tree helpers ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n /** Compute the local transform matrix from a glTF node's TRS or matrix. */\n private getNodeLocalMatrix(node: GltfNode): mat4 {\n const m = mat4.create();\n\n if (node.matrix) {\n // Column-major 4×4 matrix provided directly\n for (let i = 0; i < 16; i++) {\n (m as unknown as Float32Array)[i] = node.matrix[i];\n }\n return m;\n }\n\n const t = node.translation ?? [0, 0, 0];\n const r = node.rotation ?? [0, 0, 0, 1];\n const s = node.scale ?? [1, 1, 1];\n\n mat4.fromRotationTranslationScale(\n m,\n quat.fromValues(r[0], r[1], r[2], r[3]),\n vec3.fromValues(t[0], t[1], t[2]),\n vec3.fromValues(s[0], s[1], s[2]),\n );\n return m;\n }\n\n // ━━━ Flat-normal generation ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n /** Generate flat face-normals when the mesh doesn't include them. */\n private generateFlatNormals(vertices: Float32Array): Float32Array {\n const normals = new Float32Array(vertices.length);\n\n for (let i = 0; i < vertices.length; i += 9) {\n const ax = vertices[i],\n ay = vertices[i + 1],\n az = vertices[i + 2];\n const bx = vertices[i + 3],\n by = vertices[i + 4],\n bz = vertices[i + 5];\n const cx = vertices[i + 6],\n cy = vertices[i + 7],\n cz = vertices[i + 8];\n\n const ux = bx - ax,\n uy = by - ay,\n uz = bz - az;\n const vx = cx - ax,\n vy = cy - ay,\n vz = cz - az;\n\n let nx = uy * vz - uz * vy;\n let ny = uz * vx - ux * vz;\n let nz = ux * vy - uy * vx;\n\n const len = Math.sqrt(nx * nx + ny * ny + nz * nz);\n if (len > 0) {\n nx /= len;\n ny /= len;\n nz /= len;\n }\n\n // Assign same normal to all 3 vertices of the triangle\n for (let v = 0; v < 3; v++) {\n normals[i + v * 3] = nx;\n normals[i + v * 3 + 1] = ny;\n normals[i + v * 3 + 2] = nz;\n }\n }\n\n return normals;\n }\n}\n\n// ─── Private helpers ────────────────────────────────────────────\n\nfunction isPowerOfTwo(value: number): boolean {\n return (value & (value - 1)) === 0 && value > 0;\n}\n\n/** Read a single component from a DataView according to its glTF type. */\nfunction readComponent(\n view: DataView,\n offset: number,\n componentType: GltfComponentType,\n): number {\n switch (componentType) {\n case GltfComponentType.BYTE:\n return view.getInt8(offset);\n case GltfComponentType.UNSIGNED_BYTE:\n return view.getUint8(offset);\n case GltfComponentType.SHORT:\n return view.getInt16(offset, true);\n case GltfComponentType.UNSIGNED_SHORT:\n return view.getUint16(offset, true);\n case GltfComponentType.UNSIGNED_INT:\n return view.getUint32(offset, true);\n case GltfComponentType.FLOAT:\n return view.getFloat32(offset, true);\n default:\n return 0;\n }\n}\n"],"mappings":"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","names":["count","Ctor"]}
@@ -0,0 +1,10 @@
1
+ import { W as WebGLCore } from '../../WebGLCore-DR7ZHJB0.js';
2
+ import { b as Material } from '../../Material-BGLkldxv.js';
3
+ import { Vector3 } from '../domain/interfaces/Vectors.js';
4
+ import { i as Model } from '../../Model-CQvDXd-b.js';
5
+ import 'gl-matrix';
6
+
7
+ declare function loadMTL(url: string, webglCore: WebGLCore): Promise<Record<string, Material>>;
8
+ declare function loadOBJWithMTL(webglCore: WebGLCore, objUrl: string, mtlUrl: string | null, translation?: Vector3, scale?: Vector3, defaultMaterial?: Material): Promise<Model>;
9
+
10
+ export { loadMTL, loadOBJWithMTL };
@@ -0,0 +1,183 @@
1
+ import {
2
+ Mesh
3
+ } from "../../chunk-QCQVJCSR.js";
4
+ import {
5
+ Material
6
+ } from "../../chunk-6LS6AO5H.js";
7
+ import {
8
+ Model
9
+ } from "../../chunk-JK2HEZAT.js";
10
+ import "../../chunk-3ULETMWF.js";
11
+ import "../../chunk-5TAAXI6S.js";
12
+
13
+ // src/Core/utils/parse-obj.ts
14
+ function computeNormal(p1, p2, p3) {
15
+ const u = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];
16
+ const v = [p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2]];
17
+ return [
18
+ u[1] * v[2] - u[2] * v[1],
19
+ u[2] * v[0] - u[0] * v[2],
20
+ u[0] * v[1] - u[1] * v[0]
21
+ ];
22
+ }
23
+ async function loadMTL(url, webglCore) {
24
+ const response = await fetch(url);
25
+ if (!response.ok) throw new Error(`Failed to load MTL: ${url}`);
26
+ const text = await response.text();
27
+ const materials = {};
28
+ let current = null;
29
+ const basePath = url.split("/").slice(0, -1).join("/") + "/";
30
+ const lines = text.split("\n");
31
+ for (const line of lines) {
32
+ const trimmed = line.trim();
33
+ if (!trimmed || trimmed.startsWith("#")) continue;
34
+ const parts = trimmed.split(/\s+/);
35
+ switch (parts[0].toLowerCase()) {
36
+ case "newmtl":
37
+ current = new Material(webglCore, { albedoColor: [1, 1, 1, 1] });
38
+ materials[parts[1]] = current;
39
+ break;
40
+ case "kd":
41
+ if (!current) continue;
42
+ current.diffuse = [
43
+ parseFloat(parts[1]),
44
+ parseFloat(parts[2]),
45
+ parseFloat(parts[3])
46
+ ];
47
+ current.albedoColor = [...current.diffuse, 1];
48
+ break;
49
+ case "ks":
50
+ if (!current) continue;
51
+ current.specular = [
52
+ parseFloat(parts[1]),
53
+ parseFloat(parts[2]),
54
+ parseFloat(parts[3])
55
+ ];
56
+ break;
57
+ case "ns":
58
+ if (!current) continue;
59
+ current.shininess = parseFloat(parts[1]);
60
+ break;
61
+ case "map_kd":
62
+ if (!current) continue;
63
+ await current.loadTexture(basePath + parts[1]);
64
+ break;
65
+ }
66
+ }
67
+ return materials;
68
+ }
69
+ async function loadOBJWithMTL(webglCore, objUrl, mtlUrl, translation = [0, 0, 0], scale = [1, 1, 1], defaultMaterial = new Material(webglCore, { albedoColor: [1, 1, 1, 1] })) {
70
+ const materials = mtlUrl ? await loadMTL(mtlUrl, webglCore) : {};
71
+ const response = await fetch(objUrl);
72
+ if (!response.ok) throw new Error(`Failed to load OBJ: ${objUrl}`);
73
+ const objText = await response.text();
74
+ const positions = [];
75
+ const texCoords = [];
76
+ const vertexNormals = [];
77
+ const meshesData = {};
78
+ let currentMaterialName = null;
79
+ const lines = objText.split("\n");
80
+ for (const line of lines) {
81
+ const trimmed = line.trim();
82
+ if (!trimmed || trimmed.startsWith("#")) continue;
83
+ const parts = trimmed.split(/\s+/);
84
+ switch (parts[0]) {
85
+ case "v":
86
+ positions.push([
87
+ parseFloat(parts[1]),
88
+ parseFloat(parts[2]),
89
+ parseFloat(parts[3])
90
+ ]);
91
+ break;
92
+ case "vt":
93
+ texCoords.push([
94
+ parseFloat(parts[1]),
95
+ 1 - parseFloat(parts[2])
96
+ // flip V for WebGL
97
+ ]);
98
+ break;
99
+ case "vn":
100
+ vertexNormals.push([
101
+ parseFloat(parts[1]),
102
+ parseFloat(parts[2]),
103
+ parseFloat(parts[3])
104
+ ]);
105
+ break;
106
+ case "usemtl":
107
+ currentMaterialName = parts[1];
108
+ if (!meshesData[currentMaterialName])
109
+ meshesData[currentMaterialName] = {
110
+ vertices: [],
111
+ normals: [],
112
+ uvs: []
113
+ };
114
+ break;
115
+ case "f": {
116
+ if (!currentMaterialName) currentMaterialName = "default";
117
+ if (!meshesData[currentMaterialName])
118
+ meshesData[currentMaterialName] = {
119
+ vertices: [],
120
+ normals: [],
121
+ uvs: []
122
+ };
123
+ const faceVertices = parts.slice(1).map((token) => {
124
+ const [v, vt, vn] = token.split("/");
125
+ let vIdx = parseInt(v);
126
+ let tIdx = vt ? parseInt(vt) : null;
127
+ let nIdx = vn ? parseInt(vn) : null;
128
+ if (vIdx < 0) vIdx = positions.length + vIdx;
129
+ else vIdx--;
130
+ if (tIdx !== null) {
131
+ if (tIdx < 0) tIdx = texCoords.length + tIdx;
132
+ else tIdx--;
133
+ }
134
+ if (nIdx !== null) {
135
+ if (nIdx < 0) nIdx = vertexNormals.length + nIdx;
136
+ else nIdx--;
137
+ }
138
+ return { vIdx, tIdx, nIdx };
139
+ });
140
+ const { vertices, normals, uvs } = meshesData[currentMaterialName];
141
+ for (let i = 1; i < faceVertices.length - 1; i++) {
142
+ const tri = [faceVertices[0], faceVertices[i], faceVertices[i + 1]];
143
+ const p = tri.map((v) => positions[v.vIdx]);
144
+ let n;
145
+ if (tri.every((v) => v.nIdx !== null)) {
146
+ n = tri.map((v) => vertexNormals[v.nIdx]);
147
+ } else {
148
+ const normal = computeNormal(p[0], p[1], p[2]);
149
+ n = [normal, normal, normal];
150
+ }
151
+ for (let j = 0; j < 3; j++) {
152
+ vertices.push(...p[j]);
153
+ normals.push(...n[j]);
154
+ const tIdx = tri[j].tIdx;
155
+ const uv = tIdx !== null ? texCoords[tIdx] : [0, 0];
156
+ uvs.push(...uv);
157
+ }
158
+ }
159
+ break;
160
+ }
161
+ }
162
+ }
163
+ const meshes = [];
164
+ for (const [matName, data] of Object.entries(meshesData)) {
165
+ const material = materials[matName] || defaultMaterial || new Material(webglCore, { albedoColor: [1, 1, 1, 1] });
166
+ const mesh = new Mesh(
167
+ matName,
168
+ new Float32Array(data.vertices),
169
+ new Float32Array(data.normals),
170
+ material,
171
+ new Float32Array(data.uvs),
172
+ null
173
+ );
174
+ meshes.push(mesh);
175
+ }
176
+ const modelName = objUrl.split("/").pop().replace(".obj", "");
177
+ return new Model(meshes, translation, scale, modelName);
178
+ }
179
+ export {
180
+ loadMTL,
181
+ loadOBJWithMTL
182
+ };
183
+ //# sourceMappingURL=parse-obj.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/Core/utils/parse-obj.ts"],"sourcesContent":["import { Material, Mesh, Model, WebGLCore } from '../classes';\nimport { Vector3 } from '../domain/interfaces/Vectors';\n\nfunction computeNormal(p1: Vector3, p2: Vector3, p3: Vector3): Vector3 {\n const u: Vector3 = [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]];\n const v: Vector3 = [p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2]];\n return [\n u[1] * v[2] - u[2] * v[1],\n u[2] * v[0] - u[0] * v[2],\n u[0] * v[1] - u[1] * v[0],\n ];\n}\n\nexport async function loadMTL(\n url: string,\n webglCore: WebGLCore,\n): Promise<Record<string, Material>> {\n const response = await fetch(url);\n if (!response.ok) throw new Error(`Failed to load MTL: ${url}`);\n const text = await response.text();\n\n const materials: Record<string, Material> = {};\n let current: Material | null = null;\n\n const basePath = url.split('/').slice(0, -1).join('/') + '/';\n\n const lines = text.split('\\n');\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n\n const parts = trimmed.split(/\\s+/);\n\n switch (parts[0].toLowerCase()) {\n case 'newmtl':\n current = new Material(webglCore, { albedoColor: [1, 1, 1, 1] });\n materials[parts[1]] = current;\n break;\n\n case 'kd':\n if (!current) continue;\n current.diffuse = [\n parseFloat(parts[1]),\n parseFloat(parts[2]),\n parseFloat(parts[3]),\n ];\n current.albedoColor = [...current.diffuse, 1];\n break;\n\n case 'ks':\n if (!current) continue;\n current.specular = [\n parseFloat(parts[1]),\n parseFloat(parts[2]),\n parseFloat(parts[3]),\n ];\n break;\n\n case 'ns':\n if (!current) continue;\n current.shininess = parseFloat(parts[1]);\n break;\n\n case 'map_kd':\n if (!current) continue;\n await current.loadTexture(basePath + parts[1]);\n break;\n }\n }\n\n return materials;\n}\n\nexport async function loadOBJWithMTL(\n webglCore: WebGLCore,\n objUrl: string,\n mtlUrl: string | null,\n translation: Vector3 = [0, 0, 0],\n scale: Vector3 = [1, 1, 1],\n defaultMaterial = new Material(webglCore, { albedoColor: [1, 1, 1, 1] }),\n): Promise<Model> {\n const materials = mtlUrl ? await loadMTL(mtlUrl, webglCore) : {};\n\n const response = await fetch(objUrl);\n if (!response.ok) throw new Error(`Failed to load OBJ: ${objUrl}`);\n const objText = await response.text();\n\n const positions: Vector3[] = [];\n const texCoords: number[][] = [];\n const vertexNormals: Vector3[] = [];\n\n const meshesData: Record<\n string,\n { vertices: number[]; normals: number[]; uvs: number[] }\n > = {};\n\n let currentMaterialName: string | null = null;\n\n const lines = objText.split('\\n');\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n\n const parts = trimmed.split(/\\s+/);\n\n switch (parts[0]) {\n case 'v':\n positions.push([\n parseFloat(parts[1]),\n parseFloat(parts[2]),\n parseFloat(parts[3]),\n ]);\n break;\n\n case 'vt':\n texCoords.push([\n parseFloat(parts[1]),\n 1 - parseFloat(parts[2]), // flip V for WebGL\n ]);\n break;\n\n case 'vn':\n vertexNormals.push([\n parseFloat(parts[1]),\n parseFloat(parts[2]),\n parseFloat(parts[3]),\n ]);\n break;\n\n case 'usemtl':\n currentMaterialName = parts[1];\n if (!meshesData[currentMaterialName])\n meshesData[currentMaterialName] = {\n vertices: [],\n normals: [],\n uvs: [],\n };\n break;\n\n case 'f': {\n if (!currentMaterialName) currentMaterialName = 'default';\n if (!meshesData[currentMaterialName])\n meshesData[currentMaterialName] = {\n vertices: [],\n normals: [],\n uvs: [],\n };\n\n const faceVertices = parts.slice(1).map((token) => {\n const [v, vt, vn] = token.split('/');\n\n let vIdx = parseInt(v);\n let tIdx = vt ? parseInt(vt) : null;\n let nIdx = vn ? parseInt(vn) : null;\n\n if (vIdx < 0) vIdx = positions.length + vIdx;\n else vIdx--;\n\n if (tIdx !== null) {\n if (tIdx < 0) tIdx = texCoords.length + tIdx;\n else tIdx--;\n }\n\n if (nIdx !== null) {\n if (nIdx < 0) nIdx = vertexNormals.length + nIdx;\n else nIdx--;\n }\n\n return { vIdx, tIdx, nIdx };\n });\n\n const { vertices, normals, uvs } = meshesData[currentMaterialName];\n\n for (let i = 1; i < faceVertices.length - 1; i++) {\n const tri = [faceVertices[0], faceVertices[i], faceVertices[i + 1]];\n const p = tri.map((v) => positions[v.vIdx]);\n\n let n: Vector3[];\n if (tri.every((v) => v.nIdx !== null)) {\n n = tri.map((v) => vertexNormals[v.nIdx!]);\n } else {\n const normal = computeNormal(p[0], p[1], p[2]);\n n = [normal, normal, normal];\n }\n\n for (let j = 0; j < 3; j++) {\n vertices.push(...p[j]);\n normals.push(...n[j]);\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n const tIdx = tri[j].tIdx;\n const uv = tIdx !== null ? texCoords[tIdx] : [0, 0];\n uvs.push(...uv);\n }\n }\n break;\n }\n }\n }\n\n const meshes: Mesh[] = [];\n\n for (const [matName, data] of Object.entries(meshesData)) {\n const material =\n materials[matName] ||\n defaultMaterial ||\n new Material(webglCore, { albedoColor: [1, 1, 1, 1] });\n\n const mesh = new Mesh(\n matName,\n new Float32Array(data.vertices),\n new Float32Array(data.normals),\n material,\n new Float32Array(data.uvs),\n null,\n );\n\n meshes.push(mesh);\n }\n\n const modelName = objUrl.split('/').pop()!.replace('.obj', '');\n return new Model(meshes, translation, scale, modelName);\n}\n"],"mappings":"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","names":[]}