ANSI code renderer starts working but I have to make it utf8/wchar_t friendly.

main
Zed A. Shaw 3 weeks ago
parent 6ca4614fcb
commit ae484bf425
  1. 128
      ansi_parser.cpp
  2. 5
      ansi_parser.hpp
  3. 46
      ansi_parser.rl
  4. 8
      map.hpp
  5. 13
      meson.build
  6. 54
      render.cpp
  7. 1
      render.hpp
  8. 4
      systems.cpp
  9. 14
      tests/ansi_parser.cpp

@ -5,105 +5,108 @@
#include <charconv> #include <charconv>
#include "dbc.hpp" #include "dbc.hpp"
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include "ansi_parser.hpp"
using namespace fmt; 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[] = { static const char _foo_actions[] = {
0, 1, 0, 1, 3, 1, 4, 1, 0, 1, 0, 1, 3, 1, 4, 1,
5, 1, 9, 1, 10, 2, 1, 6, 5, 1, 6, 1, 7, 1, 11, 1,
2, 1, 7, 2, 10, 5, 3, 1, 12, 2, 1, 8, 2, 1, 9, 2,
8, 2 12, 5, 3, 1, 10, 2
}; };
static const char _foo_key_offsets[] = { static const char _foo_key_offsets[] = {
0, 0, 1, 2, 4, 6, 7, 8, 0, 0, 1, 2, 4, 6, 7, 8,
9, 11, 14, 16, 19, 21, 24, 25, 9, 11, 14, 16, 19, 21, 24, 25,
27, 28, 29, 30 27, 28, 29, 30, 31
}; };
static const char _foo_trans_keys[] = { static const char _foo_trans_keys[] = {
27, 91, 51, 52, 56, 57, 59, 50, 27, 91, 51, 52, 56, 57, 59, 50,
59, 48, 57, 59, 48, 57, 48, 57, 59, 48, 57, 59, 48, 57, 48, 57,
59, 48, 57, 48, 57, 109, 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[] = { static const char _foo_single_lengths[] = {
0, 1, 1, 2, 2, 1, 1, 1, 0, 1, 1, 2, 2, 1, 1, 1,
0, 1, 0, 1, 0, 1, 1, 2, 0, 1, 0, 1, 0, 1, 1, 2,
1, 1, 1, 1 1, 1, 1, 1, 1
}; };
static const char _foo_range_lengths[] = { static const char _foo_range_lengths[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 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[] = { static const char _foo_index_offsets[] = {
0, 0, 2, 4, 7, 10, 12, 14, 0, 0, 2, 4, 7, 10, 12, 14,
16, 18, 21, 23, 26, 28, 31, 33, 16, 18, 21, 23, 26, 28, 31, 33,
36, 38, 40, 42 36, 38, 40, 42, 44
}; };
static const char _foo_trans_targs[] = { static const char _foo_trans_targs[] = {
2, 1, 3, 0, 4, 15, 0, 5, 2, 1, 3, 0, 4, 15, 0, 5,
14, 0, 6, 0, 7, 0, 8, 0, 14, 0, 6, 0, 7, 0, 8, 0,
9, 0, 10, 9, 0, 11, 0, 12, 9, 0, 10, 9, 0, 11, 0, 12,
11, 0, 13, 0, 19, 13, 0, 19, 11, 0, 13, 0, 20, 13, 0, 20,
0, 16, 14, 0, 17, 0, 7, 0, 0, 16, 18, 0, 17, 0, 7, 0,
2, 1, 2, 1, 0 20, 0, 2, 1, 2, 1, 0
}; };
static const char _foo_trans_actions[] = { 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, 0, 0, 0, 0, 3, 0, 0, 0,
1, 0, 13, 0, 0, 1, 0, 16, 1, 0, 17, 0, 0, 1, 0, 20,
0, 0, 1, 0, 22, 0, 0, 0, 0, 0, 1, 0, 26, 0, 0, 9,
0, 0, 0, 0, 0, 0, 5, 0, 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[] = { 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, 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_start = 19;
static const int foo_first_final = 18; static const int foo_first_final = 19;
static const int foo_error = 0; 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; const char *start = NULL;
int cs = 0; int cs = 0;
unsigned int value = 0; unsigned int value = 0;
const char *p = codes.data(); const char *p = codes.data();
const char *pe = p + codes.size(); const char *pe = p + codes.size();
const char *eof = pe; const char *eof = pe;
bool is_fg = false; sf::Color bgcolor(default_bg);
sf::Color color; sf::Color color(default_fg);
sf::Color &target = bgcolor;
#line 91 ".\\ansi_parser.cpp" #line 94 ".\\ansi_parser.cpp"
{ {
cs = foo_start; 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; int _klen;
unsigned int _trans; unsigned int _trans;
@ -177,62 +180,65 @@ _match:
switch ( *_acts++ ) switch ( *_acts++ )
{ {
case 0: case 0:
#line 12 ".\\ansi_parser.rl" #line 13 ".\\ansi_parser.rl"
{ {
start = p; start = p;
} }
break; break;
case 1: case 1:
#line 16 ".\\ansi_parser.rl" #line 17 ".\\ansi_parser.rl"
{ {
auto [ptr, ec] = std::from_chars(start, p, value); auto [ptr, ec] = std::from_chars(start, p, value);
dbc::check(ec == std::errc(), "error in number parsing"); dbc::check(ec == std::errc(), "error in number parsing");
println("NUM: {}", value);
} }
break; break;
case 2: case 2:
#line 22 ".\\ansi_parser.rl" #line 22 ".\\ansi_parser.rl"
{ { }
println("color24b");
}
break; break;
case 3: case 3:
#line 26 ".\\ansi_parser.rl" #line 23 ".\\ansi_parser.rl"
{ is_fg = true; } { target = color; }
break; break;
case 4: case 4:
#line 27 ".\\ansi_parser.rl" #line 24 ".\\ansi_parser.rl"
{ is_fg = false; } { target = bgcolor; }
break; break;
case 5: case 5:
#line 29 ".\\ansi_parser.rl" #line 26 ".\\ansi_parser.rl"
{ {
println("ANY: {}:{}", int((*p)), (*p)); write(bgcolor, color, (*p));
} }
break; break;
case 6: case 6:
#line 33 ".\\ansi_parser.rl" #line 30 ".\\ansi_parser.rl"
{ color.r = value; } { color = default_fg; }
break; break;
case 7: case 7:
#line 34 ".\\ansi_parser.rl" #line 31 ".\\ansi_parser.rl"
{ color.g = value; } { bgcolor = default_bg; }
break; break;
case 8: case 8:
#line 35 ".\\ansi_parser.rl" #line 33 ".\\ansi_parser.rl"
{ color.b = value; } { target.r = value; }
break; break;
case 9: case 9:
#line 37 ".\\ansi_parser.rl" #line 34 ".\\ansi_parser.rl"
{ value = 0; } { target.g = value; }
break; break;
case 10: case 10:
#line 39 ".\\ansi_parser.rl" #line 35 ".\\ansi_parser.rl"
{ { target.b = value; }
println("fg? {}, sf:Color: {},{},{},{}", is_fg, color.r, color.g, color.b, color.a);
}
break; 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++; unsigned int __nacts = (unsigned int) *__acts++;
while ( __nacts-- > 0 ) { while ( __nacts-- > 0 ) {
switch ( *__acts++ ) { switch ( *__acts++ ) {
case 10: case 12:
#line 39 ".\\ansi_parser.rl" #line 37 ".\\ansi_parser.rl"
{ { }
println("fg? {}, sf:Color: {},{},{},{}", is_fg, color.r, color.g, color.b, color.a);
}
break; break;
#line 231 ".\\ansi_parser.cpp" #line 233 ".\\ansi_parser.cpp"
} }
} }
} }
@ -262,9 +266,7 @@ _again:
_out: {} _out: {}
} }
#line 78 ".\\ansi_parser.rl" #line 76 ".\\ansi_parser.rl"
print("PROCESSED {} CHARS of {}: {}", p - codes.data(), codes.size(), p);
return true; return p - pe == 0;
} }

@ -1,4 +1,7 @@
#pragma once #pragma once
#include <string_view> #include <string_view>
#include <SFML/Graphics.hpp>
bool parse_ansi(std::string_view codes); typedef std::function<void(sf::Color bgcolor, sf::Color color, char ch)> WriteCB;
bool parse_ansi(std::string_view codes, sf::Color default_fg, sf::Color default_bg, WriteCB write);

@ -3,6 +3,7 @@
#include <charconv> #include <charconv>
#include "dbc.hpp" #include "dbc.hpp"
#include <SFML/Graphics.hpp> #include <SFML/Graphics.hpp>
#include "ansi_parser.hpp"
using namespace fmt; using namespace fmt;
@ -16,34 +17,30 @@ using namespace fmt;
action number { action number {
auto [ptr, ec] = std::from_chars(start, fpc, value); auto [ptr, ec] = std::from_chars(start, fpc, value);
dbc::check(ec == std::errc(), "error in number parsing"); dbc::check(ec == std::errc(), "error in number parsing");
println("NUM: {}", value);
} }
action color24b { action color24b { }
println("color24b"); action is_fg { target = color; }
} action is_bg { target = bgcolor; }
action is_fg { is_fg = true; }
action is_bg { is_fg = false; }
action any { action out {
println("ANY: {}:{}", int(fc), fc); write(bgcolor, color, fc);
} }
action red { color.r = value; } action reset_fg { color = default_fg; }
action blue { color.g = value; } action reset_bg { bgcolor = default_bg; }
action green { color.b = value; }
action red { target.r = value; }
action blue { target.g = value; }
action green { target.b = value; }
action start { value = 0; } action start { value = 0; }
action end { }
action end { ESC = 0x1B;
println("fg? {}, sf:Color: {},{},{},{}", is_fg, color.r, color.g, color.b, color.a); start = ESC "[";
}
start = 0x1B "[";
fg = "38;" %is_fg; fg = "38;" %is_fg;
bg = "48;" %is_bg; bg = "48;" %is_bg;
reset = ("39" | "49"); reset = ("39" %reset_fg | "49" %reset_bg);
num = digit+ >tstart %number; num = digit+ >tstart %number;
color256 = "5;"; color256 = "5;";
color24b = "2;"; color24b = "2;";
@ -56,27 +53,26 @@ using namespace fmt;
) "m" %end ) "m" %end
); );
other = (any+ @any -- 0x1B)*; other = (any+ @out -- ESC)*;
main := (other :> ansi)**; main := (other :> ansi)**;
}%% }%%
%% write data; %% 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; const char *start = NULL;
int cs = 0; int cs = 0;
unsigned int value = 0; unsigned int value = 0;
const char *p = codes.data(); const char *p = codes.data();
const char *pe = p + codes.size(); const char *pe = p + codes.size();
const char *eof = pe; const char *eof = pe;
bool is_fg = false; sf::Color bgcolor(default_bg);
sf::Color color; sf::Color color(default_fg);
sf::Color &target = bgcolor;
%% write init; %% write init;
%% write exec; %% write exec;
print("PROCESSED {} CHARS of {}: {}", p - codes.data(), codes.size(), p); return p - pe == 0;
return true;
} }

