* Parse a Wavefront OBJ file into geometry data. * Supports: `v` (vertex positions), `vt` (texture coordinates), * `f` (faces in `v`, `v/vt`, `v/vt/vn`, or `v//vn` format), * `mtllib` (material library reference), * `usemtl` (material group boundaries — emitted as `groups[]`). * * Features: *
(text)
| 56 | * @ignore |
| 57 | */ |
| 58 | function parseOBJ(text) { |
| 59 | const positions = []; |
| 60 | const texcoords = []; |
| 61 | |
| 62 | // unified output arrays (built in a single pass) |
| 63 | const vertices = []; |
| 64 | const uvs = []; |
| 65 | const indices = []; |
| 66 | let vertexCount = 0; |
| 67 | |
| 68 | // Per-material vertex dedup: each material name owns its own |
| 69 | // `vertexMap`, so the same (v, vt) reused across different |
| 70 | // materials produces SEPARATE unified vertices (needed for |
| 71 | // per-vertex color baking in `Mesh`), but the same material |
| 72 | // reappearing in a later `usemtl` block re-uses its existing |
| 73 | // vertex slots. Pre-usemtl faces use the `null` map (the |
| 74 | // "anonymous" group). |
| 75 | const materialMaps = new Map(); |
| 76 | materialMaps.set(null, new Map()); |
| 77 | let vertexMap = materialMaps.get(null); |
| 78 | |
| 79 | // helper: look up or create a unified vertex for a v/vt pair in the |
| 80 | // current material's dedup scope |
| 81 | function addVertex(v, vt) { |
| 82 | const key = v * VT_KEY_MULTIPLIER + (vt + OBJ_INDEX_OFFSET); |
| 83 | let index = vertexMap.get(key); |
| 84 | if (index === undefined) { |
| 85 | index = vertexCount++; |
| 86 | vertexMap.set(key, index); |
| 87 | const v3 = v * POS_STRIDE; |
| 88 | vertices.push(positions[v3], positions[v3 + 1], positions[v3 + 2]); |
| 89 | if (vt >= 0) { |
| 90 | const vt2 = vt * UV_STRIDE; |
| 91 | uvs.push(texcoords[vt2], texcoords[vt2 + 1]); |
| 92 | } else { |
| 93 | uvs.push(0, 0); |
| 94 | } |
| 95 | } |
| 96 | return index; |
| 97 | } |
| 98 | |
| 99 | /** |
| 100 | * parse a face vertex component (e.g. "1/2/3" or "1//3" or "1") |
| 101 | * and return the UV index, or NO_UV if not present |
| 102 | * @param {string} part - face vertex string |
| 103 | * @returns {number} UV index (0-based) or NO_UV |
| 104 | * @ignore |
| 105 | */ |
| 106 | function parseUVIndex(part, slashIdx) { |
| 107 | if (slashIdx !== -1 && part[slashIdx + 1] !== SLASH_CHAR) { |
| 108 | return parseInt(part.substring(slashIdx + 1), 10) - OBJ_INDEX_OFFSET; |
| 109 | } |
| 110 | return NO_UV; |
| 111 | } |
| 112 | |
| 113 | // mtllib reference (if present) |
| 114 | let mtllib = null; |
| 115 |
no test coverage detected