git.lucas.co / cce-mesh-io
mesh files in: STL, OBJ, glTF and PLY
git clone https://git.lucas.co/cce-mesh-io.git

CLAUDE.md (3.1K)

 1 # cce-mesh-io
 2 
 3 Mesh files in, one scene type out: STL, OBJ (+ MTL colours), glTF/GLB and
 4 PLY. A library with no renderer and no cce-ui dependency, shared by
 5 cce-model (shows files) and, from milestone 6 of the viewer's design doc,
 6 cce-designer (imports them). Read the workspace guide
 7 (`../cce-compositor/WORKSPACE.md`) first; this covers only what is
 8 particular to this crate.
 9 
10 ## The contract
11 
12 - A reader returns a `Scene` **as the file has it**: parts in the file's own
13   coordinates and units, and `up` saying which way its format calls up
14   (`UpAxis::Z` for STL, `Y` for the rest). Readers never rotate, scale or
15   weld. `load()` welds each part, drops empty parts and names unnamed ones
16   after the file stem.
17 - **Callers decide orientation.** cce-model turns a Z-up scene upright
18   (`Mesh::z_up_to_y_up`); an importer of the designer's own exports must
19   not, because cce-designer writes its Y-up world into STL as is (its STL
20   export is not Z-up — a slicer will lay those models on their side).
21 - `unit` is what the format conventionally means (STL mm, glTF metres, OBJ
22   and PLY unspecified); a caller showing a size says which.
23 - **Materials, not a palette** (since milestone 5): each triangle names a
24   `Material` (`tri_material` → `materials`): linear colour, an optional
25   texture (an index into `Scene::textures`), metallic and roughness — glTF's
26   model; an MTL's `Kd` / `map_Kd` / `Ns` (as roughness) / `Pm` / `Pr` map
27   onto it. `Texture`s are decoded RGBA8, sRGB-encoded, top row first
28   (`Texture::decode`, PNG or JPEG via the `image` crate; `sample` for the
29   nearest texel, repeating).
30 - **Everything per corner rides on corners** (three per triangle, in
31   triangle order), so welding never chooses between two values at a point:
32   `corner_colors` (PLY, glTF `COLOR_0`, already multiplied by the material
33   colour; `Mesh::corner_color` prefers them), `corner_uvs` (image convention,
34   (0, 0) top-left; an OBJ `vt` is flipped in v; they may exceed 0..1 — textures
35   repeat), and `file_normals` (glTF `NORMAL` through the node's
36   inverse-transpose, OBJ `vn` only when every corner has one). `weld`,
37   `append` and `z_up_to_y_up` keep all three in step; `append` drops file
38   normals one side lacks.
39 - Errors are `String`s meant for a person: they name the line, the element
40   or the buffer that was wrong.
41 
42 ## Not yet
43 
44 Metallic-roughness, normal and occlusion TEXTURES (the factors are read),
45 KHR_texture_transform and other extensions, PLY texture coordinates, PLY
46 point clouds without faces (an error that says so), 3MF.
47 
48 ## Tests
49 
50 `cargo test -p cce-mesh-io`. Unit tests sit beside each reader; glTF and
51 GLB fixtures are built in the test (base64 buffer, hand-assembled GLB
52 chunks). `tests/designer_round_trip.rs` reads the designer's default project
53 as its own exporter wrote it (`tests/fixtures/designer-default.{stl,obj}`,
54 made with `cce-designer --export default_project.json …`) and requires the
55 STL and the OBJ to come back as the same 362 points and 720 triangles with
56 the same winding. Regenerate the fixtures the same way if the exporter's
57 format changes, and keep the counts in the test's doc in step.