Motion Scene (gfx_motion_scene)

Types

gfx_motion_segment_kind_t

typedef enum {
    GFX_MOTION_SEG_CAPSULE      = 0, /**< Thick capsule between joint_a → joint_b        */
    GFX_MOTION_SEG_RING         = 1, /**< Hollow ring centred at joint_a                  */
    GFX_MOTION_SEG_BEZIER_STRIP = 2, /**< Open thick Bézier curve  (e.g. brow)            */
    GFX_MOTION_SEG_BEZIER_LOOP  = 3, /**< Closed thick Bézier loop (e.g. mouth outline)   */
    GFX_MOTION_SEG_BEZIER_FILL  = 4, /**< Closed filled Bézier shape (e.g. eye sclera)    */
} gfx_motion_segment_kind_t;

gfx_motion_interp_t

typedef enum {
    GFX_MOTION_INTERP_HOLD   = 0, /**< Snap immediately to target pose */
    GFX_MOTION_INTERP_DAMPED = 1, /**< Exponential ease (damping_div)  */
} gfx_motion_interp_t;

gfx_motion_resource_t

typedef struct {
    const gfx_image_dsc_t *image;  /**< Pointer to the image descriptor (ROM .inc array)         */
    uint16_t uv_x;                 /**< Source crop origin X  (0 = full image)                   */
    uint16_t uv_y;                 /**< Source crop origin Y  (0 = full image)                   */
    uint16_t uv_w;                 /**< Source crop width     (0 = image width from uv_x)         */
    uint16_t uv_h;                 /**< Source crop height    (0 = image height from uv_y)        */
} gfx_motion_resource_t;

gfx_motion_segment_t

typedef struct {
    gfx_motion_segment_kind_t kind;
    uint16_t          joint_a;       /**< CAPSULE: start; RING: centre; BEZIER: first ctrl pt     */
    uint16_t          joint_b;       /**< CAPSULE: end  ; unused for RING/BEZIER                  */
    uint16_t          joint_count;   /**< BEZIER_*: number of consecutive control points (n=3k+1) */
    uint8_t           stroke_width;  /**< Design-space override; 0 = use layout->stroke_width     */
    uint8_t           layer_bit;     /**< Visibility layer mask bit (0 = always shown)            */
    int16_t           radius_hint;   /**< RING: design-space radius                               */
    /**
     * Texture / resource binding.
     * 0   = solid colour (driven by gfx_motion_player_set_color).
     * N>0 = use asset->resources[N-1] as the mesh_img image source.
     */
    uint8_t           resource_idx;
    /**
     * Palette colour index.
     * 0   = use runtime colour (gfx_motion_player_set_color), not affected by set_color.
     * N>0 = use asset->color_palette[N-1] (0xRRGGBB) as the fixed segment colour.
     *        set_color() skips palette-coloured segments.
     */
    uint8_t           color_idx;
    /**
     * Segment opacity 0-255.
     * 0 is treated as 255 (fully opaque) for zero-init compatibility.
     */
    uint8_t           opacity;
} gfx_motion_segment_t;

gfx_motion_pose_t

typedef struct {
    const int16_t *coords;
} gfx_motion_pose_t;

gfx_motion_action_step_t

typedef struct {
    uint16_t         pose_index;  /**< Index into gfx_motion_asset_t.poses[]     */
    uint16_t         hold_ticks;  /**< Timer ticks to hold before advancing      */
    gfx_motion_interp_t  interp;  /**< Transition style into this step           */
    int8_t           facing;      /**< 1=right  -1=left (mirrors X)              */
} gfx_motion_action_step_t;

gfx_motion_action_t

typedef struct {
    const gfx_motion_action_step_t *steps;
    uint8_t                  step_count;
    bool                     loop;
} gfx_motion_action_t;

gfx_motion_meta_t

typedef struct {
    uint32_t version;    /**< Must equal GFX_MOTION_SCENE_SCHEMA_VERSION */
    int32_t  viewbox_x;
    int32_t  viewbox_y;
    int32_t  viewbox_w;
    int32_t  viewbox_h;
} gfx_motion_meta_t;

gfx_motion_layout_t

typedef struct {
    int16_t  stroke_width;    /**< Default capsule / Bézier stroke thickness (design units) */
    int16_t  mirror_x;        /**< X axis for facing=-1 horizontal mirroring               */
    int16_t  ground_y;        /**< Informational floor position                             */
    uint16_t timer_period_ms; /**< Action-advance timer period                              */
    int16_t  damping_div;     /**< Divisor for INTERP_DAMPED easing (1 = snap)             */
} gfx_motion_layout_t;

gfx_motion_asset_t

