20 FEB 2026

rahulmnavneeth

scene graph

homedocs

Overview

MOP provides a single-level parent-child hierarchy for mesh transforms. A mesh may have one parent; when a parent has a transform, its children inherit it. This is sufficient for common patterns like attaching objects to moving platforms or grouping related geometry.

Data Model

Each internal MopMesh stores:

int32_t  parent_index;     /* -1 = no parent (root)     */
MopMat4  world_transform;  /* Computed each frame        */

The world_transform is the product of the parent's world transform and the mesh's own local TRS matrix. Root meshes have world_transform = local_transform.

Render-Time Computation

During mop_viewport_render, world transforms are computed in two passes:

  1. Pass 1 — Roots: For every mesh with parent_index == -1, world_transform = local_transform.
  2. Pass 2 — Children: For every mesh with parent_index >= 0, world_transform = parent.world_transform * local_transform.

This two-pass approach guarantees parents are resolved before children without requiring topological sorting or recursion.

API

mop_mesh_set_parent

void mop_mesh_set_parent(MopMesh *mesh, MopMesh *parent, MopViewport *viewport);

Sets the mesh's parent. Both meshes must belong to the same viewport. The viewport is needed to resolve the parent's internal index.

mop_mesh_clear_parent

void mop_mesh_clear_parent(MopMesh *mesh);

Makes the mesh a root node (removes its parent relationship).

Limitations

Usage Pattern

/* Create a platform and an object on top */
MopMesh *platform = mop_viewport_add_mesh(vp, &platform_desc);
MopMesh *object   = mop_viewport_add_mesh(vp, &object_desc);

/* Object follows platform */
mop_mesh_set_parent(object, platform, vp);
mop_mesh_set_position(object, (MopVec3){0, 1, 0});  /* local offset */

/* Moving the platform moves the object too */
mop_mesh_set_position(platform, (MopVec3){3, 0, 0});