Refactoring the GUECS UI::render and the components so that it's just calling a .render on each one. This will then let me allow registering any components people want.

main
Zed A. Shaw 7 days ago
parent a9e219ea96
commit 4d71f552aa
  1. 2
      demos/calc.cpp
  2. 65
      demos/clicker_game.cpp
  3. 12
      include/guecs/sfml/components.hpp
  4. 17
      include/guecs/ui.hpp
  5. 4
      src/guecs/sfml/backend.cpp
  6. 37
      src/guecs/sfml/components.cpp
  7. 44
      src/guecs/ui.cpp

@ -150,7 +150,7 @@ struct CalculatorUI {
} }
void init() { void init() {
$gui.set<guecs::Background>($gui.MAIN, {}); $gui.set<guecs::Background>($gui.MAIN, {$gui.$parser});
for(auto& [name, cell] : $gui.cells()) { for(auto& [name, cell] : $gui.cells()) {
auto id = $gui.entity(name); auto id = $gui.entity(name);

@ -55,7 +55,7 @@ struct Shake {
float tick = ease(); float tick = ease();
sf::Vector2f scale{ sf::Vector2f scale{
std::lerp(initial_scale.x, initial_scale.x + scale_factor, tick), std::lerp(initial_scale.x, initial_scale.x + scale_factor, tick),
std::lerp(initial_scale.y, initial_scale.y + scale_factor, tick)}; std::lerp(initial_scale.y, initial_scale.y + scale_factor, tick)};
sprite.sprite->setScale(scale); sprite.sprite->setScale(scale);
} else { } else {
@ -83,34 +83,35 @@ struct ClickerUI {
void init() { void init() {
$gui.set<guecs::Background>($gui.MAIN, {$gui.$parser, {0, 0, 0, 255}}); $gui.set<guecs::Background>($gui.MAIN, {$gui.$parser, {0, 0, 0, 255}});
for(auto& [name, cell] : $gui.cells()) { for(auto& [name, cell] : $gui.cells()) {
auto id = $gui.entity(name); auto id = $gui.entity(name);
if(name != "clicker") { if(name != "clicker") {
$gui.set<guecs::Rectangle>(id, {}); $gui.set<guecs::Rectangle>(id, {});
$gui.set<guecs::Effect>(id, {}); $gui.set<guecs::Effect>(id, {});
$gui.set<guecs::Sprite>(id, { "clicker_treat_bone" }); $gui.set<guecs::Sprite>(id, { "clicker_treat_bone" });
fmt::println("button dim: {},{}", cell.w, cell.h); fmt::println("button dim: {},{}", cell.w, cell.h);
$gui.set<guecs::Clickable>(id, { $gui.set<guecs::Clickable>(id, {
[&](auto, auto) { handle_button(Event::A_BUTTON); } [&](auto, auto) { handle_button(Event::A_BUTTON); }
}); });
} }
} }
$clicker = $gui.entity("clicker"); $clicker = $gui.entity("clicker");
$gui.set<guecs::Sprite>($clicker, {"clicker_the_dog"}); $gui.set<guecs::Sprite>($clicker, {"clicker_the_dog"});
$gui.set<guecs::Sound>($clicker, {"clicker_bark"}); $gui.set<guecs::Sound>($clicker, {"clicker_bark"});
$gui.set<guecs::Clickable>($clicker, { $gui.set<guecs::Clickable>($clicker, {
[&](auto, auto) { handle_button(Event::CLICKER); } [&](auto, auto) { handle_button(Event::CLICKER); }
}); });
// custom components need to be initialized manually // custom components need to be initialized manually
$gui.set_init<Shake>($clicker, {}); $gui.set_init<Shake>($clicker, {});
$gui.init(); $gui.init();
} }
void render(sf::RenderWindow& window) { void render(sf::RenderWindow& window) {
auto& shaker = $gui.get<Shake>($clicker); auto& shaker = $gui.get<Shake>($clicker);
if(shaker.playing) { if(shaker.playing) {
auto& sprite = $gui.get<guecs::Sprite>($clicker); auto& sprite = $gui.get<guecs::Sprite>($clicker);
shaker.render(sprite); shaker.render(sprite);
@ -130,17 +131,17 @@ struct ClickerUI {
using enum Event; using enum Event;
switch(ev) { switch(ev) {
case CLICKER: { case CLICKER: {
auto& shaker = $gui.get<Shake>($clicker); auto& shaker = $gui.get<Shake>($clicker);
auto& sprite = $gui.get<guecs::Sprite>($clicker); auto& sprite = $gui.get<guecs::Sprite>($clicker);
shaker.play(sprite); shaker.play(sprite);
fmt::println("CLICKER LOVES YOU!"); fmt::println("CLICKER LOVES YOU!");
} break; } break;
case A_BUTTON: case A_BUTTON:
fmt::println("a button clicked"); fmt::println("a button clicked");
break; break;
default: default:
assert(false && "invalid event"); assert(false && "invalid event");
} }
} }
}; };
@ -149,7 +150,7 @@ int main() {
sfml::Backend backend; sfml::Backend backend;
guecs::init(&backend); guecs::init(&backend);
sf::RenderWindow window(sf::VideoMode({WINDOW_WIDTH, WINDOW_HEIGHT}), "LEL-GUECS Calculator"); sf::RenderWindow window(sf::VideoMode({WINDOW_WIDTH, WINDOW_HEIGHT}), "Clicker the Dog");
window.setFramerateLimit(FRAME_LIMIT); window.setFramerateLimit(FRAME_LIMIT);
window.setVerticalSyncEnabled(VSYNC); window.setVerticalSyncEnabled(VSYNC);

@ -21,6 +21,7 @@ namespace guecs {
void init(lel::Cell &cell, shared_ptr<sf::Font> font_ptr); void init(lel::Cell &cell, shared_ptr<sf::Font> font_ptr);
void update(const std::wstring& new_content); void update(const std::wstring& new_content);
void render(sf::RenderWindow& window, sf::Shader *shader_ptr);
}; };
struct Label : public Textual { struct Label : public Textual {
@ -49,6 +50,7 @@ namespace guecs {
void init(lel::Cell &cell); void init(lel::Cell &cell);
void update(const string& new_name); void update(const string& new_name);
void render(sf::RenderWindow& window, sf::Shader *shader_ptr);
}; };
struct Rectangle { struct Rectangle {
@ -59,6 +61,7 @@ namespace guecs {
shared_ptr<sf::RectangleShape> shape = nullptr; shared_ptr<sf::RectangleShape> shape = nullptr;
void init(lel::Cell& cell); void init(lel::Cell& cell);
void render(sf::RenderWindow& window, sf::Shader *shader_ptr);
}; };
struct Meter { struct Meter {
@ -67,7 +70,8 @@ namespace guecs {
Rectangle bar; Rectangle bar;
void init(lel::Cell& cell); void init(lel::Cell& cell);
void render(lel::Cell& cell); void init(lel::Cell& cell, Rectangle& bg);
void render(lel::Cell& cell, sf::RenderWindow& window, sf::Shader *shader_ptr);
}; };
struct Effect { struct Effect {
@ -82,8 +86,9 @@ namespace guecs {
void init(lel::Cell &cell); void init(lel::Cell &cell);
void run(); void run();
void stop(); void stop();
void step(); void render();
shared_ptr<sf::Shader> checkout_ptr(); sf::Shader* get_shader(bool is_shape);
}; };
struct Sound { struct Sound {
@ -111,5 +116,6 @@ namespace guecs {
Background() {} Background() {}
void init(); void init();
void render(sf::RenderWindow& window);
}; };
} }

@ -209,20 +209,11 @@ namespace guecs {
} }
template<typename T> template<typename T>
void render_helper(sf::RenderWindow& window, Entity ent, bool is_shape, T& target) { void render_helper(sf::RenderWindow& window, T& target, sf::Shader *shader_ptr) {
sf::Shader *shader_ptr = nullptr; window.draw(*target, shader_ptr);
}
if(auto shader = get_if<Effect>(ent)) {
if(shader->$active) {
auto ptr = shader->checkout_ptr();
ptr->setUniform("is_shape", is_shape);
// NOTE: this is needed because SFML doesn't handle shared_ptr
shader_ptr = ptr.get();
}
}
window.draw(*target, shader_ptr); sf::Shader* find_shader(Entity ent, bool is_shape);
}
void show_sprite(const string& region, const string& sprite_name); void show_sprite(const string& region, const string& sprite_name);
void show_text(const string& region, const wstring& content); void show_text(const string& region, const wstring& content);

@ -45,8 +45,8 @@ namespace sfml {
theme.LABEL_SIZE = 20; theme.LABEL_SIZE = 20;
theme.FILL_COLOR = theme.DARK_MID; theme.FILL_COLOR = theme.DARK_MID;
theme.TEXT_COLOR = theme.LIGHT_LIGHT; theme.TEXT_COLOR = theme.LIGHT_LIGHT;
theme.BG_COLOR = theme.MID; theme.BG_COLOR = theme.DARK_DARK;
theme.BORDER_COLOR = theme.LIGHT_DARK; theme.BORDER_COLOR = theme.DARK_LIGHT;
theme.BG_COLOR_DARK = theme.BLACK; theme.BG_COLOR_DARK = theme.BLACK;
theme.FONT_FILE_NAME = "assets/text.otf"; theme.FONT_FILE_NAME = "assets/text.otf";

@ -24,6 +24,10 @@ namespace guecs {
text->setCharacterSize(size); text->setCharacterSize(size);
} }
void Textual::render(sf::RenderWindow& window, sf::Shader *shader_ptr) {
window.draw(*text, shader_ptr);
}
void Textual::update(const wstring& new_content) { void Textual::update(const wstring& new_content) {
content = new_content; content = new_content;
text->setString(content); text->setString(content);
@ -56,6 +60,10 @@ namespace guecs {
float(cell.h - padding * 2) / bounds.size.y}); float(cell.h - padding * 2) / bounds.size.y});
} }
void Sprite::render(sf::RenderWindow& window, sf::Shader *shader_ptr) {
window.draw(*sprite, shader_ptr);
}
void Rectangle::init(lel::Cell& cell) { void Rectangle::init(lel::Cell& cell) {
sf::Vector2f size{float(cell.w) - padding * 2, float(cell.h) - padding * 2}; sf::Vector2f size{float(cell.w) - padding * 2, float(cell.h) - padding * 2};
if(shape == nullptr) shape = make_shared<sf::RectangleShape>(size); if(shape == nullptr) shape = make_shared<sf::RectangleShape>(size);
@ -65,15 +73,24 @@ namespace guecs {
shape->setOutlineThickness(border_px); shape->setOutlineThickness(border_px);
} }
void Rectangle::render(sf::RenderWindow& window, sf::Shader *shader_ptr) {
window.draw(*shape, shader_ptr);
}
void Meter::init(lel::Cell& cell, Rectangle& bg) {
bg.shape->setFillColor(color);
init(cell);
}
void Meter::init(lel::Cell& cell) { void Meter::init(lel::Cell& cell) {
bar.init(cell); bar.init(cell);
} }
void Meter::render(lel::Cell& cell) { void Meter::render(lel::Cell& cell, sf::RenderWindow& window, sf::Shader *shader_ptr) {
float level = std::clamp(percent, 0.0f, 1.0f) * float(cell.w); float level = std::clamp(percent, 0.0f, 1.0f) * float(cell.w);
// ZED: this 6 is a border width, make it a thing // ZED: this 6 is a border width, make it a thing
bar.shape->setSize({std::max(level, 0.0f), float(cell.h - 6)}); bar.shape->setSize({std::max(level, 0.0f), float(cell.h - 6)});
window.draw(*bar.shape, shader_ptr);
} }
void Sound::play(bool hover) { void Sound::play(bool hover) {
@ -104,13 +121,17 @@ namespace guecs {
assert(shape != nullptr && "failed to make rectangle"); assert(shape != nullptr && "failed to make rectangle");
} }
void Background::render(sf::RenderWindow& window) {
window.draw(*shape);
}
void Effect::init(lel::Cell &cell) { void Effect::init(lel::Cell &cell) {
$shader = BACKEND->shader_get(name); $shader = BACKEND->shader_get(name);
$shader->setUniform("u_resolution", sf::Vector2f({float(cell.w), float(cell.h)})); $shader->setUniform("u_resolution", sf::Vector2f({float(cell.w), float(cell.h)}));
$clock = std::make_shared<sf::Clock>(); $clock = std::make_shared<sf::Clock>();
} }
void Effect::step() { void Effect::render() {
sf::Time cur_time = $clock->getElapsedTime(); sf::Time cur_time = $clock->getElapsedTime();
float u_time = cur_time.asSeconds(); float u_time = cur_time.asSeconds();
@ -129,12 +150,20 @@ namespace guecs {
$u_time_end = u_time.asSeconds() + duration; $u_time_end = u_time.asSeconds() + duration;
} }
shared_ptr<sf::Shader> Effect::checkout_ptr() { sf::Shader* Effect::get_shader(bool is_shape) {
sf::Shader *shader_ptr = nullptr;
if(BACKEND->shader_updated()) { if(BACKEND->shader_updated()) {
$shader = BACKEND->shader_get(name); $shader = BACKEND->shader_get(name);
} }
return $shader; if($active) {
$shader->setUniform("is_shape", is_shape);
// NOTE: this is needed because SFML doesn't handle shared_ptr
shader_ptr = $shader.get();
}
return shader_ptr;
} }
void Effect::stop() { void Effect::stop() {

@ -66,12 +66,12 @@ namespace guecs {
shader.init(cell); shader.init(cell);
}); });
query<Rectangle, Meter>([](auto, auto& bg, auto &meter) { query<lel::Cell, Meter>([this](auto ent, auto &cell, auto& meter) {
bg.shape->setFillColor(meter.color); if(auto bg = get_if<Rectangle>(ent)) {
}); meter.init(cell, *bg);
} else {
query<lel::Cell, Meter>([](auto, auto &cell, auto& meter) { meter.init(cell);
meter.init(cell); }
}); });
query<lel::Cell, Textual>([this](auto, auto& cell, auto& text) { query<lel::Cell, Textual>([this](auto, auto& cell, auto& text) {
@ -98,34 +98,46 @@ namespace guecs {
}); });
} }
sf::Shader* UI::find_shader(Entity ent, bool is_shape) {
if(auto shader = get_if<Effect>(ent)) {
return shader->get_shader(is_shape);
} else {
return nullptr;
}
}
void UI::render(sf::RenderWindow& window) { void UI::render(sf::RenderWindow& window) {
if(auto bg = get_if<Background>(MAIN)) { if(auto bg = get_if<Background>(MAIN)) {
window.draw(*(bg->shape)); bg->render(window);
} }
query<Effect>([&](auto, auto& shader) { query<Effect>([&](auto, auto& shader) {
if(shader.$active) shader.step(); if(shader.$active) shader.render();
}); });
query<Rectangle>([&](auto ent, auto& rect) { query<Rectangle>([&](auto ent, auto& rect) {
render_helper(window, ent, true, rect.shape); auto shader_ptr = find_shader(ent, true);
rect.render(window, shader_ptr);
}); });
query<lel::Cell, Meter>([&](auto ent, auto& cell, auto &meter) { query<lel::Cell, Meter>([&](auto ent, auto& cell, auto &meter) {
meter.render(cell); auto shader_ptr = find_shader(ent, true);
render_helper(window, ent, true, meter.bar.shape); meter.render(cell, window, shader_ptr);
}); });
query<Sprite>([&](auto ent, auto& sprite) { query<Sprite>([&](auto ent, auto& sprite) {
render_helper(window, ent, false, sprite.sprite); auto shader_ptr = find_shader(ent, false);
sprite.render(window, shader_ptr);
}); });
query<Label>([&](auto ent, auto& text) { query<Label>([&](auto ent, auto& text) {
render_helper(window, ent, false, text.text); auto shader_ptr = find_shader(ent, false);
text.render(window, shader_ptr);
}); });
query<Textual>([&](auto ent, auto& text) { query<Textual>([&](auto ent, auto& text) {
render_helper(window, ent, false, text.text); auto shader_ptr = find_shader(ent, false);
text.render(window, shader_ptr);
}); });
} }
@ -157,8 +169,8 @@ namespace guecs {
}); });
do_if<Sound>(ent, [hover](auto& sound) { do_if<Sound>(ent, [hover](auto& sound) {
// here set that it played then only play once // here set that it played then only play once
sound.stop(hover); sound.stop(hover);
}); });
} }
}); });

Loading…
Cancel
Save