#include "bindings/definitions.h" #include "window/window.h" namespace { void Animation_free(mrb_state *mrb, void *ptr) { UNUSED(mrb); uint64_t id = ((Wrapper *)ptr)->id; animation_pool.release(id); delete (Wrapper *)ptr; } const struct mrb_data_type Animation_type = { "Animation", Animation_free }; mrb_value Animation_init(mrb_state *mrb, mrb_value self) { Wrapper *old = (Wrapper *)DATA_PTR(self); if (old) mrb_free(mrb, old); mrb_data_init(self, nullptr, &Animation_type); Wrapper *s = new Wrapper(); const mrb_value *frames_val; mrb_int frames_len; mrb_value kwargs; mrb_get_args(mrb, "a|H", &frames_val, &frames_len, &kwargs); float fps = 1.0f; if (!mrb_nil_p(kwargs)) HASH_FLOAT(kwargs, fps, fps); std::vector frame_ids; for (mrb_int i = 0; i < frames_len; i++) { mrb_value frame_val = frames_val[i]; if (!mrb_obj_is_kind_of(mrb, frame_val, definitions::bindings.Image.cls)) { mrb_raise( mrb, mrb_class_get(mrb, "Exception"), "Expected an array of Image objects" ); return mrb_nil_value(); } Wrapper *image_wrapper = (Wrapper *)DATA_PTR(frame_val); uint64_t frame_id = image_wrapper->id; image_pool.use(frame_id); frame_ids.push_back(frame_id); } Animation *animation = new Animation{frame_ids, fps}; s->id = animation_pool.acquire(animation); animation_pool.use(s->id); mrb_data_init(self, s, &Animation_type); return self; } mrb_value static_image_animation(mrb_state *mrb, mrb_value) { mrb_value image_val; mrb_get_args(mrb, "o", &image_val); if (!mrb_obj_is_kind_of(mrb, image_val, definitions::bindings.Image.cls)) { mrb_raise( mrb, mrb_class_get(mrb, "Exception"), "Expected an Image object" ); return mrb_nil_value(); } Wrapper *image_wrapper = (Wrapper *)DATA_PTR(image_val); uint64_t frame_id = image_wrapper->id; image_pool.use(frame_id); std::vector frames = {frame_id}; Animation *animation = new Animation{frames, 1.0f}; uint64_t id = animation_pool.acquire(animation); animation_pool.use(id); return definitions::wrap(definitions::bindings.Animation, id); } mrb_value animation_equal(mrb_state *mrb, mrb_value self) { mrb_value other; mrb_get_args(mrb, "o", &other); if (!mrb_obj_is_kind_of(mrb, other, definitions::bindings.Animation.cls)) return mrb_false_value(); Wrapper *self_wrapper = (Wrapper *)DATA_PTR(self); uint64_t id_self = self_wrapper->id; Wrapper *other_wrapper = (Wrapper *)DATA_PTR(other); uint64_t id_other = other_wrapper->id; return mrb_bool_value(id_self == id_other); } mrb_value animation_hash(mrb_state *, mrb_value self) { Wrapper *wrapper = (Wrapper *)DATA_PTR(self); return mrb_fixnum_value(wrapper->id); } mrb_value animation_frames_set(mrb_state *mrb, mrb_value self) { const mrb_value *frames_val; mrb_int frames_len; mrb_get_args(mrb, "a", &frames_val, &frames_len); Wrapper *self_wrapper = (Wrapper *)DATA_PTR(self); uint64_t id = self_wrapper->id; Animation *animation = animation_pool[id]; std::vector new_frame_ids; for (mrb_int i = 0; i < frames_len; i++) { mrb_value frame_val = frames_val[i]; if (!mrb_obj_is_kind_of(mrb, frame_val, definitions::bindings.Image.cls)) { mrb_raise( mrb, mrb_class_get(mrb, "Exception"), "Expected an array of Image objects" ); return mrb_nil_value(); } Wrapper *image_wrapper = (Wrapper *)DATA_PTR(frame_val); uint64_t frame_id = image_wrapper->id; image_pool.use(frame_id); new_frame_ids.push_back(frame_id); } // Release old frames for (uint64_t frame_id : animation->frames) image_pool.release(frame_id); animation->frames = std::move(new_frame_ids); return mrb_nil_value(); } mrb_value animation_frames_get(mrb_state *mrb, mrb_value self) { Wrapper *self_wrapper = (Wrapper *)DATA_PTR(self); uint64_t id = self_wrapper->id; Animation *animation = animation_pool[id]; mrb_value frames_array = mrb_ary_new_capa(mrb, animation->frames.size()); for (uint64_t frame_id : animation->frames) { image_pool.use(frame_id); mrb_value frame_obj = definitions::wrap(definitions::bindings.Image, frame_id); mrb_ary_push(mrb, frames_array, frame_obj); } return frames_array; } mrb_value animation_fps_set(mrb_state *mrb, mrb_value self) { mrb_float fps; mrb_get_args(mrb, "f", &fps); Wrapper *self_wrapper = (Wrapper *)DATA_PTR(self); uint64_t id = self_wrapper->id; Animation *animation = animation_pool[id]; animation->frame_rate = fps; return mrb_nil_value(); } mrb_value animation_fps_get(mrb_state *mrb, mrb_value self) { Wrapper *self_wrapper = (Wrapper *)DATA_PTR(self); uint64_t id = self_wrapper->id; Animation *animation = animation_pool[id]; return mrb_float_value(mrb, animation->frame_rate); } } // namespace namespace definitions { void register_animation() { DEF_CLASS(Animation, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1)); ADD_CLASS_METHOD(Animation, "from", static_image_animation, MRB_ARGS_REQ(1)); ADD_METHOD(Animation, "==", animation_equal, MRB_ARGS_REQ(1)); ADD_METHOD(Animation, "eql?", animation_equal, MRB_ARGS_REQ(1)); ADD_METHOD(Animation, "hash", animation_hash, MRB_ARGS_NONE()); ADD_METHOD(Animation, "fps=", animation_fps_set, MRB_ARGS_REQ(1)); ADD_METHOD(Animation, "fps", animation_fps_get, MRB_ARGS_NONE()); ADD_METHOD(Animation, "frames=", animation_frames_set, MRB_ARGS_REQ(1)); ADD_METHOD(Animation, "frames", animation_frames_get, MRB_ARGS_NONE()); bindings.Animation = {Animation_class, &Animation_type}; } } // namespace definitions