Remove element script and allow images to be pixel updated for similar behaviour

This commit is contained in:
2026-06-05 11:00:15 +01:00
parent e7418fde08
commit 419e95ac89
9 changed files with 177 additions and 518 deletions
+1 -30
View File
@@ -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<float> shape;
EScript(Vec2<float> 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<float> 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> element_pool;
} // namespace app
-3
View File
@@ -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();
}
+3 -19
View File
@@ -32,15 +32,6 @@ struct Text {
}
};
struct Scripted {
SDL_Texture *texture;
Vec2<float> size;
~Scripted() {
SDL_DestroyTexture(texture);
}
};
// Image pool
inline Pool<Image> image_pool;
@@ -50,9 +41,6 @@ inline Pool<Font> font_pool;
// Text pool
inline Pool<Text> text_pool;
// Scripted pool
inline Pool<Scripted> 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<float> size, bool pixel_art);
Vec2<float> 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<float> get_text_size(uint64_t text_id);
uint64_t create_scripted(Vec2<float> size, bool pixel_art);
Vec2<float> 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<float> position, float z, float angle, Vec2<float> pivot, Vec2<float> scale, float alpha);
bool draw(uint64_t image_id, Vec2<float> position, float z, float angle, Vec2<float> pivot, Vec2<float> scale, float alpha);
@@ -166,8 +151,7 @@ private:
enum Type {
DRAW_IMAGE,
DRAW_TEXT,
DRAW_RECT,
DRAW_SCRIPTED
DRAW_RECT
} type;
float z;
+17 -9
View File
@@ -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
+3 -4
View File
@@ -74,11 +74,10 @@ mrb_value static_image_animation(mrb_state *mrb, mrb_value) {
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);
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) {
-291
View File
@@ -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<float> 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 = "#<ElementScript:0x"
+ std::format("0x{:016x}", id)
+ " w=" + std::to_string(element->size().x) // use truncation like in other elements
+ " h=" + std::to_string(element->size().y)
+ ">";
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
+43 -4
View File
@@ -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
-14
View File
@@ -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;
}
+110 -144
View File
@@ -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<float> 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<float> 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<float> position, float z, float angle,
return true;
};
uint64_t Window::create_scripted(Vec2<float> 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<float> 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<float> position, float z, float angle, Vec2<float> pivot, Vec2<float> 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<float>
return true;
};
bool Window::draw_scripted(uint64_t scripted_id, Vec2<float> position, float z, float angle, Vec2<float> pivot, Vec2<float> 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;