@ -11,10 +11,10 @@
#define INV_SPACE 1 #define INV_SPACE 1
#define WALL_VALUE 1 #define WALL_VALUE 1
#define SPACE_VALUE 0 #define SPACE_VALUE 0
#define WALL_TILE "" #define WALL_TILE "#"
#define FLOOR_TILE "#" #define FLOOR_TILE "."
#define PLAYER_TILE "" #define PLAYER_TILE "&"
#define ENEMY_TILE "Ω" #define ENEMY_TILE "!"
struct Room { struct Room {
size_t x = 0; size_t x = 0;

@ -21,12 +21,12 @@ runtests = executable('runtests', [
'collider.cpp', 'collider.cpp',
'ansi_parser.cpp', 'ansi_parser.cpp',
'render.cpp', 'render.cpp',
#'tests/fsm.cpp', 'tests/fsm.cpp',
#'tests/dbc.cpp', 'tests/dbc.cpp',
#'tests/map.cpp', 'tests/map.cpp',
#'tests/collider.cpp', 'tests/collider.cpp',
#'tests/sound.cpp', 'tests/sound.cpp',
#'tests/dinkyecs.cpp', 'tests/dinkyecs.cpp',
'tests/ansi_parser.cpp', 'tests/ansi_parser.cpp',
], ],
dependencies: dependencies) dependencies: dependencies)
@ -41,6 +41,7 @@ roguish = executable('roguish', [
'collider.cpp', 'collider.cpp',
'combat.cpp', 'combat.cpp',
'systems.cpp', 'systems.cpp',
'ansi_parser.cpp',
'render.cpp', 'render.cpp',
], ],
dependencies: dependencies) dependencies: dependencies)

