Fix major incorrect usage of mrb class definitions causing segfaults
This commit is contained in:
@@ -24,7 +24,7 @@ CFLAGS_DEBUG := \
|
|||||||
-std=c++20 -Wall -Wextra \
|
-std=c++20 -Wall -Wextra \
|
||||||
-O0 -g -fno-omit-frame-pointer \
|
-O0 -g -fno-omit-frame-pointer \
|
||||||
-Wno-unused-command-line-argument \
|
-Wno-unused-command-line-argument \
|
||||||
-I./include \
|
-I./include -I./libs/mruby/include \
|
||||||
$(SDL_CFLAGS)
|
$(SDL_CFLAGS)
|
||||||
|
|
||||||
CFLAGS_RELEASE := \
|
CFLAGS_RELEASE := \
|
||||||
@@ -32,7 +32,7 @@ CFLAGS_RELEASE := \
|
|||||||
-flto=thin \
|
-flto=thin \
|
||||||
-fno-rtti -fomit-frame-pointer -DNDEBUG -s \
|
-fno-rtti -fomit-frame-pointer -DNDEBUG -s \
|
||||||
-Wno-unused-command-line-argument \
|
-Wno-unused-command-line-argument \
|
||||||
-I./include \
|
-I./include -I./libs/mruby/include \
|
||||||
$(SDL_CFLAGS)
|
$(SDL_CFLAGS)
|
||||||
|
|
||||||
PCH_CFLAGS_DEBUG := $(CFLAGS_DEBUG) -x c++-header
|
PCH_CFLAGS_DEBUG := $(CFLAGS_DEBUG) -x c++-header
|
||||||
|
|||||||
+12
-35
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
namespace app {
|
namespace app {
|
||||||
struct Element {
|
struct Element {
|
||||||
int reference_count = 0;
|
|
||||||
Vec2<float> position = {0, 0};
|
Vec2<float> position = {0, 0};
|
||||||
float rotation = 0;
|
float rotation = 0;
|
||||||
Vec2<float> scale = {1, 1};
|
Vec2<float> scale = {1, 1};
|
||||||
@@ -21,11 +20,8 @@ struct Element {
|
|||||||
virtual Vec2<float> size(Window *window) = 0;
|
virtual Vec2<float> size(Window *window) = 0;
|
||||||
|
|
||||||
void click() {
|
void click() {
|
||||||
if (!mrb_nil_p(on_click.proc)) {
|
if (!mrb_nil_p(on_click.proc))
|
||||||
int x = mrb_gc_arena_save(Ruby::mrb);
|
|
||||||
on_click.call();
|
on_click.call();
|
||||||
mrb_gc_arena_restore(Ruby::mrb, x);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -93,21 +89,15 @@ struct ERect : Element {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Pool<Element *> element_pool;
|
inline Pool<Element> element_pool;
|
||||||
|
|
||||||
struct Scene {
|
struct Scene {
|
||||||
bool unused = false;
|
|
||||||
std::vector<int> element_ids;
|
std::vector<int> element_ids;
|
||||||
Ruby::Block update;
|
Ruby::Block update;
|
||||||
|
|
||||||
~Scene() {
|
~Scene() {
|
||||||
for (const int &id : element_ids) {
|
for (const int &id : element_ids)
|
||||||
element_pool[id]->reference_count--;
|
element_pool.release(id);
|
||||||
if (element_pool[id]->reference_count <= 0) {
|
|
||||||
delete element_pool[id];
|
|
||||||
element_pool.release(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_element(int element_id) {
|
void add_element(int element_id) {
|
||||||
@@ -116,31 +106,27 @@ struct Scene {
|
|||||||
element_ids.end(),
|
element_ids.end(),
|
||||||
element_id,
|
element_id,
|
||||||
[](auto &a, auto &b) {
|
[](auto &a, auto &b) {
|
||||||
return element_pool[a]->z < element_pool[b]->z || (element_pool[a]->z == element_pool[b]->z && a < b);
|
auto e_a = element_pool[a];
|
||||||
|
auto e_b = element_pool[b];
|
||||||
|
return e_a->z < e_b->z || (e_a->z == e_b->z && a < b);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
element_pool[element_id]->reference_count++;
|
element_pool.use(element_id);
|
||||||
element_ids.insert(it, element_id);
|
element_ids.insert(it, element_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void delete_element(int element_id) {
|
void delete_element(int element_id) {
|
||||||
auto it = std::find(element_ids.begin(), element_ids.end(), element_id);
|
auto it = std::find(element_ids.begin(), element_ids.end(), element_id);
|
||||||
if (it != element_ids.end()) {
|
if (it != element_ids.end()) {
|
||||||
element_pool[element_id]->reference_count--;
|
element_pool.release(element_id);
|
||||||
if (element_pool[element_id]->reference_count <= 0) {
|
|
||||||
delete element_pool[element_id];
|
|
||||||
element_pool.release(element_id);
|
|
||||||
}
|
|
||||||
element_ids.erase(it);
|
element_ids.erase(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_scene(uint64_t delta_time) {
|
void update_scene(uint64_t delta_time) {
|
||||||
if (!mrb_nil_p(update.proc)) {
|
if (!mrb_nil_p(update.proc)) {
|
||||||
int x = mrb_gc_arena_save(Ruby::mrb);
|
|
||||||
mrb_value dt_val = mrb_int_value(Ruby::mrb, delta_time);
|
mrb_value dt_val = mrb_int_value(Ruby::mrb, delta_time);
|
||||||
update.call(1, &dt_val);
|
update.call(1, &dt_val);
|
||||||
mrb_gc_arena_restore(Ruby::mrb, x);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,24 +151,15 @@ struct Scene {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Pool<Scene *> scene_pool;
|
inline Pool<Scene> scene_pool;
|
||||||
|
|
||||||
struct App {
|
struct App {
|
||||||
int current_scene_id = 0;
|
int current_scene_id = 0;
|
||||||
bool running = true;
|
bool running = true;
|
||||||
|
|
||||||
void switch_to_scene(int scene_id) {
|
void switch_to_scene(int scene_id) {
|
||||||
int scene_pool_size = (int)scene_pool.all().size();
|
scene_pool.release(current_scene_id);
|
||||||
for (int i = 0; i < scene_pool_size; ++i) {
|
scene_pool.use(scene_id);
|
||||||
auto &val = scene_pool[i];
|
|
||||||
if (i == scene_id && val != nullptr && val->unused)
|
|
||||||
val->unused = false;
|
|
||||||
if (val != nullptr && val->unused) {
|
|
||||||
delete val;
|
|
||||||
scene_pool.release(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
current_scene_id = scene_id;
|
current_scene_id = scene_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+215
-49
@@ -27,17 +27,63 @@ DEF_RB(
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
|
DEF_RB(
|
||||||
|
Image,
|
||||||
|
({ window.unload_image(id); }),
|
||||||
|
({
|
||||||
|
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);
|
||||||
|
#warning "Fix lifetimes for images/fonts right now they'll always exist"
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
DEF_RB(
|
||||||
|
Animation,
|
||||||
|
({
|
||||||
|
animation_pool.release(id);
|
||||||
|
}),
|
||||||
|
({
|
||||||
|
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<int> 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);
|
||||||
|
window.use_image(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);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
DEF_RB(
|
DEF_RB(
|
||||||
ElementText,
|
ElementText,
|
||||||
({
|
({
|
||||||
app::Element *element = app::element_pool[id];
|
app::element_pool.release(id);
|
||||||
if (element != nullptr)
|
|
||||||
element->reference_count--;
|
|
||||||
|
|
||||||
if (element != nullptr && element->reference_count <= 0) {
|
|
||||||
delete element;
|
|
||||||
app::element_pool.release(id);
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
({
|
({
|
||||||
mrb_value font_val;
|
mrb_value font_val;
|
||||||
@@ -48,7 +94,7 @@ DEF_RB(
|
|||||||
auto key_id = Localization::key_from_sym(mrb, key);
|
auto key_id = Localization::key_from_sym(mrb, key);
|
||||||
|
|
||||||
if (!mrb_obj_is_kind_of(mrb, font_val, mrb_class_get(mrb, "Font"))) {
|
if (!mrb_obj_is_kind_of(mrb, font_val, mrb_class_get(mrb, "Font"))) {
|
||||||
mrb_raise(mrb, mrb_class_get(Ruby::mrb, "Exception"), "Expected a Font object");
|
mrb_raise(mrb, mrb_class_get(mrb, "Exception"), "Expected a Font object");
|
||||||
return mrb_nil_value();
|
return mrb_nil_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,29 +113,32 @@ DEF_RB(
|
|||||||
|
|
||||||
Vec2<float> position = {x, y};
|
Vec2<float> position = {x, y};
|
||||||
|
|
||||||
int id = get_id(font_val);
|
int id = get_id_Font(mrb, font_val);
|
||||||
|
window.use_font(id);
|
||||||
|
|
||||||
app::EText *element = new app::EText(key_id, id, {255, 255, 255, 255});
|
app::EText *element = new app::EText(key_id, id, {255, 255, 255, 255});
|
||||||
element->reference_count++;
|
|
||||||
element->position = position;
|
element->position = position;
|
||||||
element->z = z;
|
element->z = z;
|
||||||
element->click_through = click_through;
|
element->click_through = click_through;
|
||||||
|
|
||||||
s->id = app::element_pool.acquire(element);
|
s->id = app::element_pool.acquire(element);
|
||||||
|
app::element_pool.use(s->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;
|
||||||
|
}
|
||||||
|
|
||||||
DEF_RB(
|
DEF_RB(
|
||||||
ElementRect,
|
ElementRect,
|
||||||
({
|
({
|
||||||
app::Element *element = app::element_pool[id];
|
app::element_pool.release(id);
|
||||||
if (element != nullptr)
|
|
||||||
element->reference_count--;
|
|
||||||
|
|
||||||
if (element != nullptr && element->reference_count <= 0) {
|
|
||||||
delete element;
|
|
||||||
app::element_pool.release(id);
|
|
||||||
}
|
|
||||||
}),
|
}),
|
||||||
({
|
({
|
||||||
mrb_value shape_val;
|
mrb_value shape_val;
|
||||||
@@ -119,18 +168,27 @@ DEF_RB(
|
|||||||
(uint8_t)((color >> 8) & 0xFF),
|
(uint8_t)((color >> 8) & 0xFF),
|
||||||
(uint8_t)(color & 0xFF)}
|
(uint8_t)(color & 0xFF)}
|
||||||
);
|
);
|
||||||
element->reference_count++;
|
|
||||||
element->position = position;
|
element->position = position;
|
||||||
element->z = z;
|
element->z = z;
|
||||||
|
|
||||||
s->id = app::element_pool.acquire(element);
|
s->id = app::element_pool.acquire(element);
|
||||||
|
app::element_pool.use(s->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) {
|
static mrb_value element_rect_color_set(mrb_state *mrb, mrb_value self) {
|
||||||
mrb_value color_val;
|
mrb_value color_val;
|
||||||
mrb_get_args(mrb, "o", &color_val);
|
mrb_get_args(mrb, "o", &color_val);
|
||||||
int id = get_id(self);
|
int id = get_id_ElementRect(mrb, self);
|
||||||
app::ERect *element = (app::ERect *)app::element_pool[id];
|
app::ERect *element = (app::ERect *)app::element_pool[id];
|
||||||
element->color = {
|
element->color = {
|
||||||
(uint8_t)((mrb_fixnum(color_val) >> 24) & 0xFF),
|
(uint8_t)((mrb_fixnum(color_val) >> 24) & 0xFF),
|
||||||
@@ -141,17 +199,8 @@ static mrb_value element_rect_color_set(mrb_state *mrb, mrb_value self) {
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static mrb_value element_on_click(mrb_state *mrb, mrb_value self) {
|
static mrb_value element_rect_color_get(mrb_state *mrb, mrb_value self) {
|
||||||
mrb_value block;
|
int id = get_id_ElementRect(mrb, self);
|
||||||
mrb_get_args(mrb, "&", &block);
|
|
||||||
int id = get_id(self);
|
|
||||||
app::Element *element = app::element_pool[id];
|
|
||||||
element->on_click.set_proc(block);
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
static mrb_value element_rect_color_get(mrb_state *, mrb_value self) {
|
|
||||||
int id = get_id(self);
|
|
||||||
app::ERect *element = (app::ERect *)app::element_pool[id];
|
app::ERect *element = (app::ERect *)app::element_pool[id];
|
||||||
uint32_t color = ((uint32_t)element->color.r << 24)
|
uint32_t color = ((uint32_t)element->color.r << 24)
|
||||||
| ((uint32_t)element->color.g << 16)
|
| ((uint32_t)element->color.g << 16)
|
||||||
@@ -160,16 +209,65 @@ static mrb_value element_rect_color_get(mrb_state *, mrb_value self) {
|
|||||||
return mrb_fixnum_value(color);
|
return mrb_fixnum_value(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEF_RB(
|
||||||
|
ElementImage,
|
||||||
|
({
|
||||||
|
app::element_pool.release(id);
|
||||||
|
}),
|
||||||
|
({
|
||||||
|
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);
|
||||||
|
Animation *animation = animation_pool[id];
|
||||||
|
|
||||||
|
app::EImage *element = new app::EImage(*animation);
|
||||||
|
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);
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
DEF_RB(
|
DEF_RB(
|
||||||
Scene,
|
Scene,
|
||||||
({
|
({
|
||||||
app::Scene *scene = app::scene_pool[id];
|
app::scene_pool.release(id);
|
||||||
if (scene != nullptr)
|
|
||||||
scene->unused = true;
|
|
||||||
}),
|
}),
|
||||||
({
|
({
|
||||||
app::Scene *loading_scene = new app::Scene{};
|
app::Scene *loading_scene = new app::Scene{};
|
||||||
s->id = app::scene_pool.acquire(loading_scene);
|
s->id = app::scene_pool.acquire(loading_scene);
|
||||||
|
app::scene_pool.use(s->id);
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -180,23 +278,75 @@ static mrb_value scene_add_element(mrb_state *mrb, mrb_value self) {
|
|||||||
if (
|
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, "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, "ElementRect"))
|
||||||
|
&& !mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementImage"))
|
||||||
) {
|
) {
|
||||||
mrb_raise(mrb, mrb_class_get(Ruby::mrb, "Exception"), "Expected an ElementText or ElementRect object");
|
mrb_raise(mrb, mrb_class_get(mrb, "Exception"), "Expected an ElementText, ElementRect, or ElementImage object");
|
||||||
return mrb_nil_value();
|
return mrb_nil_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
int id = get_id(self);
|
int id = get_id_Scene(mrb, self);
|
||||||
|
app::Scene *scene = app::scene_pool[id];
|
||||||
|
|
||||||
|
// int element_id = get_id_Element(mrb, element_val);
|
||||||
|
|
||||||
|
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];
|
app::Scene *scene = app::scene_pool[id];
|
||||||
|
|
||||||
int element_id;
|
int element_id;
|
||||||
if (
|
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, "ElementText"))
|
element_id = get_id_ElementText(mrb, element_val);
|
||||||
|| mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementRect"))
|
} else if (mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementRect"))) {
|
||||||
) {
|
element_id = get_id_ElementRect(mrb, element_val);
|
||||||
element_id = get_id(element_val);
|
} else if (mrb_obj_is_kind_of(mrb, element_val, mrb_class_get(mrb, "ElementImage"))) {
|
||||||
scene->add_element(element_id);
|
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;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,12 +373,13 @@ static mrb_value app_start(mrb_state *mrb, mrb_value) {
|
|||||||
mrb_get_args(mrb, "o", &scene_val);
|
mrb_get_args(mrb, "o", &scene_val);
|
||||||
|
|
||||||
if (!mrb_obj_is_kind_of(mrb, scene_val, mrb_class_get(mrb, "Scene"))) {
|
if (!mrb_obj_is_kind_of(mrb, scene_val, mrb_class_get(mrb, "Scene"))) {
|
||||||
mrb_raise(mrb, mrb_class_get(Ruby::mrb, "Exception"), "Expected a Scene object");
|
mrb_raise(mrb, mrb_class_get(mrb, "Exception"), "Expected a Scene object");
|
||||||
return mrb_nil_value();
|
return mrb_nil_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
int id = get_id(scene_val);
|
int id = get_id_Scene(mrb, scene_val);
|
||||||
app_->switch_to_scene(id);
|
app_->switch_to_scene(id);
|
||||||
|
|
||||||
app_->loop();
|
app_->loop();
|
||||||
|
|
||||||
return mrb_nil_value();
|
return mrb_nil_value();
|
||||||
@@ -239,11 +390,11 @@ static mrb_value app_switch_to(mrb_state *mrb, mrb_value) {
|
|||||||
mrb_get_args(mrb, "o", &scene_val);
|
mrb_get_args(mrb, "o", &scene_val);
|
||||||
|
|
||||||
if (!mrb_obj_is_kind_of(mrb, scene_val, mrb_class_get(mrb, "Scene"))) {
|
if (!mrb_obj_is_kind_of(mrb, scene_val, mrb_class_get(mrb, "Scene"))) {
|
||||||
mrb_raise(mrb, mrb_class_get(Ruby::mrb, "Exception"), "Expected a Scene object");
|
mrb_raise(mrb, mrb_class_get(mrb, "Exception"), "Expected a Scene object");
|
||||||
return mrb_nil_value();
|
return mrb_nil_value();
|
||||||
}
|
}
|
||||||
|
|
||||||
int id = get_id(scene_val);
|
int id = get_id_Scene(mrb, scene_val);
|
||||||
app_->switch_to_scene(id);
|
app_->switch_to_scene(id);
|
||||||
|
|
||||||
return mrb_nil_value();
|
return mrb_nil_value();
|
||||||
@@ -284,11 +435,15 @@ static mrb_value app_language_set(mrb_state *mrb, mrb_value) {
|
|||||||
inline void setup() {
|
inline void setup() {
|
||||||
DEF_CLASS(Font, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1));
|
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));
|
DEF_CLASS(ElementText, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1));
|
||||||
ADD_METHOD(
|
ADD_METHOD(
|
||||||
ElementText,
|
ElementText,
|
||||||
"on_click",
|
"on_click",
|
||||||
element_on_click,
|
element_text_on_click,
|
||||||
MRB_ARGS_BLOCK()
|
MRB_ARGS_BLOCK()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -296,7 +451,7 @@ inline void setup() {
|
|||||||
ADD_METHOD(
|
ADD_METHOD(
|
||||||
ElementRect,
|
ElementRect,
|
||||||
"on_click",
|
"on_click",
|
||||||
element_on_click,
|
element_rect_on_click,
|
||||||
MRB_ARGS_BLOCK()
|
MRB_ARGS_BLOCK()
|
||||||
);
|
);
|
||||||
ADD_METHOD(
|
ADD_METHOD(
|
||||||
@@ -312,8 +467,19 @@ inline void setup() {
|
|||||||
MRB_ARGS_NONE()
|
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());
|
DEF_CLASS(Scene, MRB_ARGS_NONE());
|
||||||
ADD_METHOD(Scene, "<<", scene_add_element, MRB_ARGS_REQ(1));
|
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);
|
DEF_MODULE(App);
|
||||||
ADD_MODULE_METHOD(App, "run", app_run, MRB_ARGS_REQ(3));
|
ADD_MODULE_METHOD(App, "run", app_run, MRB_ARGS_REQ(3));
|
||||||
|
|||||||
+23
-10
@@ -12,8 +12,12 @@
|
|||||||
#define HASH_FLOAT(h, key, out) \
|
#define HASH_FLOAT(h, key, out) \
|
||||||
do { \
|
do { \
|
||||||
mrb_value v = HASH_GET(h, key); \
|
mrb_value v = HASH_GET(h, key); \
|
||||||
if (mrb_fixnum_p(v)) \
|
if (mrb_float_p(v)) \
|
||||||
|
out = mrb_float(v); \
|
||||||
|
else if (mrb_fixnum_p(v)) \
|
||||||
out = (float)mrb_fixnum(v); \
|
out = (float)mrb_fixnum(v); \
|
||||||
|
else \
|
||||||
|
out = 0; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define HASH_BOOL(h, key, out) \
|
#define HASH_BOOL(h, key, out) \
|
||||||
@@ -40,11 +44,19 @@ struct Wrapper {
|
|||||||
}; \
|
}; \
|
||||||
static mrb_value NAME##_init(mrb_state *mrb, mrb_value self) { \
|
static mrb_value NAME##_init(mrb_state *mrb, mrb_value self) { \
|
||||||
UNUSED(mrb); \
|
UNUSED(mrb); \
|
||||||
|
Wrapper *old = (Wrapper *)DATA_PTR(self); \
|
||||||
|
if (old) \
|
||||||
|
mrb_free(mrb, old); \
|
||||||
|
mrb_data_init(self, nullptr, &NAME##_type); \
|
||||||
Wrapper *s = new Wrapper(); \
|
Wrapper *s = new Wrapper(); \
|
||||||
FN_INIT; \
|
FN_INIT; \
|
||||||
DATA_PTR(self) = s; \
|
mrb_data_init(self, s, &NAME##_type); \
|
||||||
DATA_TYPE(self) = &NAME##_type; \
|
|
||||||
return self; \
|
return self; \
|
||||||
|
} \
|
||||||
|
inline int get_id_##NAME(mrb_state *mrb, mrb_value self) { \
|
||||||
|
Wrapper *wrapper; \
|
||||||
|
Data_Get_Struct(mrb, self, &NAME##_type, wrapper); \
|
||||||
|
return wrapper->id; \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ADD_METHOD(NAME, METHOD, FUNC, ARGS) \
|
#define ADD_METHOD(NAME, METHOD, FUNC, ARGS) \
|
||||||
@@ -52,6 +64,7 @@ struct Wrapper {
|
|||||||
|
|
||||||
#define DEF_CLASS(NAME, ARGS) \
|
#define DEF_CLASS(NAME, ARGS) \
|
||||||
RClass *NAME##_class = mrb_define_class(Ruby::mrb, #NAME, Ruby::mrb->object_class); \
|
RClass *NAME##_class = mrb_define_class(Ruby::mrb, #NAME, Ruby::mrb->object_class); \
|
||||||
|
MRB_SET_INSTANCE_TT(NAME##_class, MRB_TT_CDATA); \
|
||||||
ADD_METHOD(NAME, "initialize", NAME##_init, ARGS);
|
ADD_METHOD(NAME, "initialize", NAME##_init, ARGS);
|
||||||
|
|
||||||
#define DEF_MODULE(NAME) \
|
#define DEF_MODULE(NAME) \
|
||||||
@@ -60,10 +73,6 @@ struct Wrapper {
|
|||||||
#define ADD_MODULE_METHOD(MODULE, METHOD, FUNC, ARGS) \
|
#define ADD_MODULE_METHOD(MODULE, METHOD, FUNC, ARGS) \
|
||||||
mrb_define_class_method(Ruby::mrb, MODULE##_module, METHOD, FUNC, ARGS);
|
mrb_define_class_method(Ruby::mrb, MODULE##_module, METHOD, FUNC, ARGS);
|
||||||
|
|
||||||
inline int get_id(mrb_value self) {
|
|
||||||
return ((Wrapper *)DATA_PTR(self))->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace Ruby {
|
namespace Ruby {
|
||||||
inline mrb_state *mrb = mrb_open();
|
inline mrb_state *mrb = mrb_open();
|
||||||
|
|
||||||
@@ -71,7 +80,7 @@ struct Block {
|
|||||||
mrb_value proc;
|
mrb_value proc;
|
||||||
|
|
||||||
Block(mrb_value proc) : proc(proc) {
|
Block(mrb_value proc) : proc(proc) {
|
||||||
mrb_gc_register(mrb, proc);
|
mrb_gc_protect(mrb, proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
Block() : proc(mrb_nil_value()) {}
|
Block() : proc(mrb_nil_value()) {}
|
||||||
@@ -81,7 +90,7 @@ struct Block {
|
|||||||
mrb_gc_unregister(mrb, proc);
|
mrb_gc_unregister(mrb, proc);
|
||||||
proc = new_proc;
|
proc = new_proc;
|
||||||
if (!mrb_nil_p(proc))
|
if (!mrb_nil_p(proc))
|
||||||
mrb_gc_register(mrb, proc);
|
mrb_gc_protect(mrb, proc);
|
||||||
}
|
}
|
||||||
|
|
||||||
Block(const Block &) = delete;
|
Block(const Block &) = delete;
|
||||||
@@ -90,7 +99,8 @@ struct Block {
|
|||||||
mrb_value call(int argc = 0, mrb_value *argv = nullptr) const {
|
mrb_value call(int argc = 0, mrb_value *argv = nullptr) const {
|
||||||
if (mrb_nil_p(proc))
|
if (mrb_nil_p(proc))
|
||||||
return mrb_nil_value();
|
return mrb_nil_value();
|
||||||
return mrb_funcall(mrb, proc, "call", argc, argv);
|
mrb_value result = mrb_funcall_argv(mrb, proc, mrb_intern_cstr(mrb, "call"), argc, argv);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
~Block() {
|
~Block() {
|
||||||
@@ -110,7 +120,10 @@ DEF_SYM(bold)
|
|||||||
DEF_SYM(italic)
|
DEF_SYM(italic)
|
||||||
DEF_SYM(underline)
|
DEF_SYM(underline)
|
||||||
DEF_SYM(position)
|
DEF_SYM(position)
|
||||||
|
DEF_SYM(alpha)
|
||||||
|
DEF_SYM(fps)
|
||||||
DEF_SYM(click_through)
|
DEF_SYM(click_through)
|
||||||
|
DEF_SYM(call)
|
||||||
DEF_SYM(x)
|
DEF_SYM(x)
|
||||||
DEF_SYM(y)
|
DEF_SYM(y)
|
||||||
DEF_SYM(w)
|
DEF_SYM(w)
|
||||||
|
|||||||
@@ -3,13 +3,29 @@
|
|||||||
|
|
||||||
#include "mruby.h"
|
#include "mruby.h"
|
||||||
#include "mruby/array.h"
|
#include "mruby/array.h"
|
||||||
|
#include "mruby/boxing_word.h"
|
||||||
|
#include "mruby/class.h"
|
||||||
|
#include "mruby/common.h"
|
||||||
#include "mruby/compile.h"
|
#include "mruby/compile.h"
|
||||||
#include "mruby/data.h"
|
#include "mruby/data.h"
|
||||||
|
#include "mruby/dump.h"
|
||||||
|
#include "mruby/error.h"
|
||||||
|
#include "mruby/gc.h"
|
||||||
#include "mruby/hash.h"
|
#include "mruby/hash.h"
|
||||||
|
#include "mruby/internal.h"
|
||||||
#include "mruby/irep.h"
|
#include "mruby/irep.h"
|
||||||
|
#include "mruby/numeric.h"
|
||||||
|
#include "mruby/object.h"
|
||||||
|
#include "mruby/opcode.h"
|
||||||
|
#include "mruby/presym.h"
|
||||||
|
#include "mruby/proc.h"
|
||||||
|
#include "mruby/range.h"
|
||||||
|
#include "mruby/re.h"
|
||||||
#include "mruby/string.h"
|
#include "mruby/string.h"
|
||||||
|
#include "mruby/throw.h"
|
||||||
#include "mruby/value.h"
|
#include "mruby/value.h"
|
||||||
#include "mruby/variable.h"
|
#include "mruby/variable.h"
|
||||||
|
#include "mruby/version.h"
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
#include <SDL3/SDL.h>
|
||||||
#include <SDL3/SDL_events.h>
|
#include <SDL3/SDL_events.h>
|
||||||
|
|||||||
+55
-22
@@ -152,38 +152,71 @@ struct Rect {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T = void *>
|
||||||
struct Pool {
|
struct Pool {
|
||||||
T &operator[](int index) {
|
T *operator[](int index) {
|
||||||
return items[index];
|
if (!is_valid(index)) {
|
||||||
}
|
fprintf(stderr, "Invalid pool index: %d\n", index);
|
||||||
|
return nullptr;
|
||||||
const std::vector<T> &all() {
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
int acquire(const T &item) {
|
|
||||||
if (!free_indices.empty()) {
|
|
||||||
int index = free_indices.back();
|
|
||||||
free_indices.pop_back();
|
|
||||||
items[index] = std::move(item);
|
|
||||||
return index;
|
|
||||||
} else {
|
|
||||||
items.push_back(std::move(item));
|
|
||||||
return items.size() - 1;
|
|
||||||
}
|
}
|
||||||
|
return slots[index].ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<T *> &all() {
|
||||||
|
static std::vector<T *> all_items;
|
||||||
|
all_items.clear();
|
||||||
|
for (const auto &slot : slots)
|
||||||
|
if (slot.alive)
|
||||||
|
all_items.push_back(slot.ptr);
|
||||||
|
return all_items;
|
||||||
|
}
|
||||||
|
|
||||||
|
int acquire(T *item) {
|
||||||
|
int index;
|
||||||
|
if (!free_indices.empty()) {
|
||||||
|
index = free_indices.back();
|
||||||
|
free_indices.pop_back();
|
||||||
|
} else {
|
||||||
|
index = slots.size();
|
||||||
|
slots.push_back({});
|
||||||
|
}
|
||||||
|
slots[index].ptr = item;
|
||||||
|
slots[index].refcount = 1;
|
||||||
|
slots[index].alive = true;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void use(int index) {
|
||||||
|
if (is_valid(index))
|
||||||
|
slots[index].refcount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void release(int index) {
|
void release(int index) {
|
||||||
free_indices.push_back(index);
|
if (!is_valid(index))
|
||||||
|
return;
|
||||||
|
auto &slot = slots[index];
|
||||||
|
slot.refcount--;
|
||||||
|
if (slot.refcount <= 0) {
|
||||||
|
delete slot.ptr;
|
||||||
|
slot.ptr = nullptr;
|
||||||
|
slot.alive = false;
|
||||||
|
free_indices.push_back(index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_valid(size_t index) const {
|
bool is_valid(int index) const {
|
||||||
return index >= 0 && index < items.size() && std::find(free_indices.begin(), free_indices.end(), index) == free_indices.end();
|
return index >= 0
|
||||||
|
&& index < (int)slots.size()
|
||||||
|
&& slots[index].alive;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<T> items;
|
struct Slot {
|
||||||
|
T *ptr = nullptr;
|
||||||
|
int refcount = 0;
|
||||||
|
bool alive = false;
|
||||||
|
};
|
||||||
|
std::vector<Slot> slots;
|
||||||
std::vector<int> free_indices;
|
std::vector<int> free_indices;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+11
-1
@@ -14,6 +14,11 @@ struct Font {
|
|||||||
bool pixel_art;
|
bool pixel_art;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Text {
|
||||||
|
SDL_Texture *texture;
|
||||||
|
Vec2<float> size;
|
||||||
|
};
|
||||||
|
|
||||||
struct Event {
|
struct Event {
|
||||||
enum Type {
|
enum Type {
|
||||||
NONE,
|
NONE,
|
||||||
@@ -57,8 +62,11 @@ struct Animation {
|
|||||||
std::vector<int> frames;
|
std::vector<int> frames;
|
||||||
float frame_rate;
|
float frame_rate;
|
||||||
bool loop;
|
bool loop;
|
||||||
|
int reference_count = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline Pool<Animation> animation_pool;
|
||||||
|
|
||||||
struct Window {
|
struct Window {
|
||||||
public:
|
public:
|
||||||
// title can be free'd by the caller after the window is created, as it's copied internally.
|
// title can be free'd by the caller after the window is created, as it's copied internally.
|
||||||
@@ -70,10 +78,12 @@ public:
|
|||||||
|
|
||||||
// Rendering functions
|
// Rendering functions
|
||||||
int load_image(const char *path, float alpha = 1.0f, bool pixel_art = false);
|
int load_image(const char *path, float alpha = 1.0f, bool pixel_art = false);
|
||||||
|
void use_image(int image_id);
|
||||||
void unload_image(int image_id);
|
void unload_image(int image_id);
|
||||||
Vec2<float> get_image_size(int image_id);
|
Vec2<float> get_image_size(int image_id);
|
||||||
|
|
||||||
int load_font(const char *path, int font_size, bool bold = false, bool italic = false, bool underline = false, bool pixel_art = false);
|
int load_font(const char *path, int font_size, bool bold = false, bool italic = false, bool underline = false, bool pixel_art = false);
|
||||||
|
void use_font(int font_id);
|
||||||
void unload_font(int font_id);
|
void unload_font(int font_id);
|
||||||
|
|
||||||
// text is copied internally, so it can be free'd by the caller after the text is created.
|
// text is copied internally, so it can be free'd by the caller after the text is created.
|
||||||
@@ -135,7 +145,7 @@ private:
|
|||||||
Pool<Font> font_pool;
|
Pool<Font> font_pool;
|
||||||
|
|
||||||
// Text pool
|
// Text pool
|
||||||
Pool<SDL_Texture *> text_pool;
|
Pool<Text> text_pool;
|
||||||
|
|
||||||
struct RenderInstruction {
|
struct RenderInstruction {
|
||||||
enum Type {
|
enum Type {
|
||||||
|
|||||||
+14
-5
@@ -1,8 +1,14 @@
|
|||||||
App.run 400, 400, "Button Test"
|
App.run 720, 480, "Button Test"
|
||||||
|
|
||||||
main_scene = Scene.new
|
main_scene = Scene.new
|
||||||
|
|
||||||
default_font = Font.new "assets/fonts/charybdis.ttf", 24, pixel_art: true
|
default_font = Font.new "assets/fonts/charybdis.ttf", 24, pixel_art: true
|
||||||
|
|
||||||
|
bg_image1 = Image.new "assets/images/menu_bg.png", alpha: 0.7, pixel_art: true
|
||||||
|
bg_image2 = Image.new "assets/images/game_over_dead_bg.png", alpha: 1, pixel_art: true
|
||||||
|
|
||||||
|
bg_animation = Animation.new [bg_image1, bg_image2], fps: 5
|
||||||
|
|
||||||
App.language = :en
|
App.language = :en
|
||||||
App.localize(:en, :btn_text, "Click me!")
|
App.localize(:en, :btn_text, "Click me!")
|
||||||
|
|
||||||
@@ -10,6 +16,8 @@ text = ElementText.new :btn_text, default_font, position: {x: 50, y: 50}, z: 1,
|
|||||||
|
|
||||||
rect = ElementRect.new({x: 50, y: 50, w: 100, h: 25}, 0xFF0000FF, z: 0)
|
rect = ElementRect.new({x: 50, y: 50, w: 100, h: 25}, 0xFF0000FF, z: 0)
|
||||||
|
|
||||||
|
image_element = ElementImage.new bg_animation, position: {x: 0, y: 0}, z: -1
|
||||||
|
|
||||||
rect.on_click do
|
rect.on_click do
|
||||||
rect.color = rect.color == 0xFF0000FF ?
|
rect.color = rect.color == 0xFF0000FF ?
|
||||||
0x00FF00FF
|
0x00FF00FF
|
||||||
@@ -17,14 +25,15 @@ rect.on_click do
|
|||||||
0xFF0000FF
|
0xFF0000FF
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
main_scene.on_update do |delta_time|
|
||||||
main_scene.update do |dt|
|
# puts "Delta time: #{delta_time}ms"
|
||||||
puts "Delta time: #{dt}ms"
|
# commented out to avoid spamming the console, but you can uncomment to see the delta time being printed every frame
|
||||||
|
# runs at 60fps, so you should see around 16-17ms being printed
|
||||||
end
|
end
|
||||||
=end
|
|
||||||
|
|
||||||
main_scene << text
|
main_scene << text
|
||||||
main_scene << rect
|
main_scene << rect
|
||||||
|
main_scene << image_element
|
||||||
|
|
||||||
# main_scene.delete(text) # Uncomment to test element deletion
|
# main_scene.delete(text) # Uncomment to test element deletion
|
||||||
|
|
||||||
|
|||||||
+45
-28
@@ -42,16 +42,13 @@ void Window::update(Vec2<float> new_size, const char *new_title) {
|
|||||||
|
|
||||||
Window::~Window() {
|
Window::~Window() {
|
||||||
for (auto &tex : image_pool.all())
|
for (auto &tex : image_pool.all())
|
||||||
if (tex.texture)
|
SDL_DestroyTexture(tex->texture);
|
||||||
SDL_DestroyTexture(tex.texture);
|
|
||||||
|
|
||||||
for (auto tex : text_pool.all())
|
for (auto tex : text_pool.all())
|
||||||
if (tex)
|
SDL_DestroyTexture(tex->texture);
|
||||||
SDL_DestroyTexture(tex);
|
|
||||||
|
|
||||||
for (auto &f : font_pool.all())
|
for (auto &f : font_pool.all())
|
||||||
if (f.font)
|
TTF_CloseFont(f->font);
|
||||||
TTF_CloseFont(f.font);
|
|
||||||
|
|
||||||
SDL_DestroyRenderer(renderer);
|
SDL_DestroyRenderer(renderer);
|
||||||
SDL_DestroyWindow(window);
|
SDL_DestroyWindow(window);
|
||||||
@@ -76,7 +73,15 @@ int Window::load_image(const char *path, float alpha, bool pixel_art) {
|
|||||||
float w, h;
|
float w, h;
|
||||||
SDL_GetTextureSize(texture, &w, &h);
|
SDL_GetTextureSize(texture, &w, &h);
|
||||||
|
|
||||||
return image_pool.acquire({texture, {w, h}});
|
Image *img = new Image{texture, {w, h}};
|
||||||
|
int id = image_pool.acquire(img);
|
||||||
|
image_pool.use(id);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::use_image(int image_id) {
|
||||||
|
image_pool.use(image_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2<float> Window::get_image_size(int image_id) {
|
Vec2<float> Window::get_image_size(int image_id) {
|
||||||
@@ -84,7 +89,7 @@ Vec2<float> Window::get_image_size(int image_id) {
|
|||||||
fprintf(stderr, "Invalid image ID: %d\n", image_id);
|
fprintf(stderr, "Invalid image ID: %d\n", image_id);
|
||||||
return {0, 0};
|
return {0, 0};
|
||||||
}
|
}
|
||||||
return {image_pool[image_id].size.x, image_pool[image_id].size.y};
|
return image_pool[image_id]->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::unload_image(int image_id) {
|
void Window::unload_image(int image_id) {
|
||||||
@@ -93,7 +98,7 @@ void Window::unload_image(int image_id) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_DestroyTexture(image_pool[image_id].texture);
|
SDL_DestroyTexture(image_pool[image_id]->texture);
|
||||||
image_pool.release(image_id);
|
image_pool.release(image_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +120,15 @@ int Window::load_font(const char *path, int font_size, bool bold, bool italic, b
|
|||||||
|
|
||||||
TTF_SetFontStyle(font, style);
|
TTF_SetFontStyle(font, style);
|
||||||
|
|
||||||
return font_pool.acquire({font, pixel_art});
|
Font *f = new Font{font, pixel_art};
|
||||||
|
int id = font_pool.acquire(f);
|
||||||
|
font_pool.use(id);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::use_font(int font_id) {
|
||||||
|
font_pool.use(font_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::unload_font(int font_id) {
|
void Window::unload_font(int font_id) {
|
||||||
@@ -124,7 +137,7 @@ void Window::unload_font(int font_id) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TTF_CloseFont(font_pool[font_id].font);
|
TTF_CloseFont(font_pool[font_id]->font);
|
||||||
font_pool.release(font_id);
|
font_pool.release(font_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +148,7 @@ int Window::create_text(int font_id, const char *text, uint32_t length, Color co
|
|||||||
}
|
}
|
||||||
|
|
||||||
SDL_Color sdl_color = {color.r, color.g, color.b, color.a};
|
SDL_Color sdl_color = {color.r, color.g, color.b, color.a};
|
||||||
SDL_Surface *surface = TTF_RenderText_Solid(font_pool[font_id].font, text, length, sdl_color);
|
SDL_Surface *surface = TTF_RenderText_Solid(font_pool[font_id]->font, text, length, sdl_color);
|
||||||
|
|
||||||
if (surface == nullptr) {
|
if (surface == nullptr) {
|
||||||
fprintf(stderr, "Failed to create text surface: %s\n", SDL_GetError());
|
fprintf(stderr, "Failed to create text surface: %s\n", SDL_GetError());
|
||||||
@@ -150,10 +163,17 @@ int Window::create_text(int font_id, const char *text, uint32_t length, Color co
|
|||||||
return UINT32_MAX;
|
return UINT32_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (font_pool[font_id].pixel_art)
|
if (font_pool[font_id]->pixel_art)
|
||||||
SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST);
|
SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST);
|
||||||
|
|
||||||
return text_pool.acquire(texture);
|
float w, h;
|
||||||
|
SDL_GetTextureSize(texture, &w, &h);
|
||||||
|
|
||||||
|
Text *t = new Text{texture, {w, h}};
|
||||||
|
int id = text_pool.acquire(t);
|
||||||
|
text_pool.use(id);
|
||||||
|
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2<float> Window::get_text_size(int text_id) {
|
Vec2<float> Window::get_text_size(int text_id) {
|
||||||
@@ -161,9 +181,7 @@ Vec2<float> Window::get_text_size(int text_id) {
|
|||||||
fprintf(stderr, "Invalid text ID: %d\n", text_id);
|
fprintf(stderr, "Invalid text ID: %d\n", text_id);
|
||||||
return {0, 0};
|
return {0, 0};
|
||||||
}
|
}
|
||||||
float w, h;
|
return text_pool[text_id]->size;
|
||||||
SDL_GetTextureSize(text_pool[text_id], &w, &h);
|
|
||||||
return {w, h};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::unload_text(int text_id) {
|
void Window::unload_text(int text_id) {
|
||||||
@@ -172,7 +190,7 @@ void Window::unload_text(int text_id) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_DestroyTexture(text_pool[text_id]);
|
SDL_DestroyTexture(text_pool[text_id]->texture);
|
||||||
text_pool.release(text_id);
|
text_pool.release(text_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,7 +293,8 @@ void Window::render() {
|
|||||||
for (const RenderInstruction &instruction : render_instructions) {
|
for (const RenderInstruction &instruction : render_instructions) {
|
||||||
switch (instruction.type) {
|
switch (instruction.type) {
|
||||||
case RenderInstruction::DRAW_TEXT: {
|
case RenderInstruction::DRAW_TEXT: {
|
||||||
SDL_Texture *texture = text_pool[instruction.draw_text.text_id];
|
Text *text = text_pool[instruction.draw_text.text_id];
|
||||||
|
SDL_Texture *texture = text->texture;
|
||||||
|
|
||||||
SDL_FlipMode flip = SDL_FLIP_NONE;
|
SDL_FlipMode flip = SDL_FLIP_NONE;
|
||||||
|
|
||||||
@@ -287,14 +306,12 @@ void Window::render() {
|
|||||||
float scale_x = std::abs(instruction.scale.x) * scale;
|
float scale_x = std::abs(instruction.scale.x) * scale;
|
||||||
float scale_y = std::abs(instruction.scale.y) * scale;
|
float scale_y = std::abs(instruction.scale.y) * scale;
|
||||||
|
|
||||||
float w, h;
|
|
||||||
SDL_GetTextureSize(texture, &w, &h);
|
|
||||||
|
|
||||||
SDL_FRect dst_rect;
|
SDL_FRect dst_rect;
|
||||||
dst_rect.x = instruction.draw_text.position.x * scale + offset.x;
|
dst_rect.x = instruction.draw_text.position.x * scale + offset.x;
|
||||||
dst_rect.y = instruction.draw_text.position.y * scale + offset.y;
|
dst_rect.y = instruction.draw_text.position.y * scale + offset.y;
|
||||||
dst_rect.w = scale_x * w;
|
|
||||||
dst_rect.h = scale_y * h;
|
dst_rect.w = scale_x * text->size.x;
|
||||||
|
dst_rect.h = scale_y * text->size.y;
|
||||||
|
|
||||||
SDL_RenderTextureRotated(
|
SDL_RenderTextureRotated(
|
||||||
renderer,
|
renderer,
|
||||||
@@ -308,7 +325,7 @@ void Window::render() {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case RenderInstruction::DRAW_IMAGE: {
|
case RenderInstruction::DRAW_IMAGE: {
|
||||||
Image image = image_pool[instruction.draw_image.image_id];
|
Image *image = image_pool[instruction.draw_image.image_id];
|
||||||
|
|
||||||
SDL_FlipMode flip = SDL_FLIP_NONE;
|
SDL_FlipMode flip = SDL_FLIP_NONE;
|
||||||
|
|
||||||
@@ -323,12 +340,12 @@ void Window::render() {
|
|||||||
SDL_FRect dst_rect;
|
SDL_FRect dst_rect;
|
||||||
dst_rect.x = instruction.draw_image.position.x * scale + offset.x;
|
dst_rect.x = instruction.draw_image.position.x * scale + offset.x;
|
||||||
dst_rect.y = instruction.draw_image.position.y * scale + offset.y;
|
dst_rect.y = instruction.draw_image.position.y * scale + offset.y;
|
||||||
dst_rect.w = scale_x * image.size.x;
|
dst_rect.w = scale_x * image->size.x;
|
||||||
dst_rect.h = scale_y * image.size.y;
|
dst_rect.h = scale_y * image->size.y;
|
||||||
|
|
||||||
SDL_RenderTextureRotated(
|
SDL_RenderTextureRotated(
|
||||||
renderer,
|
renderer,
|
||||||
image.texture,
|
image->texture,
|
||||||
nullptr,
|
nullptr,
|
||||||
&dst_rect,
|
&dst_rect,
|
||||||
instruction.angle,
|
instruction.angle,
|
||||||
|
|||||||
Reference in New Issue
Block a user