Added pixel texture element
This commit is contained in:
+32
-2
@@ -8,7 +8,8 @@
|
|||||||
|
|
||||||
enum Type { IMAGE,
|
enum Type { IMAGE,
|
||||||
TEXT,
|
TEXT,
|
||||||
RECT };
|
RECT,
|
||||||
|
SCRIPT };
|
||||||
|
|
||||||
enum ClickMode { PASS,
|
enum ClickMode { PASS,
|
||||||
BLOCK,
|
BLOCK,
|
||||||
@@ -72,8 +73,9 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ERect : Element {
|
struct ERect : Element {
|
||||||
Vec2<float> shape = {0, 0};
|
|
||||||
Color color = {255, 255, 255};
|
Color color = {255, 255, 255};
|
||||||
|
Vec2<float> shape = {0, 0};
|
||||||
|
|
||||||
Vec2<float> size() override;
|
Vec2<float> size() override;
|
||||||
|
|
||||||
ERect(Vec2<float> shape, Color color) : Element(Type::RECT), shape(shape), color(color) {}
|
ERect(Vec2<float> shape, Color color) : Element(Type::RECT), shape(shape), color(color) {}
|
||||||
@@ -81,6 +83,34 @@ struct ERect : Element {
|
|||||||
void render(uint64_t) override;
|
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;
|
inline Pool<Element> element_pool;
|
||||||
} // namespace app
|
} // namespace app
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ inline struct RubyBindings {
|
|||||||
Binding ElementText;
|
Binding ElementText;
|
||||||
Binding ElementRect;
|
Binding ElementRect;
|
||||||
Binding ElementImage;
|
Binding ElementImage;
|
||||||
|
Binding ElementScript;
|
||||||
Binding Scene;
|
Binding Scene;
|
||||||
} bindings;
|
} bindings;
|
||||||
|
|
||||||
@@ -43,6 +44,7 @@ void register_animation();
|
|||||||
void register_element_text();
|
void register_element_text();
|
||||||
void register_element_rect();
|
void register_element_rect();
|
||||||
void register_element_image();
|
void register_element_image();
|
||||||
|
void register_element_script();
|
||||||
void register_scene();
|
void register_scene();
|
||||||
void register_app();
|
void register_app();
|
||||||
|
|
||||||
@@ -55,6 +57,7 @@ inline void setup() {
|
|||||||
register_element_text();
|
register_element_text();
|
||||||
register_element_rect();
|
register_element_rect();
|
||||||
register_element_image();
|
register_element_image();
|
||||||
|
register_element_script();
|
||||||
register_scene();
|
register_scene();
|
||||||
register_app();
|
register_app();
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-2
@@ -32,6 +32,15 @@ struct Text {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Scripted {
|
||||||
|
SDL_Texture *texture;
|
||||||
|
Vec2<float> size;
|
||||||
|
|
||||||
|
~Scripted() {
|
||||||
|
SDL_DestroyTexture(texture);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Image pool
|
// Image pool
|
||||||
inline Pool<Image> image_pool;
|
inline Pool<Image> image_pool;
|
||||||
|
|
||||||
@@ -41,6 +50,9 @@ inline Pool<Font> font_pool;
|
|||||||
// Text pool
|
// Text pool
|
||||||
inline Pool<Text> text_pool;
|
inline Pool<Text> text_pool;
|
||||||
|
|
||||||
|
// Scripted pool
|
||||||
|
inline Pool<Scripted> scripted_pool;
|
||||||
|
|
||||||
struct Event {
|
struct Event {
|
||||||
enum Type {
|
enum Type {
|
||||||
NONE,
|
NONE,
|
||||||
@@ -107,12 +119,19 @@ public:
|
|||||||
uint64_t create_text(uint64_t font_id, const char *text, uint32_t length, Color color);
|
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);
|
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 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);
|
bool draw(uint64_t image_id, Vec2<float> position, float z, float angle, Vec2<float> pivot, Vec2<float> scale, float alpha);
|
||||||
|
|
||||||
bool draw_rect(Rect rect, Color color, float z, float angle, Vec2<float> pivot, Vec2<float> scale, float alpha);
|
bool draw_rect(Rect rect, Color color, float z, float angle, Vec2<float> pivot, Vec2<float> scale, float alpha);
|
||||||
|
|
||||||
|
bool draw_scripted(uint64_t scripted_id, Vec2<float> position, float z, float angle, Vec2<float> pivot, Vec2<float> scale, float alpha);
|
||||||
|
|
||||||
void render(); // the rest of the calls only build the instruction list, this actually renders everything added to the screen (following z order)
|
void render(); // the rest of the calls only build the instruction list, this actually renders everything added to the screen (following z order)
|
||||||
|
|
||||||
void clear(); // clears the instruction list
|
void clear(); // clears the instruction list
|
||||||
@@ -147,7 +166,8 @@ private:
|
|||||||
enum Type {
|
enum Type {
|
||||||
DRAW_IMAGE,
|
DRAW_IMAGE,
|
||||||
DRAW_TEXT,
|
DRAW_TEXT,
|
||||||
DRAW_RECT
|
DRAW_RECT,
|
||||||
|
DRAW_SCRIPTED
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
float z;
|
float z;
|
||||||
@@ -171,10 +191,15 @@ private:
|
|||||||
Rect rect;
|
Rect rect;
|
||||||
Color color;
|
Color color;
|
||||||
} draw_rect;
|
} draw_rect;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
uint64_t scripted_id;
|
||||||
|
Vec2<float> position;
|
||||||
|
} draw_scripted;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<struct RenderInstruction> render_instructions;
|
std::vector<RenderInstruction> render_instructions;
|
||||||
|
|
||||||
void compute_transform();
|
void compute_transform();
|
||||||
|
|
||||||
|
|||||||
+11
-3
@@ -20,7 +20,9 @@ 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
|
image_element = ElementImage.new bg_animation, position: {x: 0, y: 0}, z: -1, click_mode: :block, alpha: 1
|
||||||
|
|
||||||
pp text, rect, image_element
|
script_element = ElementScript.new 100, 100, position: {x: 200, y: 200}, z: 2, click_mode: :block, alpha: 1
|
||||||
|
|
||||||
|
pp text, rect, image_element, script_element
|
||||||
|
|
||||||
end_scene = Scene.new
|
end_scene = Scene.new
|
||||||
end_scene << rect
|
end_scene << rect
|
||||||
@@ -56,9 +58,15 @@ App.update do |delta_time|
|
|||||||
c_ += delta_time
|
c_ += delta_time
|
||||||
c_c += 1
|
c_c += 1
|
||||||
|
|
||||||
# commented out to avoid spamming the console, but you can uncomment to see the delta time being printed every frame
|
|
||||||
# puts "Delta time: #{delta_time}s"
|
# 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
|
||||||
|
raw_bytes = (c_p * (50 * 50)).pack('C*')
|
||||||
|
script_element.update(0, 0, 50, 50, raw_bytes)
|
||||||
|
|
||||||
el = App.scene.elements_at(App.mouse_position)
|
el = App.scene.elements_at(App.mouse_position)
|
||||||
|
|
||||||
pp App.text_input if App.text_input != ""
|
pp App.text_input if App.text_input != ""
|
||||||
@@ -82,7 +90,7 @@ end
|
|||||||
main_scene << text
|
main_scene << text
|
||||||
main_scene << rect
|
main_scene << rect
|
||||||
main_scene << image_element
|
main_scene << image_element
|
||||||
|
main_scene << script_element
|
||||||
App.start main_scene
|
App.start main_scene
|
||||||
|
|
||||||
time = Time.now - start
|
time = Time.now - start
|
||||||
|
|||||||
+6
-4
@@ -96,7 +96,7 @@ end
|
|||||||
# for entities it does similarly
|
# for entities it does similarly
|
||||||
# mouse state can be read in systems always
|
# mouse state can be read in systems always
|
||||||
|
|
||||||
query = tag(:enemy) & component(:health, true) & anti(name("Trap Preview", true))
|
query = Query.from(tag(:enemy) & component(:health, true) & anti(name("Trap Preview", true)))
|
||||||
# in the match name will return just the one entity
|
# in the match name will return just the one entity
|
||||||
# tag and componet return list-like tables but they will be parallel and in order
|
# tag and componet return list-like tables but they will be parallel and in order
|
||||||
# empty columns will be filled with nil (not possible if only & is used)
|
# empty columns will be filled with nil (not possible if only & is used)
|
||||||
@@ -105,7 +105,7 @@ query = tag(:enemy) & component(:health, true) & anti(name("Trap Preview", true)
|
|||||||
|
|
||||||
world.system :health_regen, for: query do |match, dt| # no trigger means always
|
world.system :health_regen, for: query do |match, dt| # no trigger means always
|
||||||
# example of a simple health regeneration system that regenerates health for all entities with a health component
|
# example of a simple health regeneration system that regenerates health for all entities with a health component
|
||||||
healths = match[0]
|
healths = query.get[0] # get the first component in the query, in this case health, this will be a list of all health components for entities that match the query
|
||||||
healths.add_scalar! :health, 1 * dt
|
healths.add_scalar! :health, 1 * dt
|
||||||
healths.clamp! :health, 0, 100
|
healths.clamp! :health, 0, 100
|
||||||
end
|
end
|
||||||
@@ -136,12 +136,14 @@ world.system :trap_placement, trigger: trigger do |dt|
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
name_query = Query.from(name("Trap Preview", true) & component(:sprite, true))
|
||||||
|
|
||||||
# could be done as so or
|
# could be done as so or
|
||||||
world.system :trap_preview, for: name("Trap Preview", true) do |match, dt| # example from teh game mist trying to be made with this engine
|
world.system :trap_preview do |match, dt| # example from teh game mist trying to be made with this engine
|
||||||
# do trap placement logic when a trap is held
|
# do trap placement logic when a trap is held
|
||||||
return unless world.holding_trap?
|
return unless world.holding_trap?
|
||||||
# show a preview of the trap at the mouse position, you can use the mouse position relative to the world for this
|
# show a preview of the trap at the mouse position, you can use the mouse position relative to the world for this
|
||||||
e = match.first
|
e = name_query.get[0] # get the first entity that matches the name query, in this case the trap preview entity, this will be nil if no entity matches
|
||||||
e.position = world.mouse_position_world
|
e.position = world.mouse_position_world
|
||||||
e.active = true # enable the trap preview entity to show it at the mouse position
|
e.active = true # enable the trap preview entity to show it at the mouse position
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -0,0 +1,291 @@
|
|||||||
|
#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
|
||||||
+58
-18
@@ -34,6 +34,7 @@ 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.ElementText.cls)
|
||||||
&& !mrb_obj_is_kind_of(mrb, element_val, definitions::bindings.ElementRect.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.ElementImage.cls)
|
||||||
|
&& !mrb_obj_is_kind_of(mrb, element_val, definitions::bindings.ElementScript.cls)
|
||||||
) {
|
) {
|
||||||
mrb_raise(
|
mrb_raise(
|
||||||
mrb,
|
mrb,
|
||||||
@@ -60,6 +61,7 @@ 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.ElementText.cls)
|
||||||
&& !mrb_obj_is_kind_of(mrb, element_val, definitions::bindings.ElementRect.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.ElementImage.cls)
|
||||||
|
&& !mrb_obj_is_kind_of(mrb, element_val, definitions::bindings.ElementScript.cls)
|
||||||
) {
|
) {
|
||||||
mrb_raise(
|
mrb_raise(
|
||||||
mrb,
|
mrb,
|
||||||
@@ -107,18 +109,37 @@ mrb_value scene_elements_at(mrb_state *mrb, mrb_value self) {
|
|||||||
for (uint64_t element_id : element_ids) {
|
for (uint64_t element_id : element_ids) {
|
||||||
app::Element *element = app::element_pool[element_id];
|
app::Element *element = app::element_pool[element_id];
|
||||||
app::element_pool.use(element_id);
|
app::element_pool.use(element_id);
|
||||||
if (element->type == Type::TEXT) {
|
mrb_value obj;
|
||||||
mrb_value obj = definitions::wrap(definitions::bindings.ElementText, element_id);
|
switch (element->type) {
|
||||||
|
case Type::TEXT:
|
||||||
|
obj = definitions::wrap(
|
||||||
|
definitions::bindings.ElementText,
|
||||||
|
element_id
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case Type::RECT:
|
||||||
|
obj = definitions::wrap(
|
||||||
|
definitions::bindings.ElementRect,
|
||||||
|
element_id
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case Type::IMAGE:
|
||||||
|
obj = definitions::wrap(
|
||||||
|
definitions::bindings.ElementImage,
|
||||||
|
element_id
|
||||||
|
);
|
||||||
mrb_ary_push(mrb, result, obj);
|
mrb_ary_push(mrb, result, obj);
|
||||||
} else if (element->type == Type::RECT) {
|
break;
|
||||||
mrb_value obj = definitions::wrap(definitions::bindings.ElementRect, element_id);
|
case Type::SCRIPT:
|
||||||
mrb_ary_push(mrb, result, obj);
|
obj = definitions::wrap(
|
||||||
} else if (element->type == Type::IMAGE) {
|
definitions::bindings.ElementScript,
|
||||||
mrb_value obj = definitions::wrap(definitions::bindings.ElementImage, element_id);
|
element_id
|
||||||
mrb_ary_push(mrb, result, obj);
|
);
|
||||||
} else {
|
break;
|
||||||
|
default:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
mrb_ary_push(mrb, result, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@@ -134,18 +155,37 @@ mrb_value scene_elements(mrb_state *mrb, mrb_value self) {
|
|||||||
for (uint64_t element_id : element_ids) {
|
for (uint64_t element_id : element_ids) {
|
||||||
app::Element *element = app::element_pool[element_id];
|
app::Element *element = app::element_pool[element_id];
|
||||||
app::element_pool.use(element_id);
|
app::element_pool.use(element_id);
|
||||||
if (element->type == Type::TEXT) {
|
mrb_value obj;
|
||||||
mrb_value obj = definitions::wrap(definitions::bindings.ElementText, element_id);
|
switch (element->type) {
|
||||||
|
case Type::TEXT:
|
||||||
|
obj = definitions::wrap(
|
||||||
|
definitions::bindings.ElementText,
|
||||||
|
element_id
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case Type::RECT:
|
||||||
|
obj = definitions::wrap(
|
||||||
|
definitions::bindings.ElementRect,
|
||||||
|
element_id
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case Type::IMAGE:
|
||||||
|
obj = definitions::wrap(
|
||||||
|
definitions::bindings.ElementImage,
|
||||||
|
element_id
|
||||||
|
);
|
||||||
mrb_ary_push(mrb, result, obj);
|
mrb_ary_push(mrb, result, obj);
|
||||||
} else if (element->type == Type::RECT) {
|
break;
|
||||||
mrb_value obj = definitions::wrap(definitions::bindings.ElementRect, element_id);
|
case Type::SCRIPT:
|
||||||
mrb_ary_push(mrb, result, obj);
|
obj = definitions::wrap(
|
||||||
} else if (element->type == Type::IMAGE) {
|
definitions::bindings.ElementScript,
|
||||||
mrb_value obj = definitions::wrap(definitions::bindings.ElementImage, element_id);
|
element_id
|
||||||
mrb_ary_push(mrb, result, obj);
|
);
|
||||||
} else {
|
break;
|
||||||
|
default:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
mrb_ary_push(mrb, result, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -177,6 +177,83 @@ bool Window::write(uint64_t text_id, Vec2<float> position, float z, float angle,
|
|||||||
return true;
|
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) {
|
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)) {
|
if (!image_pool.is_valid(image_id)) {
|
||||||
fprintf(stderr, "Invalid image ID: %llu\n", (unsigned long long)image_id);
|
fprintf(stderr, "Invalid image ID: %llu\n", (unsigned long long)image_id);
|
||||||
@@ -216,6 +293,28 @@ bool Window::draw_rect(Rect rect, Color color, float z, float angle, Vec2<float>
|
|||||||
return true;
|
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() {
|
void Window::draw_letterbox() {
|
||||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
|
||||||
|
|
||||||
@@ -335,6 +434,45 @@ void Window::render() {
|
|||||||
);
|
);
|
||||||
} break;
|
} 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: {
|
case RenderInstruction::DRAW_RECT: {
|
||||||
SDL_FRect dst_rect;
|
SDL_FRect dst_rect;
|
||||||
dst_rect.x = instruction.draw_rect.rect.x() * scale + offset.x;
|
dst_rect.x = instruction.draw_rect.rect.x() * scale + offset.x;
|
||||||
|
|||||||
+1
-1
@@ -138,7 +138,7 @@ The target users for this project could be one of 2 categories:
|
|||||||
|
|
||||||
Survey:
|
Survey:
|
||||||
|
|
||||||
In order to help me gague what my users would like,
|
In order to help me gauge what my users would like,
|
||||||
|
|
||||||
we'll be splitting the survey into 2 sections, one for indie developers and one for educators
|
we'll be splitting the survey into 2 sections, one for indie developers and one for educators
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user