Make localization parameters better, and add a single frame animation helper
This commit is contained in:
+6
-15
@@ -68,40 +68,30 @@ struct EText : Element {
|
||||
Localization::Key key;
|
||||
uint64_t font_id = UINT64_MAX;
|
||||
Color color = {255, 255, 255};
|
||||
mrb_value params = mrb_nil_value();
|
||||
std::unordered_map<std::string, std::string> params;
|
||||
|
||||
~EText() {
|
||||
if (text_id != UINT64_MAX)
|
||||
text_pool.release(text_id);
|
||||
if (font_id != UINT64_MAX)
|
||||
font_pool.release(font_id);
|
||||
if (!mrb_nil_p(params))
|
||||
mrb_gc_unregister(Ruby::mrb, params);
|
||||
}
|
||||
|
||||
EText(Localization::Key key, uint64_t font_id, Color color, mrb_value params)
|
||||
: Element(Type::TEXT), key(key), font_id(font_id), color(color), params(params) {
|
||||
mrb_gc_register(Ruby::mrb, params);
|
||||
font_pool.use(font_id);
|
||||
}
|
||||
|
||||
void reload_params() {
|
||||
// Force re-render by resetting last_key (without affecting this frame)
|
||||
// this can be changed to use a dirty flag or version counter if needed
|
||||
last_key = UINT16_MAX;
|
||||
}
|
||||
EText(Localization::Key key, uint64_t font_id, Color color, std::unordered_map<std::string, std::string> params)
|
||||
: Element(Type::TEXT), key(key), font_id(font_id), color(color), params(params) {}
|
||||
|
||||
Vec2<float> size() override {
|
||||
if (text_id == UINT64_MAX)
|
||||
return {0, 0};
|
||||
return window.get_text_size(text_id);
|
||||
};
|
||||
}
|
||||
|
||||
void render(Window &window, uint64_t) override {
|
||||
if (
|
||||
last_language != Localization::current_language
|
||||
|| last_key != key || text_id == UINT64_MAX
|
||||
|| last_color != color
|
||||
|| params_changed
|
||||
) {
|
||||
std::string localized_str = Localization::get(Ruby::mrb, key, params);
|
||||
if (text_id != UINT64_MAX)
|
||||
@@ -119,6 +109,7 @@ private:
|
||||
Color last_color = color;
|
||||
Localization::LanguageCode last_language = UINT32_MAX;
|
||||
Localization::Key last_key = UINT16_MAX;
|
||||
bool params_changed = true;
|
||||
};
|
||||
|
||||
struct ERect : Element {
|
||||
|
||||
+101
-24
@@ -16,6 +16,59 @@ inline mrb_value wrap(mrb_state *mrb, RClass *cls, const mrb_data_type *type, ui
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void Params_free(mrb_state *mrb, void *ptr) {
|
||||
UNUSED(mrb);
|
||||
uint64_t id = ((Wrapper *)ptr)->id;
|
||||
app::element_pool.release(id);
|
||||
delete (Wrapper *)ptr;
|
||||
}
|
||||
|
||||
static const struct mrb_data_type Params_type = {"Params", Params_free};
|
||||
|
||||
static mrb_value Params_init(mrb_state *mrb, mrb_value self) {
|
||||
Wrapper *old = (Wrapper *)DATA_PTR(self);
|
||||
if (old)
|
||||
mrb_free(mrb, old);
|
||||
mrb_data_init(self, nullptr, &Params_type);
|
||||
Wrapper *s = new Wrapper();
|
||||
|
||||
mrb_int id;
|
||||
mrb_get_args(mrb, "z", &id);
|
||||
|
||||
s->id = id;
|
||||
|
||||
mrb_data_init(self, s, &Params_type);
|
||||
return self;
|
||||
}
|
||||
|
||||
static mrb_value params_get(mrb_state *mrb, mrb_value self) {
|
||||
mrb_sym key;
|
||||
mrb_get_args(mrb, "n", &key);
|
||||
|
||||
uint64_t id = ((Wrapper *)DATA_PTR(self))->id;
|
||||
app::element_pool.use(id);
|
||||
app::EText *element = (app::EText *)app::element_pool[id];
|
||||
|
||||
auto it = element->params.find(mrb_sym2name(mrb, key));
|
||||
if (it == element->params.end())
|
||||
return mrb_nil_value();
|
||||
return mrb_str_new_cstr(mrb, it->second.c_str());
|
||||
}
|
||||
|
||||
static mrb_value params_set(mrb_state *mrb, mrb_value self) {
|
||||
mrb_sym key;
|
||||
mrb_value value;
|
||||
mrb_get_args(mrb, "no", &key, &value);
|
||||
|
||||
uint64_t id = ((Wrapper *)DATA_PTR(self))->id;
|
||||
app::element_pool.use(id);
|
||||
app::EText *element = (app::EText *)app::element_pool[id];
|
||||
|
||||
element->params[mrb_sym2name(mrb, key)] = mrb_str_to_cstr(mrb, mrb_obj_as_string(mrb, value));
|
||||
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
static void Font_free(mrb_state *mrb, void *ptr) {
|
||||
UNUSED(mrb);
|
||||
uint64_t id = ((Wrapper *)ptr)->id;
|
||||
@@ -26,7 +79,6 @@ static void Font_free(mrb_state *mrb, void *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);
|
||||
@@ -89,7 +141,6 @@ static void Image_free(mrb_state *mrb, void *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);
|
||||
@@ -156,7 +207,6 @@ static const struct mrb_data_type Animation_type = {
|
||||
};
|
||||
|
||||
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);
|
||||
@@ -202,6 +252,31 @@ inline uint64_t get_id_Animation(mrb_state *mrb, mrb_value self) {
|
||||
return wrapper->id;
|
||||
}
|
||||
|
||||
static 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, mrb_class_get(mrb, "Image"))) {
|
||||
mrb_raise(
|
||||
mrb,
|
||||
mrb_class_get(mrb, "Exception"),
|
||||
"Expected an Image object"
|
||||
);
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
uint64_t frame_id = get_id_Image(mrb, image_val);
|
||||
image_pool.use(frame_id);
|
||||
|
||||
std::vector<uint64_t> frames = {frame_id};
|
||||
Animation *animation = new Animation{frames, 1.0f};
|
||||
Wrapper *s = new Wrapper();
|
||||
s->id = animation_pool.acquire(animation);
|
||||
animation_pool.use(s->id);
|
||||
|
||||
return wrap(mrb, mrb_class_get(mrb, "Animation"), &Animation_type, s->id);
|
||||
}
|
||||
|
||||
static mrb_value animation_equal(mrb_state *mrb, mrb_value self) {
|
||||
mrb_value other;
|
||||
mrb_get_args(mrb, "o", &other);
|
||||
@@ -296,7 +371,6 @@ static const struct mrb_data_type ElementText_type = {
|
||||
};
|
||||
|
||||
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);
|
||||
@@ -358,7 +432,18 @@ static mrb_value ElementText_init(mrb_state *mrb, mrb_value self) {
|
||||
(uint8_t)((color_i) & 0xFF)
|
||||
};
|
||||
|
||||
app::EText *element = new app::EText(key_id, id, color, t_args);
|
||||
std::unordered_map<std::string, std::string> params;
|
||||
if (!mrb_nil_p(t_args)) {
|
||||
mrb_value keys = mrb_hash_keys(mrb, t_args);
|
||||
for (mrb_int i = 0; i < RARRAY_LEN(keys); i++) {
|
||||
mrb_value key = RARRAY_PTR(keys)[i];
|
||||
mrb_value val = mrb_hash_get(mrb, t_args, key);
|
||||
params[mrb_str_to_cstr(mrb, mrb_obj_as_string(mrb, key))] =
|
||||
mrb_str_to_cstr(mrb, mrb_obj_as_string(mrb, val));
|
||||
}
|
||||
}
|
||||
|
||||
app::EText *element = new app::EText(key_id, id, color, params);
|
||||
element->position = {x, y};
|
||||
element->scale = {scale_x, scale_y};
|
||||
element->rotation = rotation;
|
||||
@@ -459,6 +544,12 @@ static mrb_value element_text_font_get(mrb_state *mrb, mrb_value self) {
|
||||
return wrap(mrb, mrb_class_get(mrb, "Font"), &Font_type, element->font_id);
|
||||
}
|
||||
|
||||
static mrb_value element_text_params(mrb_state *mrb, mrb_value self) {
|
||||
uint64_t id = get_id_ElementText(mrb, self);
|
||||
app::element_pool.use(id);
|
||||
return wrap(mrb, mrb_class_get(mrb, "Params"), &Params_type, id);
|
||||
}
|
||||
|
||||
static mrb_value element_text_font_set(mrb_state *mrb, mrb_value self) {
|
||||
mrb_value font_val;
|
||||
mrb_get_args(mrb, "o", &font_val);
|
||||
@@ -501,19 +592,6 @@ static mrb_value element_text_color_set(mrb_state *mrb, mrb_value self) {
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
static mrb_value element_text_params(mrb_state *mrb, mrb_value self) {
|
||||
uint64_t id = get_id_ElementText(mrb, self);
|
||||
app::EText *element = (app::EText *)app::element_pool[id];
|
||||
return element->params;
|
||||
}
|
||||
|
||||
static mrb_value element_text_params_load(mrb_state *mrb, mrb_value self) {
|
||||
uint64_t id = get_id_ElementText(mrb, self);
|
||||
app::EText *element = (app::EText *)app::element_pool[id];
|
||||
element->reload_params();
|
||||
return mrb_nil_value();
|
||||
}
|
||||
|
||||
static mrb_value element_text_position_get(mrb_state *mrb, mrb_value self) {
|
||||
uint64_t id = get_id_ElementText(mrb, self);
|
||||
app::EText *element = (app::EText *)app::element_pool[id];
|
||||
@@ -695,7 +773,6 @@ static const struct mrb_data_type ElementRect_type = {
|
||||
};
|
||||
|
||||
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);
|
||||
@@ -1042,7 +1119,6 @@ static const struct mrb_data_type ElementImage_type = {
|
||||
};
|
||||
|
||||
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);
|
||||
@@ -1371,7 +1447,6 @@ static void Scene_free(mrb_state *mrb, void *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);
|
||||
@@ -1633,7 +1708,6 @@ static mrb_value app_current_scene(mrb_state *mrb, mrb_value) {
|
||||
uint64_t id = app_->current_scene_id;
|
||||
if (id == UINT64_MAX)
|
||||
return mrb_nil_value();
|
||||
app::Scene *scene = app::scene_pool[id];
|
||||
app::scene_pool.use(id);
|
||||
return wrap(mrb, mrb_class_get(mrb, "Scene"), &Scene_type, id);
|
||||
}
|
||||
@@ -1762,6 +1836,10 @@ static mrb_value app_exit(mrb_state *, mrb_value) {
|
||||
}
|
||||
|
||||
inline void setup() {
|
||||
DEF_CLASS(Params, MRB_ARGS_REQ(1));
|
||||
ADD_METHOD(Params, "[]", params_get, MRB_ARGS_REQ(1));
|
||||
ADD_METHOD(Params, "[]=", params_set, MRB_ARGS_REQ(2));
|
||||
|
||||
DEF_CLASS(Font, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1));
|
||||
ADD_METHOD(Font, "==", font_equal, MRB_ARGS_REQ(1));
|
||||
ADD_METHOD(Font, "eql?", font_equal, MRB_ARGS_REQ(1));
|
||||
@@ -1775,6 +1853,7 @@ inline void setup() {
|
||||
ADD_METHOD(Image, "height", image_height, MRB_ARGS_NONE());
|
||||
|
||||
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());
|
||||
@@ -1796,9 +1875,7 @@ inline void setup() {
|
||||
ADD_METHOD(ElementText, "color", element_text_color_get, MRB_ARGS_NONE());
|
||||
ADD_METHOD(ElementText, "font=", element_text_font_set, MRB_ARGS_REQ(1));
|
||||
ADD_METHOD(ElementText, "font", element_text_font_get, MRB_ARGS_NONE());
|
||||
#warning "Make text params a proper class instead of using a hash for text params"
|
||||
ADD_METHOD(ElementText, "params", element_text_params, MRB_ARGS_NONE());
|
||||
ADD_METHOD(ElementText, "params!", element_text_params_load, MRB_ARGS_NONE());
|
||||
#warning "Make vector a proper class instead of using a hash for vectors"
|
||||
ADD_METHOD(ElementText, "position=", element_text_position_set, MRB_ARGS_REQ(1));
|
||||
ADD_METHOD(ElementText, "position", element_text_position_get, MRB_ARGS_NONE());
|
||||
|
||||
@@ -35,9 +35,15 @@ struct Wrapper {
|
||||
uint64_t id;
|
||||
};
|
||||
|
||||
#define ADD_FUNCTION(NAME, FUNC, ARGS) \
|
||||
mrb_define_method(Ruby::mrb, Ruby::mrb->object_class, NAME, FUNC, ARGS);
|
||||
|
||||
#define ADD_METHOD(NAME, METHOD, FUNC, ARGS) \
|
||||
mrb_define_method(Ruby::mrb, NAME##_class, METHOD, FUNC, ARGS);
|
||||
|
||||
#define ADD_CLASS_METHOD(CLASS, METHOD, FUNC, ARGS) \
|
||||
mrb_define_class_method(Ruby::mrb, CLASS##_class, METHOD, FUNC, ARGS);
|
||||
|
||||
#define DEF_CLASS(NAME, ARGS) \
|
||||
RClass *NAME##_class = mrb_define_class(Ruby::mrb, #NAME, Ruby::mrb->object_class); \
|
||||
MRB_SET_INSTANCE_TT(NAME##_class, MRB_TT_CDATA); \
|
||||
|
||||
@@ -71,7 +71,7 @@ inline void set(LanguageCode lang_code, Key key, const std::string &text) {
|
||||
localized_strings[join_keys(lang_code, key)] = parse_localized(text);
|
||||
}
|
||||
|
||||
inline std::string get(mrb_state *mrb, Key key, mrb_value hash) {
|
||||
inline std::string get(mrb_state *mrb, Key key, const std::unordered_map<std::string, std::string> ¶ms) {
|
||||
auto it = localized_strings.find(join_keys(current_language, key));
|
||||
if (it == localized_strings.end())
|
||||
return "Localization not set!";
|
||||
@@ -85,15 +85,12 @@ inline std::string get(mrb_state *mrb, Key key, mrb_value hash) {
|
||||
if (!seg.is_var) {
|
||||
result += seg.text;
|
||||
} else {
|
||||
mrb_sym sym = get_var_sym(mrb, seg.text);
|
||||
if (mrb_nil_p(hash) || mrb_nil_p(mrb_hash_get(mrb, hash, mrb_symbol_value(sym)))) {
|
||||
auto param_it = params.find(seg.text);
|
||||
if (param_it == params.end()) {
|
||||
result += "%{" + seg.text + "}";
|
||||
continue;
|
||||
}
|
||||
mrb_value val = mrb_hash_get(mrb, hash, mrb_symbol_value(sym));
|
||||
if (mrb_nil_p(val))
|
||||
continue;
|
||||
result += mrb_str_to_cstr(mrb, val);
|
||||
result += param_it->second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user