A barely working tool to find font characters and pick their color.
This commit is contained in:
parent
6b3ce5eb3d
commit
0edd948101
17 changed files with 406 additions and 72 deletions
4
Makefile
4
Makefile
|
@ -34,3 +34,7 @@ debug_run: build
|
|||
|
||||
cover:
|
||||
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;
|
||||
|
||||
|
||||
#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[] = {
|
||||
0, 0, 1, 2, 10, 11, 13, 16,
|
||||
19, 20, 24, 25, 26, 27, 28, 30,
|
||||
33, 35, 38, 40, 43, 44, 47, 48,
|
||||
49, 50, 51, 52
|
||||
20, 21, 25, 26, 27, 28, 29, 31,
|
||||
34, 36, 39, 41, 44, 45, 48, 49,
|
||||
50, 51, 52, 53
|
||||
};
|
||||
|
||||
static const int _ansi_parser_trans_keys[] = {
|
||||
27, 91, 49, 50, 51, 52, 55, 57,
|
||||
48, 54, 109, 48, 109, 34, 48, 55,
|
||||
50, 55, 109, 109, 49, 56, 57, 109,
|
||||
109, 59, 50, 59, 48, 57, 59, 48,
|
||||
57, 48, 57, 59, 48, 57, 48, 57,
|
||||
109, 48, 57, 109, 56, 57, 109, 59,
|
||||
50, 109, 109, 27, 27, 0
|
||||
50, 52, 55, 109, 109, 49, 56, 57,
|
||||
109, 109, 59, 50, 59, 48, 57, 59,
|
||||
48, 57, 48, 57, 59, 48, 57, 48,
|
||||
57, 109, 48, 57, 109, 56, 57, 109,
|
||||
59, 50, 109, 109, 27, 27, 0
|
||||
};
|
||||
|
||||
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,
|
||||
0, 1, 0, 1, 1, 3, 1, 1,
|
||||
1, 1, 1, 1
|
||||
|
@ -56,35 +56,35 @@ static const char _ansi_parser_range_lengths[] = {
|
|||
|
||||
static const char _ansi_parser_index_offsets[] = {
|
||||
0, 0, 2, 4, 12, 14, 17, 21,
|
||||
25, 27, 32, 34, 36, 38, 40, 42,
|
||||
45, 47, 50, 52, 55, 57, 61, 63,
|
||||
65, 67, 69, 71
|
||||
26, 28, 33, 35, 37, 39, 41, 43,
|
||||
46, 48, 51, 53, 56, 58, 62, 64,
|
||||
66, 68, 70, 72
|
||||
};
|
||||
|
||||
static const char _ansi_parser_trans_targs[] = {
|
||||
2, 1, 3, 0, 5, 7, 9, 21,
|
||||
25, 6, 4, 0, 27, 0, 6, 27,
|
||||
0, 4, 4, 4, 0, 4, 8, 27,
|
||||
0, 27, 0, 10, 11, 20, 27, 0,
|
||||
27, 0, 12, 0, 13, 0, 14, 0,
|
||||
15, 0, 16, 15, 0, 17, 0, 18,
|
||||
17, 0, 19, 0, 27, 19, 0, 27,
|
||||
0, 22, 24, 27, 0, 23, 0, 13,
|
||||
0, 27, 0, 27, 0, 2, 1, 2,
|
||||
1, 0
|
||||
0, 4, 4, 4, 0, 4, 4, 8,
|
||||
27, 0, 27, 0, 10, 11, 20, 27,
|
||||
0, 27, 0, 12, 0, 13, 0, 14,
|
||||
0, 15, 0, 16, 15, 0, 17, 0,
|
||||
18, 17, 0, 19, 0, 27, 19, 0,
|
||||
27, 0, 22, 24, 27, 0, 23, 0,
|
||||
13, 0, 27, 0, 27, 0, 2, 1,
|
||||
2, 1, 0
|
||||
};
|
||||
|
||||
static const char _ansi_parser_trans_actions[] = {
|
||||
0, 7, 0, 0, 21, 21, 21, 21,
|
||||
21, 21, 21, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 17,
|
||||
0, 15, 0, 0, 0, 0, 0, 0,
|
||||
19, 0, 0, 0, 3, 0, 0, 0,
|
||||
1, 0, 25, 0, 0, 1, 0, 28,
|
||||
0, 0, 1, 0, 34, 0, 0, 9,
|
||||
0, 0, 0, 0, 0, 0, 0, 5,
|
||||
0, 11, 0, 13, 0, 0, 7, 23,
|
||||
31, 0
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
17, 0, 15, 0, 0, 0, 0, 0,
|
||||
0, 19, 0, 0, 0, 3, 0, 0,
|
||||
0, 1, 0, 25, 0, 0, 1, 0,
|
||||
28, 0, 0, 1, 0, 34, 0, 0,
|
||||
9, 0, 0, 0, 0, 0, 0, 0,
|
||||
5, 0, 11, 0, 13, 0, 0, 7,
|
||||
23, 31, 0
|
||||
};
|
||||
|
||||
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;
|
||||
|
||||
|
||||
#line 124 "ansi_parser.rl"
|
||||
#line 125 "ansi_parser.rl"
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
#line 145 "ansi_parser.rl"
|
||||
#line 146 "ansi_parser.rl"
|
||||
|
||||
#line 121 "ansi_parser.cpp"
|
||||
{
|
||||
|
@ -349,7 +349,7 @@ _again:
|
|||
_out: {}
|
||||
}
|
||||
|
||||
#line 146 "ansi_parser.rl"
|
||||
#line 147 "ansi_parser.rl"
|
||||
|
||||
bool good = pe - p == 0;
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ using namespace fmt;
|
|||
"7" %invert |
|
||||
"31" %red_text |
|
||||
"22" |
|
||||
"24" |
|
||||
"27" %reset_invert |
|
||||
"9" ["0"-"7"] |
|
||||
"10" ["0"-"7"] |
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
"FLOOR_TILE": "\u2849",
|
||||
"PLAYER_TILE": "\ua66b",
|
||||
"ENEMY_TILE": "Ω",
|
||||
"BG_TILE": "█"
|
||||
"BG_TILE": "█",
|
||||
"WATER_TILE": "\u26c6"
|
||||
},
|
||||
"enemy": {
|
||||
"HEARING_DISTANCE": 8
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace components {
|
|||
std::string PLAYER_TILE;
|
||||
std::string ENEMY_TILE;
|
||||
std::string BG_TILE;
|
||||
std::string WATER_TILE;
|
||||
};
|
||||
|
||||
struct EnemyConfig {
|
||||
|
|
|
@ -12,3 +12,8 @@ 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 MAX_FONT_SIZE = 140;
|
||||
const int MIN_FONT_SIZE = 20;
|
||||
const int SCREEN_WIDTH = 40;
|
||||
const int SCREEN_HEIGHT = 30;
|
||||
|
|
16
gui.cpp
16
gui.cpp
|
@ -21,9 +21,7 @@
|
|||
#include "events.hpp"
|
||||
#include "render.hpp"
|
||||
#include "save.hpp"
|
||||
|
||||
const int MAX_FONT_SIZE = 140;
|
||||
const int MIN_FONT_SIZE = 20;
|
||||
#include "constants.hpp"
|
||||
|
||||
using std::string;
|
||||
using namespace fmt;
|
||||
|
@ -210,13 +208,11 @@ bool GUI::handle_ui_events() {
|
|||
$status_ui.$component->OnEvent(Event::Return);
|
||||
}
|
||||
} else if(MOUSE::isButtonPressed(MOUSE::Left)) {
|
||||
Point pos = $renderer.mouse_position();
|
||||
Mouse mev{
|
||||
.button=Mouse::Button::Left,
|
||||
.x=int(pos.x), .y=int(pos.y)
|
||||
};
|
||||
|
||||
$status_ui.$component->OnEvent(Event::Mouse("", mev));
|
||||
Point pos;
|
||||
if($renderer.mouse_position($status_ui, pos)) {
|
||||
$status_ui.mouse_click(Mouse::Button::Left, pos);
|
||||
event_happened = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
4
gui.hpp
4
gui.hpp
|
@ -24,9 +24,6 @@ using std::string;
|
|||
using ftxui::Canvas, ftxui::Component, ftxui::Screen, ftxui::Button;
|
||||
using lighting::LightRender;
|
||||
|
||||
constexpr int SCREEN_WIDTH = 40;
|
||||
constexpr int SCREEN_HEIGHT = 30;
|
||||
|
||||
struct ActionLog {
|
||||
std::deque<std::string> messages;
|
||||
|
||||
|
@ -38,7 +35,6 @@ struct ActionLog {
|
|||
}
|
||||
};
|
||||
|
||||
const int GAME_MAP_POS = 600;
|
||||
|
||||
class GUI {
|
||||
string $status_text = "NOT DEAD";
|
||||
|
|
14
meson.build
14
meson.build
|
@ -77,6 +77,20 @@ roguish = executable('roguish', [
|
|||
],
|
||||
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', [
|
||||
'dbc.cpp',
|
||||
'panel.cpp',
|
||||
|
|
10
panel.cpp
10
panel.cpp
|
@ -35,6 +35,16 @@ const std::wstring& Panel::to_string() {
|
|||
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() {
|
||||
return $screen;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include <ftxui/dom/node.hpp> // for Render
|
||||
#include <ftxui/component/component.hpp>
|
||||
#include <ftxui/component/mouse.hpp>
|
||||
#include <ftxui/dom/canvas.hpp>
|
||||
#include <ftxui/screen/screen.hpp>
|
||||
#include <ftxui/dom/canvas.hpp>
|
||||
|
@ -10,6 +11,7 @@
|
|||
#include <locale>
|
||||
#include <codecvt>
|
||||
#include "color.hpp"
|
||||
#include "point.hpp"
|
||||
|
||||
const int UI_PANEL_BORDER_PX=5;
|
||||
|
||||
|
@ -49,6 +51,7 @@ struct Panel {
|
|||
void set_renderer(Component renderer);
|
||||
void add(Component child);
|
||||
void render();
|
||||
void mouse_click(ftxui::Mouse::Button btn, Point pos);
|
||||
const std::wstring &to_string();
|
||||
const Screen &screen();
|
||||
};
|
||||
|
|
43
render.cpp
43
render.cpp
|
@ -32,7 +32,7 @@ SFMLRender::SFMLRender() :
|
|||
$ui_text.setCharacterSize($config.ui_font_size);
|
||||
$ui_text.setFillColor(ColorValue::LIGHT_MID);
|
||||
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) {
|
||||
|
@ -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
|
||||
$line_spacing = $font.getLineSpacing($map_font_size);
|
||||
$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);
|
||||
}
|
||||
|
||||
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
|
||||
// should look into caching all this instead of calcing it each time
|
||||
sp_bounds = sprite.getLocalBounds();
|
||||
|
||||
// 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;
|
||||
height_delta = bg_bounds.height > sp_bounds.width ? (bg_bounds.height - sp_bounds.height) / 2 : 0;
|
||||
width_delta = grid_bounds.width > sp_bounds.width ? (grid_bounds.width - sp_bounds.width) / 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) {
|
||||
|
@ -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
|
||||
if(last_tile != 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
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
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)
|
||||
{
|
||||
text.setString(out);
|
||||
text.setPosition({x, y});
|
||||
// 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) {
|
||||
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) {
|
||||
if(out.size() > 0 ) {
|
||||
auto bounds = draw_chunk($window,
|
||||
$ui_bounds, $ui_text,
|
||||
$text_bounds, $ui_text,
|
||||
default_bg, cur_bg, $config.bg_box_offset, x, y, out);
|
||||
x += bounds.width;
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ void SFMLRender::render_text(const std::wstring &text, sf::Color default_fg, sf:
|
|||
sf::FloatRect bounds;
|
||||
|
||||
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);
|
||||
} else {
|
||||
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) {
|
||||
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) {
|
||||
const std::wstring &panelout = panel.to_string();
|
||||
|
||||
// BUG: ui vs bg doesn't make sense. maybe grid vs. text?
|
||||
auto bounds = panel.grid ? $bg_bounds : $ui_bounds;
|
||||
auto bounds = panel.grid ? $grid_bounds : $text_bounds;
|
||||
|
||||
sf::RectangleShape backing(
|
||||
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);
|
||||
auto bounds = panel.grid ? $grid_bounds : $text_bounds;
|
||||
|
||||
return {
|
||||
size_t(pos.x / $ui_bounds.width),
|
||||
size_t(pos.y / $ui_bounds.height)
|
||||
if(pos.x >= panel.x && pos.y >= panel.y
|
||||
&& 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() {
|
||||
|
|
|
@ -36,13 +36,13 @@ struct SFMLRender {
|
|||
sf::Texture $font_texture;
|
||||
sf::Glyph $base_glyph;
|
||||
sf::Sprite $bg_sprite;
|
||||
sf::FloatRect $bg_bounds;
|
||||
sf::FloatRect $grid_bounds;
|
||||
sf::Text $ui_text;
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> $converter;
|
||||
sf::Color $default_fg;
|
||||
sf::Color $default_bg;
|
||||
ANSIParser $ansi;
|
||||
sf::FloatRect $ui_bounds;
|
||||
sf::FloatRect $text_bounds;
|
||||
|
||||
SFMLRender();
|
||||
|
||||
|
@ -67,6 +67,6 @@ struct SFMLRender {
|
|||
int font_size() { return $map_font_size; }
|
||||
void clear() { $window.clear(); }
|
||||
void display() { $window.display(); }
|
||||
Point mouse_position();
|
||||
bool mouse_position(Panel &panel, Point &out);
|
||||
static void init_terminal();
|
||||
};
|
||||
|
|
3
save.cpp
3
save.cpp
|
@ -93,7 +93,8 @@ void save::load_configs(DinkyECS::World &world) {
|
|||
map["FLOOR_TILE"],
|
||||
map["PLAYER_TILE"],
|
||||
map["ENEMY_TILE"],
|
||||
map["BG_TILE"]
|
||||
map["BG_TILE"],
|
||||
map["WATER_TILE"],
|
||||
});
|
||||
|
||||
auto enemy = config["enemy"];
|
||||
|
|
20
status.txt
20
status.txt
|
@ -1,13 +1,31 @@
|
|||
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 BUG markers as much as possible.
|
||||
|
||||
* 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
|
||||
|
||||
* Enemies stuck in walls after generation.
|
||||
|
||||
* 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.
|
||||
|
|
15
systems.cpp
15
systems.cpp
|
@ -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_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 x = 0; x < end_x; ++x) {
|
||||
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];
|
||||
|
||||
|
@ -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.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 {
|
||||
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) {
|
||||
pixel.foreground_color = Color::HSV(30, 40, light_value);
|
||||
pixel.background_color = Color::HSV(30, 20, light_value / 3);
|
||||
});
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
262
tools/designer.cpp
Normal file
262
tools/designer.cpp
Normal file
|
@ -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…
Add table
Add a link
Reference in a new issue