@ -1,5 +1,7 @@
#include "render.hpp" #include "render.hpp"
#include "ansi_parser.hpp"
#include <cmath> #include <cmath>
#include <fmt/core.h>
std::array<sf::Color, 10> VALUES{ std::array<sf::Color, 10> VALUES{
sf::Color{1, 4, 2}, // black sf::Color{1, 4, 2}, // black
@ -66,13 +68,16 @@ bool SFMLRender::resize_map(int new_size) {
} }
} }
void SFMLRender::draw_main_ui() {
void SFMLRender::draw_screen(bool clear, float map_off_x, float map_off_y) {
if(clear) $window.clear();
std::string screenout = $screen.ToString(); std::string screenout = $screen.ToString();
std::wstring main_screen_utf8 = $converter.from_bytes(screenout); std::wstring main_screen_utf8 = $converter.from_bytes(screenout);
$ui_text.setString(main_screen_utf8); $ui_text.setString(main_screen_utf8);
$window.draw($ui_text); $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::string map_screenout = $map_screen.ToString();
std::wstring map_screen_utf8 = $converter.from_bytes(map_screenout); 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 // make a copy so we don't modify the cached one
auto bg_sprite = get_text_sprite(L''); auto bg_sprite = get_text_sprite(L'');
auto bg_bounds = bg_sprite.getLocalBounds(); auto bg_bounds = bg_sprite.getLocalBounds();
bg_sprite.setColor(sf::Color(20,20,20)); sf::Color def_fg(color(Value::LIGHT_LIGHT));
auto add_sprite = get_text_sprite(L'!'); sf::Color def_bg(color(Value::BLACK));
bool has_add = false;
for(size_t i = 0; i < map_screen_utf8.size(); i++) { parse_ansi(map_screenout, def_fg, def_bg, [&](sf::Color bg, sf::Color fg, char tile) {
wchar_t tile = map_screen_utf8[i]; if(tile == '\n') {
if(tile == L'\n') {
// don't bother processing newlines, just skip // don't bother processing newlines, just skip
y += $line_spacing; y += $line_spacing;
x = GAME_MAP_POS; x = GAME_MAP_POS;
} else if(tile == L'\r') { } else if(tile == L'\r') {
continue; // skip these, just windows junk return; // skip these, just windows junk
} else { } 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 // it's a visual cell
bg_sprite.setPosition({x+map_off_x, y+map_off_y}); bg_sprite.setPosition({x+map_off_x, y+map_off_y});
sf::Sprite &sprite = get_text_sprite(tile); sf::Sprite &sprite = get_text_sprite(tile);
bg_sprite.setColor(bg);
// should look into caching all this instead of calcing it each time // should look into caching all this instead of calcing it each time
auto sp_bounds = sprite.getLocalBounds(); 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 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; 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.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(bg_sprite);
$window.draw(sprite); $window.draw(sprite);
if(has_add) {
$window.draw(add_sprite);
has_add = false;
}
// next cell // next cell
x += $base_glyph.advance; x += $base_glyph.advance;
} }
} });
$window.display(); $window.display();
} }

