# LibreMetaverse MeshFoundry renderer `libremetaverse-rendering-mesh-foundry` is the bounded native renderer for legacy prims, sculpt maps, terrain, and Second Life LLSD mesh assets. It uses the checked SimpleRenderer/PrimMesher path for legacy geometry and the native StructuredData binary codec for mesh containers. It does not wrap, load, or invoke the C# renderer or duplicate the LLSD and image codecs. ## Pipelines The mapped `MeshFoundry` methods cover: - simple and face-grouped legacy prim geometry at every `DetailLevel`, always retaining finite normals and UVs; - plane, cylinder, sphere, and torus sculpt maps; - rectangular height-map terrain with generated normals and UVs; - packed mesh-asset headers and individually zlib-compressed LLSD sections; - requested visual LOD selection (`high_lod`, `medium_lod`, `low_lod`, and `lowest_lod`) with deterministic highest-to-lowest fallback; - single-section simple-mesh extraction and physics convex/bounding hulls; and - default or planar texture transforms, repeats, offsets, rotation, and prim scale through the common `IRendering` contract. Mesh vertices remain in prim-local coordinates. Quantized positions use each submesh's `PositionDomain`; normals and tangent components use the format's fixed `[-1, 1]` domain; UV0 and optional UV1 use their independent domains. Triangle and face order is preserved, while flattened multi-face output rebases indices without reordering vertices. Missing normals and tangents are generated deterministically from triangles and UVs. Degenerate UV gradients receive a stable normal-orthogonal fallback tangent. The mapped `Face` type has no tangent field. Mesh tangents are therefore kept without changing the public C# layout in a public `MeshFaceAux` value stored in `Face.user_data`; recover it with `face.user_data.downcast_ref::()`. Its `Vector4.w` is the bitangent handedness. UV1 remains in `Face.tex_coords1`. ## Rigged meshes and materials The `skin` section decodes bounded joint names, inverse-bind matrices, bind-shape matrix, alternative inverse-bind matrices, pelvis offset, and the joint-position scale lock into the shared `MeshSkinData`. Per-vertex weight streams accept the protocol's sentinel form and its exactly-four-influence form, validate every joint index, clamp protocol weights, normalize four influences, and bind missing vertices to joint zero. The output is directly consumable by `RiggedSkinMath` and `AnimeshSkinning`. Each submesh retains its original face ID and the effective inherited `PrimitiveTextureEntryFace`, including texture, legacy material, and render material overrides. `NormalizedScale`, face bounds, centers, optional UV1, weights, normals, tangents, and winding are kept together. Mesh sculpt mirror and invert flags apply the viewer-compatible reflection, normal inversion, and XOR winding rule to every face and tangent domain. ## Bounds and failure contract Assets and compressed/decompressed sections are capped at 64 MiB. Header sections and submeshes are capped at 256, each face remains within the 16-bit 65,536-vertex index domain, aggregate visual geometry is capped at 1,000,000 vertices and 6,000,000 indices, skins at 512 joints, and convex data at 65,536 hulls and 1,000,000 vertices. All sizes, offsets, index rebasing, buffer strides, and allocation products use checked arithmetic before slicing or allocation. Malformed LLSD, zlib data, domains, parallel buffers, matrices, weights, offsets, and indices return `Error::Rendering` with the source primitive UUID and a stable operation context. `UnpackMesh` has no primitive parameter and uses the zero UUID. This crate performs no asset download, scene traversal, world transform, GPU upload, material shading, texture fetch, or drawing. ## Reproducible gates and benchmark ```console python3 tools/check_milestone_10_issue_77.py CARGO_BUILD_JOBS=1 cargo test -p libremetaverse-compat-tests --test imaging_meshing_semantics --locked -j1 CARGO_BUILD_JOBS=1 cargo test -p libremetaverse-rendering-mesh-foundry --locked -j1 CARGO_BUILD_JOBS=1 cargo bench -p libremetaverse-rendering-mesh-foundry --bench mesh_decode --profile benchmark --locked -j1 ``` The named `benchmark` profile uses bounded-memory moderate optimization because full release optimization of the generated core surface can exceed small Gitea-worker memory before the fixture runs. The non-statistical benchmark builds and decodes a deterministic 57,600-vertex, 342,726-index mesh asset and reports elapsed time plus allocation counts. It is diagnostic evidence for regressions; correctness and malformed-input tests remain the release gates.