From a24f54770935621a32da167413bc9f5ce05d7e41 Mon Sep 17 00:00:00 2001 From: codegirl-007 Date: Fri, 14 Aug 2026 23:07:58 -0700 Subject: [PATCH] Add set_sprite_clip_def for pre-resolved clip switches. --- engine/animation_test.odin | 31 +++++++++++++++++++++++++++++++ engine/sprite.odin | 11 +++++++++++ 2 files changed, 42 insertions(+) diff --git a/engine/animation_test.odin b/engine/animation_test.odin index 4ce7a31..e95b64e 100644 --- a/engine/animation_test.odin +++ b/engine/animation_test.odin @@ -144,6 +144,37 @@ set_sprite_clip_caches_clip_def :: proc(t: ^testing.T) { testing.expect_value(t, len(sprite.clip_def.frames), 3) } +@(test) +set_sprite_clip_def_applies_and_guards :: proc(t: ^testing.T) { + data := make_test_character() + defer destroy_test_character(&data) + + sprite := spawn_sprite(&data, {}, "idle", 0) + sprite.frame = 2 + sprite.time = 0.05 + + once := data.def.clips["once"] + set_sprite_clip_def(&sprite, "once", once) + testing.expect_value(t, sprite.clip, "once") + testing.expect(t, sprite.has_clip, "def apply should mark clip present") + testing.expect_value(t, sprite.frame, 0) + testing.expect_value(t, sprite.time, f32(0)) + testing.expect(t, !sprite.clip_def.loop, "once clip does not loop") + testing.expect_value(t, len(sprite.clip_def.frames), 3) + + sprite.frame = 1 + sprite.time = 0.09 + set_sprite_clip_def(&sprite, "once", once) + testing.expect_value(t, sprite.frame, 1) + testing.expect_value(t, sprite.time, f32(0.09)) + + set_sprite_clip_def(&sprite, "empty", Clip_Def{loop = true, fps = 10, frames = nil}) + testing.expect_value(t, sprite.clip, "once") + testing.expect_value(t, sprite.frame, 1) + + set_sprite_clip_def(nil, "once", once) +} + @(test) spawn_sprite_valid_and_invalid :: proc(t: ^testing.T) { data := make_test_character() diff --git a/engine/sprite.odin b/engine/sprite.odin index 28b66fc..af6a6be 100644 --- a/engine/sprite.odin +++ b/engine/sprite.odin @@ -183,6 +183,17 @@ set_sprite_clip :: proc(sprite: ^Sprite, clip: string) { def, ok := character_clip(sprite.data, clip) if !ok do return + set_sprite_clip_def(sprite, clip, def) +} + +// Applies a pre-resolved clip without looking up the character clip map. +// Use when callers already hold Clip_Def (e.g. thrashing between known clips). +set_sprite_clip_def :: proc(sprite: ^Sprite, clip: string, def: Clip_Def) { + if sprite == nil do return + if len(def.frames) == 0 do return + + if sprite.clip == clip && sprite.has_clip do return + sprite.clip = clip sprite.clip_def = def sprite.has_clip = true