diff --git a/ansi_parser.cpp b/ansi_parser.cpp index 9cf9d21..fb345eb 100644 --- a/ansi_parser.cpp +++ b/ansi_parser.cpp @@ -5,105 +5,108 @@ #include #include "dbc.hpp" #include +#include "ansi_parser.hpp" using namespace fmt; -#line 62 ".\\ansi_parser.rl" +#line 59 ".\\ansi_parser.rl" -#line 12 ".\\ansi_parser.cpp" +#line 13 ".\\ansi_parser.cpp" static const char _foo_actions[] = { 0, 1, 0, 1, 3, 1, 4, 1, - 5, 1, 9, 1, 10, 2, 1, 6, - 2, 1, 7, 2, 10, 5, 3, 1, - 8, 2 + 5, 1, 6, 1, 7, 1, 11, 1, + 12, 2, 1, 8, 2, 1, 9, 2, + 12, 5, 3, 1, 10, 2 }; static const char _foo_key_offsets[] = { 0, 0, 1, 2, 4, 6, 7, 8, 9, 11, 14, 16, 19, 21, 24, 25, - 27, 28, 29, 30 + 27, 28, 29, 30, 31 }; static const char _foo_trans_keys[] = { 27, 91, 51, 52, 56, 57, 59, 50, 59, 48, 57, 59, 48, 57, 48, 57, 59, 48, 57, 48, 57, 109, 48, 57, - 109, 56, 57, 59, 50, 27, 27, 0 + 109, 56, 57, 59, 50, 109, 27, 27, + 0 }; static const char _foo_single_lengths[] = { 0, 1, 1, 2, 2, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 2, - 1, 1, 1, 1 + 1, 1, 1, 1, 1 }; static const char _foo_range_lengths[] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, - 0, 0, 0, 0 + 0, 0, 0, 0, 0 }; static const char _foo_index_offsets[] = { 0, 0, 2, 4, 7, 10, 12, 14, 16, 18, 21, 23, 26, 28, 31, 33, - 36, 38, 40, 42 + 36, 38, 40, 42, 44 }; static const char _foo_trans_targs[] = { 2, 1, 3, 0, 4, 15, 0, 5, 14, 0, 6, 0, 7, 0, 8, 0, 9, 0, 10, 9, 0, 11, 0, 12, - 11, 0, 13, 0, 19, 13, 0, 19, - 0, 16, 14, 0, 17, 0, 7, 0, - 2, 1, 2, 1, 0 + 11, 0, 13, 0, 20, 13, 0, 20, + 0, 16, 18, 0, 17, 0, 7, 0, + 20, 0, 2, 1, 2, 1, 0 }; static const char _foo_trans_actions[] = { - 0, 7, 0, 0, 9, 9, 0, 0, + 0, 7, 0, 0, 13, 13, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, - 1, 0, 13, 0, 0, 1, 0, 16, - 0, 0, 1, 0, 22, 0, 0, 0, + 1, 0, 17, 0, 0, 1, 0, 20, + 0, 0, 1, 0, 26, 0, 0, 9, 0, 0, 0, 0, 0, 0, 5, 0, - 0, 7, 11, 19, 0 + 11, 0, 0, 7, 15, 23, 0 }; static const char _foo_eof_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 11 + 0, 0, 0, 0, 15 }; -static const int foo_start = 18; -static const int foo_first_final = 18; +static const int foo_start = 19; +static const int foo_first_final = 19; static const int foo_error = 0; -static const int foo_en_main = 18; +static const int foo_en_main = 19; -#line 65 ".\\ansi_parser.rl" +#line 62 ".\\ansi_parser.rl" -bool parse_ansi(std::string_view codes) { +bool parse_ansi(std::string_view codes, sf::Color default_fg, sf::Color default_bg, WriteCB write) { const char *start = NULL; int cs = 0; unsigned int value = 0; const char *p = codes.data(); const char *pe = p + codes.size(); const char *eof = pe; - bool is_fg = false; - sf::Color color; + sf::Color bgcolor(default_bg); + sf::Color color(default_fg); + sf::Color &target = bgcolor; -#line 91 ".\\ansi_parser.cpp" +#line 94 ".\\ansi_parser.cpp" { cs = foo_start; } -#line 77 ".\\ansi_parser.rl" +#line 75 ".\\ansi_parser.rl" -#line 94 ".\\ansi_parser.cpp" +#line 97 ".\\ansi_parser.cpp" { int _klen; unsigned int _trans; @@ -177,62 +180,65 @@ _match: switch ( *_acts++ ) { case 0: -#line 12 ".\\ansi_parser.rl" +#line 13 ".\\ansi_parser.rl" { start = p; } break; case 1: -#line 16 ".\\ansi_parser.rl" +#line 17 ".\\ansi_parser.rl" { auto [ptr, ec] = std::from_chars(start, p, value); dbc::check(ec == std::errc(), "error in number parsing"); - println("NUM: {}", value); } break; case 2: #line 22 ".\\ansi_parser.rl" - { - println("color24b"); - } + { } break; case 3: -#line 26 ".\\ansi_parser.rl" - { is_fg = true; } +#line 23 ".\\ansi_parser.rl" + { target = color; } break; case 4: -#line 27 ".\\ansi_parser.rl" - { is_fg = false; } +#line 24 ".\\ansi_parser.rl" + { target = bgcolor; } break; case 5: -#line 29 ".\\ansi_parser.rl" +#line 26 ".\\ansi_parser.rl" { - println("ANY: {}:{}", int((*p)), (*p)); + write(bgcolor, color, (*p)); } break; case 6: -#line 33 ".\\ansi_parser.rl" - { color.r = value; } +#line 30 ".\\ansi_parser.rl" + { color = default_fg; } break; case 7: -#line 34 ".\\ansi_parser.rl" - { color.g = value; } +#line 31 ".\\ansi_parser.rl" + { bgcolor = default_bg; } break; case 8: -#line 35 ".\\ansi_parser.rl" - { color.b = value; } +#line 33 ".\\ansi_parser.rl" + { target.r = value; } break; case 9: -#line 37 ".\\ansi_parser.rl" - { value = 0; } +#line 34 ".\\ansi_parser.rl" + { target.g = value; } break; case 10: -#line 39 ".\\ansi_parser.rl" - { - println("fg? {}, sf:Color: {},{},{},{}", is_fg, color.r, color.g, color.b, color.a); - } +#line 35 ".\\ansi_parser.rl" + { target.b = value; } break; -#line 211 ".\\ansi_parser.cpp" + case 11: +#line 36 ".\\ansi_parser.rl" + { value = 0; } + break; + case 12: +#line 37 ".\\ansi_parser.rl" + { } + break; +#line 215 ".\\ansi_parser.cpp" } } @@ -248,13 +254,11 @@ _again: unsigned int __nacts = (unsigned int) *__acts++; while ( __nacts-- > 0 ) { switch ( *__acts++ ) { - case 10: -#line 39 ".\\ansi_parser.rl" - { - println("fg? {}, sf:Color: {},{},{},{}", is_fg, color.r, color.g, color.b, color.a); - } + case 12: +#line 37 ".\\ansi_parser.rl" + { } break; -#line 231 ".\\ansi_parser.cpp" +#line 233 ".\\ansi_parser.cpp" } } } @@ -262,9 +266,7 @@ _again: _out: {} } -#line 78 ".\\ansi_parser.rl" - - print("PROCESSED {} CHARS of {}: {}", p - codes.data(), codes.size(), p); +#line 76 ".\\ansi_parser.rl" - return true; + return p - pe == 0; } diff --git a/ansi_parser.hpp b/ansi_parser.hpp index ec4026f..3d403ce 100644 --- a/ansi_parser.hpp +++ b/ansi_parser.hpp @@ -1,4 +1,7 @@ #pragma once #include +#include -bool parse_ansi(std::string_view codes); +typedef std::function WriteCB; + +bool parse_ansi(std::string_view codes, sf::Color default_fg, sf::Color default_bg, WriteCB write); diff --git a/ansi_parser.rl b/ansi_parser.rl index e6a2484..be7577c 100644 --- a/ansi_parser.rl +++ b/ansi_parser.rl @@ -3,6 +3,7 @@ #include #include "dbc.hpp" #include +#include "ansi_parser.hpp" using namespace fmt; @@ -16,34 +17,30 @@ using namespace fmt; action number { auto [ptr, ec] = std::from_chars(start, fpc, value); dbc::check(ec == std::errc(), "error in number parsing"); - println("NUM: {}", value); } - action color24b { - println("color24b"); - } - - action is_fg { is_fg = true; } - action is_bg { is_fg = false; } + action color24b { } + action is_fg { target = color; } + action is_bg { target = bgcolor; } - action any { - println("ANY: {}:{}", int(fc), fc); + action out { + write(bgcolor, color, fc); } - action red { color.r = value; } - action blue { color.g = value; } - action green { color.b = value; } + action reset_fg { color = default_fg; } + action reset_bg { bgcolor = default_bg; } + action red { target.r = value; } + action blue { target.g = value; } + action green { target.b = value; } action start { value = 0; } + action end { } - action end { - println("fg? {}, sf:Color: {},{},{},{}", is_fg, color.r, color.g, color.b, color.a); - } - - start = 0x1B "["; + ESC = 0x1B; + start = ESC "["; fg = "38;" %is_fg; bg = "48;" %is_bg; - reset = ("39" | "49"); + reset = ("39" %reset_fg | "49" %reset_bg); num = digit+ >tstart %number; color256 = "5;"; color24b = "2;"; @@ -56,27 +53,26 @@ using namespace fmt; ) "m" %end ); - other = (any+ @any -- 0x1B)*; + other = (any+ @out -- ESC)*; main := (other :> ansi)**; }%% %% write data; -bool parse_ansi(std::string_view codes) { +bool parse_ansi(std::string_view codes, sf::Color default_fg, sf::Color default_bg, WriteCB write) { const char *start = NULL; int cs = 0; unsigned int value = 0; const char *p = codes.data(); const char *pe = p + codes.size(); const char *eof = pe; - bool is_fg = false; - sf::Color color; + sf::Color bgcolor(default_bg); + sf::Color color(default_fg); + sf::Color &target = bgcolor; %% write init; %% write exec; - print("PROCESSED {} CHARS of {}: {}", p - codes.data(), codes.size(), p); - - return true; + return p - pe == 0; } diff --git a/map.hpp b/map.hpp index 4815c53..e403a89 100644 --- a/map.hpp +++ b/map.hpp @@ -11,10 +11,10 @@ #define INV_SPACE 1 #define WALL_VALUE 1 #define SPACE_VALUE 0 -#define WALL_TILE "█" -#define FLOOR_TILE "#" -#define PLAYER_TILE "☺" -#define ENEMY_TILE "Ω" +#define WALL_TILE "#" +#define FLOOR_TILE "." +#define PLAYER_TILE "&" +#define ENEMY_TILE "!" struct Room { size_t x = 0; diff --git a/meson.build b/meson.build index 96224a7..8b3e324 100644 --- a/meson.build +++ b/meson.build @@ -21,12 +21,12 @@ runtests = executable('runtests', [ 'collider.cpp', 'ansi_parser.cpp', 'render.cpp', - #'tests/fsm.cpp', - #'tests/dbc.cpp', - #'tests/map.cpp', - #'tests/collider.cpp', - #'tests/sound.cpp', - #'tests/dinkyecs.cpp', + 'tests/fsm.cpp', + 'tests/dbc.cpp', + 'tests/map.cpp', + 'tests/collider.cpp', + 'tests/sound.cpp', + 'tests/dinkyecs.cpp', 'tests/ansi_parser.cpp', ], dependencies: dependencies) @@ -41,6 +41,7 @@ roguish = executable('roguish', [ 'collider.cpp', 'combat.cpp', 'systems.cpp', + 'ansi_parser.cpp', 'render.cpp', ], dependencies: dependencies) diff --git a/render.cpp b/render.cpp index dd716fa..9870435 100644 --- a/render.cpp +++ b/render.cpp @@ -1,5 +1,7 @@ #include "render.hpp" +#include "ansi_parser.hpp" #include +#include std::array VALUES{ sf::Color{1, 4, 2}, // black @@ -66,13 +68,16 @@ bool SFMLRender::resize_map(int new_size) { } } - -void SFMLRender::draw_screen(bool clear, float map_off_x, float map_off_y) { - if(clear) $window.clear(); +void SFMLRender::draw_main_ui() { std::string screenout = $screen.ToString(); std::wstring main_screen_utf8 = $converter.from_bytes(screenout); $ui_text.setString(main_screen_utf8); $window.draw($ui_text); +} + +void SFMLRender::draw_screen(bool clear, float map_off_x, float map_off_y) { + if(clear) $window.clear(); + draw_main_ui(); std::string map_screenout = $map_screen.ToString(); std::wstring map_screen_utf8 = $converter.from_bytes(map_screenout); @@ -82,23 +87,23 @@ void SFMLRender::draw_screen(bool clear, float map_off_x, float map_off_y) { // make a copy so we don't modify the cached one auto bg_sprite = get_text_sprite(L'█'); auto bg_bounds = bg_sprite.getLocalBounds(); - bg_sprite.setColor(sf::Color(20,20,20)); - auto add_sprite = get_text_sprite(L'!'); - bool has_add = false; + sf::Color def_fg(color(Value::LIGHT_LIGHT)); + sf::Color def_bg(color(Value::BLACK)); - for(size_t i = 0; i < map_screen_utf8.size(); i++) { - wchar_t tile = map_screen_utf8[i]; - - if(tile == L'\n') { + parse_ansi(map_screenout, def_fg, def_bg, [&](sf::Color bg, sf::Color fg, char tile) { + if(tile == '\n') { // don't bother processing newlines, just skip y += $line_spacing; x = GAME_MAP_POS; } else if(tile == L'\r') { - continue; // skip these, just windows junk + return; // skip these, just windows junk } else { + // fmt::println("FG: {},{},{},{}; BG: {},{},{},{}; ch: {}", + // fg.r, fg.g, fg.b, fg.a, bg.r, bg.g, bg.b, bg.a, int(tile)); // it's a visual cell bg_sprite.setPosition({x+map_off_x, y+map_off_y}); sf::Sprite &sprite = get_text_sprite(tile); + bg_sprite.setColor(bg); // should look into caching all this instead of calcing it each time auto sp_bounds = sprite.getLocalBounds(); @@ -107,38 +112,15 @@ void SFMLRender::draw_screen(bool clear, float map_off_x, float map_off_y) { auto width_delta = bg_bounds.width > sp_bounds.width ? (bg_bounds.width - sp_bounds.width) / 2 : 0; auto height_delta = bg_bounds.height > sp_bounds.width ? (bg_bounds.height - sp_bounds.height) / 2 : 0; - // TODO: need to center it inside the bg_sprite sprite.setPosition({x+width_delta+map_off_x, y+height_delta+map_off_y}); + sprite.setColor(fg); - // get the entity combat and make them light gray if dead - if(tile == L'█') { - sprite.setColor(sf::Color(80,80,80)); - } else if(tile == L'☺') { - sprite.setColor(sf::Color::Blue); - } else if(tile == L'Ω') { - sprite.setColor(sf::Color::Red); - // HACK: just playing with adding multiple characters for drawing - add_sprite.setColor(sf::Color::Red); - add_sprite.setPosition({x-3,y-3}); - has_add = true; - } else if(tile == L'#') { - sprite.setColor(sf::Color(5,5,5)); - } else { - sprite.setColor(color(Value::MID)); - } - - // now draw the background sprite and sprite - // TODO: this can become a standard sprite description $window.draw(bg_sprite); $window.draw(sprite); - if(has_add) { - $window.draw(add_sprite); - has_add = false; - } // next cell x += $base_glyph.advance; } - } + }); $window.display(); } diff --git a/render.hpp b/render.hpp index dac9171..a4d41d5 100644 --- a/render.hpp +++ b/render.hpp @@ -49,6 +49,7 @@ struct SFMLRender { sf::Color color(Value val); sf::Sprite &get_text_sprite(wchar_t tile); bool resize_map(int new_size); + void draw_main_ui(); void draw_screen(bool clear=true, float map_off_x=0.0f, float map_off_y=0.0f); bool poll_event(sf::Event &event) { diff --git a/systems.cpp b/systems.cpp index 01efa1a..6d3a258 100644 --- a/systems.cpp +++ b/systems.cpp @@ -5,10 +5,12 @@ #include "rand.hpp" #include "collider.hpp" #include "events.hpp" +#include "ftxui/screen/color.hpp" using std::string; using namespace fmt; using namespace Components; +using ftxui::Color; #define HEARING_DISTANCE 8 @@ -142,7 +144,7 @@ void System::draw_map(DinkyECS::World &world, Map &game_map, ftxui::Canvas &canv for(size_t y = 0; y < end_y; ++y) { string tile = walls[start.y+y][start.x+x] == 1 ? WALL_TILE : FLOOR_TILE; // the 2 and 4 are from ftxui::Canvas since it does a kind of "subpixel" drawing - canvas.DrawText(x * 2, y * 4, tile); + canvas.DrawText(x * 2, y * 4, tile, Color::HSV(100, 10, 10)); } } diff --git a/tests/ansi_parser.cpp b/tests/ansi_parser.cpp index d32d05e..ab29b40 100644 --- a/tests/ansi_parser.cpp +++ b/tests/ansi_parser.cpp @@ -33,7 +33,6 @@ std::string generate_colors() { count++; } array.push_back(hbox(std::move(line))); - break; /// UNDO ME } println("MADE {} CHARS", count); @@ -53,7 +52,18 @@ std::string generate_colors() { TEST_CASE("test out ragel parser", "[gui]") { std::string colors = generate_colors(); + sf::Color default_fg(0,0,0); + sf::Color default_bg(100,100,100); println("--- PARSING"); - REQUIRE(parse_ansi(colors)); + bool good = parse_ansi(colors, default_fg, default_bg, [&](sf::Color bgcolor, sf::Color color, char ch) { + bool correct_char = ch == '#' || ch == ' ' || ch == '\n' || ch == '\r'; + // println("FG: {},{},{},{}; BG: {},{},{},{}; ch: {}", + // color.r, color.g, color.b, color.a, + // bgcolor.r, bgcolor.g, bgcolor.b, bgcolor.a, + // int(ch)); + REQUIRE(correct_char); + }); + + REQUIRE(good); }