diff --git a/Makefile b/Makefile index ff8c808..ed9318a 100644 --- a/Makefile +++ b/Makefile @@ -27,4 +27,4 @@ clean: meson compile --clean -C builddir debug: - gdb --nx -x .gdbinit builddir/roguish.exe + gdb --nx -x .gdbinit builddir/img2ansi.exe diff --git a/ansi_parser.cpp b/ansi_parser.cpp index f61e6fe..d0443f6 100644 --- a/ansi_parser.cpp +++ b/ansi_parser.cpp @@ -10,96 +10,98 @@ using namespace fmt; -#line 110 "ansi_parser.rl" +#line 115 "ansi_parser.rl" #line 13 "ansi_parser.cpp" -static const char _foo_actions[] = { +static const char _ansi_parser_actions[] = { 0, 1, 0, 1, 3, 1, 4, 1, 5, 1, 6, 1, 7, 1, 8, 1, - 9, 1, 10, 1, 14, 1, 15, 2, - 1, 11, 2, 1, 12, 2, 15, 5, - 3, 1, 13, 2 + 9, 1, 10, 1, 11, 1, 15, 1, + 16, 2, 1, 12, 2, 1, 13, 2, + 16, 5, 3, 1, 14, 2 }; -static const char _foo_key_offsets[] = { +static const char _ansi_parser_key_offsets[] = { 0, 0, 1, 2, 10, 11, 13, 16, - 19, 20, 23, 24, 25, 26, 28, 31, - 33, 36, 38, 41, 42, 45, 46, 47, - 48, 49, 50 + 19, 20, 24, 25, 26, 27, 28, 30, + 33, 35, 38, 40, 43, 44, 47, 48, + 49, 50, 51, 52 }; -static const int _foo_trans_keys[] = { +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, 56, 57, 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, 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 _foo_single_lengths[] = { +static const char _ansi_parser_single_lengths[] = { 0, 1, 1, 6, 1, 2, 3, 3, - 1, 3, 1, 1, 1, 0, 1, 0, - 1, 0, 1, 1, 3, 1, 1, 1, - 1, 1, 1 + 1, 4, 1, 1, 1, 1, 0, 1, + 0, 1, 0, 1, 1, 3, 1, 1, + 1, 1, 1, 1 }; -static const char _foo_range_lengths[] = { +static const char _ansi_parser_range_lengths[] = { 0, 0, 0, 1, 0, 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, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0 }; -static const char _foo_index_offsets[] = { +static const char _ansi_parser_index_offsets[] = { 0, 0, 2, 4, 12, 14, 17, 21, - 25, 27, 31, 33, 35, 37, 39, 42, - 44, 47, 49, 52, 54, 58, 60, 62, - 64, 66, 68 + 25, 27, 32, 34, 36, 38, 40, 42, + 45, 47, 50, 52, 55, 57, 61, 63, + 65, 67, 69, 71 }; -static const char _foo_trans_targs[] = { - 2, 1, 3, 0, 5, 7, 9, 20, - 24, 6, 4, 0, 26, 0, 6, 26, - 0, 4, 4, 4, 0, 4, 8, 26, - 0, 26, 0, 10, 19, 26, 0, 11, - 0, 12, 0, 13, 0, 14, 0, 15, - 14, 0, 16, 0, 17, 16, 0, 18, - 0, 26, 18, 0, 26, 0, 21, 23, - 26, 0, 22, 0, 12, 0, 26, 0, - 26, 0, 2, 1, 2, 1, 0 +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 }; -static const char _foo_trans_actions[] = { - 0, 7, 0, 0, 19, 19, 19, 19, - 19, 19, 19, 0, 0, 0, 0, 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, - 0, 3, 0, 0, 0, 1, 0, 23, - 0, 0, 1, 0, 26, 0, 0, 1, - 0, 32, 0, 0, 9, 0, 0, 0, - 0, 0, 0, 0, 5, 0, 11, 0, - 13, 0, 0, 7, 21, 29, 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 _foo_eof_actions[] = { +static const char _ansi_parser_eof_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 21 + 0, 0, 0, 23 }; -static const int foo_start = 25; -static const int foo_first_final = 25; -static const int foo_error = 0; +static const int ansi_parser_start = 26; +static const int ansi_parser_first_final = 26; +static const int ansi_parser_error = 0; -static const int foo_en_main = 25; +static const int ansi_parser_en_main = 26; -#line 113 "ansi_parser.rl" +#line 118 "ansi_parser.rl" #include @@ -125,14 +127,14 @@ bool ANSIParser::parse(std::wstring_view codes, ColorCB color_cb, WriteCB write_ sf::Color &target = color; -#line 120 "ansi_parser.cpp" +#line 122 "ansi_parser.cpp" { - cs = foo_start; + cs = ansi_parser_start; } -#line 138 "ansi_parser.rl" +#line 143 "ansi_parser.rl" -#line 123 "ansi_parser.cpp" +#line 125 "ansi_parser.cpp" { int _klen; unsigned int _trans; @@ -145,10 +147,10 @@ bool ANSIParser::parse(std::wstring_view codes, ColorCB color_cb, WriteCB write_ if ( cs == 0 ) goto _out; _resume: - _keys = _foo_trans_keys + _foo_key_offsets[cs]; - _trans = _foo_index_offsets[cs]; + _keys = _ansi_parser_trans_keys + _ansi_parser_key_offsets[cs]; + _trans = _ansi_parser_index_offsets[cs]; - _klen = _foo_single_lengths[cs]; + _klen = _ansi_parser_single_lengths[cs]; if ( _klen > 0 ) { const int *_lower = _keys; const int *_mid; @@ -171,7 +173,7 @@ _resume: _trans += _klen; } - _klen = _foo_range_lengths[cs]; + _klen = _ansi_parser_range_lengths[cs]; if ( _klen > 0 ) { const int *_lower = _keys; const int *_mid; @@ -194,12 +196,12 @@ _resume: } _match: - cs = _foo_trans_targs[_trans]; + cs = _ansi_parser_trans_targs[_trans]; - if ( _foo_trans_actions[_trans] == 0 ) + if ( _ansi_parser_trans_actions[_trans] == 0 ) goto _again; - _acts = _foo_actions + _foo_trans_actions[_trans]; + _acts = _ansi_parser_actions + _ansi_parser_trans_actions[_trans]; _nacts = (unsigned int) *_acts++; while ( _nacts-- > 0 ) { @@ -291,26 +293,33 @@ _match: } break; case 11: -#line 71 "ansi_parser.rl" - { target.r = value; } +#line 70 "ansi_parser.rl" + { + color = sf::Color::Red; + color_cb(color, bgcolor); + } break; case 12: -#line 72 "ansi_parser.rl" - { target.g = value; } +#line 75 "ansi_parser.rl" + { target.r = value; } break; case 13: -#line 73 "ansi_parser.rl" - { target.b = value; } +#line 76 "ansi_parser.rl" + { target.g = value; } break; case 14: -#line 74 "ansi_parser.rl" - { value = 0; } +#line 77 "ansi_parser.rl" + { target.b = value; } break; case 15: -#line 75 "ansi_parser.rl" +#line 78 "ansi_parser.rl" + { value = 0; } + break; + case 16: +#line 79 "ansi_parser.rl" {} break; -#line 284 "ansi_parser.cpp" +#line 292 "ansi_parser.cpp" } } @@ -322,15 +331,15 @@ _again: _test_eof: {} if ( p == eof ) { - const char *__acts = _foo_actions + _foo_eof_actions[cs]; + const char *__acts = _ansi_parser_actions + _ansi_parser_eof_actions[cs]; unsigned int __nacts = (unsigned int) *__acts++; while ( __nacts-- > 0 ) { switch ( *__acts++ ) { - case 15: -#line 75 "ansi_parser.rl" + case 16: +#line 79 "ansi_parser.rl" {} break; -#line 302 "ansi_parser.cpp" +#line 310 "ansi_parser.cpp" } } } @@ -338,16 +347,20 @@ _again: _out: {} } -#line 139 "ansi_parser.rl" +#line 144 "ansi_parser.rl" - bool good = p - pe == 0; + bool good = pe - p == 0; if(!good) { - println("FAIL AT {}", p - pe); + println("FAIL AT {}", pe - p); p -= 10; // dear cthuhlu, save me from the pain that is wstring for(int i = 0; i < 100; i++) { - print("{}", char(p[i])); + try { + print("{}", p[i] == 0x1B ? '^' : char(p[i])); + } catch(...) { + print("?=", int(p[i])); + } } } diff --git a/ansi_parser.rl b/ansi_parser.rl index 49aa594..595caec 100644 --- a/ansi_parser.rl +++ b/ansi_parser.rl @@ -67,6 +67,10 @@ using namespace fmt; color = sf::Color(100,100,100); color_cb(color, bgcolor); } + action red_text { + color = sf::Color::Red; + color_cb(color, bgcolor); + } action red { target.r = value; } action blue { target.g = value; } @@ -96,6 +100,7 @@ using namespace fmt; "5" | "6" | "7" %invert | + "31" %red_text | "22" | "27" %reset_invert | "9" ["0"-"7"] | @@ -137,14 +142,18 @@ bool ANSIParser::parse(std::wstring_view codes, ColorCB color_cb, WriteCB write_ %% write init; %% write exec; - bool good = p - pe == 0; + bool good = pe - p == 0; if(!good) { - println("FAIL AT {}", p - pe); + println("FAIL AT {}", pe - p); p -= 10; // dear cthuhlu, save me from the pain that is wstring for(int i = 0; i < 100; i++) { - print("{}", char(p[i])); + try { + print("{}", p[i] == 0x1B ? '^' : char(p[i])); + } catch(...) { + print("?=", int(p[i])); + } } } diff --git a/gui.cpp b/gui.cpp index 1dd5493..295f6d8 100644 --- a/gui.cpp +++ b/gui.cpp @@ -49,7 +49,7 @@ GUI::GUI(DinkyECS::World &world, Map& game_map) : } void GUI::resize_map(int new_size) { - if($renderer.resize_map(new_size, $view_port)) { + if($renderer.resize_grid(new_size, $view_port)) { // set canvas to best size $canvas = Canvas($view_port.x * 2, $view_port.y * 4); $map_view.resize($view_port.x, $view_port.y); diff --git a/render.cpp b/render.cpp index 6398394..8c03422 100644 --- a/render.cpp +++ b/render.cpp @@ -57,13 +57,21 @@ inline bool base_glyph_check(sf::Font &font, sf::Glyph &base_glyph, Point &view_ font_size = new_size; return true; } else { + println("VIEW TOO BIG, view={},{} MAP={},{}", view_x, view_y, + GAME_MAP_X, GAME_MAP_Y); return false; } } -bool SFMLRender::resize_map(int new_size, Point &view_port) { - if($map_font_size == new_size || new_size < MIN_FONT_SIZE || new_size > MAX_FONT_SIZE) return false; +bool SFMLRender::resize_grid(int new_size, Point &view_port) { + if($map_font_size == new_size || new_size < MIN_FONT_SIZE || new_size > MAX_FONT_SIZE) { + println("invalid map font size {}, =={}, min={}, max={}", + new_size, $map_font_size, MIN_FONT_SIZE, MAX_FONT_SIZE); + return false; + } else { + println("NEW SIZE SELECTED {}", new_size); + } if(base_glyph_check($font, $base_glyph, view_port, $map_font_size, new_size)) { $sprites.clear(); // need to reset the sprites for the new size @@ -72,6 +80,7 @@ bool SFMLRender::resize_map(int new_size, Point &view_port) { $bg_bounds = $bg_sprite.getLocalBounds(); return true; } else { + println("BASE GLYPH FAILED!"); // something else here return false; } diff --git a/render.hpp b/render.hpp index 6eb12e4..67200d0 100644 --- a/render.hpp +++ b/render.hpp @@ -47,7 +47,7 @@ struct SFMLRender { SFMLRender(SFMLRender &other) = delete; sf::Sprite &get_text_sprite(wchar_t tile); - bool resize_map(int new_size, Point &view_port); + bool resize_grid(int new_size, Point &view_port); void render_grid(const std::wstring &text, float x, float y); void render_text(const std::wstring &text, sf::Color bgcolor, float x, float y); diff --git a/scratchpad/img2ansi.cpp b/scratchpad/img2ansi.cpp index 90bea16..1afbf9d 100644 --- a/scratchpad/img2ansi.cpp +++ b/scratchpad/img2ansi.cpp @@ -1,3 +1,5 @@ +#include // for operator""s, chrono_literals +#include // for sleep_for #include #include #include "panel.hpp" @@ -5,11 +7,67 @@ #include "render.hpp" #include "dbc.hpp" #include +#include +#include +#include +#include +#include +#include +using namespace std::chrono_literals; using namespace fmt; -using namespace std; +using std::string, std::cout, std::vector; + +struct HSVColor { + unsigned long h = 0; + unsigned long s = 0; + unsigned long v = 0; +}; + +struct RGBColor { + unsigned long r = 0; + unsigned long g = 0; + unsigned long b = 0; +}; + +// taken from https://github.com/python/cpython/blob/3.9/Lib/colorsys.py#L140 +HSVColor rgb_to_hsv(sf::Color rgb) { + float r = rgb.r / 255.0f; + float g = rgb.g / 255.0f; + float b = rgb.b / 255.0f; + + float maxc = std::max({rgb.r, rgb.g, rgb.b}); + float minc = std::min({rgb.r, rgb.g, rgb.b}); + float v = maxc; + + // if minc == maxc: + if(minc == maxc) { + // no hue no sat, so gray with value + return {0, 0, uint8_t(v * 255.0)}; + } + + float s = (maxc - minc) / maxc; + float rc = (maxc - r) / (maxc - minc); + float gc = (maxc - g) / (maxc - minc); + float bc = (maxc - b) / (maxc - minc); + float h = 0.0f; + + if(r == maxc) { + h = bc-gc; + } else if(g == maxc) { + h = 2.0 + rc - bc; + } else { + h = 4.0 + gc - rc; + h = std::fmod((h/6.0), 1.0); + } + + return {uint8_t(h * 255.0f), uint8_t(s * 255.0f), uint8_t(v * 255.0f)}; +} int main(int argc, char *argv[]) { + ftxui::Terminal::SetColorSupport(ftxui::Terminal::Color::TrueColor); + + _setmode(_fileno(stdout), _O_U16TEXT); dbc::check(argc == 2, "USAGE: img2ansi "); string image_file(argv[1]); @@ -20,14 +78,89 @@ int main(int argc, char *argv[]) { sf::Image image; image.loadFromFile(image_file); - // create a grid panel to hold the cells - Panel panel(40,40, 0, 0, true); // divide the image into cells + auto size = image.getSize(); + + const int cell = 10; + + // create a grid panel to hold the cells + Panel panel(0, 0, GAME_MAP_POS, 0, true); + Point view_port{0,0}; + + println("IMAGE SIZE {},{}", size.x, size.y); + RGBColor avg{0,0,0}; + + typedef vector ColorRow; + vector colors(size.x / cell, ColorRow(size.y / cell)); + + // LOL, so bad but just the start + for(unsigned int i = 0; i < size.x / cell; i++) { + for(unsigned int j = 0; j < size.y / cell; j++) { + + // sum the cell + for(unsigned int x = 0; x < cell ; x++) { + for(unsigned int y = 0; y < cell ; y++) { + auto pixel = image.getPixel((i*cell) + x, (j * cell) + y); + + avg.r += pixel.r; + avg.g += pixel.g; + avg.b += pixel.b; + } + } + + // average it for the cell size + RGBColor color = {avg.r / (cell * cell), + avg.g / (cell * cell), avg.b / (cell * cell)}; + + // add it + colors[i][j] = color; + + // reset + avg = {0,0,0}; + } + } + + Canvas drawing; + + + SFMLRender renderer; + // NEED TO RESIZE FOR IT TO SHOW + // this shows that I need more refinement on the renderer + // for example, this won't let me do arbitrary resize and + // is still locked to the map, but I need arbitrary for the + // scenes + if(renderer.resize_grid(50, view_port)) { + println("RESIZED: {},{}", view_port.x, view_port.y); + // set canvas to best size + drawing = Canvas(view_port.x * 2, view_port.y * 4); + panel.resize(view_port.x, view_port.y); + } + + panel.set_renderer(Renderer([&]{ + for(size_t x = 0; x < colors.size(); x++) { + for(size_t y = 0; y < colors[0].size(); y++) { + auto color = colors[x][y]; + ftxui::Color block = ftxui::Color::RGB(color.r, color.g, color.b); + drawing.DrawText(x * 2, y * 4, "█", block); + } + } + return ftxui::canvas(drawing); + })); + + sf::Event event; + + while(renderer.is_open()) { + renderer.draw(panel); + renderer.display(); + + while(renderer.poll_event(event)) { + if(event.type == sf::Event::Closed) { + renderer.close(); + } + } + + std::this_thread::sleep_for(10ms); + } - // for each cell: - // get the color - // calculate value - // find character that's closest - // write to panel/canvas with ftxui - // display in sfml window with renderer + return 0; }