Tinkering with a way to do modal UIs for things like inventory etc.

main
Zed A. Shaw 3 days ago
parent db441000f8
commit d8400d0a76
  1. 19
      constants.hpp
  2. 107
      gui.cpp
  3. 24
      gui.hpp
  4. 4
      main.cpp
  5. 4
      render.cpp
  6. 24
      render.hpp
  7. 23
      shaders/modal.frag
  8. 1
      status.txt
  9. 4
      tools/designer.cpp

@ -12,11 +12,24 @@ const int WALL_LIGHT_LEVEL = 3;
const int WORLDBUILD_DIVISION = 4;
const int WORLDBUILD_SHRINK = 2;
const int WORLDBUILD_MAX_PATH = 200;
const int GAME_MAP_POS = 600;
const int VIDEO_WINDOW_X=1600;
const int VIDEO_WINDOW_Y=900;
const int UI_FONT_SIZE=30;
const int BASE_MAP_FONT_SIZE=90;
const int GAME_MAP_PIXEL_POS = 600;
const int MAX_FONT_SIZE = 140;
const int MIN_FONT_SIZE = 20;
const int SCREEN_WIDTH = 40;
const int SCREEN_HEIGHT = 30;
const int STATUS_UI_WIDTH = 40;
const int STATUS_UI_HEIGHT = 30;
const float PERCENT = 0.01f;
const wchar_t BG_TILE = L'';
const wchar_t UI_BASE_CHAR = L'';
const int BG_BOX_OFFSET=5;
const int GAME_MAP_X=40;
const int GAME_MAP_Y=40;
const int INVENTORY_PIXEL_X=50;
const int INVENTORY_PIXEL_Y=50;
const int INVENTORY_WIDTH=99;
const int INVENTORY_HEIGHT=STATUS_UI_HEIGHT-3;
#define FONT_FILE_NAME "./assets/text.otf"
#define TILE_MAP_CONFIG "./assets/tiles.json"

