diff --git a/include/app/elements.h b/include/app/elements.h index e6db08d..be40375 100644 --- a/include/app/elements.h +++ b/include/app/elements.h @@ -8,8 +8,7 @@ enum Type { IMAGE, TEXT, - RECT, - SCRIPT }; + RECT }; enum ClickMode { PASS, BLOCK, @@ -83,34 +82,6 @@ struct ERect : Element { void render(uint64_t) override; }; -struct EScript : Element { - Ruby::Block script; - uint64_t scripted_id = UINT64_MAX; - bool pixel_art = false; - Vec2 shape; - - EScript(Vec2 shape) : Element(Type::SCRIPT), shape(shape) { - scripted_id = window.create_scripted(shape, pixel_art); - } - - ~EScript() { - if (scripted_id != UINT64_MAX) - scripted_pool.release(scripted_id); - }; - - Vec2 size() override { - return shape; - } - - bool update_scripted(Rect content_rect, const char *new_content, uint32_t length) { - return window.update_scripted(scripted_id, content_rect, new_content, length); - } - - void render(uint64_t) override { - window.draw_scripted(scripted_id, position, z, rotation, pivot, scale, alpha); - }; -}; - inline Pool element_pool; } // namespace app diff --git a/include/bindings/definitions.h b/include/bindings/definitions.h index ab42ac2..27cac02 100644 --- a/include/bindings/definitions.h +++ b/include/bindings/definitions.h @@ -18,7 +18,6 @@ inline struct RubyBindings { Binding ElementText; Binding ElementRect; Binding ElementImage; - Binding ElementScript; Binding Scene; } bindings; @@ -44,7 +43,6 @@ void register_animation(); void register_element_text(); void register_element_rect(); void register_element_image(); -void register_element_script(); void register_scene(); void register_app(); @@ -57,7 +55,6 @@ inline void setup() { register_element_text(); register_element_rect(); register_element_image(); - register_element_script(); register_scene(); register_app(); } diff --git a/include/window/window.h b/include/window/window.h index 6e44309..5052eb3 100644 --- a/include/window/window.h +++ b/include/window/window.h @@ -32,15 +32,6 @@ struct Text { } }; -struct Scripted { - SDL_Texture *texture; - Vec2 size; - - ~Scripted() { - SDL_DestroyTexture(texture); - } -}; - // Image pool inline Pool image_pool; @@ -50,9 +41,6 @@ inline Pool font_pool; // Text pool inline Pool text_pool; -// Scripted pool -inline Pool scripted_pool; - struct Event { enum Type { NONE, @@ -111,7 +99,9 @@ public: // Rendering functions uint64_t load_image(const char *path, bool pixel_art); + uint64_t create_image(Vec2 size, bool pixel_art); Vec2 get_image_size(uint64_t image_id); + bool update_image(uint64_t image_id, Rect content_rect, const char *new_content, uint32_t length); uint64_t load_font(const char *path, int font_size, bool bold, bool italic, bool underline, bool pixel_art); @@ -119,11 +109,6 @@ public: uint64_t create_text(uint64_t font_id, const char *text, uint32_t length, Color color); Vec2 get_text_size(uint64_t text_id); - uint64_t create_scripted(Vec2 size, bool pixel_art); - Vec2 get_scripted_size(uint64_t scripted_id); - - bool update_scripted(uint64_t scripted_id, Rect content_rect, const char *new_content, uint32_t length); - bool write(uint64_t text_id, Vec2 position, float z, float angle, Vec2 pivot, Vec2 scale, float alpha); bool draw(uint64_t image_id, Vec2 position, float z, float angle, Vec2 pivot, Vec2 scale, float alpha); @@ -166,8 +151,7 @@ private: enum Type { DRAW_IMAGE, DRAW_TEXT, - DRAW_RECT, - DRAW_SCRIPTED + DRAW_RECT } type; float z; diff --git a/samples/button.rb b/samples/button.rb index e8628fa..ba3bd8b 100644 --- a/samples/button.rb +++ b/samples/button.rb @@ -4,8 +4,8 @@ main_scene = Scene.new default_font = Font.new "assets/fonts/charybdis.ttf", 24, pixel_art: true -bg_image1 = Image.new "assets/images/menu_bg.png", pixel_art: true -bg_image2 = Image.new "assets/images/game_over_dead_bg.png", pixel_art: true +bg_image1 = Image.load "assets/images/menu_bg.png", pixel_art: true +bg_image2 = Image.load "assets/images/game_over_dead_bg.png", pixel_art: true bg_animation = Animation.new [bg_image1, bg_image2], fps: 5 @@ -20,9 +20,13 @@ rect = ElementRect.new 100, 25, 0xFF0000, position: {x: 50, y: 50}, z: 0, rotati image_element = ElementImage.new bg_animation, position: {x: 0, y: 0}, z: -1, click_mode: :block, alpha: 1 -script_element = ElementScript.new 100, 100, position: {x: 200, y: 200}, z: 2, click_mode: :block, alpha: 1 +image1 = Image.new 50, 50, pixel_art: true -pp text, rect, image_element, script_element +image2_animation = Animation.from(image1) + +image_element2 = ElementImage.new image2_animation, position: {x: 200, y: 200}, z: 0, click_mode: :block, alpha: 1 + +pp text, rect, image_element, image_element2 end_scene = Scene.new end_scene << rect @@ -60,12 +64,12 @@ App.update do |delta_time| # puts "Delta time: #{delta_time}s" - red_pixel = [0xFF, 0, 0, 255] # ARGB green_pixel = [0xFF, 0, 255, 0] # ARGB - c_p = c_c % 2 == 0 ? red_pixel : green_pixel + c_p = ((c_c / 10) % 2) == 1 ? red_pixel : green_pixel raw_bytes = (c_p * (50 * 50)).pack('C*') - script_element.update(0, 0, 50, 50, raw_bytes) + bg_image1.update(0, 0, 50, 50, raw_bytes) + image1.update(0, 0, 50, 50, raw_bytes) el = App.scene.elements_at(App.mouse_position) @@ -83,14 +87,18 @@ App.update do |delta_time| elsif elem == text pp "Down over text element" end - elem.position.x += 10 + dy = rand(-10..10) + dx = rand(-10..10) + elem.position.y += dy + elem.position.x += dx end end main_scene << text main_scene << rect main_scene << image_element -main_scene << script_element +main_scene << image_element2 + App.start main_scene time = Time.now - start diff --git a/src/bindings/animation.cc b/src/bindings/animation.cc index ef9ddfd..eb7c8cd 100644 --- a/src/bindings/animation.cc +++ b/src/bindings/animation.cc @@ -74,11 +74,10 @@ mrb_value static_image_animation(mrb_state *mrb, mrb_value) { std::vector 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); + uint64_t id = animation_pool.acquire(animation); + animation_pool.use(id); - return definitions::wrap(definitions::bindings.Animation, s->id); + return definitions::wrap(definitions::bindings.Animation, id); } mrb_value animation_equal(mrb_state *mrb, mrb_value self) { diff --git a/src/bindings/element_script.cc b/src/bindings/element_script.cc deleted file mode 100644 index 9860a85..0000000 --- a/src/bindings/element_script.cc +++ /dev/null @@ -1,291 +0,0 @@ -#include "app/app.h" -#include "bindings/definitions.h" - -namespace { -void ElementScript_free(mrb_state *mrb, void *ptr) { - UNUSED(mrb); - uint64_t id = ((Wrapper *)ptr)->id; - app::element_pool.release(id); - delete (Wrapper *)ptr; -} - -const struct mrb_data_type ElementScript_type = { - "ElementScript", - ElementScript_free -}; - -mrb_value ElementScript_init(mrb_state *mrb, mrb_value self) { - Wrapper *old = (Wrapper *)DATA_PTR(self); - if (old) - mrb_free(mrb, old); - mrb_data_init(self, nullptr, &ElementScript_type); - Wrapper *s = new Wrapper(); - - mrb_float shape_x, shape_y; - mrb_value kwargs; - mrb_get_args(mrb, "ff|H", &shape_x, &shape_y, &kwargs); - - Vec2 shape = {(float)shape_x, (float)shape_y}; - - float x = 0, y = 0, z = 0, rotation = 0; - float scale_x = 1, scale_y = 1, alpha = 1, pivot_x = 0.5, pivot_y = 0.5; - mrb_sym click_mode_sym = sym_block; - if (!mrb_nil_p(kwargs)) { - mrb_value pos_hash = HASH_GET(kwargs, position); - if (!mrb_nil_p(pos_hash)) { - HASH_FLOAT(pos_hash, x, x); - HASH_FLOAT(pos_hash, y, y); - } - - mrb_value scale_hash = HASH_GET(kwargs, scale); - if (!mrb_nil_p(scale_hash)) { - HASH_FLOAT(scale_hash, x, scale_x); - HASH_FLOAT(scale_hash, y, scale_y); - } - - mrb_value pivot_hash = HASH_GET(kwargs, pivot); - if (!mrb_nil_p(pivot_hash)) { - HASH_FLOAT(pivot_hash, x, pivot_x); - HASH_FLOAT(pivot_hash, y, pivot_y); - } - - HASH_FLOAT(kwargs, z, z); - HASH_FLOAT(kwargs, rotation, rotation); - HASH_FLOAT(kwargs, alpha, alpha); - mrb_value v = HASH_GET(kwargs, click_mode); - if (!mrb_nil_p(v)) { - click_mode_sym = mrb_symbol(v); - } - } - - app::EScript *element = new app::EScript(shape); - element->position = {x, y}; - element->scale = {scale_x, scale_y}; - element->rotation = rotation; - element->pivot = {pivot_x, pivot_y}; - element->alpha = alpha; - element->z = z; - - std::string click_mode = mrb_sym2name(mrb, click_mode_sym); - - if (click_mode == "pass") - element->click_mode = ClickMode::PASS; - else if (click_mode == "block") - element->click_mode = ClickMode::BLOCK; - else if (click_mode == "ignore") - element->click_mode = ClickMode::IGNORE; - - s->id = app::element_pool.acquire(element); - app::element_pool.use(s->id); - - mrb_data_init(self, s, &ElementScript_type); - return self; -} - -mrb_value element_script_on_click(mrb_state *mrb, mrb_value self) { - mrb_value block; - mrb_get_args(mrb, "&", &block); - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - uint64_t id = wrapper->id; - app::Element *element = app::element_pool[id]; - element->on_click.set_proc(block); - return self; -} - -mrb_value element_script_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.ElementScript.cls)) - return mrb_false_value(); - - Wrapper *wrapper_self = (Wrapper *)DATA_PTR(self); - Wrapper *wrapper_other = (Wrapper *)DATA_PTR(other); - return mrb_bool_value(wrapper_self->id == wrapper_other->id); -} - -mrb_value element_script_inspect(mrb_state *mrb, mrb_value self) { - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - uint64_t id = wrapper->id; - app::EScript *element = (app::EScript *)app::element_pool[id]; - std::string str = "#"; - return mrb_str_new_cstr(mrb, str.c_str()); -} - -mrb_value element_script_hash(mrb_state *, mrb_value self) { - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - return mrb_fixnum_value(wrapper->id); -} - -mrb_value element_script_position_get(mrb_state *, mrb_value self) { - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - uint64_t id = wrapper->id; - - app::EScript *element = (app::EScript *)app::element_pool[id]; - return definitions::Vec2_wrap(id, &element->position); -} - -mrb_value element_script_rotation_get(mrb_state *mrb, mrb_value self) { - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - uint64_t id = wrapper->id; - app::EScript *element = (app::EScript *)app::element_pool[id]; - return mrb_float_value(mrb, element->rotation); -} - -mrb_value element_script_rotation_set(mrb_state *mrb, mrb_value self) { - mrb_float rotation; - mrb_get_args(mrb, "f", &rotation); - - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - uint64_t id = wrapper->id; - app::EScript *element = (app::EScript *)app::element_pool[id]; - element->rotation = rotation; - - return mrb_nil_value(); -} - -mrb_value element_script_pivot_get(mrb_state *, mrb_value self) { - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - uint64_t id = wrapper->id; - app::EScript *element = (app::EScript *)app::element_pool[id]; - return definitions::Vec2_wrap(id, &element->pivot); -} - -mrb_value element_script_scale_get(mrb_state *, mrb_value self) { - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - uint64_t id = wrapper->id; - app::EScript *element = (app::EScript *)app::element_pool[id]; - return definitions::Vec2_wrap(id, &element->scale); -} - -mrb_value element_script_alpha_get(mrb_state *mrb, mrb_value self) { - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - uint64_t id = wrapper->id; - app::EScript *element = (app::EScript *)app::element_pool[id]; - return mrb_float_value(mrb, element->alpha); -} - -mrb_value element_script_alpha_set(mrb_state *mrb, mrb_value self) { - mrb_float alpha; - mrb_get_args(mrb, "f", &alpha); - - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - uint64_t id = wrapper->id; - app::EScript *element = (app::EScript *)app::element_pool[id]; - element->alpha = alpha; - - return mrb_nil_value(); -} - -mrb_value element_script_z_get(mrb_state *mrb, mrb_value self) { - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - uint64_t id = wrapper->id; - app::EScript *element = (app::EScript *)app::element_pool[id]; - return mrb_float_value(mrb, element->z); -} - -mrb_value element_script_z_set(mrb_state *mrb, mrb_value self) { - mrb_float z; - mrb_get_args(mrb, "f", &z); - - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - uint64_t id = wrapper->id; - app::EScript *element = (app::EScript *)app::element_pool[id]; - element->z = z; - - return mrb_nil_value(); -} - -mrb_value element_script_click_mode_get(mrb_state *mrb, mrb_value self) { - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - uint64_t id = wrapper->id; - app::EScript *element = (app::EScript *)app::element_pool[id]; - - std::string click_mode_str; - switch (element->click_mode) { - case ClickMode::PASS: - click_mode_str = "pass"; - break; - case ClickMode::BLOCK: - click_mode_str = "block"; - break; - case ClickMode::IGNORE: - click_mode_str = "ignore"; - break; - } - - return mrb_symbol_value(mrb_intern_cstr(mrb, click_mode_str.c_str())); -} - -mrb_value element_script_click_mode_set(mrb_state *mrb, mrb_value self) { - mrb_sym click_mode_sym; - mrb_get_args(mrb, "n", &click_mode_sym); - - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - uint64_t id = wrapper->id; - app::EScript *element = (app::EScript *)app::element_pool[id]; - - std::string click_mode = mrb_sym2name(mrb, click_mode_sym); - - if (click_mode == "pass") - element->click_mode = ClickMode::PASS; - else if (click_mode == "block") - element->click_mode = ClickMode::BLOCK; - else if (click_mode == "ignore") - element->click_mode = ClickMode::IGNORE; - - return mrb_nil_value(); -} - -mrb_value element_script_update(mrb_state *mrb, mrb_value self) { - const char *content; - mrb_int content_len; - mrb_int x, y, w, h; - mrb_get_args(mrb, "iiiis", &x, &y, &w, &h, &content, &content_len); - - uint32_t expected_len = (uint32_t)(w * h * 4); - if ((uint32_t)content_len < expected_len) { - mrb_raise(mrb, mrb_class_get(mrb, "ArgumentError"), "Pixel string length is too short for the specified rectangle bounds."); - } - - Wrapper *wrapper = (Wrapper *)DATA_PTR(self); - uint64_t id = wrapper->id; - - Rect content_rect = Rect::from({(float)x, (float)y}, {(float)w, (float)h}); - - app::EScript *element = (app::EScript *)app::element_pool[id]; - bool success = element->update_scripted(content_rect, content, content_len); - - return mrb_bool_value(success); -} -} // namespace - -namespace definitions { -void register_element_script() { - DEF_CLASS(ElementScript, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1)); - ADD_METHOD(ElementScript, "click", element_script_on_click, MRB_ARGS_BLOCK()); - ADD_METHOD(ElementScript, "==", element_script_equal, MRB_ARGS_REQ(1)); - ADD_METHOD(ElementScript, "eql?", element_script_equal, MRB_ARGS_REQ(1)); - ADD_METHOD(ElementScript, "inspect", element_script_inspect, MRB_ARGS_NONE()); - ADD_METHOD(ElementScript, "to_s", element_script_inspect, MRB_ARGS_NONE()); - ADD_METHOD(ElementScript, "hash", element_script_hash, MRB_ARGS_NONE()); - ADD_METHOD(ElementScript, "update", element_script_update, MRB_ARGS_REQ(5)); - ADD_METHOD(ElementScript, "position", element_script_position_get, MRB_ARGS_NONE()); - ADD_METHOD(ElementScript, "scale", element_script_scale_get, MRB_ARGS_NONE()); - ADD_METHOD(ElementScript, "rotation=", element_script_rotation_set, MRB_ARGS_REQ(1)); - ADD_METHOD(ElementScript, "rotation", element_script_rotation_get, MRB_ARGS_NONE()); - ADD_METHOD(ElementScript, "pivot", element_script_pivot_get, MRB_ARGS_NONE()); - ADD_METHOD(ElementScript, "alpha=", element_script_alpha_set, MRB_ARGS_REQ(1)); - ADD_METHOD(ElementScript, "alpha", element_script_alpha_get, MRB_ARGS_NONE()); - ADD_METHOD(ElementScript, "z=", element_script_z_set, MRB_ARGS_REQ(1)); - ADD_METHOD(ElementScript, "z", element_script_z_get, MRB_ARGS_NONE()); - ADD_METHOD(ElementScript, "click_mode=", element_script_click_mode_set, MRB_ARGS_REQ(1)); - ADD_METHOD(ElementScript, "click_mode", element_script_click_mode_get, MRB_ARGS_NONE()); - - bindings.ElementScript = {ElementScript_class, &ElementScript_type}; -} -} // namespace definitions \ No newline at end of file diff --git a/src/bindings/image.cc b/src/bindings/image.cc index 581502b..e0b99c7 100644 --- a/src/bindings/image.cc +++ b/src/bindings/image.cc @@ -18,6 +18,21 @@ mrb_value Image_init(mrb_state *mrb, mrb_value self) { mrb_data_init(self, nullptr, &Image_type); Wrapper *s = new Wrapper(); + mrb_float width, height; + mrb_value kwargs; + mrb_get_args(mrb, "ff|H", &width, &height, &kwargs); + + bool pixel_art = false; + if (!mrb_nil_p(kwargs)) + HASH_BOOL(kwargs, pixel_art, pixel_art); + + s->id = window.create_image({(float)width, (float)height}, pixel_art); + + mrb_data_init(self, s, &Image_type); + return self; +} + +mrb_value image_load(mrb_state *mrb, mrb_value) { char *path; mrb_value kwargs; mrb_get_args(mrb, "z|H", &path, &kwargs); @@ -26,10 +41,9 @@ mrb_value Image_init(mrb_state *mrb, mrb_value self) { if (!mrb_nil_p(kwargs)) HASH_BOOL(kwargs, pixel_art, pixel_art); - s->id = window.load_image(path, pixel_art); + uint64_t id = window.load_image(path, pixel_art); - mrb_data_init(self, s, &Image_type); - return self; + return definitions::wrap(definitions::bindings.Image, id); } mrb_value image_equal(mrb_state *mrb, mrb_value self) { @@ -63,16 +77,41 @@ mrb_value image_height(mrb_state *mrb, mrb_value self) { uint64_t id = wrapper->id; return mrb_float_value(mrb, window.get_image_size(id).y); } + +mrb_value image_update(mrb_state *mrb, mrb_value self) { + Wrapper *wrapper = (Wrapper *)DATA_PTR(self); + uint64_t id = wrapper->id; + + mrb_float x, y, width, height; + char *new_content; + mrb_int length; + mrb_get_args(mrb, "ffffs", &x, &y, &width, &height, &new_content, &length); + + bool success = window.update_image( + id, + Rect::from( + {(float)x, (float)y}, + {(float)width, (float)height} + ), + new_content, + (uint32_t)length + ); + + return mrb_bool_value(success); +} } // namespace namespace definitions { void register_image() { - DEF_CLASS(Image, MRB_ARGS_REQ(1) | MRB_ARGS_OPT(1)); + DEF_CLASS(Image, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1)); + ADD_CLASS_METHOD(Image, "load", image_load, MRB_ARGS_REQ(2) | MRB_ARGS_OPT(1)); ADD_METHOD(Image, "==", image_equal, MRB_ARGS_REQ(1)); ADD_METHOD(Image, "eql?", image_equal, MRB_ARGS_REQ(1)); ADD_METHOD(Image, "hash", image_hash, MRB_ARGS_NONE()); ADD_METHOD(Image, "width", image_width, MRB_ARGS_NONE()); ADD_METHOD(Image, "height", image_height, MRB_ARGS_NONE()); + ADD_METHOD(Image, "update", image_update, MRB_ARGS_REQ(5)); + bindings.Image = {Image_class, &Image_type}; } } // namespace definitions \ No newline at end of file diff --git a/src/bindings/scene.cc b/src/bindings/scene.cc index 3f344e5..00d7e8f 100644 --- a/src/bindings/scene.cc +++ b/src/bindings/scene.cc @@ -34,7 +34,6 @@ mrb_value scene_add_element(mrb_state *mrb, mrb_value self) { !mrb_obj_is_kind_of(mrb, element_val, definitions::bindings.ElementText.cls) && !mrb_obj_is_kind_of(mrb, element_val, definitions::bindings.ElementRect.cls) && !mrb_obj_is_kind_of(mrb, element_val, definitions::bindings.ElementImage.cls) - && !mrb_obj_is_kind_of(mrb, element_val, definitions::bindings.ElementScript.cls) ) { mrb_raise( mrb, @@ -61,7 +60,6 @@ mrb_value scene_delete_element(mrb_state *mrb, mrb_value self) { !mrb_obj_is_kind_of(mrb, element_val, definitions::bindings.ElementText.cls) && !mrb_obj_is_kind_of(mrb, element_val, definitions::bindings.ElementRect.cls) && !mrb_obj_is_kind_of(mrb, element_val, definitions::bindings.ElementImage.cls) - && !mrb_obj_is_kind_of(mrb, element_val, definitions::bindings.ElementScript.cls) ) { mrb_raise( mrb, @@ -130,12 +128,6 @@ mrb_value scene_elements_at(mrb_state *mrb, mrb_value self) { ); mrb_ary_push(mrb, result, obj); break; - case Type::SCRIPT: - obj = definitions::wrap( - definitions::bindings.ElementScript, - element_id - ); - break; default: continue; } @@ -176,12 +168,6 @@ mrb_value scene_elements(mrb_state *mrb, mrb_value self) { ); mrb_ary_push(mrb, result, obj); break; - case Type::SCRIPT: - obj = definitions::wrap( - definitions::bindings.ElementScript, - element_id - ); - break; default: continue; } diff --git a/src/window/window.cc b/src/window/window.cc index f3c6a94..588b3c0 100644 --- a/src/window/window.cc +++ b/src/window/window.cc @@ -57,17 +57,52 @@ Window::~Window() { } uint64_t Window::load_image(const char *path, bool pixel_art) { - SDL_Texture *texture = IMG_LoadTexture(renderer, path); + SDL_Surface *surface = IMG_Load(path); + + if (!surface) { + fprintf(stderr, "Failed to load image: %s\n", SDL_GetError()); + return UINT64_MAX; + } + + SDL_Surface *rgba = SDL_ConvertSurface( + surface, + SDL_PIXELFORMAT_RGBA8888 + ); + + SDL_DestroySurface(surface); + + if (!rgba) { + fprintf(stderr, "Failed to convert image: %s\n", SDL_GetError()); + return UINT64_MAX; + } + + SDL_Texture *texture = SDL_CreateTexture( + renderer, + SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_STREAMING, + rgba->w, + rgba->h + ); + + if (!texture) { + SDL_DestroySurface(rgba); + fprintf(stderr, "Failed to create texture: %s\n", SDL_GetError()); + return UINT64_MAX; + } + + SDL_UpdateTexture( + texture, + nullptr, + rgba->pixels, + rgba->pitch + ); + + SDL_DestroySurface(rgba); if (pixel_art) { SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST); } - if (texture == nullptr) { - fprintf(stderr, "Failed to load image: %s\n", SDL_GetError()); - return UINT64_MAX; - } - float w, h; SDL_GetTextureSize(texture, &w, &h); @@ -78,6 +113,75 @@ uint64_t Window::load_image(const char *path, bool pixel_art) { return id; } +uint64_t Window::create_image(Vec2 size, bool pixel_art) { + SDL_Texture *texture = SDL_CreateTexture( + renderer, + SDL_PIXELFORMAT_RGBA8888, + SDL_TEXTUREACCESS_STREAMING, + (int)size.x, + (int)size.y + ); + + if (!texture) { + fprintf(stderr, "Failed to create scripted texture: %s\n", SDL_GetError()); + return UINT64_MAX; + } + + SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); + + if (pixel_art) + SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST); + + Image *img = new Image{texture, size}; + uint64_t id = image_pool.acquire(img); + image_pool.use(id); + + char *buffer = (char *)malloc(size.x * size.y * 4 * sizeof(char)); + + for (unsigned int i = 0; i < (unsigned int)(size.x * size.y * 4); i += 4) { + buffer[i] = 0xFF; + buffer[i + 1] = 0xFF; + buffer[i + 2] = 0xFF; + buffer[i + 3] = 0xFF; + } + + SDL_UpdateTexture( + img->texture, + nullptr, + buffer, + (int)(size.x * 4) + ); + + free(buffer); + + return id; +} + +bool Window::update_image(uint64_t image_id, Rect content_rect, const char *new_content, uint32_t length) { + if (!image_pool.is_valid(image_id)) { + fprintf(stderr, "Invalid image ID: %llu\n", (unsigned long long)image_id); + return false; + } + + Image *img = image_pool[image_id]; + + SDL_Rect sdl_rect = { + (int)content_rect.x(), + (int)content_rect.y(), + (int)content_rect.w(), + (int)content_rect.h() + }; + + SDL_UpdateTexture( + img->texture, + &sdl_rect, + new_content, + (int)(content_rect.w() * 4) + ); + + return true; +}; + Vec2 Window::get_image_size(uint64_t image_id) { if (!image_pool.is_valid(image_id)) { fprintf(stderr, "Invalid image ID: %llu\n", (unsigned long long)image_id); @@ -177,83 +281,6 @@ bool Window::write(uint64_t text_id, Vec2 position, float z, float angle, return true; }; -uint64_t Window::create_scripted(Vec2 size, bool pixel_art) { - SDL_Texture *texture = SDL_CreateTexture( - renderer, - SDL_PIXELFORMAT_RGBA8888, - SDL_TEXTUREACCESS_STREAMING, - (int)size.x, - (int)size.y - ); - - if (!texture) { - fprintf(stderr, "Failed to create scripted texture: %s\n", SDL_GetError()); - return UINT64_MAX; - } - - SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); - - if (pixel_art) - SDL_SetTextureScaleMode(texture, SDL_SCALEMODE_NEAREST); - - Scripted *s = new Scripted{texture, size}; - uint64_t id = scripted_pool.acquire(s); - scripted_pool.use(id); - - char *buffer = (char *)malloc(size.x * size.y * 4 * sizeof(char)); - - for (unsigned int i = 0; i < (unsigned int)(size.x * size.y * 4); i += 4) { - buffer[i] = 0xFF; - buffer[i + 1] = 0xFF; - buffer[i + 2] = 0xFF; - buffer[i + 3] = 0xFF; - } - - SDL_UpdateTexture( - s->texture, - nullptr, - buffer, - (int)(size.x * 4) - ); - - free(buffer); - - return id; -} - -Vec2 Window::get_scripted_size(uint64_t scripted_id) { - if (!scripted_pool.is_valid(scripted_id)) { - fprintf(stderr, "Invalid scripted ID: %llu\n", (unsigned long long)scripted_id); - return {0, 0}; - } - return scripted_pool[scripted_id]->size; -} - -bool Window::update_scripted(uint64_t scripted_id, Rect content_rect, const char *new_content, uint32_t length) { - if (!scripted_pool.is_valid(scripted_id)) { - fprintf(stderr, "Invalid scripted ID: %llu\n", (unsigned long long)scripted_id); - return false; - } - - Scripted *s = scripted_pool[scripted_id]; - - SDL_Rect sdl_rect = { - (int)content_rect.x(), - (int)content_rect.y(), - (int)content_rect.w(), - (int)content_rect.h() - }; - - SDL_UpdateTexture( - s->texture, - &sdl_rect, - new_content, - (int)(content_rect.w() * 4) - ); - - return true; -}; - bool Window::draw(uint64_t image_id, Vec2 position, float z, float angle, Vec2 pivot, Vec2 scale, float alpha) { if (!image_pool.is_valid(image_id)) { fprintf(stderr, "Invalid image ID: %llu\n", (unsigned long long)image_id); @@ -293,28 +320,6 @@ bool Window::draw_rect(Rect rect, Color color, float z, float angle, Vec2 return true; }; -bool Window::draw_scripted(uint64_t scripted_id, Vec2 position, float z, float angle, Vec2 pivot, Vec2 scale, float alpha) { - if (!scripted_pool.is_valid(scripted_id)) { - fprintf(stderr, "Invalid scripted ID: %llu\n", (unsigned long long)scripted_id); - return false; - } - - render_instructions.push_back( - {.type = RenderInstruction::DRAW_SCRIPTED, - .z = z, - .angle = angle, - .pivot = pivot, - .scale = scale, - .alpha = alpha, - .draw_scripted = { - .scripted_id = scripted_id, - .position = position, - }} - ); - - return true; -}; - void Window::draw_letterbox() { SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); @@ -434,45 +439,6 @@ void Window::render() { ); } break; - case RenderInstruction::DRAW_SCRIPTED: { - Scripted *scripted = scripted_pool[instruction.draw_scripted.scripted_id]; - SDL_Texture *texture = scripted->texture; - - SDL_FlipMode flip = SDL_FLIP_NONE; - - if (instruction.scale.x < 0) - flip = (SDL_FlipMode)(flip | SDL_FLIP_HORIZONTAL); - if (instruction.scale.y < 0) - flip = (SDL_FlipMode)(flip | SDL_FLIP_VERTICAL); - - float scale_x = std::abs(instruction.scale.x) * scale; - float scale_y = std::abs(instruction.scale.y) * scale; - - SDL_FRect dst_rect; - dst_rect.x = instruction.draw_scripted.position.x * scale + offset.x; - dst_rect.y = instruction.draw_scripted.position.y * scale + offset.y; - - dst_rect.w = scale_x * scripted->size.x; - dst_rect.h = scale_y * scripted->size.y; - - SDL_SetTextureAlphaModFloat(texture, instruction.alpha); - - SDL_FPoint pivot_point = { - instruction.pivot.x * scale_x, - instruction.pivot.y * scale_y - }; - - SDL_RenderTextureRotated( - renderer, - texture, - nullptr, - &dst_rect, - instruction.angle, - &pivot_point, - flip - ); - } break; - case RenderInstruction::DRAW_RECT: { SDL_FRect dst_rect; dst_rect.x = instruction.draw_rect.rect.x() * scale + offset.x;