From fedb5f64f36bc3543b931bc791f5ea39dfecd94b Mon Sep 17 00:00:00 2001 From: Markus Gans Date: Thu, 15 Dec 2016 23:11:34 +0100 Subject: [PATCH] Reduce the character output by using character erase and character repeat --- ChangeLog | 4 + README.md | 40 +++++----- doc/VTerm.txt | 40 +++++----- src/fenum.h | 2 + src/foptimove.cpp | 34 +++++++++ src/foptimove.h | 4 + src/ftcap_map.h | 2 + src/fterm.cpp | 14 ++-- src/fterm.h | 3 + src/fvterm.cpp | 185 +++++++++++++++++++++++++++++++++------------- src/fvterm.h | 1 + 11 files changed, 236 insertions(+), 93 deletions(-) diff --git a/ChangeLog b/ChangeLog index e9fcfd58..d09089dc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2016-12-15 Markus Gans + * Reduce the character output by using character erase + and character repeat + 2016-12-11 Markus Gans * Accelerates text line drawing by clear with CSI sequences to begin or to end of the current line. diff --git a/README.md b/README.md index 0437a995..ee4055ba 100644 --- a/README.md +++ b/README.md @@ -79,24 +79,28 @@ printf(...) ║ │ resizeVTerm()║ ╚═══▼═══════════════════════════════════════════════════════╝ │ - │ putVTerm() ┌───────────────┐ - └───────────────────►│ output_buffer │ - updateTerminal() └───────┬───────┘ - │ - │ flush_out() - │ + - │ Fputchar(char) - │ - ▼ - ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ - ▌ ▐ - ▌ screen ▐ - ▌ ───────────── ▐ - ▌ real terminal ▐ - ▌ ▐ - ▀▀▀▀▀▀▀███▀▀▀▀▀▀▀ - ███ - ▀▀▀▀▀▀▀▀▀ + │ putVTerm() + └──────────────────► updateTerminalLine(y) + updateTerminal() │ + ▼ + ┌───────────────┐ + │ output_buffer │ + └───────────────┘ + │ + │ flush_out() + │ + + │ Fputchar(char) + │ + ▼ + ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ + ▌ ▐ + ▌ screen ▐ + ▌ ───────────── ▐ + ▌ real terminal ▐ + ▌ ▐ + ▀▀▀▀▀▀▀███▀▀▀▀▀▀▀ + ███ + ▀▀▀▀▀▀▀▀▀ diff --git a/doc/VTerm.txt b/doc/VTerm.txt index 995f1a8d..fd8bf239 100644 --- a/doc/VTerm.txt +++ b/doc/VTerm.txt @@ -30,22 +30,26 @@ printf(...) ║ │ resizeVTerm()║ ╚═══▼═══════════════════════════════════════════════════════╝ │ - │ putVTerm() ┌───────────────┐ - └───────────────────►│ output_buffer │ - updateTerminal() └───────┬───────┘ - │ - │ flush_out() - │ + - │ Fputchar(char) - │ - ▼ - ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ - ▌ ▐ - ▌ screen ▐ - ▌ ───────────── ▐ - ▌ real terminal ▐ - ▌ ▐ - ▀▀▀▀▀▀▀███▀▀▀▀▀▀▀ - ███ - ▀▀▀▀▀▀▀▀▀ + │ putVTerm() + └──────────────────► updateTerminalLine(y) + updateTerminal() │ + ▼ + ┌───────────────┐ + │ output_buffer │ + └───────────────┘ + │ + │ flush_out() + │ + + │ Fputchar(char) + │ + ▼ + ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ + ▌ ▐ + ▌ screen ▐ + ▌ ───────────── ▐ + ▌ real terminal ▐ + ▌ ▐ + ▀▀▀▀▀▀▀███▀▀▀▀▀▀▀ + ███ + ▀▀▀▀▀▀▀▀▀ diff --git a/src/fenum.h b/src/fenum.h index 85f872a9..ad8a2144 100644 --- a/src/fenum.h +++ b/src/fenum.h @@ -971,6 +971,7 @@ class fc enum termcaps { t_bell, + t_erase_chars, t_clear_screen, t_clr_eos, t_clr_eol, @@ -983,6 +984,7 @@ class fc t_insert_padding, t_insert_character, t_parm_ich, + t_repeat_char, t_initialize_color, t_initialize_pair, t_set_a_foreground, diff --git a/src/foptimove.cpp b/src/foptimove.cpp index f616a794..3bfb722f 100644 --- a/src/foptimove.cpp +++ b/src/foptimove.cpp @@ -27,6 +27,8 @@ FOptiMove::FOptiMove (int baud) , F_parm_down_cursor() , F_parm_left_cursor() , F_parm_right_cursor() + , F_erase_chars() + , F_repeat_char() , F_clr_bol() , F_clr_eol() , automatic_left_margin(false) @@ -320,6 +322,38 @@ int FOptiMove::set_parm_right_cursor (char*& cap) return F_parm_right_cursor.length; } +//---------------------------------------------------------------------- +int FOptiMove::set_erase_chars (char*& cap) +{ + if ( cap ) + { + char* temp = tparm(cap, 23); + F_erase_chars.cap = cap; + F_erase_chars.duration = capDuration (temp, 1); + F_erase_chars.length = capDurationToLength (F_erase_chars.duration); + } + else + F_erase_chars.duration = LONG_DURATION; + + return F_erase_chars.length; +} + +//---------------------------------------------------------------------- +int FOptiMove::set_repeat_char (char*& cap) +{ + if ( cap ) + { + char* temp = tparm(cap, ' ', 23); + F_repeat_char.cap = cap; + F_repeat_char.duration = capDuration (temp, 1); + F_repeat_char.length = capDurationToLength (F_repeat_char.duration); + } + else + F_repeat_char.duration = LONG_DURATION; + + return F_repeat_char.length; +} + //---------------------------------------------------------------------- int FOptiMove::set_clr_bol (char*& cap) { diff --git a/src/foptimove.h b/src/foptimove.h index 2f78b789..a8c402ea 100644 --- a/src/foptimove.h +++ b/src/foptimove.h @@ -60,6 +60,8 @@ class FOptiMove int set_parm_down_cursor (char*&); int set_parm_left_cursor (char*&); int set_parm_right_cursor (char*&); + int set_erase_chars (char*&); + int set_repeat_char (char*&); int set_clr_bol (char*&); int set_clr_eol (char*&); void set_auto_left_margin (bool&); @@ -112,6 +114,8 @@ class FOptiMove capability F_parm_down_cursor; capability F_parm_left_cursor; capability F_parm_right_cursor; + capability F_erase_chars; + capability F_repeat_char; capability F_clr_bol; capability F_clr_eol; diff --git a/src/ftcap_map.h b/src/ftcap_map.h index d8811ddb..617d462b 100644 --- a/src/ftcap_map.h +++ b/src/ftcap_map.h @@ -12,6 +12,7 @@ static FTermcap::tcap_map term_caps[] = // | | // variable name -> description //----------------------------------------------------------------------------- { 0, "bl" }, // bell -> audible signal (bell) (P) + { 0, "ec" }, // erase_chars -> erase #1 characters (P) { 0, "cl" }, // clear_screen -> clear screen and home cursor (P*) { 0, "cd" }, // clr_eos -> clear to end of screen (P*) { 0, "ce" }, // clr_eol -> clear to end of line (P) @@ -24,6 +25,7 @@ static FTermcap::tcap_map term_caps[] = { 0, "ip" }, // insert_padding -> insert padding after inserted character { 0, "ic" }, // insert_character -> insert character (P) { 0, "IC" }, // parm_ich -> insert #1 characters (P*) + { 0, "rp" }, // repeat_char -> repeat char #1 #2 times (P*) { 0, "Ic" }, // initialize_color -> initialize color #1 to (#2,#3,#4) { 0, "Ip" }, // initialize_pair -> Initialize color pair #1 to // fg=(#2,#3,#4), bg=(#5,#6,#7) diff --git a/src/fterm.cpp b/src/fterm.cpp index cb519a0c..be7876c8 100644 --- a/src/fterm.cpp +++ b/src/fterm.cpp @@ -24,8 +24,11 @@ int FTerm::stdin_no; int FTerm::stdout_no; int FTerm::fd_tty; int FTerm::stdin_status_flags; +int FTerm::erase_ch_length; +int FTerm::repeat_char_length; int FTerm::clr_bol_length; int FTerm::clr_eol_length; +int FTerm::cursor_addres_lengths; uInt FTerm::baudrate; bool FTerm::resize_term; bool FTerm::mouse_support; @@ -2905,7 +2908,7 @@ void FTerm::init_termcaps() opti_move->set_cursor_down (tcap[fc::t_cursor_down].string); opti_move->set_cursor_left (tcap[fc::t_cursor_left].string); opti_move->set_cursor_right (tcap[fc::t_cursor_right].string); - opti_move->set_cursor_address (tcap[fc::t_cursor_address].string); + cursor_addres_lengths = opti_move->set_cursor_address (tcap[fc::t_cursor_address].string); opti_move->set_column_address (tcap[fc::t_column_address].string); opti_move->set_row_address (tcap[fc::t_row_address].string); opti_move->set_parm_up_cursor (tcap[fc::t_parm_up_cursor].string); @@ -2914,6 +2917,8 @@ void FTerm::init_termcaps() opti_move->set_parm_right_cursor (tcap[fc::t_parm_right_cursor].string); opti_move->set_auto_left_margin (FTermcap::automatic_left_margin); opti_move->set_eat_newline_glitch (FTermcap::eat_nl_glitch); + erase_ch_length = opti_move->set_erase_chars (tcap[fc::t_erase_chars].string); + repeat_char_length = opti_move->set_repeat_char (tcap[fc::t_repeat_char].string); clr_bol_length = opti_move->set_clr_bol (tcap[fc::t_clr_bol].string); clr_eol_length = opti_move->set_clr_eol (tcap[fc::t_clr_eol].string); @@ -3106,12 +3111,9 @@ void FTerm::init() if ( isatty(stdout_no) ) opti_move->setBaudRate(int(baudrate)); - // detect the type of the terminal + // get the set type of the terminal identifyTermType(); - // initialize 256 colors terminals - new_termtype = init_256colorTerminal(); - if ( std::strncmp(termtype, "cygwin", 6) == 0 ) cygwin_terminal = true; else @@ -3143,6 +3145,8 @@ void FTerm::init() t.c_cc[VMIN] = 0; // Minimum number of characters tcsetattr (stdin_no, TCSANOW, &t); + // initialize 256 colors terminals + new_termtype = init_256colorTerminal(); // Identify the terminal via the answerback-message new_termtype = parseAnswerbackMsg (new_termtype); diff --git a/src/fterm.h b/src/fterm.h index 0f21b162..d915c6cd 100644 --- a/src/fterm.h +++ b/src/fterm.h @@ -254,8 +254,11 @@ class FTerm // Data Members static int stdin_no; static int stdout_no; + static int erase_ch_length; + static int repeat_char_length; static int clr_bol_length; static int clr_eol_length; + static int cursor_addres_lengths; static bool NewFont; static bool VGAFont; static bool no_shadow_character; diff --git a/src/fvterm.cpp b/src/fvterm.cpp index 336ff163..cfffe1d0 100644 --- a/src/fvterm.cpp +++ b/src/fvterm.cpp @@ -127,7 +127,7 @@ void FVTerm::clearTerm (int fillchar) for (int i=0; i < vdesktop->height; i++) { vdesktop->changes[i].xmin = 0; - vdesktop->changes[i].xmax = vdesktop->width - 1; + vdesktop->changes[i].xmax = uInt(vdesktop->width) - 1; vdesktop->changes[i].trans_count = 0; } @@ -289,6 +289,7 @@ void FVTerm::updateTerminal() //---------------------------------------------------------------------- void FVTerm::updateTerminalLine (uInt y) { + // Updates pending changes from line y to the terminal term_area* vt = vterm; uInt& xmin = vt->changes[y].xmin; uInt& xmax = vt->changes[y].xmax; @@ -302,18 +303,20 @@ void FVTerm::updateTerminalLine (uInt y) bool draw_tailing_ws = false; char*& ce = tcap[fc::t_clr_eol].string; char*& cb = tcap[fc::t_clr_bol].string; + char*& ec = tcap[fc::t_erase_chars].string; + char*& rp = tcap[fc::t_repeat_char].string; bool ut = FTermcap::background_color_erase; char_data* first_char = &vt->text[y * uInt(vt->width)]; char_data* last_char = &vt->text[(y+1) * uInt(vt->width) - 1]; char_data* min_char = &vt->text[y * uInt(vt->width) + xmin]; // Is the line from xmin to the end of the line blank? - if ( min_char->code == ' ' ) + if ( ce && min_char->code == ' ' ) { uInt beginning_whitespace = 1; bool normal = isNormal(min_char); - for (register uInt x=xmin+1; x < uInt(vt->width); x++) + for (uInt x=xmin+1; x < uInt(vt->width); x++) { if ( *min_char == vt->text[y * uInt(vt->width) + x] ) beginning_whitespace++; @@ -322,54 +325,57 @@ void FVTerm::updateTerminalLine (uInt y) } if ( beginning_whitespace == uInt(vt->width) - xmin - && ce && (ut || normal) + && (ut || normal) && clr_eol_length < int(beginning_whitespace) ) is_eol_clean = true; } - // leading whitespace - if ( ! is_eol_clean && first_char->code == ' ' ) + if ( ! is_eol_clean ) { - uInt leading_whitespace = 1; - bool normal = isNormal(first_char); - - for (register uInt x=1; x < uInt(vt->width); x++) + // leading whitespace + if ( cb && first_char->code == ' ' ) { - if ( *first_char == vt->text[y * uInt(vt->width) + x] ) - leading_whitespace++; - else - break; + uInt leading_whitespace = 1; + bool normal = isNormal(first_char); + + for (uInt x=1; x < uInt(vt->width); x++) + { + if ( *first_char == vt->text[y * uInt(vt->width) + x] ) + leading_whitespace++; + else + break; + } + + if ( leading_whitespace > xmin + && (ut || normal) + && clr_bol_length < int(leading_whitespace) ) + { + draw_leading_ws = true; + xmin = leading_whitespace - 1; + } } - if ( leading_whitespace > xmin - && cb && (ut || normal) - && clr_bol_length < int(leading_whitespace) ) + // tailing whitespace + if ( ce && last_char->code == ' ' ) { - draw_leading_ws = true; - xmin = leading_whitespace - 1; - } - } + uInt tailing_whitespace = 1; + bool normal = isNormal(last_char); - // tailing whitespace - if ( ! is_eol_clean && last_char->code == ' ' ) - { - uInt tailing_whitespace = 1; - bool normal = isNormal(last_char); + for (uInt x=uInt(vt->width)-1; x > 0 ; x--) + { + if ( *last_char == vt->text[y * uInt(vt->width) + x] ) + tailing_whitespace++; + else + break; + } - for (register uInt x=uInt(vt->width)-1; x > 0 ; x--) - { - if ( *last_char == vt->text[y * uInt(vt->width) + x] ) - tailing_whitespace++; - else - break; - } - - if ( tailing_whitespace > uInt(vt->width) - xmax - && ce && (ut || normal) - && clr_bol_length < int(tailing_whitespace) ) - { - draw_tailing_ws = true; - xmax = uInt(vt->width) - tailing_whitespace; + if ( tailing_whitespace > uInt(vt->width) - xmax + && (ut || normal) + && clr_bol_length < int(tailing_whitespace) ) + { + draw_tailing_ws = true; + xmax = uInt(vt->width) - tailing_whitespace; + } } } @@ -388,18 +394,78 @@ void FVTerm::updateTerminalLine (uInt y) appendOutputBuffer (cb); } - for (register uInt x=xmin; x <= xmax; x++) + for (uInt x=xmin; x <= xmax; x++) { char_data* print_char; print_char = &vt->text[y * uInt(vt->width) + x]; - if ( term_pos->getX() == term_width - && term_pos->getY() == term_height ) - appendLowerRight (print_char); + // Erase a number of characters to draw simple whitespaces + if ( ec && print_char->code == ' ' ) + { + uInt whitespace = 1; + bool normal = isNormal(print_char); + + for (uInt i=x+1; i <= xmax; i++) + { + if ( *print_char == vt->text[y * uInt(vt->width) + i] ) + whitespace++; + else + break; + } + + if ( whitespace > uInt(erase_ch_length) + uInt(cursor_addres_lengths) + && (ut || normal) ) + { + appendAttributes (print_char); + appendOutputBuffer (tparm(ec, whitespace)); + + if ( x + whitespace - 1 < xmax || draw_tailing_ws ) + setTermXY (int(x + whitespace), int(y)); + else + break; + + x = x + whitespace - 1; + } + else + { + x--; + + for (uInt i=0; i < whitespace; i++, x++) + appendCharacter (print_char); + } + } + else if ( rp ) // Repeat one character n-fold + { + uInt repetitions = 1; + + for (uInt i=x+1; i <= xmax; i++) + { + if ( *print_char == vt->text[y * uInt(vt->width) + i] ) + repetitions++; + else + break; + } + + if ( repetitions > uInt(repeat_char_length) + && print_char->code < 128 ) + { + newFontChanges (print_char); + charsetChanges (print_char); + appendAttributes (print_char); + appendOutputBuffer (tparm(rp, print_char->code, repetitions)); + term_pos->x_ref() += short(repetitions); + x = x + repetitions - 1; + } + else + { + x--; + + for (uInt i=0; i < repetitions; i++, x++) + appendCharacter (print_char); + } + } else appendCharacter (print_char); - - term_pos->x_ref()++; } if ( draw_tailing_ws ) @@ -944,6 +1010,21 @@ inline void FVTerm::charsetChanges (char_data*& next_char) //---------------------------------------------------------------------- inline void FVTerm::appendCharacter (char_data*& next_char) +{ + int term_width = vterm->width - 1; + int term_height = vterm->height - 1; + + if ( term_pos->getX() == term_width + && term_pos->getY() == term_height ) + appendLowerRight (next_char); + else + appendChar (next_char); + + term_pos->x_ref()++; +} + +//---------------------------------------------------------------------- +inline void FVTerm::appendChar (char_data*& next_char) { newFontChanges (next_char); charsetChanges (next_char); @@ -973,12 +1054,12 @@ int FVTerm::appendLowerRight (char_data*& screen_char) if ( ! FTermcap::automatic_right_margin ) { - appendCharacter (screen_char); + appendChar (screen_char); } else if ( SA && RA ) { appendOutputBuffer (RA); - appendCharacter (screen_char); + appendChar (screen_char); appendOutputBuffer (SA); } else @@ -993,7 +1074,7 @@ int FVTerm::appendLowerRight (char_data*& screen_char) x = getColumnNumber() - 2; y = getLineNumber() - 1; setTermXY (x, y); - appendCharacter (screen_char); + appendChar (screen_char); term_pos->x_ref()++; setTermXY (x, y); @@ -1002,12 +1083,12 @@ int FVTerm::appendLowerRight (char_data*& screen_char) if ( IC ) { appendOutputBuffer (tparm(IC, 1)); - appendCharacter (screen_char); + appendChar (screen_char); } else if ( im && ei ) { appendOutputBuffer (im); - appendCharacter (screen_char); + appendChar (screen_char); if ( ip ) appendOutputBuffer (ip); @@ -1017,7 +1098,7 @@ int FVTerm::appendLowerRight (char_data*& screen_char) else if ( ic ) { appendOutputBuffer (ic); - appendCharacter (screen_char); + appendChar (screen_char); if ( ip ) appendOutputBuffer (ip); diff --git a/src/fvterm.h b/src/fvterm.h index a2746f4a..c1441738 100644 --- a/src/fvterm.h +++ b/src/fvterm.h @@ -220,6 +220,7 @@ class FVTerm : public FObject, public FTerm static void newFontChanges (char_data*&); static void charsetChanges (char_data*&); static void appendCharacter (char_data*&); + static void appendChar (char_data*&); static void appendAttributes (char_data*&); static int appendLowerRight (char_data*&); static void appendOutputBuffer (std::string&);