Squash of 25 work commits (Sep 1–12):237da90render: the sprite lane hands the screen draw back the way it found it895b9a7particles: an emitter can ride a body's own frame914471fai-hub: a feed session whose last socket left ends on its idle timeout; skin: parent, skinned centroid and a nodes-only rig for retargets3fcccf3sim: the whole world is implicitly editable, and one seam says where the ground is5692fabsim: the landform world proves itself — walker through the tunnel includedf4af6dfsim: terrain knows who changed it — a plan layer over player historyadbb078render: a water volume can be physics without a picturec17480frender: a non-rigid body may carry its own orientationacad401sim: an agent with no route holds and retries instead of walking into the wall22b2bf9sim + chat: the composed world surface takes a map floor; the chat gets plan toolsfaf8112web path: the tessellator's lap timer, the trace span and the fusion cycle timer have no clock on the webd3472ebtsdf: the clock-taking XR helpers are native-only — the browser has no depth camera and no Instant4946c9esim + render: a repaint is not a world edit — colour and glow restyles never rebake the lightmap4317f58sim + render + chat: walk decks as a surface, the filmed body is no obstruction, the brief never asks9791279render: support rigged models and custom materials across viewers3ce2792sim: use deck geometry for collision and sensing c8b79ff Add portable PBR, rig and soft-body authoring support 108d423 Add transactional polygon modeling and editable asset documents 38f4d3b Refine editable modeling and firm yarn character behavior 08a2637 sim: add entity-owned lights and vehicle headlights 00d96a7 render: add clustered lights, local shadows and incremental GI cf916af render: import glTF asset extensions and wire clustered GI c6d2cca model: cut transaction memory and raise capacity limits 41af47a raytrace: add a CPU probe-ray BVH budget example c963d0a libs: the game sim splits into makepad-scene and makepad-soft-body; render, model, fab and the asset importer retarget Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
6.8 KiB
makepad-mesh-edit
A synchronous CPU polygon kernel for worker-owned asset documents. Mesh is
Clone + Send + Sync, has no shared locks, and can be published as Arc<Mesh>.
Vertices, faces and face corners live in flat arrays. A sorted endpoint-keyed
table holds explicit edge seam/crease attributes and loose edges. adjacency
builds a transient index on request; callers can cache it by document revision.
use makepad_mesh_edit::{Context, Mesh};
let mut context = Context::default();
let mut mesh = Mesh::cube([1.0, 1.0, 1.0], &mut context)?;
let front = mesh.faces()[1].id;
let extruded = mesh.extrude_face(front, [0.0, 0.0, 0.25], &mut context)?;
assert_eq!(extruded.cap, front);
let triangles = mesh.triangulate(&mut context)?;
let bytes = mesh.to_bytes(&mut context)?;
let reopened = Mesh::from_bytes(&bytes, &mut context)?;
assert_eq!(reopened.to_bytes(&mut context)?, bytes);
# Ok::<(), makepad_mesh_edit::MeshError>(())
Stable vertex, face and corner IDs share a monotonic allocation watermark.
Deleting an element does not make its ID reusable. IDs are local to a mesh;
the owning document supplies mesh/object/revision identity. Restoring an older
checkpoint restores its watermark, so selectors across undo branches require
the owning document's exact expected head. Immutable array
positions and corner ranges may change. EdgeKey consists of sorted stable
endpoint IDs, so changing either endpoint changes that edge's identity.
Every edit stages a candidate, checks its structure and geometry, and installs
it only on success. The original mesh and ID watermark survive errors,
cancellation and budget refusal exactly. ChangeSet reports created, retained,
deleted and explicitly remapped IDs; document checkpoints provide undo rather
than embedding another full mesh inside each change set.
Supported operations are affine selected-vertex transforms, single-face extrusion, face deletion, whole-mesh reflection/duplication, selected-vertex welding, strictly convex planar face inset, and weight/UV/normal/material/edge attribute editing. Batch smoothing, grab brushes, planar UV projection and Catmull–Clark subdivision support organic cages. Empty selections are empty, never an implicit "all". Import supports arbitrary simple polygon faces, independent corner UVs, materials and normalized sparse weights. Cube and XZ plane constructors use metres, Y-up, centered coordinates and outward winding.
Extrusion preserves the source face and corner IDs as its translated cap. Copied vertices retain weights and the cap retains UVs. Side faces inherit the material, receive a perimeter/height UV strip in object units, and use computed normals. New rim edges inherit seam/crease values. Adjacent faces retain their own discontinuous UVs. Inset preserves its cap identities and interpolates UVs and weights from the source triangulation. Reflection duplicates the mesh, reverses corner winding, and preserves reflected split normals and edge data. It does not weld automatically. Weld preserves the lowest-ID representative position, averages its group's weights, retains corner UV seams, combines seams with OR and creases with max, and deletes collapsed faces. A surviving pinched or self-crossing projected face refuses the entire edit.
Smoothing uses simultaneous uniform Laplacian updates, with optional fixed boundary vertices and a maximum of 64 iterations. Grab brushes use smoothstep radial falloff inside the requested sphere and an explicit displacement cap. Both retain IDs, weights and UVs; affected split normals are invalidated. Catmull–Clark supports one to three levels on oriented manifold surfaces, retains updated original vertex IDs and maps replaced faces/corners/edges to their children. Boundary vertices use the cubic boundary stencil. Geometry and weights share stencils; face-local bilinear UV refinement preserves seam discontinuities. Seam markers propagate, while nonzero geometric edge creases are explicitly refused. Evaluated subdivision normals are averaged per vertex.
Triangulation uses checked, deterministic ear clipping with the existing CSG
adaptive-precision orientation predicate. Simple nonplanar faces are projected
using their Newell normal, allowing ordinary subdivision quads. Input winding is retained. Output
has one vertex per source corner, with position, normal, UV, weights, source
vertex/corner IDs and a source face/material per triangle. No partial fan is
returned on failure. Bounded local coordinates and normalized face projection
avoid large-coordinate arithmetic overflow. Coordinates and UVs must be
finite and at most 1e100 in magnitude. Relative face planarity tolerance is
1e-8 for the planarity diagnostic and planar-only inset. Collapsed edges/area
below 1e-12 at the normalized face scale are rejected. Faces have one simple
boundary and no holes.
Validation distinguishes boundary edges from nonmanifold edges, checks vertex
fan connectivity (including bow ties), winding, isolated/loose elements and
individual face geometry. Open surfaces and nonmanifold neighborhoods can be
represented and inspected; extrusion requires a manifold local neighborhood.
is_closed_manifold describes locally valid, closed, oriented manifold topology.
It does not certify global self-intersection freedom. Ordinary local
validation reports self_intersections: NotChecked. Explicit validate_global
checks bounded triangle intersections, shell orientation and disconnected
components, and can establish solid validity. Nonplanarity remains a diagnostic.
The kernel includes bounded bevel, creased subdivision, UV unwrap/pack/relax,
loop editing, bridge/fill, region extrusion, deformers, sculpt and decimation.
Rig evaluation and rendering live in their respective engine crates; general
concave polygon inset remains an explicit refusal. See
the modeling operation contract for supported domains.
Context applies caller-selected element, byte and work limits. Cancellation
uses an optional caller callback and does not start or wait for threads.
Work accounting is cumulative across calls; create a fresh context per job.
Working-storage estimates include candidate and operation scratch, and may
conservatively refuse an operation before reaching the configured element
limit. The default profile is provisional, not a device performance claim.
The canonical MPMESH01 format records all attributes and the allocation
watermark in little-endian fields. Floating negative zero is encoded as zero.
The exact decoder bounds counts before allocation and rejects unknown formats,
duplicate IDs, noncanonical field ordering, malformed references, invalid
floats/flags/geometry, truncated input and trailing bytes. It does not silently
repair or reinterpret corrupt records.
Run focused validation from the repository workspace:
cargo test --release -p makepad-mesh-edit