A barely working tool to find font characters and pick their color.

main
Zed A. Shaw 5 days ago
parent 6b3ce5eb3d
commit 0edd948101
  1. 4
      Makefile
  2. 64
      ansi_parser.cpp
  3. 1
      ansi_parser.rl
  4. 3
      assets/config.json
  5. 1
      components.hpp
  6. 5
      constants.hpp
  7. 16
      gui.cpp
  8. 4
      gui.hpp
  9. 14
      meson.build
  10. 10
      panel.cpp
  11. 3
      panel.hpp
  12. 45
      render.cpp
  13. 6
      render.hpp
  14. 3
      save.cpp
  15. 20
      status.txt
  16. 15
      systems.cpp
  17. 262
      tools/designer.cpp

@ -34,3 +34,7 @@ debug_run: build
cover: cover:
gcovr --html coverage/index.html --gcov-ignore-errors=no_working_dir_found --exclude "scratchpad.*" --exclude "subprojects.*" --html-nested coverage/ gcovr --html coverage/index.html --gcov-ignore-errors=no_working_dir_found --exclude "scratchpad.*" --exclude "subprojects.*" --html-nested coverage/
designer: build
powershell "cp ./builddir/designer.exe ."
./designer

@ -10,7 +10,7 @@
using namespace fmt; using namespace fmt;
#line 121 "ansi_parser.rl" #line 122 "ansi_parser.rl"
@ -25,23 +25,23 @@ static const char _ansi_parser_actions[] = {
static const char _ansi_parser_key_offsets[] = { static const char _ansi_parser_key_offsets[] = {
0, 0, 1, 2, 10, 11, 13, 16, 0, 0, 1, 2, 10, 11, 13, 16,
19, 20, 24, 25, 26, 27, 28, 30, 20, 21, 25, 26, 27, 28, 29, 31,
33, 35, 38, 40, 43, 44, 47, 48, 34, 36, 39, 41, 44, 45, 48, 49,
49, 50, 51, 52 50, 51, 52, 53
}; };
static const int _ansi_parser_trans_keys[] = { static const int _ansi_parser_trans_keys[] = {
27, 91, 49, 50, 51, 52, 55, 57, 27, 91, 49, 50, 51, 52, 55, 57,
48, 54, 109, 48, 109, 34, 48, 55, 48, 54, 109, 48, 109, 34, 48, 55,
50, 55, 109, 109, 49, 56, 57, 109, 50, 52, 55, 109, 109, 49, 56, 57,
109, 59, 50, 59, 48, 57, 59, 48, 109, 109, 59, 50, 59, 48, 57, 59,
57, 48, 57, 59, 48, 57, 48, 57, 48, 57, 48, 57, 59, 48, 57, 48,
109, 48, 57, 109, 56, 57, 109, 59, 57, 109, 48, 57, 109, 56, 57, 109,
50, 109, 109, 27, 27, 0 59, 50, 109, 109, 27, 27, 0
}; };
static const char _ansi_parser_single_lengths[] = { static const char _ansi_parser_single_lengths[] = {
0, 1, 1, 6, 1, 2, 3, 3, 0, 1, 1, 6, 1, 2, 3, 4,
1, 4, 1, 1, 1, 1, 0, 1, 1, 4, 1, 1, 1, 1, 0, 1,
0, 1, 0, 1, 1, 3, 1, 1, 0, 1, 0, 1, 1, 3, 1, 1,
1, 1, 1, 1 1, 1, 1, 1
@ -56,35 +56,35 @@ static const char _ansi_parser_range_lengths[] = {
static const char _ansi_parser_index_offsets[] = { static const char _ansi_parser_index_offsets[] = {
0, 0, 2, 4, 12, 14, 17, 21, 0, 0, 2, 4, 12, 14, 17, 21,
25, 27, 32, 34, 36, 38, 40, 42, 26, 28, 33, 35, 37, 39, 41, 43,
45, 47, 50, 52, 55, 57, 61, 63, 46, 48, 51, 53, 56, 58, 62, 64,
65, 67, 69, 71 66, 68, 70, 72
}; };
static const char _ansi_parser_trans_targs[] = { static const char _ansi_parser_trans_targs[] = {
2, 1, 3, 0, 5, 7, 9, 21, 2, 1, 3, 0, 5, 7, 9, 21,
25, 6, 4, 0, 27, 0, 6, 27, 25, 6, 4, 0, 27, 0, 6, 27,
0, 4, 4, 4, 0, 4, 8, 27, 0, 4, 4, 4, 0, 4, 4, 8,
0, 27, 0, 10, 11, 20, 27, 0, 27, 0, 27, 0, 10, 11, 20, 27,
27, 0, 12, 0, 13, 0, 14, 0, 0, 27, 0, 12, 0, 13, 0, 14,
15, 0, 16, 15, 0, 17, 0, 18, 0, 15, 0, 16, 15, 0, 17, 0,
17, 0, 19, 0, 27, 19, 0, 27, 18, 17, 0, 19, 0, 27, 19, 0,
0, 22, 24, 27, 0, 23, 0, 13, 27, 0, 22, 24, 27, 0, 23, 0,
0, 27, 0, 27, 0, 2, 1, 2, 13, 0, 27, 0, 27, 0, 2, 1,
1, 0 2, 1, 0
}; };
static const char _ansi_parser_trans_actions[] = { static const char _ansi_parser_trans_actions[] = {
0, 7, 0, 0, 21, 21, 21, 21, 0, 7, 0, 0, 21, 21, 21, 21,
21, 21, 21, 0, 0, 0, 0, 0, 21, 21, 21, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0,
0, 15, 0, 0, 0, 0, 0, 0, 17, 0, 15, 0, 0, 0, 0, 0,
19, 0, 0, 0, 3, 0, 0, 0, 0, 19, 0, 0, 0, 3, 0, 0,
1, 0, 25, 0, 0, 1, 0, 28, 0, 1, 0, 25, 0, 0, 1, 0,
0, 0, 1, 0, 34, 0, 0, 9, 28, 0, 0, 1, 0, 34, 0, 0,
0, 0, 0, 0, 0, 0, 0, 5, 9, 0, 0, 0, 0, 0, 0, 0,
0, 11, 0, 13, 0, 0, 7, 23, 5, 0, 11, 0, 13, 0, 0, 7,
31, 0 23, 31, 0
}; };
static const char _ansi_parser_eof_actions[] = { static const char _ansi_parser_eof_actions[] = {
@ -101,7 +101,7 @@ static const int ansi_parser_error = 0;
static const int ansi_parser_en_main = 26; static const int ansi_parser_en_main = 26;
#line 124 "ansi_parser.rl" #line 125 "ansi_parser.rl"
#include <ftxui/screen/terminal.hpp> #include <ftxui/screen/terminal.hpp>
@ -128,7 +128,7 @@ bool ANSIParser::parse(std::wstring_view codes, ColorCB color_cb, WriteCB write_
cs = ansi_parser_start; cs = ansi_parser_start;
} }
#line 145 "ansi_parser.rl" #line 146 "ansi_parser.rl"
#line 121 "ansi_parser.cpp" #line 121 "ansi_parser.cpp"
{ {
@ -349,7 +349,7 @@ _again:
_out: {} _out: {}
} }
#line 146 "ansi_parser.rl" #line 147 "ansi_parser.rl"
bool good = pe - p == 0; bool good = pe - p == 0;

@ -108,6 +108,7 @@ using namespace fmt;
"7" %invert | "7" %invert |
"31" %red_text | "31" %red_text |
"22" | "22" |
"24" |
"27" %reset_invert | "27" %reset_invert |
"9" ["0"-"7"] | "9" ["0"-"7"] |
"10" ["0"-"7"] | "10" ["0"-"7"] |

@ -4,7 +4,8 @@
"FLOOR_TILE": "\u2849", "FLOOR_TILE": "\u2849",
"PLAYER_TILE": "\ua66b", "PLAYER_TILE": "\ua66b",
"ENEMY_TILE": "Ω", "ENEMY_TILE": "Ω",
"BG_TILE": "█" "BG_TILE": "█",
"WATER_TILE": "\u26c6"
}, },
"enemy": { "enemy": {
"HEARING_DISTANCE": 8 "HEARING_DISTANCE": 8

@ -43,6 +43,7 @@ namespace components {
std::string PLAYER_TILE; std::string PLAYER_TILE;
std::string ENEMY_TILE; std::string ENEMY_TILE;
std::string BG_TILE; std::string BG_TILE;
std::string WATER_TILE;
}; };
struct EnemyConfig { struct EnemyConfig {

@ -12,3 +12,8 @@ const int WALL_LIGHT_LEVEL = 3;
const int WORLDBUILD_DIVISION = 4; const int WORLDBUILD_DIVISION = 4;
const int WORLDBUILD_SHRINK = 2; const int WORLDBUILD_SHRINK = 2;
const int WORLDBUILD_MAX_PATH = 200; const int WORLDBUILD_MAX_PATH = 200;
const int GAME_MAP_POS = 600;
const int MAX_FONT_SIZE = 140;
const int MIN_FONT_SIZE = 20;
const int SCREEN_WIDTH = 40;
const int SCREEN_HEIGHT = 30;

@ -21,9 +21,7 @@
#include "events.hpp" #include "events.hpp"
#include "render.hpp" #include "render.hpp"
#include "save.hpp" #include "save.hpp"
#include "constants.hpp"
const int MAX_FONT_SIZE = 140;
const int MIN_FONT_SIZE = 20;
using std::string; using std::string;
using namespace fmt; using namespace fmt;
@ -210,13 +208,11 @@ bool GUI::handle_ui_events() {
$status_ui.$component->OnEvent(Event::Return); $status_ui.$component->OnEvent(Event::Return);
} }
} else if(MOUSE::isButtonPressed(MOUSE::Left)) { } else if(MOUSE::isButtonPressed(MOUSE::Left)) {
Point pos = $renderer.mouse_position(); Point pos;
Mouse mev{ if($renderer.mouse_position($status_ui, pos)) {
.button=Mouse::Button::Left, $status_ui.mouse_click(Mouse::Button::Left, pos);
.x=int(pos.x), .y=int(pos.y) event_happened = true;
}; }
$status_ui.$component->OnEvent(Event::Mouse("", mev));
} }
} }

@ -24,9 +24,6 @@ using std::string;
using ftxui::Canvas, ftxui::Component, ftxui::Screen, ftxui::Button; using ftxui::Canvas, ftxui::Component, ftxui::Screen, ftxui::Button;
using lighting::LightRender; using lighting::LightRender;
constexpr int SCREEN_WIDTH = 40;
constexpr int SCREEN_HEIGHT = 30;
struct ActionLog { struct ActionLog {
std::deque<std::string> messages; std::deque<std::string> messages;
@ -38,7 +35,6 @@ struct ActionLog {
} }
}; };
const int GAME_MAP_POS = 600;
class GUI { class GUI {
string $status_text = "NOT DEAD"; string $status_text = "NOT DEAD";

@ -77,6 +77,20 @@ roguish = executable('roguish', [
], ],
dependencies: dependencies) dependencies: dependencies)
designer = executable('designer', [
'matrix.cpp',
'dbc.cpp',
'rand.cpp',
'ansi_parser.cpp',
'render.cpp',
'config.cpp',
'panel.cpp',
'pathing.cpp',
'lights.cpp',
'tools/designer.cpp'
],
dependencies: dependencies)
img2ansi = executable('img2ansi', [ img2ansi = executable('img2ansi', [
'dbc.cpp', 'dbc.cpp',
'panel.cpp', 'panel.cpp',

@ -35,6 +35,16 @@ const std::wstring& Panel::to_string() {
return $screenout; return $screenout;
} }
void Panel::mouse_click(ftxui::Mouse::Button btn, Point pos) {
ftxui::Mouse mev{
.button=btn,
.x=int(pos.x), .y=int(pos.y)
};
$component->OnEvent(ftxui::Event::Mouse("", mev));
}
const Screen &Panel::screen() { const Screen &Panel::screen() {
return $screen; return $screen;
} }

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <ftxui/dom/node.hpp> // for Render #include <ftxui/dom/node.hpp> // for Render
#include <ftxui/component/component.hpp> #include <ftxui/component/component.hpp>
#include <ftxui/component/mouse.hpp>
#include <ftxui/dom/canvas.hpp> #include <ftxui/dom/canvas.hpp>
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp>
#include <ftxui/dom/canvas.hpp> #include <ftxui/dom/canvas.hpp>
@ -10,6 +11,7 @@
#include <locale> #include <locale>
#include <codecvt> #include <codecvt>
#include "color.hpp" #include "color.hpp"
#include "point.hpp"
const int UI_PANEL_BORDER_PX=5; const int UI_PANEL_BORDER_PX=5;
@ -49,6 +51,7 @@ struct Panel {
void set_renderer(Component renderer); void set_renderer(Component renderer);
void add(Component child); void add(Component child);
void render(); void render();
void mouse_click(ftxui::Mouse::Button btn, Point pos);
const std::wstring &to_string(); const std::wstring &to_string();
const Screen &screen(); const Screen &screen();
}; };

@ -32,7 +32,7 @@ SFMLRender::SFMLRender() :
$ui_text.setCharacterSize($config.ui_font_size); $ui_text.setCharacterSize($config.ui_font_size);
$ui_text.setFillColor(ColorValue::LIGHT_MID); $ui_text.setFillColor(ColorValue::LIGHT_MID);
sf::Glyph glyph = $font.getGlyph($config.ui_base_char, $config.ui_font_size, false); sf::Glyph glyph = $font.getGlyph($config.ui_base_char, $config.ui_font_size, false);
$ui_bounds = glyph.bounds; $text_bounds = glyph.bounds;
} }
sf::Sprite &SFMLRender::get_text_sprite(wchar_t tile) { sf::Sprite &SFMLRender::get_text_sprite(wchar_t tile) {
@ -62,18 +62,18 @@ void SFMLRender::resize_grid(int new_size, Panel &panel_out) {
$sprites.clear(); // need to reset the sprites for the new size $sprites.clear(); // need to reset the sprites for the new size
$line_spacing = $font.getLineSpacing($map_font_size); $line_spacing = $font.getLineSpacing($map_font_size);
$bg_sprite = get_text_sprite($config.bg_tile); $bg_sprite = get_text_sprite($config.bg_tile);
$bg_bounds = $bg_sprite.getLocalBounds(); $grid_bounds = $bg_sprite.getLocalBounds();
panel_out.resize(view_x, view_y); panel_out.resize(view_x, view_y);
} }
inline void configure_tile(const sf::Sprite &sprite, sf::FloatRect &sp_bounds, sf::FloatRect bg_bounds, float &width_delta, float &height_delta) { inline void configure_tile(const sf::Sprite &sprite, sf::FloatRect &sp_bounds, sf::FloatRect grid_bounds, float &width_delta, float &height_delta) {
// BUG: I think I could create a struct that kept this info for all sprites loaded // BUG: I think I could create a struct that kept this info for all sprites loaded
// should look into caching all this instead of calcing it each time // should look into caching all this instead of calcing it each time
sp_bounds = sprite.getLocalBounds(); sp_bounds = sprite.getLocalBounds();
// calculate where to center the sprite, but only if it's smaller // calculate where to center the sprite, but only if it's smaller
width_delta = bg_bounds.width > sp_bounds.width ? (bg_bounds.width - sp_bounds.width) / 2 : 0; width_delta = grid_bounds.width > sp_bounds.width ? (grid_bounds.width - sp_bounds.width) / 2 : 0;
height_delta = bg_bounds.height > sp_bounds.width ? (bg_bounds.height - sp_bounds.height) / 2 : 0; height_delta = grid_bounds.height > sp_bounds.width ? (grid_bounds.height - sp_bounds.height) / 2 : 0;
} }
void SFMLRender::render_grid(const std::wstring &text, sf::Color default_fg, sf::Color default_bg, float x, float y) { void SFMLRender::render_grid(const std::wstring &text, sf::Color default_fg, sf::Color default_bg, float x, float y) {
@ -106,7 +106,7 @@ void SFMLRender::render_grid(const std::wstring &text, sf::Color default_fg, sf:
// only get a new sprite if the tile changed // only get a new sprite if the tile changed
if(last_tile != tile) { if(last_tile != tile) {
sprite = get_text_sprite(tile); sprite = get_text_sprite(tile);
configure_tile(sprite, sp_bounds, $bg_bounds, width_delta, height_delta); configure_tile(sprite, sp_bounds, $grid_bounds, width_delta, height_delta);
last_tile = tile; // update last tile seen last_tile = tile; // update last tile seen
} }
@ -129,13 +129,13 @@ void SFMLRender::render_grid(const std::wstring &text, sf::Color default_fg, sf:
} }
inline sf::FloatRect draw_chunk(sf::RenderWindow& window, inline sf::FloatRect draw_chunk(sf::RenderWindow& window,
sf::FloatRect ui_bounds, sf::Text& text, sf::Color default_bg, sf::FloatRect text_bounds, sf::Text& text, sf::Color default_bg,
sf::Color bgcolor, int bg_box_offset, float x, float y, std::wstring &out) sf::Color bgcolor, int bg_box_offset, float x, float y, std::wstring &out)
{ {
text.setString(out); text.setString(out);
text.setPosition({x, y}); text.setPosition({x, y});
// get a base character for the cell size // get a base character for the cell size
sf::FloatRect bounds(x, y, ui_bounds.width * out.size(), ui_bounds.height); sf::FloatRect bounds(x, y, text_bounds.width * out.size(), text_bounds.height);
if(default_bg != bgcolor) { if(default_bg != bgcolor) {
sf::RectangleShape backing({bounds.width, bounds.height}); sf::RectangleShape backing({bounds.width, bounds.height});
@ -162,7 +162,7 @@ void SFMLRender::render_text(const std::wstring &text, sf::Color default_fg, sf:
[&](auto fg, auto bg) { [&](auto fg, auto bg) {
if(out.size() > 0 ) { if(out.size() > 0 ) {
auto bounds = draw_chunk($window, auto bounds = draw_chunk($window,
$ui_bounds, $ui_text, $text_bounds, $ui_text,
default_bg, cur_bg, $config.bg_box_offset, x, y, out); default_bg, cur_bg, $config.bg_box_offset, x, y, out);
x += bounds.width; x += bounds.width;
} }
@ -176,7 +176,7 @@ void SFMLRender::render_text(const std::wstring &text, sf::Color default_fg, sf:
sf::FloatRect bounds; sf::FloatRect bounds;
if(out.size() > 0) { if(out.size() > 0) {
bounds = draw_chunk($window, $ui_bounds, bounds = draw_chunk($window, $text_bounds,
$ui_text, default_bg, cur_bg, $config.bg_box_offset, x, y, out); $ui_text, default_bg, cur_bg, $config.bg_box_offset, x, y, out);
} else { } else {
bounds = $ui_text.getLocalBounds(); bounds = $ui_text.getLocalBounds();
@ -194,7 +194,7 @@ void SFMLRender::render_text(const std::wstring &text, sf::Color default_fg, sf:
); );
if(out.size() > 0) { if(out.size() > 0) {
draw_chunk($window, $ui_bounds, $ui_text, default_bg, cur_bg, $config.bg_box_offset, x, y, out); draw_chunk($window, $text_bounds, $ui_text, default_bg, cur_bg, $config.bg_box_offset, x, y, out);
} }
} }
@ -205,8 +205,7 @@ void SFMLRender::render_text(const std::wstring &text, sf::Color default_fg, sf:
void SFMLRender::draw(Panel &panel, float x_offset, float y_offset) { void SFMLRender::draw(Panel &panel, float x_offset, float y_offset) {
const std::wstring &panelout = panel.to_string(); const std::wstring &panelout = panel.to_string();
// BUG: ui vs bg doesn't make sense. maybe grid vs. text? auto bounds = panel.grid ? $grid_bounds : $text_bounds;
auto bounds = panel.grid ? $bg_bounds : $ui_bounds;
sf::RectangleShape backing( sf::RectangleShape backing(
sf::Vector2f(bounds.width * panel.width + panel.border_px, sf::Vector2f(bounds.width * panel.width + panel.border_px,
@ -229,13 +228,23 @@ void SFMLRender::draw(Panel &panel, float x_offset, float y_offset) {
} }
} }
Point SFMLRender::mouse_position() { bool SFMLRender::mouse_position(Panel &panel, Point &out) {
sf::Vector2i pos = sf::Mouse::getPosition($window); sf::Vector2i pos = sf::Mouse::getPosition($window);
auto bounds = panel.grid ? $grid_bounds : $text_bounds;
return {
size_t(pos.x / $ui_bounds.width), if(pos.x >= panel.x && pos.y >= panel.y
size_t(pos.y / $ui_bounds.height) && pos.x <= (panel.x + panel.width * bounds.width)
&& pos.y <= (panel.y + panel.height * bounds.height))
{
out = {
size_t((pos.x - panel.x) / bounds.width),
size_t((pos.y - panel.y) / bounds.height)
}; };
return true;
}
return false;
} }
void SFMLRender::init_terminal() { void SFMLRender::init_terminal() {

@ -36,13 +36,13 @@ struct SFMLRender {
sf::Texture $font_texture; sf::Texture $font_texture;
sf::Glyph $base_glyph; sf::Glyph $base_glyph;
sf::Sprite $bg_sprite; sf::Sprite $bg_sprite;
sf::FloatRect $bg_bounds; sf::FloatRect $grid_bounds;
sf::Text $ui_text; sf::Text $ui_text;
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> $converter; std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> $converter;
sf::Color $default_fg; sf::Color $default_fg;
sf::Color $default_bg; sf::Color $default_bg;
ANSIParser $ansi; ANSIParser $ansi;
sf::FloatRect $ui_bounds; sf::FloatRect $text_bounds;
SFMLRender(); SFMLRender();
@ -67,6 +67,6 @@ struct SFMLRender {
int font_size() { return $map_font_size; } int font_size() { return $map_font_size; }
void clear() { $window.clear(); } void clear() { $window.clear(); }
void display() { $window.display(); } void display() { $window.display(); }
Point mouse_position(); bool mouse_position(Panel &panel, Point &out);
static void init_terminal(); static void init_terminal();
}; };

@ -93,7 +93,8 @@ void save::load_configs(DinkyECS::World &world) {
map["FLOOR_TILE"], map["FLOOR_TILE"],
map["PLAYER_TILE"], map["PLAYER_TILE"],
map["ENEMY_TILE"], map["ENEMY_TILE"],
map["BG_TILE"] map["BG_TILE"],
map["WATER_TILE"],
}); });
auto enemy = config["enemy"]; auto enemy = config["enemy"];

@ -1,13 +1,31 @@
TODAY'S GOAL: TODAY'S GOAL:
1. Why do Sliders only have to be kept around forever and can't go in containers like everything else?
2. Why are sliders not selected when I click on them? Is it a hover?
3. Why do fonts render blank? Also when I scroll they slowly disappear until there's a column.
* A designer tool to help find characters for foreground, background, and figure out their colors.
* renderer's mouse coordinates are totally wrong. Need to put glyph bounds into the panel and then you can ask if a mouse click is on a panel, and what the _panel's_ coordinates are.
* Use a vector of strings with 1 char each again.
TODO:
* Make a unicode helper.
* Fix " room should always be found" * Fix " room should always be found"
* Fix BUG markers as much as possible. * Fix BUG markers as much as possible.
* Make room generation have "texture" or state like mossy, flooded, etc. * Make room generation have "texture" or state like mossy, flooded, etc.
TODO: * A condition map that indicates what each tile's condition is, so it can have "watery", "wet", "mossy", "burned", and that changes the color of the foreground/background but not the actual tile.
* A tile will then denote a kind of surface, so stone, water, lava, etc.
* Lua integration * Lua integration
* Enemies stuck in walls after generation.
* Save file needs work, it's not saving gold and lights. * Save file needs work, it's not saving gold and lights.
* Move all keyboard and mouse events into SFMLRender so it's completely abstracted away and can be changed to a different backend if I want. * Move all keyboard and mouse events into SFMLRender so it's completely abstracted away and can be changed to a different backend if I want.

@ -188,8 +188,8 @@ void System::draw_map(DinkyECS::World &world, Map &game_map, const Matrix &light
size_t end_x = std::min(view_x, game_map.width() - start.x); size_t end_x = std::min(view_x, game_map.width() - start.x);
size_t end_y = std::min(view_y, game_map.height() - start.y); size_t end_y = std::min(view_y, game_map.height() - start.y);
for(size_t x = 0; x < end_x; ++x) {
for(size_t y = 0; y < end_y; ++y) { for(size_t y = 0; y < end_y; ++y) {
for(size_t x = 0; x < end_x; ++x) {
string tile = walls[start.y+y][start.x+x] == 1 ? config.WALL_TILE : config.FLOOR_TILE; string tile = walls[start.y+y][start.x+x] == 1 ? config.WALL_TILE : config.FLOOR_TILE;
int light_value = lighting[start.y+y][start.x+x]; int light_value = lighting[start.y+y][start.x+x];
@ -207,11 +207,24 @@ void System::draw_map(DinkyECS::World &world, Map &game_map, const Matrix &light
pixel.foreground_color = Color::HSV(dnum * 20, 150, 200); pixel.foreground_color = Color::HSV(dnum * 20, 150, 200);
pixel.background_color = Color::HSV(30, 20, light_value / 5); pixel.background_color = Color::HSV(30, 20, light_value / 5);
}); });
} else if(tile == config.WATER_TILE) {
canvas.DrawText(x * 2, y * 4, tile, [light_value](auto &pixel) {
pixel.foreground_color = Color::HSV(132, 200, std::min(int(light_value * 1.5), 200));
pixel.background_color = Color::HSV(147, 220, light_value / 1.5);
});
} else { } else {
canvas.DrawText(x * 2, y * 4, tile, [light_value](auto &pixel) {
pixel.foreground_color = Color::HSV(80, 100, light_value / 1.5);
pixel.background_color = Color::HSV(30, 20, light_value / 3);
});
/*
// swapped!
canvas.DrawText(x * 2, y * 4, tile, [light_value](auto &pixel) { canvas.DrawText(x * 2, y * 4, tile, [light_value](auto &pixel) {
pixel.foreground_color = Color::HSV(30, 40, light_value); pixel.foreground_color = Color::HSV(30, 40, light_value);
pixel.background_color = Color::HSV(30, 20, light_value / 3); pixel.background_color = Color::HSV(30, 20, light_value / 3);
}); });
*/
} }
} }
} }

@ -0,0 +1,262 @@
#include <chrono> // for operator""s, chrono_literals
#include <thread> // for sleep_for
#include "dinkyecs.hpp"
#include "events.hpp"
#include "dbc.hpp"
#include "render.hpp"
#include "lights.hpp"
#include <filesystem>
#include <fcntl.h>
#include "constants.hpp"
#include "point.hpp"
#include <fmt/core.h>
#include <locale>
#include <codecvt>
#include <vector>
using namespace fmt;
using namespace ftxui;
using namespace std::chrono_literals;
using lighting::LightSource, lighting::LightRender;
namespace fs = std::filesystem;
using std::string, std::wstring, std::vector;
const Point GRID_SIZE={15,8};
const int DEFAULT_FONT_SIZE=200;
struct FontGrid {
size_t width;
size_t height;
vector<vector<string>> $chars;
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> $converter;
FontGrid(size_t width, size_t height) :
width(width), height(height),
$chars(height, vector<string>(width, ""))
{
}
void render(wchar_t start_char, bool fill) {
wchar_t cur_char = start_char;
for(size_t y = 0; y < height; ++y) {
for(size_t x = 0; x < width; ++x) {
if(!fill) {
cur_char += (x+1) * (y+1);
}
wstring out_w{cur_char};
$chars[y][x] = from_unicode(out_w);
}
}
}
string from_unicode(wstring input) {
return $converter.to_bytes(input);
}
wchar_t to_unicode_char(size_t x, size_t y) {
string input = $chars[y][x];
return $converter.from_bytes(input)[0];
}
string at(size_t x, size_t y) {
return $chars[y][x];
}
unsigned int page_size() {
return width * height;
}
};
struct WhatTheColor {
int h;
int s;
int v;
Component h_slider;
Component s_slider;
Component v_slider;
};
class GUI {
public:
DinkyECS::World& $world;
Panel $font_view;
Panel $status_ui;
Canvas $canvas;
SFMLRender $renderer;
FontGrid $font_grid;
wchar_t $start_char = L'\ua66b';
wchar_t $fill_char = WCHAR_MIN;
WhatTheColor $fg_color;
WhatTheColor $bg_color;
Component $fg_settings;
Component $bg_settings;
GUI(DinkyECS::World &world) :
$world(world),
$font_view(GAME_MAP_POS, 0, GRID_SIZE.x, GRID_SIZE.y, true),
$status_ui(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT),
$font_grid(GRID_SIZE.x, GRID_SIZE.y),
$fg_color{.h=20, .s=50, .v=20},
$bg_color{.h=100, .s=100, .v=100}
{
resize_fonts(DEFAULT_FONT_SIZE);
$font_grid.render($start_char, false);
}
void resize_fonts(int new_size) {
println("RESIZE MAP TO {}", new_size);
$renderer.resize_grid(new_size, $font_view);
// set canvas to best size
$canvas = Canvas($font_view.width * 2, $font_view.height * 4);
}
void draw_font_grid() {
for(size_t y = 0; y < $font_grid.height; y++) {
for(size_t x = 0; x < $font_grid.width; x++) {
$canvas.DrawText(x * 2, y * 4, $font_grid.at(x, y), [&](auto &pixel) {
pixel.foreground_color = Color::HSV($fg_color.h, $fg_color.s, $fg_color.v);
pixel.background_color = Color::HSV($bg_color.h, $bg_color.s, $bg_color.v);
});
}
}
}
void create_renderer() {
$renderer.init_terminal();
$font_view.set_renderer(Renderer([&]{
draw_font_grid();
return canvas($canvas);
}));
$fg_color.h_slider = Slider("FG H:", &$fg_color.h, 0, 255, 1);
$fg_color.s_slider = Slider("FG S:", &$fg_color.s, 0, 255, 1);
$fg_color.v_slider = Slider("FG V:", &$fg_color.v, 0, 255, 1);
$bg_color.h_slider = Slider("BG H:", &$bg_color.h, 0, 255, 1);
$bg_color.s_slider = Slider("BG S:", &$bg_color.s, 0, 255, 1);
$bg_color.v_slider = Slider("BG V:", &$bg_color.v, 0, 255, 1);
$status_ui.set_renderer(Renderer([&]{
return hbox({
hflow(
vbox(
text(format("\\u{:x}", int($fill_char))) | border,
separator(),
text(format("FG H: {}, S: {}, V: {}",
$fg_color.h, $fg_color.s, $fg_color.v)) | border,
$fg_color.h_slider->Render(),
separator(),
$fg_color.s_slider->Render(),
separator(),
$fg_color.v_slider->Render(),
separator(),
text(format("BG H: {}, S: {}, V: {}",
$bg_color.h, $bg_color.s, $bg_color.v)) | border,
$bg_color.h_slider->Render(),
separator(),
$bg_color.s_slider->Render(),
separator(),
$bg_color.v_slider->Render()
) | flex_grow
),
separator(),
hbox(),
});
}));
$status_ui.add($fg_color.h_slider);
$status_ui.add($fg_color.s_slider);
$status_ui.add($fg_color.v_slider);
$status_ui.add($bg_color.h_slider);
$status_ui.add($bg_color.s_slider);
$status_ui.add($bg_color.v_slider);
}
void shutdown() {
$renderer.close();
}
void select_cell(Point pos) {
$fill_char = $font_grid.to_unicode_char(pos.x, pos.y);
$font_grid.render($fill_char, true);
}
void deselect_cell() {
$font_grid.render($start_char, false);
}
bool handle_ui_events() {
bool event_happened;
using KB = sf::Keyboard;
using MOUSE = sf::Mouse;
sf::Event event;
int font_size = $renderer.font_size();
while($renderer.poll_event(event)) {
if(event.type == sf::Event::Closed) {
shutdown();
return true;
} else if(event.type == sf::Event::KeyPressed) {
println("KEY PRESSED");
if(KB::isKeyPressed(KB::Up)) {
$start_char = std::min(WCHAR_MAX, $start_char + $font_grid.page_size());
$font_grid.render($start_char, false);
event_happened = true;
} else if(KB::isKeyPressed(KB::Down)) {
$start_char = std::max(WCHAR_MIN+1, $start_char - $font_grid.page_size());
$font_grid.render($start_char, false);
} else if(KB::isKeyPressed(KB::Equal)) {
resize_fonts(font_size + 10);
} else if(KB::isKeyPressed(KB::Hyphen)) {
resize_fonts(font_size - 10);
event_happened = true;
}
} else if(MOUSE::isButtonPressed(MOUSE::Left)) {
Point pos;
if($renderer.mouse_position($font_view, pos)) {
select_cell(pos);
event_happened = true;
} else if($renderer.mouse_position($status_ui, pos)) {
$status_ui.mouse_click(Mouse::Button::Left, pos);
}
}
}
return event_happened;
}
void render_scene() {
$renderer.clear();
$status_ui.render();
$renderer.draw($status_ui);
$font_view.render();
$renderer.draw($font_view);
$renderer.display();
}
};
int main(int argc, char *argv[]) {
DinkyECS::World world;
GUI gui(world);
gui.create_renderer();
do {
gui.render_scene();
if(gui.handle_ui_events()) {
println("THERE WERE EVENTS");
}
std::this_thread::sleep_for(10ms);
} while(gui.$renderer.is_open());
return 0;
}
Loading…
Cancel
Save