API Design

/* A render view = one PVR2 scene submission cycle. */
typedef struct {
    int             priority;       /* Lower = rendered first */
    int             enabled;        /* 0 = skip this frame */
    char            name[16];       /* Debug label */

    /* What to render */
    void           *stage;          /* Game-defined stage pointer (scene data) */

    /* Camera */
    sh_mat4_t       view_matrix;
    sh_mat4_t       proj_matrix;
    float           near_z, far_z;

    /* Viewport (screen region) */
    int             vp_x, vp_y;
    int             vp_w, vp_h;

    /* Callbacks */
    void (*submit)(struct sh_view *view);  /* Called during render to submit geometry */

} sh_view_t;

/* Compositor manages ordered views. */
typedef struct {
    sh_view_t      *views[8];      /* Max 8 views */
    int             view_count;
    int             frame_count;    /* Running frame counter */
} sh_compositor_t;

/* Initialize compositor. */
void sh_compositor_init(sh_compositor_t *comp);

/* Add a view. Returns view index. */
int sh_compositor_add_view(sh_compositor_t *comp, sh_view_t *view);

/* Remove a view by index. */
void sh_compositor_remove_view(sh_compositor_t *comp, int index);

/* Execute one frame. Sorts views by priority, calls submit() for each.
   Wraps pvr_scene_begin() / pvr_scene_finish(). */
void sh_compositor_render(sh_compositor_t *comp);


/* --- Typical frame --- */
/*
 * sh_compositor_render() does:
 *   1. Sort views by priority
 *   2. pvr_wait_ready()
 *   3. pvr_scene_begin()
 *   4. For each enabled view:
 *      a. Set viewport (pvr_set_bg_color or scissor)
 *      b. Load view/proj matrices to XMTRX
 *      c. Call view->submit(view)
 *         (game code submits pvr_poly_hdr + vertices per material)
 *   5. pvr_scene_finish()
 *   6. comp->frame_count++
 *
 * VMU rendering happens OUTSIDE the PVR2 scene cycle — it's Maple bus,
 * not PVR2. Games call sh_vmu_present() whenever they want.
 */