@ -29,38 +29,13 @@ using namespace std::chrono_literals;
using namespace ftxui;
using namespace components;
const std::string modal_shader = R"(
uniform sampler2D source;
uniform sampler2D bloom;
uniform vec2 offsetFactor;
uniform float darkness;
void main()
{
vec2 textureCoordinates = gl_TexCoord[0].xy;
vec4 color = vec4(0.0);
color += texture2D(source, textureCoordinates - 4.0 * offsetFactor) * 0.0162162162;
color += texture2D(source, textureCoordinates - 3.0 * offsetFactor) * 0.0540540541;
color += texture2D(source, textureCoordinates - 2.0 * offsetFactor) * 0.1216216216;
color += texture2D(source, textureCoordinates - offsetFactor) * 0.1945945946;
color += texture2D(source, textureCoordinates) * 0.2270270270;
color += texture2D(source, textureCoordinates + offsetFactor) * 0.1945945946;
color += texture2D(source, textureCoordinates + 2.0 * offsetFactor) * 0.1216216216;
color += texture2D(source, textureCoordinates + 3.0 * offsetFactor) * 0.0540540541;
color += texture2D(source, textureCoordinates + 4.0 * offsetFactor) * 0.0162162162;
vec4 sourceFragment = texture2D(source, gl_TexCoord[0].xy);
vec4 bloomFragment = texture2D(bloom, gl_TexCoord[0].xy);
gl_FragColor = color + sourceFragment - bloomFragment - darkness;
}
)";
GUI::GUI(DinkyECS::World &world, Map& game_map) :
$game_map(game_map),
$log({{"Welcome to the game!"}}),
$status_ui(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT),
$map_view(GAME_MAP_POS, 0, 0, 0, true),
$status_ui(0, 0, STATUS_UI_WIDTH, STATUS_UI_HEIGHT),
$map_view(GAME_MAP_PIXEL_POS, 0, 0, 0, true),
$inventory_ui(INVENTORY_PIXEL_X, INVENTORY_PIXEL_Y, INVENTORY_WIDTH, INVENTORY_HEIGHT),
$lights(game_map.width(), game_map.height()),
$world(world),
$sounds("./assets"),
@ -72,8 +47,8 @@ GUI::GUI(DinkyECS::World &world, Map& game_map) :
$sounds.load("combat_player_hit", "combat_player_hit.mp3");
$sounds.load("combat_enemy_hit", "combat_enemy_hit.mp3");
$sounds.load("combat_miss", "combat_miss.mp3");
resize_map(MAX_FONT_SIZE);
init_shaders();
}
void GUI::resize_map(int new_size) {
@ -96,27 +71,21 @@ void GUI::create_renderer() {
return canvas($canvas);
}));
auto modal_buttons = Container::Horizontal({
Button("OK", [&]{ $show_modal = false; }),
Button("CANCEL", [&]{ $show_modal = false; }),
});
auto modal_test = Renderer([&, modal_buttons] {
return hbox({
hflow(
vbox(
text("Hello!"),
modal_buttons->Render()
))}) | border;
});
modal_test->Add(modal_buttons);
auto test_button = Container::Horizontal({
Button("Open Test Modal", [&]{ $show_modal = true; }),
Button("Close It", [&]{ $show_modal = false; }),
auto cell = [](const char* t) { return text(t) | border; };
auto inventory_test = Renderer([cell] {
return hflow({
gridbox({
{cell("one"), cell("two"), cell("three")},
{cell("four"), cell("five"), cell("six")},
{cell("seven"), cell("eight"), cell("nine")},
}) | yflex_grow,
separator() | yflex_grow,
paragraph("Item UI Goes Here") | yflex_grow
}) | border | flex;
});
auto status_rend = Renderer(test_button, [&, modal_test, test_button, player]{
auto status_rend = Renderer([&, player]{
const auto& player_combat = $world.get<Combat>(player.entity);
const auto& inventory = $world.get<Inventory>(player.entity);
$status_text = player_combat.hp > 0 ? "NOT DEAD" : "DEAD!!!!!!";
@ -131,7 +100,6 @@ void GUI::create_renderer() {
return hbox({
hflow(
vbox(
test_button->Render(),
text(format("HP: {: >3} GOLD: {: >3}",
player_combat.hp, inventory.gold)) | border,
text($status_text) | border,
@ -144,10 +112,8 @@ void GUI::create_renderer() {
});
});
status_rend |= Modal(modal_test, &$show_modal);
$status_ui.set_renderer(status_rend);
$status_ui.add(modal_test);
$inventory_ui.set_renderer(inventory_test);
}
void GUI::handle_world_events() {
@ -232,8 +198,13 @@ bool GUI::handle_ui_events() {
auto &debug = $world.get_the<Debug>();
debug.LIGHT = !debug.LIGHT;
} else if(KB::isKeyPressed(KB::I)) {
create_modal();
$show_modal = !$show_modal;
// yes, using an if to avoid double grabbing screen
if($show_modal) {
$show_modal = false;
} else {
pause_screen();
$show_modal = true;
}
} else if(KB::isKeyPressed(KB::P)) {
auto &debug = $world.get_the<Debug>();
debug.PATHS = !debug.PATHS;
@ -257,24 +228,24 @@ bool GUI::handle_ui_events() {
return event_happened;
}
void GUI::create_modal() {
println("CREATING MODAL");
void GUI::init_shaders() {
auto& shader = $paused.load_shader("./shaders/modal.frag");
shader.setUniform("offsetFactor", sf::Glsl::Vec2{0.001f, 0.001f});
shader.setUniform("darkness", 0.05f);
}
void GUI::pause_screen() {
auto &window = $renderer.$window;
auto size = window.getSize();
paused_texture.create(size.x, size.y);
paused_texture.update(window);
bool good = paused_shader.loadFromMemory(modal_shader, sf::Shader::Fragment);
paused_shader.setUniform("offsetFactor", sf::Glsl::Vec2{0.001f, 0.001f});
paused_shader.setUniform("darkness", 0.05f);
dbc::check(good, "shader could not be loaded");
paused_sprite.setTexture(paused_texture);
paused_sprite.setPosition(0,0);
$paused.texture.create(size.x, size.y);
$paused.texture.update(window);
$paused.sprite.setTexture($paused.texture);
$paused.sprite.setPosition(0,0);
}
void GUI::draw_modal() {
auto &window = $renderer.$window;
window.draw(paused_sprite, &paused_shader);
void GUI::draw_paused() {
$renderer.draw_sprite($paused.sprite, &$paused.shader);
}
void GUI::run_systems() {
@ -301,7 +272,9 @@ void GUI::render_scene() {
$renderer.clear();
if($show_modal) {
draw_modal();
draw_paused();
$inventory_ui.render();
$renderer.draw($inventory_ui);
} else {
$map_view.render();
$renderer.draw($map_view);

@ -35,6 +35,18 @@ struct ActionLog {
}
};
struct UnDumbTSS {
sf::Texture texture;
sf::Sprite sprite;
sf::Shader shader;
sf::Shader& load_shader(string filename) {
bool good = shader.loadFromFile(filename, sf::Shader::Fragment);
dbc::check(good, "shader could not be loaded");
return shader;
}
};
class GUI {
string $status_text = "NOT DEAD";
@ -43,16 +55,14 @@ class GUI {
ActionLog $log;
Panel $status_ui;
Panel $map_view;
Panel $inventory_ui;
LightRender $lights;
bool $show_modal = false;
Component $test_button;
DinkyECS::World& $world;
SoundManager $sounds;
SFMLRender $renderer;
sf::Texture paused_texture;
sf::Sprite paused_sprite;
sf::Shader paused_shader;
UnDumbTSS $paused;
public:
GUI(DinkyECS::World& world, Map& game_map);
@ -69,7 +79,9 @@ public:
void save_world();
void shake();
void shutdown();
void create_modal();
void draw_modal();
int main(bool run_once=false);
void pause_screen();
void draw_paused();
void init_shaders();
};

@ -3,6 +3,7 @@
#include "systems.hpp"
#include "events.hpp"
#include "components.hpp"
#include "constants.hpp"
#include "dbc.hpp"
#include "collider.hpp"
#include "render.hpp"
@ -59,9 +60,6 @@ void configure_world(DinkyECS::World &world, Map &game_map) {
world.set<Tile>(wall_torch, {""});
}
const int GAME_MAP_X = 40;
const int GAME_MAP_Y = 40;
int main(int argc, char *argv[]) {
DinkyECS::World world;
Map game_map(GAME_MAP_X, GAME_MAP_Y);

@ -203,6 +203,10 @@ void SFMLRender::render_text(const std::wstring &text, sf::Color default_fg, sf:
}
}
void SFMLRender::draw_sprite(sf::Sprite &sprite, sf::Shader *shader) {
$window.draw(sprite, shader);
}
/*
* Does not render the panel, you have to do that so you can control
* when things render.

@ -10,20 +10,23 @@
#include <codecvt>
#include "ansi_parser.hpp"
#include "panel.hpp"
#include "constants.hpp"
using ftxui::Canvas, ftxui::Screen;
/*
* BUG: This could be so much better.
*/
struct RenderConfig {
int video_x = 1600;
int video_y = 900;
int ui_font_size=30;
int base_map_font_size=90;
wchar_t bg_tile = L'';
wchar_t ui_base_char = L'';
int bg_box_offset=5;
int game_map_x=40;
int game_map_y=40;
int video_x = VIDEO_WINDOW_X;
int video_y = VIDEO_WINDOW_Y;
int ui_font_size=UI_FONT_SIZE;
int base_map_font_size=BASE_MAP_FONT_SIZE;
wchar_t bg_tile = BG_TILE;
wchar_t ui_base_char = UI_BASE_CHAR;
int bg_box_offset=BG_BOX_OFFSET;
int game_map_x=GAME_MAP_X;
int game_map_y=GAME_MAP_Y;
};
struct SFMLRender {
@ -55,6 +58,7 @@ struct SFMLRender {
void render_text(const std::wstring &text, sf::Color default_fg, sf::Color default_bg, float x, float y);
void draw(Panel &panel, float x_offset=0.0f, float y_offset=0.0f);
void draw_sprite(sf::Sprite &sprite, sf::Shader *shader);
bool poll_event(sf::Event &event) {
return $window.pollEvent(event);

@ -0,0 +1,23 @@
uniform sampler2D source;
uniform sampler2D bloom;
uniform vec2 offsetFactor;
uniform float darkness;
void main()
{
vec2 textureCoordinates = gl_TexCoord[0].xy;
vec4 color = vec4(0.0);
color += texture2D(source, textureCoordinates - 4.0 * offsetFactor) * 0.0162162162;
color += texture2D(source, textureCoordinates - 3.0 * offsetFactor) * 0.0540540541;
color += texture2D(source, textureCoordinates - 2.0 * offsetFactor) * 0.1216216216;
color += texture2D(source, textureCoordinates - offsetFactor) * 0.1945945946;
color += texture2D(source, textureCoordinates) * 0.2270270270;
color += texture2D(source, textureCoordinates + offsetFactor) * 0.1945945946;
color += texture2D(source, textureCoordinates + 2.0 * offsetFactor) * 0.1216216216;
color += texture2D(source, textureCoordinates + 3.0 * offsetFactor) * 0.0540540541;
color += texture2D(source, textureCoordinates + 4.0 * offsetFactor) * 0.0162162162;
vec4 sourceFragment = texture2D(source, gl_TexCoord[0].xy);
vec4 bloomFragment = texture2D(bloom, gl_TexCoord[0].xy);
gl_FragColor = color + sourceFragment - bloomFragment - darkness;
}

@ -1,5 +1,6 @@
TODAY'S GOAL:
* Create a move function for iterators that recalculates their position to make it easy to move them inside the matrix. This can then be used in lighting. Just make an iterator once, and move it around after.
* Components::Tile must also die.
* MapConfig must die.
* Tile component needs to go, use the Tiles from the json.

@ -138,8 +138,8 @@ class GUI {
Component $bg_settings;
GUI(string font_list) :
$font_view(GAME_MAP_POS, 0, GRID_SIZE.x, GRID_SIZE.y, true),
$status_ui(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT),
$font_view(GAME_MAP_PIXEL_POS, 0, GRID_SIZE.x, GRID_SIZE.y, true),
$status_ui(0, 0, STATUS_UI_WIDTH, STATUS_UI_HEIGHT),
$font_grid(font_list, GRID_SIZE.x, GRID_SIZE.y),
$fg_color{.h=20, .s=50, .v=20},
$bg_color{.h=100, .s=100, .v=100}

Loading…
Cancel
Save