#include "guecs/ui.hpp" #include "guecs/sfml/backend.hpp" #include #include #include namespace guecs { using std::make_shared; template void sfml_center_helper(T& obj, lel::Cell& cell, int padding) { sf::Vector2f position{float(cell.x + padding), float(cell.y + padding)}; if(cell.center) { auto bounds = obj->getLocalBounds(); position = {float(cell.mid_x), float(cell.mid_y)}; obj->setOrigin({bounds.size.x/2, bounds.size.y/2}); } obj->setPosition(position); } inline SpriteTexture load_texture(const string& name, bool is_icon) { if(is_icon) { return BACKEND->get_icon(name); } else { return BACKEND->get_sprite(name); } } void Text::init(lel::Cell &cell, shared_ptr font_ptr) { assert(font_ptr != nullptr && "you failed to initialize this WideText"); if(font == nullptr) font = font_ptr; if(text == nullptr) text = make_shared(*font, content, size); text->setFillColor(color); if(centered || cell.center) { auto bounds = text->getLocalBounds(); auto text_cell = lel::center(bounds.size.x, bounds.size.y, cell); // this stupid / 2 is because SFML renders from baseline rather than from the claimed bounding box text->setPosition({float(text_cell.x), float(text_cell.y) - text_cell.h / 2}); } else { text->setPosition({float(cell.x + padding * 2), float(cell.y + padding * 2)}); } text->setCharacterSize(size); } void Text::render(sf::RenderWindow& window, sf::Shader *shader_ptr) { window.draw(*text, shader_ptr); } void Text::update(const wstring& new_content) { content = new_content; text->setString(content); } void Sprite::update(const string& new_name) { if(new_name != name) { name = new_name; auto sprite_texture = BACKEND->get_sprite(name); sprite->setTexture(*sprite_texture.texture); sprite->setTextureRect({{0,0},sprite_texture.frame_size}); } } void Sprite::init(lel::Cell &cell) { if(cell.center) stretch = false; auto sprite_texture = load_texture(name, is_icon); auto bounds = sprite_texture.frame_size; sf::IntRect rect{{0,0}, bounds}; sprite = make_shared(*sprite_texture.texture, rect); if(stretch) { sprite->setScale({ float(cell.w - padding * 2) / float(bounds.x), float(cell.h - padding * 2) / float(bounds.y)}); } else { float box_width = float(cell.w - padding * 2); float box_height = float(cell.h - padding * 2); float scale = std::min(box_width / float(bounds.x), box_height / float(bounds.y)); sprite->setScale({scale, scale}); } sfml_center_helper(sprite, cell, padding); } void Sprite::render(sf::RenderWindow& window, sf::Shader *shader_ptr) { window.draw(*sprite, shader_ptr); } void Rectangle::init(lel::Cell& cell) { sf::Vector2f size{float(cell.w) - padding * 2, float(cell.h) - padding * 2}; if(shape == nullptr) shape = make_shared(size); shape->setFillColor(color); shape->setOutlineColor(border_color); 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) { bar.init(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); // ZED: this 6 is a border width, make it a thing bar.shape->setSize({std::max(level, 0.0f), float(cell.h - 6)}); window.draw(*bar.shape, shader_ptr); } void Sound::play(bool hover) { if(!hover) { BACKEND->sound_play(on_click); } } void Sound::stop(bool hover) { if(!hover) { BACKEND->sound_stop(on_click); } } void Background::init() { assert(w > 0.0f && "Background.w must be > 0.0f. Forgot $gui.$parser?"); assert(h > 0.0f && "Background.h must be > 0.0f. Forgot $gui.$parser?"); std::cout << "x=" << x << " y=" << y << " w=" << w << " h=" << h << std::endl; sf::Vector2f size{float(w), float(h)}; if(shape == nullptr) { shape = make_shared(size); } else { shape->setSize(size); } shape->setPosition({float(x), float(y)}); shape->setFillColor(color); assert(shape != nullptr && "failed to make rectangle"); } void Background::set_color(sf::Color c) { color = c; } void Background::set_sprite(const std::string& name, bool stretch) { auto sprite_texture = BACKEND->get_sprite(name); sf::IntRect rect{{0,0},sprite_texture.frame_size}; sprite = make_shared(*sprite_texture.texture, rect); sprite->setPosition({float(x), float(y)}); if(stretch) { auto bounds = sprite->getLocalBounds(); sprite->setScale({ float(w) / bounds.size.x, float(h) / bounds.size.y}); } } void Background::render(sf::RenderWindow& window) { if(shape != nullptr) { window.draw(*shape); } if(sprite != nullptr) { window.draw(*sprite); } } void Effect::init(lel::Cell &cell) { $shader = BACKEND->get_shader(name); $shader->setUniform("u_resolution", sf::Vector2f({float(cell.w), float(cell.h)})); $clock = std::make_shared(); } void Effect::render() { sf::Time cur_time = $clock->getElapsedTime(); float u_time = cur_time.asSeconds(); if(u_time < $u_time_end) { $shader->setUniform("u_duration", duration); $shader->setUniform("u_time_end", $u_time_end); $shader->setUniform("u_time", u_time); } else { $active = false; } } void Effect::run() { $active = true; sf::Time u_time = $clock->getElapsedTime(); $u_time_end = u_time.asSeconds() + duration; } sf::Shader* Effect::get_shader(bool is_shape) { sf::Shader *shader_ptr = nullptr; if(BACKEND->shader_updated()) { $shader = BACKEND->get_shader(name); } 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() { $active = false; } }