#ifndef DEFINITIONS_H #define DEFINITIONS_H #include "app/app.h" #warning "Define ==, eql?, hash for each class" #warning "Define and bind elements_at in Scene (same as click method already defined but without callback)" namespace definitions { inline mrb_value wrap(mrb_state *mrb, RClass *cls, mrb_data_type *type, int id) { RBasic *obj_b = mrb_obj_alloc(mrb, MRB_TT_DATA, cls); mrb_value obj = mrb_obj_value(obj_b); Wrapper *w = new Wrapper(); w->id = id; mrb_data_init(obj, w, type); return obj; } static void Font_free(mrb_state *mrb, void *ptr) { UNUSED(mrb); int id = ((Wrapper *)ptr)->id; font_pool.release(id); delete (Wrapper *)ptr; } static const struct mrb_data_type Font_type = {"Font", Font_free}; static mrb_value Font_init(mrb_state *mrb, mrb_value self) { UNUSED(mrb); Wrapper *old = (Wrapper *)DATA_PTR(self); if (old) mrb_free(mrb, old); mrb_data_init(self, nullptr, &Font_type); Wrapper *s = new Wrapper(); char *path; mrb_int size; mrb_value kwargs; mrb_get_args(mrb, "zi|H", &path, &size, &kwargs); bool pixel_art = false; bool bold = false; bool italic = false; bool underline = false; if (!mrb_nil_p(kwargs)) { HASH_BOOL(kwargs, pixel_art, pixel_art); HASH_BOOL(kwargs, bold, bold); HASH_BOOL(kwargs, italic, italic); HASH_BOOL(kwargs, underline, underline); } s->id = window.load_font(path, size, bold, italic, underline, pixel_art); mrb_data_init(self, s, &Font_type); return self; } inline int get_id_Font(mrb_state *mrb, mrb_value self) { Wrapper *wrapper; Data_Get_Struct(mrb, self, &Font_type, wrapper); return wrapper->id; } static void Image_free(mrb_state *mrb, void *ptr) { UNUSED(mrb); int id = ((Wrapper *)ptr)->id; image_pool.release(id); delete (Wrapper *)ptr; } static const struct mrb_data_type Image_type = {"Image", Image_free}; static mrb_value Image_init(mrb_state *mrb, mrb_value self) { UNUSED(mrb); Wrapper *old = (Wrapper *)DATA_PTR(self); if (old) mrb_free(mrb, old); mrb_data_init(self, nullptr, &Image_type); Wrapper *s = new Wrapper(); char *path; mrb_value kwargs; mrb_get_args(mrb, "z|H", &path, &kwargs); float alpha = 1.0f; bool pixel_art = false; if (!mrb_nil_p(kwargs)) { HASH_FLOAT(kwargs, alpha, alpha); HASH_BOOL(kwargs, pixel_art, pixel_art); } s->id = window.load_image(path, alpha, pixel_art); mrb_data_init(self, s, &Image_type); return self; } inline int get_id_Image(mrb_state *mrb, mrb_value self) { Wrapper *wrapper; Data_Get_Struct(mrb, self, &Image_type, wrapper); return wrapper->id; } static void Animation_free(mrb_state *mrb, void *ptr) { UNUSED(mrb); int id = ((Wrapper *)ptr)->id; animation_pool.release(id); delete (Wrapper *)ptr; } static const struct mrb_data_type Animation_type = { "Animation", Animation_free }; static mrb_value Animation_init(mrb_state *mrb, mrb_value self) { UNUSED(mrb); 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, mrb_class_get(mrb, "Image"))) { mrb_raise( mrb, mrb_class_get(mrb, "Exception"), "Expected an array of Image objects" ); return mrb_nil_value(); } int frame_id = get_id_Image(mrb, frame_val); image_pool.use(frame_id); frame_ids.push_back(frame_id); } Animation *animation = new Animation{frame_ids, fps, true}; s->id = animation_pool.acquire(animation); animation_pool.use(s->id); mrb_data_init(self, s, &Animation_type); return self; } inline int get_id_Animation(mrb_state *mrb, mrb_value self) { Wrapper *wrapper; Data_Get_Struct(mrb, self, &Animation_type, wrapper); return wrapper->id; } static void ElementText_free(mrb_state *mrb, void *ptr) { UNUSED(mrb); int id = ((Wrapper *)ptr)->id; app::element_pool.release(id); delete (Wrapper *)ptr; } static const struct mrb_data_type ElementText_type = { "ElementText", ElementText_free }; static mrb_value ElementText_init(mrb_state *mrb, mrb_value self) { UNUSED(mrb); Wrapper *old = (Wrapper *)DATA_PTR(self); if (old) mrb_free(mrb, old); mrb_data_init(self, nullptr, &ElementText_type); Wrapper *s = new Wrapper(); mrb_value font_val; mrb_sym key; mrb_value kwargs; mrb_get_args(mrb, "no|H", &key, &font_val, &kwargs); auto key_id = Localization::key_from_sym(mrb, key); if (!mrb_obj_is_kind_of(mrb, font_val, mrb_class_get(mrb, "Font"))) { mrb_raise(mrb, mrb_class_get(mrb, "Exception"), "Expected a Font object"); return mrb_nil_value(); } float x = 0; float y = 0; float z = 0; bool click_through = false; if (!mrb_nil_p(kwargs)) { mrb_value pos_hash = HASH_GET(kwargs, position); HASH_FLOAT(pos_hash, x, x); HASH_FLOAT(pos_hash, y, y); HASH_FLOAT(kwargs, z, z); HASH_BOOL(kwargs, click_through, click_through); } Vec2 position = {x, y}; int id = get_id_Font(mrb, font_val); font_pool.use(id); app::EText *element = new app::EText(key_id, id, {255, 255, 255, 255}); element->position = position; element->z = z; element->click_through = click_through; s->id = app::element_pool.acquire(element); app::element_pool.use(s->id); mrb_data_init(self, s, &ElementText_type); return self; } inline int get_id_ElementText(mrb_state *mrb, mrb_value self) { Wrapper *wrapper; Data_Get_Struct(mrb, self, &ElementText_type, wrapper); return wrapper->id; } static mrb_value element_text_on_click(mrb_state *mrb, mrb_value self) { mrb_value block; mrb_get_args(mrb, "&", &block); int id = get_id_ElementText(mrb, self); app::Element *element = app::element_pool[id]; element->on_click.set_proc(block); return self; } static void ElementRect_free(mrb_state *mrb, void *ptr) { UNUSED(mrb); int id = ((Wrapper *)ptr)->id; app::element_pool.release(id); delete (Wrapper *)ptr; } static const struct mrb_data_type ElementRect_type = { "ElementRect", ElementRect_free }; static mrb_value ElementRect_init(mrb_state *mrb, mrb_value self) { UNUSED(mrb); Wrapper *old = (Wrapper *)DATA_PTR(self); if (old) mrb_free(mrb, old); mrb_data_init(self, nullptr, &ElementRect_type); Wrapper *s = new Wrapper(); mrb_value shape_val; mrb_int color; mrb_value kwargs; mrb_get_args(mrb, "Hi|H", &shape_val, &color, &kwargs); float x = 0, y = 0, w = 0, h = 0; if (!mrb_nil_p(shape_val)) { HASH_FLOAT(shape_val, x, x); HASH_FLOAT(shape_val, y, y); HASH_FLOAT(shape_val, w, w); HASH_FLOAT(shape_val, h, h); } float z = 0; if (!mrb_nil_p(kwargs)) HASH_FLOAT(kwargs, z, z); Vec2 position = {x, y}; Vec2 shape = {w, h}; app::ERect *element = new app::ERect( shape, {(uint8_t)((color >> 24) & 0xFF), (uint8_t)((color >> 16) & 0xFF), (uint8_t)((color >> 8) & 0xFF), (uint8_t)(color & 0xFF)} ); element->position = position; element->z = z; s->id = app::element_pool.acquire(element); app::element_pool.use(s->id); mrb_data_init(self, s, &ElementRect_type); return self; } inline int get_id_ElementRect(mrb_state *mrb, mrb_value self) { Wrapper *wrapper; Data_Get_Struct(mrb, self, &ElementRect_type, wrapper); return wrapper->id; } static mrb_value element_rect_on_click(mrb_state *mrb, mrb_value self) { mrb_value block; mrb_get_args(mrb, "&", &block); int id = get_id_ElementRect(mrb, self); app::Element *element = app::element_pool[id]; element->on_click.set_proc(block); return self; } static mrb_value element_rect_color_set(mrb_state *mrb, mrb_value self) { mrb_value color_val; mrb_get_args(mrb, "o", &color_val); int id = get_id_ElementRect(mrb, self); app::ERect *element = (app::ERect *)app::element_pool[id]; element->color = { (uint8_t)((mrb_fixnum(color_val) >> 24) & 0xFF), (uint8_t)((mrb_fixnum(color_val) >> 16) & 0xFF), (uint8_t)((mrb_fixnum(color_val) >> 8) & 0xFF), (uint8_t)(mrb_fixnum(color_val) & 0xFF) }; return self; } static mrb_value element_rect_color_get(mrb_state *mrb, mrb_value self) { int id = get_id_ElementRect(mrb, self); app::ERect *element = (app::ERect *)app::element_pool[id]; uint32_t color = ((uint32_t)element->color.r << 24) | ((uint32_t)element->color.g << 16) | ((uint32_t)element->color.b << 8) | (uint32_t)element->color.a; return mrb_fixnum_value(color); } static void ElementImage_free(mrb_state *mrb, void *ptr) { UNUSED(mrb); int id = ((Wrapper *)ptr)->id; app::element_pool.release(id); delete (Wrapper *)ptr; } static const struct mrb_data_type ElementImage_type = { "ElementImage", ElementImage_free }; static mrb_value ElementImage_init(mrb_state *mrb, mrb_value self) { UNUSED(mrb); Wrapper *old = (Wrapper *)DATA_PTR(self); if (old) mrb_free(mrb, old); mrb_data_init(self, nullptr, &ElementImage_type); Wrapper *s = new Wrapper(); mrb_value animation_val; mrb_value kwargs; mrb_get_args(mrb, "o|H", &animation_val, &kwargs); if (!mrb_obj_is_kind_of( mrb, animation_val, mrb_class_get(mrb, "Animation") )) { mrb_raise( mrb, mrb_class_get(mrb, "Exception"), "Expected an Animation object" ); return mrb_nil_value(); } float x = 0; float y = 0; float z = 0; bool click_through = false; if (!mrb_nil_p(kwargs)) { mrb_value pos_hash = HASH_GET(kwargs, position); HASH_FLOAT(pos_hash, x, x); HASH_FLOAT(pos_hash, y, y); HASH_FLOAT(kwargs, z, z); HASH_BOOL(kwargs, click_through, click_through); } int id = get_id_Animation(mrb, animation_val); app::EImage *element = new app::EImage(id); element->position = {x, y}; element->z = z; element->click_through = click_through; s->id = app::element_pool.acquire(element); app::element_pool.use(s->id); mrb_data_init(self, s, &ElementImage_type); return self; } inline int get_id_ElementImage(mrb_state *mrb, mrb_value self) { Wrapper *wrapper; Data_Get_Struct(mrb, self, &ElementImage_type, wrapper); return wrapper->id; } static mrb_value element_image_on_click(mrb_state *mrb, mrb_value self) { mrb_value block; mrb_get_args(mrb, "&", &block); int id = get_id_ElementImage(mrb, self); app::Element *element = app::element_pool[id]; element->on_click.set_proc(block); return self; } static void Scene_free(mrb_state *mrb, void *ptr) { UNUSED(mrb); int id = ((Wrapper *)ptr)->id; app::scene_pool.release(id); delete (Wrapper *)ptr; } static const struct mrb_data_type Scene_type = {"Scene", Scene_free}; static mrb_value Scene_init(mrb_state *mrb, mrb_value self) { UNUSED(mrb); Wrapper *old = (Wrapper *)DATA_PTR(self); if (old) mrb_free(mrb, old); mrb_data_init(self, nullptr, &Scene_type); Wrapper *s = new Wrapper(); app::Scene *loading_scene = new app::Scene{}; s->id = app::scene_pool.acquire(loading_scene); app::scene_pool.use(s->id); mrb_data_init(self, s, &Scene_type); return self; } inline int get_id_Scene(mrb_state *mrb, mrb_value self) { Wrapper *wrapper; Data_Get_Struct(mrb, self, &Scene_type, wrapper); return wrapper->id; } static mrb_value scene_add_element(mrb_state *mrb, mrb_value self) { mrb_value element_val; mrb_get_args(mrb, "o", &element_val); if ( !mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementText")) && !mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementRect")) && !mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementImage")) ) { mrb_raise( mrb, mrb_class_get(mrb, "Exception"), "Expected an ElementText, ElementRect, or ElementImage object" ); return mrb_nil_value(); } int id = get_id_Scene(mrb, self); app::Scene *scene = app::scene_pool[id]; int element_id; if (mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementText"))) { element_id = get_id_ElementText(mrb, element_val); } else if ( mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementRect")) ) { element_id = get_id_ElementRect(mrb, element_val); } else if ( mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementImage")) ) { element_id = get_id_ElementImage(mrb, element_val); } else { mrb_raise( mrb, mrb_class_get(mrb, "Exception"), "Expected an ElementText, ElementRect, or ElementImage object" ); return mrb_nil_value(); } scene->add_element(element_id); return self; } static mrb_value scene_delete_element(mrb_state *mrb, mrb_value self) { mrb_value element_val; mrb_get_args(mrb, "o", &element_val); if ( !mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementText")) && !mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementRect")) && !mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementImage")) ) { mrb_raise( mrb, mrb_class_get(mrb, "Exception"), "Expected an ElementText, ElementRect, or ElementImage object" ); return mrb_nil_value(); } int id = get_id_Scene(mrb, self); app::Scene *scene = app::scene_pool[id]; int element_id; if (mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementText"))) { element_id = get_id_ElementText(mrb, element_val); } else if ( mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementRect")) ) { element_id = get_id_ElementRect(mrb, element_val); } else if ( mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementImage")) ) { element_id = get_id_ElementImage(mrb, element_val); } else { mrb_raise( mrb, mrb_class_get(mrb, "Exception"), "Expected an ElementText, ElementRect, or ElementImage object" ); return mrb_nil_value(); } scene->delete_element(element_id); return self; } static mrb_value scene_on_update(mrb_state *mrb, mrb_value self) { mrb_value block; mrb_get_args(mrb, "&", &block); int id = get_id_Scene(mrb, self); app::Scene *scene = app::scene_pool[id]; scene->update.set_proc(block); return self; } static mrb_value app_run(mrb_state *mrb, mrb_value) { mrb_int width, height; char *title = nullptr; mrb_get_args(mrb, "iiz", &width, &height, &title); app_ = new app::App({(float)width, (float)height}, title); return mrb_nil_value(); } static mrb_value app_start(mrb_state *mrb, mrb_value) { mrb_value scene_val; mrb_get_args(mrb, "o", &scene_val); if (!mrb_obj_is_kind_of(mrb, scene_val, mrb_class_get(mrb, "Scene"))) { mrb_raise(mrb, mrb_class_get(mrb, "Exception"), "Expected a Scene object"); return mrb_nil_value(); } int id = get_id_Scene(mrb, scene_val); app_->switch_to_scene(id); app_->loop(); return mrb_nil_value(); } static mrb_value app_switch_to(mrb_state *mrb, mrb_value) { mrb_value scene_val; mrb_get_args(mrb, "o", &scene_val); if (!mrb_obj_is_kind_of(mrb, scene_val, mrb_class_get(mrb, "Scene"))) { mrb_raise(mrb, mrb_class_get(mrb, "Exception"), "Expected a Scene object"); return mrb_nil_value(); } int id = get_id_Scene(mrb, scene_val); app_->switch_to_scene(id); return mrb_nil_value(); } static mrb_value app_localize(mrb_state *mrb, mrb_value) { mrb_sym lang_sym, key_sym; char *text; mrb_get_args(mrb, "nnz", &lang_sym, &key_sym, &text); auto lang = Localization::lang_from_sym(mrb, lang_sym); const char *key_name = mrb_sym2name(mrb, key_sym); auto it = Localization::localization_key_map.find(key_name); Localization::Key key_id; if (it == Localization::localization_key_map.end()) { key_id = (Localization::Key)Localization::localization_key_map.size(); Localization::localization_key_map[key_name] = key_id; } else { key_id = it->second; } Localization::localized_strings[Localization::join_keys(lang, key_id)] = text; return mrb_nil_value(); } static mrb_value app_language_set(mrb_state *mrb, mrb_value) { mrb_sym lang_sym; mrb_get_args(mrb, "n", &lang_sym); Localization::current_language = Localization::lang_from_sym(mrb, lang_sym); return mrb_nil_value(); } inline void setup() { DEF_CLASS(Font, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1)); DEF_CLASS(Image, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1)); DEF_CLASS(Animation, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1)); DEF_CLASS(ElementText, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1)); ADD_METHOD(ElementText, "on_click", element_text_on_click, MRB_ARGS_BLOCK()); DEF_CLASS(ElementRect, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1)); ADD_METHOD(ElementRect, "on_click", element_rect_on_click, MRB_ARGS_BLOCK()); ADD_METHOD(ElementRect, "color=", element_rect_color_set, MRB_ARGS_REQ(1)); ADD_METHOD(ElementRect, "color", element_rect_color_get, MRB_ARGS_NONE()); DEF_CLASS(ElementImage, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1)); ADD_METHOD(ElementImage, "on_click", element_image_on_click, MRB_ARGS_BLOCK()); DEF_CLASS(Scene, MRB_ARGS_NONE()); ADD_METHOD(Scene, "<<", scene_add_element, MRB_ARGS_REQ(1)); ADD_METHOD(Scene, "delete", scene_delete_element, MRB_ARGS_REQ(1)); ADD_METHOD(Scene, "remove", scene_delete_element, MRB_ARGS_REQ(1)); ADD_METHOD(Scene, "on_update", scene_on_update, MRB_ARGS_BLOCK()); DEF_MODULE(App); ADD_MODULE_METHOD(App, "run", app_run, MRB_ARGS_REQ(3)); ADD_MODULE_METHOD(App, "start", app_start, MRB_ARGS_REQ(1)); ADD_MODULE_METHOD(App, "switch_to", app_switch_to, MRB_ARGS_REQ(1)); ADD_MODULE_METHOD(App, "localize", app_localize, MRB_ARGS_REQ(3)); ADD_MODULE_METHOD(App, "language=", app_language_set, MRB_ARGS_REQ(1)); } } // namespace definitions #endif