Rewrote the ansi parser to exactly callback on color setting, so now just need to clean this all up and fix a few little bugs.

This commit is contained in:
Zed A. Shaw 2024-11-16 12:10:14 -05:00
parent 96ee16e598
commit 89a70f398a
9 changed files with 274 additions and 126 deletions

View file

@ -4,6 +4,7 @@
#include <fmt/core.h>
#include <array>
#include "map.hpp"
#include <iostream>
using namespace fmt;
@ -104,45 +105,113 @@ inline void configure_tile(const sf::Sprite &sprite, sf::FloatRect &sp_bounds,
height_delta = bg_bounds.height > sp_bounds.width ? (bg_bounds.height - sp_bounds.height) / 2 : 0;
}
void SFMLRender::render_text(const std::wstring &text, float x, float y) {
void SFMLRender::render_grid(const std::wstring &text, float x, float y) {
wchar_t last_tile = '#';
sf::FloatRect sp_bounds;
float width_delta = 0;
float height_delta = 0;
sf::Sprite &sprite = get_text_sprite(last_tile);
const float start_x = x;
sf::Color cur_fg = $default_fg;
// make a copy so we don't modify the cached one
$ansi.parse(text, [&](sf::Color bg, sf::Color fg, wchar_t tile) {
if(tile == '\n') {
// don't bother processing newlines, just skip
y += $line_spacing;
x = start_x;
} else if(tile == L'\r') {
return; // skip these, just windows junk
} else {
$bg_sprite.setPosition({x, y});
$ansi.parse(text, [&](sf::Color fg, sf::Color bg) {
cur_fg = fg;
$bg_sprite.setColor(bg);
},
// only get a new sprite if the tile changed
if(last_tile != tile) {
last_tile = tile; // update last tile seen
sprite = get_text_sprite(tile);
configure_tile(sprite, sp_bounds, $bg_bounds, width_delta, height_delta);
[&](wchar_t tile) {
if(tile == '\n') {
// don't bother processing newlines, just skip
y += $line_spacing;
x = start_x;
} else if(tile == L'\r') {
return; // skip these, just windows junk
} else {
$bg_sprite.setPosition({x, y});
// only get a new sprite if the tile changed
if(last_tile != tile) {
last_tile = tile; // update last tile seen
sprite = get_text_sprite(tile);
configure_tile(sprite, sp_bounds, $bg_bounds, width_delta, height_delta);
}
sprite.setPosition({x+width_delta, y+height_delta});
sprite.setColor(cur_fg);
$window.draw($bg_sprite);
$window.draw(sprite);
// next cell
x += $base_glyph.advance;
}
sprite.setPosition({x+width_delta, y+height_delta});
sprite.setColor(fg);
$window.draw($bg_sprite);
$window.draw(sprite);
// next cell
x += $base_glyph.advance;
}
});
}
void SFMLRender::draw_text_ui(Panel &panel, bool with_border) {
inline sf::FloatRect draw_chunk(sf::RenderWindow& window, sf::Text& text, float x, float y, std::wstring &out) {
text.setString(out);
text.setPosition(x, y);
sf::FloatRect bounds = text.getLocalBounds();
// need left,top,width,height for box to be accurate
window.draw(text);
out.clear();
return bounds;
}
void SFMLRender::render_text(const std::wstring &text, float start_x, float start_y) {
std::wstring out;
float x = start_x;
float y = start_y;
enum State { START=1, BUILDING=2 };
enum Event { NL=1, CHAR=3, SKIP=5 };
State state = START;
Event event = CHAR;
// start with the default_fg until it's changed
$ui_text.setFillColor($default_fg);
$ansi.parse(text,
[&](sf::Color fg, sf::Color bg){
if(out.size() > 0 ) {
auto bounds = draw_chunk($window, $ui_text, x, y, out);
x += bounds.width;
}
$ui_text.setFillColor(fg);
},
[&](wchar_t tile) {
if(tile == '\r') event = SKIP;
else if(tile == '\n') event = NL;
else event = CHAR;
switch(event) {
case SKIP: break; // ignore it
case NL: {
if(state == START) {
state = BUILDING;
} else if(state == BUILDING) {
sf::FloatRect bounds;
if(out.size() > 0) {
bounds = draw_chunk($window, $ui_text, x, y, out);
} else {
bounds = $ui_text.getLocalBounds();
}
y += bounds.height;
x = start_x; // reset to the original position
}
}
break;
case CHAR:
state = BUILDING;
out += tile;
break;
}
}
);
}
void SFMLRender::draw_text(Panel &panel, bool with_border) {
sf::RectangleShape backing(
sf::Vector2f($ui_bounds.width * panel.width,
$ui_bounds.height * panel.height));
@ -159,13 +228,11 @@ void SFMLRender::draw_text_ui(Panel &panel, bool with_border) {
panel.render();
const std::wstring &panelout = panel.to_string();
$ui_text.setPosition(panel.x, panel.y);
$ui_text.setString(panelout);
$window.draw($ui_text);
render_text(panelout, panel.x, panel.y);
}
void SFMLRender::draw_screen(Panel &panel, float x, float y) {
void SFMLRender::draw_grid(Panel &panel, float x, float y) {
panel.render();
const std::wstring &panelout = panel.to_string();
render_text(panelout, panel.x + x, panel.y + y);
render_grid(panelout, panel.x + x, panel.y + y);
}