@ -49,6 +49,7 @@ struct SFMLRender {
sf::Color color(Value val); sf::Color color(Value val);
sf::Sprite &get_text_sprite(wchar_t tile); sf::Sprite &get_text_sprite(wchar_t tile);
bool resize_map(int new_size); 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); void draw_screen(bool clear=true, float map_off_x=0.0f, float map_off_y=0.0f);
bool poll_event(sf::Event &event) { bool poll_event(sf::Event &event) {

@ -5,10 +5,12 @@
#include "rand.hpp" #include "rand.hpp"
#include "collider.hpp" #include "collider.hpp"
#include "events.hpp" #include "events.hpp"
#include "ftxui/screen/color.hpp"
using std::string; using std::string;
using namespace fmt; using namespace fmt;
using namespace Components; using namespace Components;
using ftxui::Color;
#define HEARING_DISTANCE 8 #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) { for(size_t y = 0; y < end_y; ++y) {
string tile = walls[start.y+y][start.x+x] == 1 ? WALL_TILE : FLOOR_TILE; 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 // 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));
} }
} }

@ -33,7 +33,6 @@ std::string generate_colors() {
count++; count++;
} }
array.push_back(hbox(std::move(line))); array.push_back(hbox(std::move(line)));
break; /// UNDO ME
} }
println("MADE {} CHARS", count); println("MADE {} CHARS", count);
@ -53,7 +52,18 @@ std::string generate_colors() {
TEST_CASE("test out ragel parser", "[gui]") { TEST_CASE("test out ragel parser", "[gui]") {
std::string colors = generate_colors(); std::string colors = generate_colors();
sf::Color default_fg(0,0,0);
sf::Color default_bg(100,100,100);
println("--- PARSING"); 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);
} }

Loading…
Cancel
Save