typedef struct {
    const gfx_motion_meta_t    *meta;

    /** Control point name table (joint_count entries; field name kept for ABI). */
    const char *const       *joint_names;
    uint16_t                 joint_count;

    /** Segment wiring (segment_count entries; 0 is valid). */
    const gfx_motion_segment_t *segments;
    uint8_t                  segment_count;

    /** Pose library. */
    const gfx_motion_pose_t    *poses;
    uint16_t                 pose_count;

    /** Action library. */
    const gfx_motion_action_t    *actions;
    uint16_t                 action_count;

    /** Default playback sequence (action indices). */
    const uint16_t          *sequence;
    uint16_t                 sequence_count;

    /** Rendering hints. */
    const gfx_motion_layout_t  *layout;

    /**
     * Optional texture/image resource table.
     * Segments reference entries here via segment.resource_idx (1-based).
     * NULL and resource_count=0 are valid (all segments use solid colour).
     */
    const gfx_motion_resource_t *resources;
    uint8_t                   resource_count;

    /**
     * Optional per-segment colour palette.
     * Stored as 0xRRGGBB 24-bit values; converted to native pixel at runtime init.
     * Segments reference entries via segment.color_idx (1-based).
     * NULL and color_palette_count=0 are valid (all non-resource segments use
     * the runtime colour set by gfx_motion_player_set_color).
     */
    const uint32_t *color_palette;
    uint8_t         color_palette_count;
} gfx_motion_asset_t;

gfx_motion_point_t

typedef struct {
    int16_t x;
    int16_t y;
} gfx_motion_point_t;

gfx_motion_scene_t

typedef struct {
    const gfx_motion_asset_t *asset;

    gfx_motion_point_t  pose_cur[GFX_MOTION_SCENE_MAX_POINTS]; /**< Current (animated) positions */
    gfx_motion_point_t  pose_tgt[GFX_MOTION_SCENE_MAX_POINTS]; /**< Target positions              */

    uint16_t     active_action;
    uint8_t      active_step;
    uint16_t     step_ticks;
    bool         action_loop_override_en;
    bool         action_loop_override;
    bool         dirty;
} gfx_motion_scene_t;

gfx_motion_player_t

typedef struct {
    gfx_motion_scene_t  scene;
    gfx_motion_t        motion;
    /* ── private ── */
    gfx_obj_t      *seg_objs[GFX_MOTION_PLAYER_MAX_SEGMENTS]; /**< One mesh_img per segment */
    uint8_t         seg_grid_cols[GFX_MOTION_PLAYER_MAX_SEGMENTS];
    uint8_t         seg_grid_rows[GFX_MOTION_PLAYER_MAX_SEGMENTS];
    uint8_t         seg_obj_count;
    gfx_color_t     stroke_color;
    uint32_t        layer_mask;
    uint16_t        solid_pixel;
    gfx_image_dsc_t solid_img;
    /** Per-palette-entry native pixels and their 1×1 image descriptors. */
    uint16_t        palette_pixels[GFX_MOTION_PALETTE_MAX];
    gfx_image_dsc_t palette_imgs[GFX_MOTION_PALETTE_MAX];
    gfx_coord_t     canvas_x;
    gfx_coord_t     canvas_y;
    uint16_t        canvas_w;
    uint16_t        canvas_h;
    bool            mesh_dirty;
    void           *scratch;
} gfx_motion_player_t;

Functions

gfx_motion_scene_tick()

bool gfx_motion_scene_tick(gfx_motion_scene_t *scene);

gfx_motion_scene_advance()

void gfx_motion_scene_advance(gfx_motion_scene_t *scene);

gfx_motion_scene_log_active_step()

void gfx_motion_scene_log_active_step(const gfx_motion_scene_t *scene, const char *reason);

gfx_motion_player_init()

esp_err_t gfx_motion_player_init(gfx_motion_player_t *player,
                              gfx_disp_t *disp,
                              const gfx_motion_asset_t *asset);

gfx_motion_player_deinit()

void gfx_motion_player_deinit(gfx_motion_player_t *player);

gfx_motion_player_set_color()

esp_err_t gfx_motion_player_set_color(gfx_motion_player_t *player, gfx_color_t color);

gfx_motion_player_set_canvas()

esp_err_t gfx_motion_player_set_canvas(gfx_motion_player_t *player,
                                    gfx_coord_t x, gfx_coord_t y,
                                    uint16_t w, uint16_t h);

gfx_motion_player_set_layer_mask()

esp_err_t gfx_motion_player_set_layer_mask(gfx_motion_player_t *player, uint32_t layer_mask);

gfx_motion_player_sync()

esp_err_t gfx_motion_player_sync(gfx_motion_player_t *player);

gfx_motion_player_set_action()

esp_err_t gfx_motion_player_set_action(gfx_motion_player_t *player, uint16_t action_idx, bool snap);