From 19b8bf1850b010baee99deac4aa7ea9293516af4 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Thu, 21 Nov 2024 02:49:58 -0500 Subject: [PATCH] Totally a pile of garbage with a bunch of debug prints because I'm going to have to rewrite the renderer resizing to allow for any size image, not just the map. But this does display an image using averaged squares. --- Makefile | 2 +- ansi_parser.cpp | 175 +++++++++++++++++++++------------------- ansi_parser.rl | 15 +++- gui.cpp | 2 +- render.cpp | 13 ++- render.hpp | 2 +- scratchpad/img2ansi.cpp | 151 +++++++++++++++++++++++++++++++--- 7 files changed, 262 insertions(+), 98 deletions(-) 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; }