From 71bead4e3928805d27cf32f154c0bcbb59a0fd19 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 5 May 2018 19:43:10 -0400 Subject: [PATCH 01/25] do some performance optimizations on highlighting of tty status --- src/botl.c | 7 ++- win/tty/wintty.c | 156 +++++++++++++++++++++++++++++------------------ 2 files changed, 100 insertions(+), 63 deletions(-) diff --git a/src/botl.c b/src/botl.c index f58c45947..5b573d856 100644 --- a/src/botl.c +++ b/src/botl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 botl.c $NHDT-Date: 1506903619 2017/10/02 00:20:19 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.81 $ */ +/* NetHack 3.6 botl.c $NHDT-Date: 1525563781 2018/05/05 23:43:01 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.90 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -858,7 +858,10 @@ boolean : TRUE; fieldname = initblstats[i].fldname; - fieldfmt = initblstats[i].fldfmt; + if (fld == BL_TITLE && iflags.wc2_hitpointbar) + fieldfmt = "%-30s"; + else + fieldfmt = initblstats[i].fldfmt; status_enablefield(fld, fieldname, fieldfmt, fldenabled); } update_all = TRUE; diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 63d1aac8c..d0f364574 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wintty.c $NHDT-Date: 1520825319 2018/03/12 03:28:39 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.142 $ */ +/* NetHack 3.6 wintty.c $NHDT-Date: 1525563766 2018/05/05 23:42:46 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.144 $ */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ @@ -66,7 +66,7 @@ struct window_procs tty_procs = { | WC2_SELECTSAVED #endif #if defined(STATUS_HILITES) - | WC2_HILITE_STATUS | WC2_HITPOINTBAR | WC2_FLUSH_STATUS + | WC2_HILITE_STATUS | WC2_HITPOINTBAR #endif | WC2_DARKGRAY), tty_init_nhwindows, tty_player_selection, tty_askname, tty_get_nh_event, @@ -177,6 +177,21 @@ STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL boolean NDECL(reset_role_filtering); +#ifdef STATUS_HILITES +static long tty_condition_bits; +static struct tty_status_fields { + int color; + int attr; + coord loc; + boolean valid; +} tty_status[MAXBLSTATS], prev_tty_status[MAXBLSTATS]; +static int st_fld; +int hpbar_percent, hpbar_color; + +static int FDECL(condcolor, (long, unsigned long *)); +static int FDECL(condattr, (long, unsigned long *)); +#endif /* STATUS_HILITES */ + /* * A string containing all the default commands -- to add to a list * of acceptable inputs. @@ -2491,6 +2506,7 @@ const char *str; register char *ob; register const char *nb; register long i, j, n0; + boolean attr_match = FALSE; /* Assume there's a real problem if the window is missing -- * probably a panic message @@ -2530,16 +2546,19 @@ const char *str; str = nb - 2; } nb = str; +#ifdef STATUS_HILITES + if (prev_tty_status[st_fld].valid + && tty_status[st_fld].loc.x == prev_tty_status[st_fld].loc.x + && tty_status[st_fld].loc.y == prev_tty_status[st_fld].loc.y + && tty_status[st_fld].color == prev_tty_status[st_fld].color + && tty_status[st_fld].attr == prev_tty_status[st_fld].attr) +#endif + attr_match = TRUE; for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { if (!*nb) { #ifndef STATUS_HILITES if (*ob || context.botlx) { #else - /* STATUS_HILITES will call cl_end() when finished - * its sequence of putstr's. We don't want to call - * cl_end() with each putstr() which may cause flashing - * in the Windows port - */ if (context.botlx) { #endif /* last char printed may be in middle of line */ @@ -2548,17 +2567,14 @@ const char *str; } break; } + if (*ob != *nb || !attr_match) { #ifdef STATUS_HILITES - /* Don't optimize the putsym away, in case it happens - to be the same character but different color/attr. - We don't optimize on iflags.use_status_hilites either, - in case old chars were written with highlighting and - that option has just now been toggled off. [We could - do better by tracking color/attr more closely.] */ -#else - if (*ob != *nb) + tty_curs(WIN_STATUS, + tty_status[st_fld].loc.x, + tty_status[st_fld].loc.y); #endif tty_putsym(WIN_STATUS, i, cw->cury, *nb); + } if (*ob) ob++; } @@ -3426,7 +3442,7 @@ char *posbar; video_update_positionbar(posbar); #endif } -#endif +#endif /* POSITIONBAR */ /* * The following data structures come from the genl_ routines in @@ -3439,23 +3455,20 @@ extern char *status_vals[MAXBLSTATS]; extern boolean status_activefields[MAXBLSTATS]; extern winid WIN_STATUS; -#ifdef STATUS_HILITES -static long tty_condition_bits; -static int tty_status_colors[MAXBLSTATS]; -int hpbar_percent, hpbar_color; - -static int FDECL(condcolor, (long, unsigned long *)); -static int FDECL(condattr, (long, unsigned long *)); -#endif /* STATUS_HILITES */ - void tty_status_init() { #ifdef STATUS_HILITES int i; - for (i = 0; i < MAXBLSTATS; ++i) - tty_status_colors[i] = NO_COLOR; /* no color */ + for (i = 0; i < MAXBLSTATS; ++i) { + tty_status[i].color = NO_COLOR; /* no color */ + tty_status[i].attr = ATR_NONE; + tty_status[i].loc.x = 0; + tty_status[i].loc.y = 0; + tty_status[i].valid = FALSE; + prev_tty_status[i] = tty_status[i]; + } tty_condition_bits = 0L; hpbar_percent = 0, hpbar_color = NO_COLOR; #endif /* STATUS_HILITES */ @@ -3552,14 +3565,14 @@ tty_status_init() #ifdef TEXTCOLOR #define MaybeDisplayCond(bm,txt) \ if (tty_condition_bits & (bm)) { \ - putstr(WIN_STATUS, 0, " "); \ + tty_putstr(WIN_STATUS, 0, " "); \ if (iflags.hilite_delta) { \ attrmask = condattr(bm, colormasks); \ Begin_Attr(attrmask); \ if ((coloridx = condcolor(bm, colormasks)) != NO_COLOR) \ term_start_color(coloridx); \ } \ - putstr(WIN_STATUS, 0, txt); \ + tty_putstr(WIN_STATUS, 0, txt); \ if (iflags.hilite_delta) { \ if (coloridx != NO_COLOR) \ term_end_color(); \ @@ -3569,17 +3582,23 @@ tty_status_init() #else #define MaybeDisplayCond(bm,txt) \ if (tty_condition_bits & (bm)) { \ - putstr(WIN_STATUS, 0, " "); \ + tty_putstr(WIN_STATUS, 0, " "); \ if (iflags.hilite_delta) { \ attrmask = condattr(bm, colormasks); \ Begin_Attr(attrmask); \ } \ - putstr(WIN_STATUS, 0, txt); \ + tty_putstr(WIN_STATUS, 0, txt); \ if (iflags.hilite_delta) { \ End_Attr(attrmask); \ } \ } #endif +#define status_putstr(s) \ + tty_status[st_fld].loc.x = (xchar) cw->curx; \ + tty_status[st_fld].loc.y = (xchar) cw->cury; \ + tty_status[st_fld].valid = TRUE; \ + tty_putstr(WIN_STATUS, 0, s); + void tty_status_update(fldidx, ptr, chg, percent, color, colormasks) @@ -3592,6 +3611,8 @@ unsigned long *colormasks; #ifdef TEXTCOLOR int coloridx = NO_COLOR; #endif + struct WinDesc *cw = 0; + char *text = (char *) ptr; static boolean oncearound = FALSE; /* prevent premature partial display */ enum statusfields fieldorder[2][15] = { @@ -3602,53 +3623,62 @@ unsigned long *colormasks; BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, BL_CAP, BL_CONDITION, BL_FLUSH } }; - int attridx = 0; + int attridx = 0; + st_fld = fldidx; if (fldidx != BL_FLUSH) { if (!status_activefields[fldidx]) return; switch (fldidx) { - case BL_CONDITION: - tty_condition_bits = *condptr; - oncearound = TRUE; - break; - default: - Sprintf(status_vals[fldidx], - (fldidx == BL_TITLE && iflags.wc2_hitpointbar) ? "%-30s" : - status_fieldfmt[fldidx] ? status_fieldfmt[fldidx] : "%s", + case BL_CONDITION: + tty_condition_bits = *condptr; + oncearound = TRUE; + break; + default: + Sprintf(status_vals[fldidx], + status_fieldfmt[fldidx] ? + status_fieldfmt[fldidx] : "%s", text); #ifdef TEXTCOLOR - tty_status_colors[fldidx] = color; + tty_status[fldidx].color = (color & 0x00FF); #else - tty_status_colors[fldidx] = NO_COLOR; + tty_status[fldidx].color = NO_COLOR; #endif - if (iflags.wc2_hitpointbar && fldidx == BL_HP) { - hpbar_percent = percent; + tty_status[fldidx].attr = (color & 0xFF00) >> 8; + + if (iflags.wc2_hitpointbar && fldidx == BL_HP) { + hpbar_percent = percent; #ifdef TEXTCOLOR - hpbar_color = color; + hpbar_color = color; #else - hpbar_color = NO_COLOR; + hpbar_color = NO_COLOR; #endif - } - break; + } + break; } } if (!oncearound) return; + if (WIN_STATUS == WIN_ERR + || (cw = wins[WIN_STATUS]) == (struct WinDesc *) 0) { + paniclog("status", "WIN_ERR on status window."); + return; + } + curs(WIN_STATUS, 1, 0); for (i = 0; fieldorder[0][i] != BL_FLUSH; ++i) { int fldidx1 = fieldorder[0][i]; if (status_activefields[fldidx1]) { if (fldidx1 != BL_TITLE || !iflags.wc2_hitpointbar) { #ifdef TEXTCOLOR - coloridx = tty_status_colors[fldidx1] & 0x00FF; + coloridx = tty_status[fldidx1].color; #endif - attridx = (tty_status_colors[fldidx1] & 0xFF00) >> 8; + attridx = tty_status[fldidx1].attr; text = status_vals[fldidx1]; if (iflags.hilite_delta) { if (*text == ' ') { - putstr(WIN_STATUS, 0, " "); + status_putstr(" "); text++; } /* multiple attributes can be in effect concurrently */ @@ -3659,7 +3689,7 @@ unsigned long *colormasks; #endif } - putstr(WIN_STATUS, 0, text); + status_putstr(text); if (iflags.hilite_delta) { #ifdef TEXTCOLOR @@ -3692,7 +3722,7 @@ unsigned long *colormasks; } } if (iflags.hilite_delta && iflags.wc2_hitpointbar) { - putstr(WIN_STATUS, 0, "["); + status_putstr("["); #ifdef TEXTCOLOR coloridx = hpbar_color & 0x00FF; /* attridx = (hpbar_color & 0xFF00) >> 8; */ @@ -3700,7 +3730,7 @@ unsigned long *colormasks; term_start_color(coloridx); #endif term_start_attr(ATR_INVERSE); - putstr(WIN_STATUS, 0, bar); + tty_putstr(WIN_STATUS, 0, bar); term_end_attr(ATR_INVERSE); #ifdef TEXTCOLOR if (coloridx != NO_COLOR) @@ -3708,11 +3738,11 @@ unsigned long *colormasks; #endif if (twoparts) { *bar2 = savedch; - putstr(WIN_STATUS, 0, bar2); + tty_putstr(WIN_STATUS, 0, bar2); } - putstr(WIN_STATUS, 0, "]"); + tty_putstr(WIN_STATUS, 0, "]"); } else - putstr(WIN_STATUS, 0, text); + tty_putstr(WIN_STATUS, 0, text); } } } @@ -3724,13 +3754,13 @@ unsigned long *colormasks; if (status_activefields[fldidx2]) { if (fldidx2 != BL_CONDITION) { #ifdef TEXTCOLOR - coloridx = tty_status_colors[fldidx2] & 0x00FF; + coloridx = tty_status[fldidx2].color; #endif - attridx = (tty_status_colors[fldidx2] & 0xFF00) >> 8; + attridx = tty_status[fldidx2].attr; text = status_vals[fldidx2]; if (iflags.hilite_delta) { if (*text == ' ') { - putstr(WIN_STATUS, 0, " "); + tty_putstr(WIN_STATUS, 0, " "); text++; } /* multiple attributes can be in effect concurrently */ @@ -3742,10 +3772,13 @@ unsigned long *colormasks; } if (fldidx2 == BL_GOLD) { + tty_status[st_fld].loc.x = (xchar) cw->curx; + tty_status[st_fld].loc.y = (xchar) cw->cury; + tty_status[st_fld].valid = TRUE; \ /* putmixed() due to GOLD glyph */ putmixed(WIN_STATUS, 0, text); } else { - putstr(WIN_STATUS, 0, text); + status_putstr(text); } if (iflags.hilite_delta) { @@ -3771,6 +3804,7 @@ unsigned long *colormasks; MaybeDisplayCond(BL_MASK_RIDE, "Ride"); } } + prev_tty_status[st_fld] = tty_status[st_fld]; /* copy struct */ } cl_end(); return; From e9483c7bbaf0dae95eec963358d1caae086dcf20 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 5 May 2018 20:42:55 -0400 Subject: [PATCH 02/25] uncomment BETA for fix-test binary --- include/global.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/global.h b/include/global.h index 420cd8491..831717c36 100644 --- a/include/global.h +++ b/include/global.h @@ -8,7 +8,7 @@ #include -/* #define BETA */ /* development or beta testing [MRS] */ +#define BETA /* development or beta testing [MRS] */ #define DEBUG From d6f9790d797c2686e58f25bd868eab69cd640c0c Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 6 May 2018 01:13:30 -0700 Subject: [PATCH 03/25] Implemented a fix to the lag problems that are occuring with the Win32 console port. The fix implements a console back buffer which significantly reduces the number of calls made to WriteConsoleOutputXXX and eliminates the lag users have been experiencing. --- sys/winnt/nttty.c | 269 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 216 insertions(+), 53 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index f0532b083..bf00cb94d 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -151,6 +151,180 @@ SOURCEWHERE pSourceWhere; SOURCEAUTHOR pSourceAuthor; KEYHANDLERNAME pKeyHandlerName; +/* CP437 to Unicode mapping according to the Unicode Consortium */ +static const WCHAR cp437[] = { + 0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, + 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, + 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, + 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, + 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, + 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, + 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, + 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, + 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, + 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, + 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 +}; + +/* + * cpConsole provides the mapping of characters in the console code page to UNICODE. + * It maps a character to at most two WCHARs storing the number of WCHARs in count. + * + * NOTE: cpConsole is only valid if has_unicode is TRUE. + */ + +typedef struct { + WCHAR characters[2]; + int count; +} CodePageMapping; + +static CodePageMapping cpConsole[256]; + +static void initialize_cp_console() +{ + if (has_unicode) { + UINT codePage = GetConsoleOutputCP(); + + for (int i = 0; i < 256; i++) { + char c = (char)i; + cpConsole[i].count = MultiByteToWideChar(codePage, 0, &c, 1, &cpConsole[i].characters[0], 2); + } + } +} + +/* + * Console Buffer Flipping Support + * + * To minimize the number of calls into the WriteConsoleOutputXXX methods, we implement a notion + * of a console back buffer which keeps the next frame of console output as it is being composed. + * When ready to show the new frame, we compare this next frame to what is currently being output + * and only call WriteConsoleOutputXXX for those console values that need to change. + */ + +#define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) +#define CONSOLE_CLEAR_CHARACTER (' ') + +#define CONSOLE_BUFFER_WIDTH 80 +#define CONSOLE_BUFFER_HEIGHT 25 +#define CONSOLE_BUFFER_SIZE (CONSOLE_BUFFER_WIDTH * CONSOLE_BUFFER_HEIGHT) + +typedef struct { + WCHAR characters[2]; + int count; + WORD attribute; +} cell_t; + +typedef struct { + cell_t cells[CONSOLE_BUFFER_HEIGHT][CONSOLE_BUFFER_WIDTH]; +} console_buffer_t; + +console_buffer_t back_buffer; +console_buffer_t front_buffer; +cell_t clear_cell; +cell_t undefined_cell; + +static boolean buffer_flipping_initialized = FALSE; + +static void initialize_buffer_flipping(); + +static void back_buffer_flip(); + +static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * cell, int x, int y); +static void back_buffer_clear_to_end_of_line(int x, int y); +static void back_buffer_write(cell_t * cell, int x, int y); + + +static void initialize_buffer_flipping() +{ + clear_cell.attribute = CONSOLE_CLEAR_ATTRIBUTE; + clear_cell.characters[0] = CONSOLE_CLEAR_CHARACTER; + clear_cell.characters[1] = 0; + clear_cell.count = 1; + + undefined_cell = clear_cell; + undefined_cell.count = 0; + + buffer_fill_to_end(&front_buffer, &undefined_cell, 0, 0); + buffer_fill_to_end(&back_buffer, &clear_cell, 0, 0); + + buffer_flipping_initialized = TRUE; +} + +static void back_buffer_flip() +{ + cell_t * back_cell = &back_buffer.cells[0][0]; + cell_t * front_cell = &front_buffer.cells[0][0]; + COORD pos; + + if (!buffer_flipping_initialized) + return; + + for (pos.Y = 0; pos.Y < CONSOLE_BUFFER_HEIGHT; pos.Y++) { + for (pos.X = 0; pos.X < CONSOLE_BUFFER_WIDTH; pos.X++, back_cell++, front_cell++) { + if (back_cell->attribute != front_cell->attribute) { + WriteConsoleOutputAttribute(hConOut, &back_cell->attribute, 1, pos, &acount); + front_cell->attribute = back_cell->attribute; + } + if (back_cell->count != front_cell->count || + back_cell->characters[0] != front_cell->characters[0] || + back_cell->characters[1] != front_cell->characters[1]) { + if (has_unicode) { + WriteConsoleOutputCharacterW(hConOut, back_cell->characters, back_cell->count, pos, &ccount); + } else { + char ch = (char)back_cell->characters[0]; + WriteConsoleOutputCharacterA(hConOut, &ch, 1, pos, &ccount); + } + *front_cell = *back_cell; + } + } + } +} + +static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, int x, int y) +{ + cell_t * dst = &buffer->cells[y][x]; + cell_t * sentinel = &buffer->cells[0][0] + CONSOLE_BUFFER_SIZE; + while (dst != sentinel) + *dst++ = clear_cell; +} + +static void back_buffer_write(cell_t * cell, int x, int y) +{ + back_buffer.cells[y][x] = *cell; +} + +static void back_buffer_clear_to_end_of_line(int x, int y) +{ + cell_t * cell; + cell_t *sentinel; + + cell = &back_buffer.cells[y][x]; + sentinel = &back_buffer.cells[y+1][0]; + while (cell != sentinel) + *cell++ = clear_cell; +} + /* * Called after returning from ! or ^Z */ @@ -197,7 +371,7 @@ setftty() adjust_palette(); #endif start_screen(); - has_unicode = ((GetVersion() & 0x80000000) == 0); + initialize_buffer_flipping(); } void @@ -232,6 +406,10 @@ tty_end_screen() clear_screen(); really_move_cursor(); if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { + + buffer_fill_to_end(&back_buffer, &clear_cell, 0, 0); + buffer_fill_to_end(&front_buffer, &clear_cell, 0, 0); + DWORD ccnt; COORD newcoord; @@ -279,6 +457,10 @@ int mode; DWORD cmode; long mask; + has_unicode = ((GetVersion() & 0x80000000) == 0); + + initialize_cp_console(); + GUILaunched = 0; try : @@ -440,6 +622,8 @@ really_move_cursor() console.cursor.Y = ttyDisplay->cury; } SetConsoleCursorPosition(hConOut, console.cursor); + + back_buffer_flip(); } void @@ -498,6 +682,7 @@ xputc_core(ch) char ch; { boolean inverse = FALSE; + cell_t cell; switch (ch) { case '\n': console.cursor.Y++; @@ -515,17 +700,19 @@ char ch; ttycolors[console.current_nhcolor]; if (console.current_nhattr[ATR_BOLD]) console.attr |= (inverse) ? - BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; - WriteConsoleOutputAttribute(hConOut, &console.attr, 1, console.cursor, &acount); + BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; + + cell.attribute = console.attr; if (has_unicode) { - /* Avoid bug in ANSI API on WinNT */ - WCHAR c2[2]; - int rc; - rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, &ch, 1, c2, 2); - WriteConsoleOutputCharacterW(hConOut, c2, rc, console.cursor, &ccount); + cell.characters[0] = cpConsole[ch].characters[0]; + cell.characters[1] = cpConsole[ch].characters[1]; + cell.count = cpConsole[ch].count; } else { - WriteConsoleOutputCharacterA(hConOut, &ch, 1, console.cursor, &ccount); + cell.characters[0] = ch; + cell.characters[1] = 0; + cell.count = 1; } + back_buffer_write(&cell, console.cursor.X, console.cursor.Y); console.cursor.X++; } } @@ -535,46 +722,11 @@ char ch; * for win32. It is used for glyphs only, not text. */ -/* CP437 to Unicode mapping according to the Unicode Consortium */ -static const WCHAR cp437[] = { - 0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, - 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, - 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, - 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, - 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, - 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, - 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, - 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, - 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, - 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, - 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, - 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, - 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, - 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, - 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, - 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, - 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, - 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 -}; - void g_putch(in_ch) int in_ch; { + cell_t cell; boolean inverse = FALSE; unsigned char ch = (unsigned char) in_ch; @@ -587,23 +739,24 @@ int in_ch; ttycolors[console.current_nhcolor]; if (console.current_nhattr[ATR_BOLD]) console.attr |= (inverse) ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; - WriteConsoleOutputAttribute(hConOut, &console.attr, 1, console.cursor, &acount); - + cell.attribute = console.attr; + cell.characters[1] = 0; + cell.count = 1; if (has_unicode) - WriteConsoleOutputCharacterW(hConOut, &cp437[ch], 1, console.cursor, &ccount); + cell.characters[0] = cp437[ch]; else - WriteConsoleOutputCharacterA(hConOut, &ch, 1, console.cursor, &ccount); + cell.characters[0] = ch; + back_buffer_write(&cell, console.cursor.X, console.cursor.Y); } void cl_end() { - int cx; console.cursor.X = ttyDisplay->curx; console.cursor.Y = ttyDisplay->cury; - cx = CO - console.cursor.X; - FillConsoleOutputAttribute(hConOut, DEFTEXTCOLOR, cx, console.cursor, &acount); - FillConsoleOutputCharacter(hConOut, ' ', cx, console.cursor, &ccount); + + back_buffer_clear_to_end_of_line(console.cursor.X, console.cursor.Y); + tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury); } @@ -611,6 +764,10 @@ void raw_clear_screen() { if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { + + buffer_fill_to_end(&front_buffer, &clear_cell, 0, 0); + buffer_fill_to_end(&back_buffer, &clear_cell, 0, 0); + DWORD ccnt; COORD newcoord; @@ -621,6 +778,7 @@ raw_clear_screen() csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); FillConsoleOutputCharacter( hConOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); + } } @@ -651,11 +809,16 @@ cl_eos() { int cy = ttyDisplay->cury + 1; if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { + + buffer_fill_to_end(&front_buffer, &clear_cell, ttyDisplay->curx, ttyDisplay->cury); + buffer_fill_to_end(&back_buffer, &clear_cell, ttyDisplay->curx, ttyDisplay->cury); + DWORD ccnt; COORD newcoord; newcoord.X = ttyDisplay->curx; newcoord.Y = ttyDisplay->cury; + FillConsoleOutputAttribute( hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, csbi.dwSize.X * csbi.dwSize.Y - cy, newcoord, &ccnt); From ea2f2d1aac6b91e9ff8dc88d42119acffe9d3329 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 6 May 2018 01:40:13 -0700 Subject: [PATCH 04/25] Quick fix to buffer height. Will need to determine why we needed a buffer height of 26. --- sys/winnt/nttty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index bf00cb94d..d6bd4c582 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -226,7 +226,7 @@ static void initialize_cp_console() #define CONSOLE_CLEAR_CHARACTER (' ') #define CONSOLE_BUFFER_WIDTH 80 -#define CONSOLE_BUFFER_HEIGHT 25 +#define CONSOLE_BUFFER_HEIGHT 26 #define CONSOLE_BUFFER_SIZE (CONSOLE_BUFFER_WIDTH * CONSOLE_BUFFER_HEIGHT) typedef struct { From 8db7237cfcb741e6d38fc977768ac4e904ac2daf Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 6 May 2018 02:47:17 -0700 Subject: [PATCH 05/25] Console buffer support for variable size console windows. --- sys/winnt/nttty.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index d6bd4c582..e19244703 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -225,10 +225,6 @@ static void initialize_cp_console() #define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define CONSOLE_CLEAR_CHARACTER (' ') -#define CONSOLE_BUFFER_WIDTH 80 -#define CONSOLE_BUFFER_HEIGHT 26 -#define CONSOLE_BUFFER_SIZE (CONSOLE_BUFFER_WIDTH * CONSOLE_BUFFER_HEIGHT) - typedef struct { WCHAR characters[2]; int count; @@ -236,9 +232,12 @@ typedef struct { } cell_t; typedef struct { - cell_t cells[CONSOLE_BUFFER_HEIGHT][CONSOLE_BUFFER_WIDTH]; + cell_t * cells; } console_buffer_t; +static int buffer_width; +static int buffer_height; + console_buffer_t back_buffer; console_buffer_t front_buffer; cell_t clear_cell; @@ -247,6 +246,7 @@ cell_t undefined_cell; static boolean buffer_flipping_initialized = FALSE; static void initialize_buffer_flipping(); +static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y); static void back_buffer_flip(); @@ -257,6 +257,14 @@ static void back_buffer_write(cell_t * cell, int x, int y); static void initialize_buffer_flipping() { + buffer_width = origcsbi.srWindow.Right - origcsbi.srWindow.Left + 1; + buffer_height = origcsbi.srWindow.Bottom - origcsbi.srWindow.Top + 1; + + if (buffer_width > 80) buffer_width = 80; + + back_buffer.cells = (cell_t *)malloc(sizeof(cell_t) * buffer_width * buffer_height); + front_buffer.cells = (cell_t *)malloc(sizeof(cell_t) * buffer_width * buffer_height); + clear_cell.attribute = CONSOLE_CLEAR_ATTRIBUTE; clear_cell.characters[0] = CONSOLE_CLEAR_CHARACTER; clear_cell.characters[1] = 0; @@ -271,17 +279,22 @@ static void initialize_buffer_flipping() buffer_flipping_initialized = TRUE; } +static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y) +{ + return buffer->cells + (buffer_width * y) + x; +} + static void back_buffer_flip() { - cell_t * back_cell = &back_buffer.cells[0][0]; - cell_t * front_cell = &front_buffer.cells[0][0]; + cell_t * back_cell = back_buffer.cells; + cell_t * front_cell = front_buffer.cells; COORD pos; if (!buffer_flipping_initialized) return; - for (pos.Y = 0; pos.Y < CONSOLE_BUFFER_HEIGHT; pos.Y++) { - for (pos.X = 0; pos.X < CONSOLE_BUFFER_WIDTH; pos.X++, back_cell++, front_cell++) { + for (pos.Y = 0; pos.Y < buffer_height; pos.Y++) { + for (pos.X = 0; pos.X < buffer_width; pos.X++, back_cell++, front_cell++) { if (back_cell->attribute != front_cell->attribute) { WriteConsoleOutputAttribute(hConOut, &back_cell->attribute, 1, pos, &acount); front_cell->attribute = back_cell->attribute; @@ -303,15 +316,16 @@ static void back_buffer_flip() static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, int x, int y) { - cell_t * dst = &buffer->cells[y][x]; - cell_t * sentinel = &buffer->cells[0][0] + CONSOLE_BUFFER_SIZE; + cell_t * dst = buffer_get_cell(buffer, x, y); + cell_t * sentinel = buffer_get_cell(buffer, 0, buffer_height); while (dst != sentinel) *dst++ = clear_cell; } static void back_buffer_write(cell_t * cell, int x, int y) { - back_buffer.cells[y][x] = *cell; + cell_t * dst = buffer_get_cell(&back_buffer, x, y); + *dst = *cell; } static void back_buffer_clear_to_end_of_line(int x, int y) @@ -319,8 +333,8 @@ static void back_buffer_clear_to_end_of_line(int x, int y) cell_t * cell; cell_t *sentinel; - cell = &back_buffer.cells[y][x]; - sentinel = &back_buffer.cells[y+1][0]; + cell = buffer_get_cell(&back_buffer, x, y); + sentinel = buffer_get_cell(&back_buffer, 0, y+1); while (cell != sentinel) *cell++ = clear_cell; } From 64cec86abb765d777ddaf738bbdfaf9edb2b587e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 6 May 2018 06:04:33 -0400 Subject: [PATCH 06/25] more performance fixes for the port code portion --- sys/winnt/nttty.c | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index d6bd4c582..e19244703 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -225,10 +225,6 @@ static void initialize_cp_console() #define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) #define CONSOLE_CLEAR_CHARACTER (' ') -#define CONSOLE_BUFFER_WIDTH 80 -#define CONSOLE_BUFFER_HEIGHT 26 -#define CONSOLE_BUFFER_SIZE (CONSOLE_BUFFER_WIDTH * CONSOLE_BUFFER_HEIGHT) - typedef struct { WCHAR characters[2]; int count; @@ -236,9 +232,12 @@ typedef struct { } cell_t; typedef struct { - cell_t cells[CONSOLE_BUFFER_HEIGHT][CONSOLE_BUFFER_WIDTH]; + cell_t * cells; } console_buffer_t; +static int buffer_width; +static int buffer_height; + console_buffer_t back_buffer; console_buffer_t front_buffer; cell_t clear_cell; @@ -247,6 +246,7 @@ cell_t undefined_cell; static boolean buffer_flipping_initialized = FALSE; static void initialize_buffer_flipping(); +static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y); static void back_buffer_flip(); @@ -257,6 +257,14 @@ static void back_buffer_write(cell_t * cell, int x, int y); static void initialize_buffer_flipping() { + buffer_width = origcsbi.srWindow.Right - origcsbi.srWindow.Left + 1; + buffer_height = origcsbi.srWindow.Bottom - origcsbi.srWindow.Top + 1; + + if (buffer_width > 80) buffer_width = 80; + + back_buffer.cells = (cell_t *)malloc(sizeof(cell_t) * buffer_width * buffer_height); + front_buffer.cells = (cell_t *)malloc(sizeof(cell_t) * buffer_width * buffer_height); + clear_cell.attribute = CONSOLE_CLEAR_ATTRIBUTE; clear_cell.characters[0] = CONSOLE_CLEAR_CHARACTER; clear_cell.characters[1] = 0; @@ -271,17 +279,22 @@ static void initialize_buffer_flipping() buffer_flipping_initialized = TRUE; } +static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y) +{ + return buffer->cells + (buffer_width * y) + x; +} + static void back_buffer_flip() { - cell_t * back_cell = &back_buffer.cells[0][0]; - cell_t * front_cell = &front_buffer.cells[0][0]; + cell_t * back_cell = back_buffer.cells; + cell_t * front_cell = front_buffer.cells; COORD pos; if (!buffer_flipping_initialized) return; - for (pos.Y = 0; pos.Y < CONSOLE_BUFFER_HEIGHT; pos.Y++) { - for (pos.X = 0; pos.X < CONSOLE_BUFFER_WIDTH; pos.X++, back_cell++, front_cell++) { + for (pos.Y = 0; pos.Y < buffer_height; pos.Y++) { + for (pos.X = 0; pos.X < buffer_width; pos.X++, back_cell++, front_cell++) { if (back_cell->attribute != front_cell->attribute) { WriteConsoleOutputAttribute(hConOut, &back_cell->attribute, 1, pos, &acount); front_cell->attribute = back_cell->attribute; @@ -303,15 +316,16 @@ static void back_buffer_flip() static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, int x, int y) { - cell_t * dst = &buffer->cells[y][x]; - cell_t * sentinel = &buffer->cells[0][0] + CONSOLE_BUFFER_SIZE; + cell_t * dst = buffer_get_cell(buffer, x, y); + cell_t * sentinel = buffer_get_cell(buffer, 0, buffer_height); while (dst != sentinel) *dst++ = clear_cell; } static void back_buffer_write(cell_t * cell, int x, int y) { - back_buffer.cells[y][x] = *cell; + cell_t * dst = buffer_get_cell(&back_buffer, x, y); + *dst = *cell; } static void back_buffer_clear_to_end_of_line(int x, int y) @@ -319,8 +333,8 @@ static void back_buffer_clear_to_end_of_line(int x, int y) cell_t * cell; cell_t *sentinel; - cell = &back_buffer.cells[y][x]; - sentinel = &back_buffer.cells[y+1][0]; + cell = buffer_get_cell(&back_buffer, x, y); + sentinel = buffer_get_cell(&back_buffer, 0, y+1); while (cell != sentinel) *cell++ = clear_cell; } From b7f351fdbbcac1812710c426a03892c1f090bb89 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 6 May 2018 13:22:36 -0700 Subject: [PATCH 07/25] Updated console back buffer support to correctly size the buffers as appropriate. --- sys/winnt/nttty.c | 188 +++++++++++++++++++++++++++++----------------- 1 file changed, 121 insertions(+), 67 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index e19244703..1f95e4b97 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -188,8 +188,9 @@ static const WCHAR cp437[] = { }; /* - * cpConsole provides the mapping of characters in the console code page to UNICODE. - * It maps a character to at most two WCHARs storing the number of WCHARs in count. + * cpConsole provides the mapping of characters in the console code page to + * UNICODE. It maps a character to at most two WCHARs storing the number of + * WCHARs in count. * * NOTE: cpConsole is only valid if has_unicode is TRUE. */ @@ -208,7 +209,8 @@ static void initialize_cp_console() for (int i = 0; i < 256; i++) { char c = (char)i; - cpConsole[i].count = MultiByteToWideChar(codePage, 0, &c, 1, &cpConsole[i].characters[0], 2); + cpConsole[i].count = MultiByteToWideChar(codePage, 0, &c, 1, + &cpConsole[i].characters[0], 2); } } } @@ -216,13 +218,17 @@ static void initialize_cp_console() /* * Console Buffer Flipping Support * - * To minimize the number of calls into the WriteConsoleOutputXXX methods, we implement a notion - * of a console back buffer which keeps the next frame of console output as it is being composed. - * When ready to show the new frame, we compare this next frame to what is currently being output - * and only call WriteConsoleOutputXXX for those console values that need to change. + * To minimize the number of calls into the WriteConsoleOutputXXX methods, + * we implement a notion of a console back buffer which keeps the next frame + * of console output as it is being composed. When ready to show the new + * frame, we compare this next frame to what is currently being output and + * only call WriteConsoleOutputXXX for those console values that need to + * change. + * */ -#define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE) +#define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN \ + | FOREGROUND_BLUE) #define CONSOLE_CLEAR_CHARACTER (' ') typedef struct { @@ -245,25 +251,28 @@ cell_t undefined_cell; static boolean buffer_flipping_initialized = FALSE; -static void initialize_buffer_flipping(); +static void check_buffer_size(int width, int height); static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y); static void back_buffer_flip(); -static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * cell, int x, int y); +static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * cell, + int x, int y); static void back_buffer_clear_to_end_of_line(int x, int y); static void back_buffer_write(cell_t * cell, int x, int y); - -static void initialize_buffer_flipping() +static void initialize_buffer_flipping(int width, int height) { - buffer_width = origcsbi.srWindow.Right - origcsbi.srWindow.Left + 1; - buffer_height = origcsbi.srWindow.Bottom - origcsbi.srWindow.Top + 1; + if (buffer_flipping_initialized) { + check_buffer_size(width, height); + return; + } - if (buffer_width > 80) buffer_width = 80; + buffer_width = 0; + buffer_height = 0; - back_buffer.cells = (cell_t *)malloc(sizeof(cell_t) * buffer_width * buffer_height); - front_buffer.cells = (cell_t *)malloc(sizeof(cell_t) * buffer_width * buffer_height); + back_buffer.cells = NULL; + front_buffer.cells = NULL; clear_cell.attribute = CONSOLE_CLEAR_ATTRIBUTE; clear_cell.characters[0] = CONSOLE_CLEAR_CHARACTER; @@ -273,12 +282,43 @@ static void initialize_buffer_flipping() undefined_cell = clear_cell; undefined_cell.count = 0; - buffer_fill_to_end(&front_buffer, &undefined_cell, 0, 0); - buffer_fill_to_end(&back_buffer, &clear_cell, 0, 0); + check_buffer_size(width, height); buffer_flipping_initialized = TRUE; } +static void resize_buffer(console_buffer_t * buffer, cell_t * fill, + int width, int height) +{ + cell_t * cells = (cell_t *)malloc(sizeof(cell_t) * width * height); + cell_t * dst = cells; + cell_t * sentinel = dst + (width * height); + + while (dst != sentinel) + *dst++ = *fill; + + int height_to_copy = (buffer_height > height ? height : buffer_height); + int bytes_to_copy = (buffer_width > width ? width : buffer_width) + * sizeof(cell_t); + + for (int y = 0; y < height_to_copy; y++) + memcpy(cells + (width * y), buffer->cells + (buffer_width * y), + bytes_to_copy); + + free(buffer->cells); + buffer->cells = cells; +} + +static void check_buffer_size(int width, int height) +{ + if (width != buffer_width || height != buffer_height) { + resize_buffer(&back_buffer, &clear_cell, width, height); + resize_buffer(&front_buffer, &undefined_cell, width, height); + buffer_width = width; + buffer_height = height; + } +} + static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y) { return buffer->cells + (buffer_width * y) + x; @@ -286,35 +326,41 @@ static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y) static void back_buffer_flip() { - cell_t * back_cell = back_buffer.cells; - cell_t * front_cell = front_buffer.cells; - COORD pos; - if (!buffer_flipping_initialized) return; + cell_t * back = back_buffer.cells; + cell_t * front = front_buffer.cells; + COORD pos; + for (pos.Y = 0; pos.Y < buffer_height; pos.Y++) { - for (pos.X = 0; pos.X < buffer_width; pos.X++, back_cell++, front_cell++) { - if (back_cell->attribute != front_cell->attribute) { - WriteConsoleOutputAttribute(hConOut, &back_cell->attribute, 1, pos, &acount); - front_cell->attribute = back_cell->attribute; + for (pos.X = 0; pos.X < buffer_width; pos.X++) { + if (back->attribute != front->attribute) { + WriteConsoleOutputAttribute(hConOut, &back->attribute, + 1, pos, &acount); + front->attribute = back->attribute; } - if (back_cell->count != front_cell->count || - back_cell->characters[0] != front_cell->characters[0] || - back_cell->characters[1] != front_cell->characters[1]) { + if (back->count != front->count || + back->characters[0] != front->characters[0] || + back->characters[1] != front->characters[1]) { if (has_unicode) { - WriteConsoleOutputCharacterW(hConOut, back_cell->characters, back_cell->count, pos, &ccount); + WriteConsoleOutputCharacterW(hConOut, back->characters, + back->count, pos, &ccount); } else { - char ch = (char)back_cell->characters[0]; - WriteConsoleOutputCharacterA(hConOut, &ch, 1, pos, &ccount); + char ch = (char)back->characters[0]; + WriteConsoleOutputCharacterA(hConOut, &ch, 1, pos, + &ccount); } - *front_cell = *back_cell; + *front = *back; } + back++; + front++; } } } -static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, int x, int y) +static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, + int x, int y) { cell_t * dst = buffer_get_cell(buffer, x, y); cell_t * sentinel = buffer_get_cell(buffer, 0, buffer_height); @@ -385,7 +431,6 @@ setftty() adjust_palette(); #endif start_screen(); - initialize_buffer_flipping(); } void @@ -462,7 +507,16 @@ DWORD ctrltype; } } -/* called by init_tty in wintty.c for WIN32 port only */ +/* + * ntty_open() is called in several places. It is called by win_tty_init + * passing in a mode of zero. It is then later called again by pcmain passing + * in a mode of one. Finally, it can also be called by process_options also + * with a mode of one. + * + * barthouse - The fact this is getting called multiple times needs to be + * reviewed and perhaps cleaned up. + * + */ void nttty_open(mode) int mode; @@ -503,6 +557,9 @@ int mode; mode = 0; goto try; } else { + /* barthouse - Need to understand how this can happen and + * whether we should bail instead of returning. + */ return; } @@ -510,6 +567,24 @@ int mode; hConIn = GetStdHandle(STD_INPUT_HANDLE); hConOut = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(hConOut, &csbi); + + int height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + int width = min(csbi.srWindow.Right - csbi.srWindow.Left + 1, 80); + + /* If the window is not big enough to meet our minimum requirements, + * grow the console's buffer to be large enough. The user will have + * to manually extend the size of the window. + */ + + width = max(80, width); + height = max(25, height); + + COORD size = { max(80, width), max(25, height) }; + SetConsoleScreenBufferSize(hConOut, size); + + initialize_buffer_flipping(width, height); + load_keyboard_handler(); /* Initialize the function pointer that points to * the kbhit() equivalent, in this TTY case nttty_kbhit() @@ -534,7 +609,10 @@ int mode; /* Unable to set control handler */ cmode = 0; /* just to have a statement to break on for debugger */ } - get_scr_size(); + + LI = height; + CO = width; + console.cursor.X = console.cursor.Y = 0; really_move_cursor(); } @@ -559,32 +637,6 @@ nttty_kbhit() return pNHkbhit(hConIn, &ir); } -void -get_scr_size() -{ - int lines, cols; - - GetConsoleScreenBufferInfo(hConOut, &csbi); - - lines = csbi.srWindow.Bottom - (csbi.srWindow.Top + 1); - cols = csbi.srWindow.Right - (csbi.srWindow.Left + 1); - - LI = lines; - CO = min(cols, 80); - - if ((LI < 25) || (CO < 80)) { - COORD newcoord; - - LI = 25; - CO = 80; - - newcoord.Y = LI; - newcoord.X = CO; - - SetConsoleScreenBufferSize(hConOut, newcoord); - } -} - int tgetch() { @@ -824,8 +876,10 @@ cl_eos() int cy = ttyDisplay->cury + 1; if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { - buffer_fill_to_end(&front_buffer, &clear_cell, ttyDisplay->curx, ttyDisplay->cury); - buffer_fill_to_end(&back_buffer, &clear_cell, ttyDisplay->curx, ttyDisplay->cury); + buffer_fill_to_end(&front_buffer, &clear_cell, ttyDisplay->curx, + ttyDisplay->cury); + buffer_fill_to_end(&back_buffer, &clear_cell, ttyDisplay->curx, + ttyDisplay->cury); DWORD ccnt; COORD newcoord; @@ -1240,10 +1294,10 @@ VA_DECL(const char *, fmt) else { if(!init_ttycolor_completed) init_ttycolor(); - xputs(buf); if (ttyDisplay) curs(BASE_WINDOW, console.cursor.X + 1, console.cursor.Y); + really_move_cursor(); } VA_END(); return; From f2e9b8a60ab182cb68564d82cf2dd642bf1daa9f Mon Sep 17 00:00:00 2001 From: nhmall Date: Sun, 6 May 2018 17:52:29 -0400 Subject: [PATCH 08/25] merge glitch cleanup --- sys/winnt/nttty.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 0567d4776..128c4de6c 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 nttty.c $NHDT-Date: 1524931557 2018/04/28 16:05:57 $ $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.71 $ */ +/* NetHack 3.6 nttty.c $NHDT-Date: 1525643540 2018/05/06 21:52:20 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.77 $ */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ @@ -9,6 +9,7 @@ * Switch to low level console output routines M. Allison 2003/10/01 * Restrict cursor movement until input pending M. Lehotay 2003/10/02 * Call Unicode version of output API on NT R. Chason 2005/10/28 + * Use of back buffer to improve performance B. House 2018/05/06 * */ @@ -289,9 +290,6 @@ static void initialize_buffer_flipping(int width, int height) static void resize_buffer(console_buffer_t * buffer, cell_t * fill, int width, int height) - return buffer->cells + (buffer_width * y) + x; -} - { cell_t * cells = (cell_t *)malloc(sizeof(cell_t) * width * height); cell_t * dst = cells; From 4b922f3e8b77b731e6735bca2fedbb8caa3fc2a8 Mon Sep 17 00:00:00 2001 From: Bart House Date: Sun, 6 May 2018 01:13:30 -0700 Subject: [PATCH 09/25] Implemented a fix to the lag problems that are occuring with the Win32 console port. The fix implements a console back buffer which significantly reduces the number of calls made to WriteConsoleOutputXXX and eliminates the lag users have been experiencing. --- sys/winnt/nttty.c | 401 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 319 insertions(+), 82 deletions(-) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index f0532b083..f4c3a3bf8 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -151,6 +151,240 @@ SOURCEWHERE pSourceWhere; SOURCEAUTHOR pSourceAuthor; KEYHANDLERNAME pKeyHandlerName; +/* CP437 to Unicode mapping according to the Unicode Consortium */ +static const WCHAR cp437[] = { + 0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, + 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, + 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, + 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, + 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, + 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, + 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, + 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, + 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, + 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, + 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, + 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, + 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, + 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, + 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, + 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, + 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 +}; + +/* + * cpConsole provides the mapping of characters in the console code page to + * UNICODE. It maps a character to at most two WCHARs storing the number of + * WCHARs in count. + * + * NOTE: cpConsole is only valid if has_unicode is TRUE. + */ + +typedef struct { + WCHAR characters[2]; + int count; +} CodePageMapping; + +static CodePageMapping cpConsole[256]; + +static void initialize_cp_console() +{ + if (has_unicode) { + UINT codePage = GetConsoleOutputCP(); + + for (int i = 0; i < 256; i++) { + char c = (char)i; + cpConsole[i].count = MultiByteToWideChar(codePage, 0, &c, 1, + &cpConsole[i].characters[0], 2); + } + } +} + +/* + * Console Buffer Flipping Support + * + * To minimize the number of calls into the WriteConsoleOutputXXX methods, + * we implement a notion of a console back buffer which keeps the next frame + * of console output as it is being composed. When ready to show the new + * frame, we compare this next frame to what is currently being output and + * only call WriteConsoleOutputXXX for those console values that need to + * change. + * + */ + +#define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN \ + | FOREGROUND_BLUE) +#define CONSOLE_CLEAR_CHARACTER (' ') + +typedef struct { + WCHAR characters[2]; + int count; + WORD attribute; +} cell_t; + +typedef struct { + cell_t * cells; +} console_buffer_t; + +static int buffer_width; +static int buffer_height; + +console_buffer_t back_buffer; +console_buffer_t front_buffer; +cell_t clear_cell; +cell_t undefined_cell; + +static boolean buffer_flipping_initialized = FALSE; + +static void check_buffer_size(int width, int height); +static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y); + +static void back_buffer_flip(); + +static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * cell, + int x, int y); +static void back_buffer_clear_to_end_of_line(int x, int y); +static void back_buffer_write(cell_t * cell, int x, int y); + +static void initialize_buffer_flipping(int width, int height) +{ + if (buffer_flipping_initialized) { + check_buffer_size(width, height); + return; + } + + buffer_width = 0; + buffer_height = 0; + + back_buffer.cells = NULL; + front_buffer.cells = NULL; + + clear_cell.attribute = CONSOLE_CLEAR_ATTRIBUTE; + clear_cell.characters[0] = CONSOLE_CLEAR_CHARACTER; + clear_cell.characters[1] = 0; + clear_cell.count = 1; + + undefined_cell = clear_cell; + undefined_cell.count = 0; + + check_buffer_size(width, height); + + buffer_flipping_initialized = TRUE; +} + +static void resize_buffer(console_buffer_t * buffer, cell_t * fill, + int width, int height) +{ + cell_t * cells = (cell_t *)malloc(sizeof(cell_t) * width * height); + cell_t * dst = cells; + cell_t * sentinel = dst + (width * height); + + while (dst != sentinel) + *dst++ = *fill; + + int height_to_copy = (buffer_height > height ? height : buffer_height); + int bytes_to_copy = (buffer_width > width ? width : buffer_width) + * sizeof(cell_t); + + for (int y = 0; y < height_to_copy; y++) + memcpy(cells + (width * y), buffer->cells + (buffer_width * y), + bytes_to_copy); + + free(buffer->cells); + buffer->cells = cells; +} + +static void check_buffer_size(int width, int height) +{ + if (width != buffer_width || height != buffer_height) { + resize_buffer(&back_buffer, &clear_cell, width, height); + resize_buffer(&front_buffer, &undefined_cell, width, height); + buffer_width = width; + buffer_height = height; + } +} + +static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y) +{ + return buffer->cells + (buffer_width * y) + x; +} + +static void back_buffer_flip() +{ + if (!buffer_flipping_initialized) + return; + + cell_t * back = back_buffer.cells; + cell_t * front = front_buffer.cells; + COORD pos; + + for (pos.Y = 0; pos.Y < buffer_height; pos.Y++) { + for (pos.X = 0; pos.X < buffer_width; pos.X++) { + if (back->attribute != front->attribute) { + WriteConsoleOutputAttribute(hConOut, &back->attribute, + 1, pos, &acount); + front->attribute = back->attribute; + } + if (back->count != front->count || + back->characters[0] != front->characters[0] || + back->characters[1] != front->characters[1]) { + if (has_unicode) { + WriteConsoleOutputCharacterW(hConOut, back->characters, + back->count, pos, &ccount); + } else { + char ch = (char)back->characters[0]; + WriteConsoleOutputCharacterA(hConOut, &ch, 1, pos, + &ccount); + } + *front = *back; + } + back++; + front++; + } + } +} + +static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, + int x, int y) +{ + cell_t * dst = buffer_get_cell(buffer, x, y); + cell_t * sentinel = buffer_get_cell(buffer, 0, buffer_height); + while (dst != sentinel) + *dst++ = clear_cell; +} + +static void back_buffer_write(cell_t * cell, int x, int y) +{ + cell_t * dst = buffer_get_cell(&back_buffer, x, y); + *dst = *cell; +} + +static void back_buffer_clear_to_end_of_line(int x, int y) +{ + cell_t * cell; + cell_t *sentinel; + + cell = buffer_get_cell(&back_buffer, x, y); + sentinel = buffer_get_cell(&back_buffer, 0, y+1); + while (cell != sentinel) + *cell++ = clear_cell; +} + /* * Called after returning from ! or ^Z */ @@ -197,7 +431,6 @@ setftty() adjust_palette(); #endif start_screen(); - has_unicode = ((GetVersion() & 0x80000000) == 0); } void @@ -232,6 +465,10 @@ tty_end_screen() clear_screen(); really_move_cursor(); if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { + + buffer_fill_to_end(&back_buffer, &clear_cell, 0, 0); + buffer_fill_to_end(&front_buffer, &clear_cell, 0, 0); + DWORD ccnt; COORD newcoord; @@ -270,7 +507,16 @@ DWORD ctrltype; } } -/* called by init_tty in wintty.c for WIN32 port only */ +/* + * ntty_open() is called in several places. It is called by win_tty_init + * passing in a mode of zero. It is then later called again by pcmain passing + * in a mode of one. Finally, it can also be called by process_options also + * with a mode of one. + * + * barthouse - The fact this is getting called multiple times needs to be + * reviewed and perhaps cleaned up. + * + */ void nttty_open(mode) int mode; @@ -279,6 +525,10 @@ int mode; DWORD cmode; long mask; + has_unicode = ((GetVersion() & 0x80000000) == 0); + + initialize_cp_console(); + GUILaunched = 0; try : @@ -307,6 +557,9 @@ int mode; mode = 0; goto try; } else { + /* barthouse - Need to understand how this can happen and + * whether we should bail instead of returning. + */ return; } @@ -314,6 +567,30 @@ int mode; hConIn = GetStdHandle(STD_INPUT_HANDLE); hConOut = GetStdHandle(STD_OUTPUT_HANDLE); + GetConsoleScreenBufferInfo(hConOut, &csbi); + + int height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1; + + /* NOTE: We currently force to a width of 80 due to unresolved issues + * within the TTY code. These issues will need to resolved before + * we could allow widths > 80. We will always need a width of + * atleast 80. + */ + + int width = 80; + + /* If the window is not big enough to meet our minimum height needs, + * grow the console's buffer to be large enough. The user will have + * to manually extend the size of the window. + */ + + height = max(25, height); + + COORD size = { width, height }; + SetConsoleScreenBufferSize(hConOut, size); + + initialize_buffer_flipping(width, height); + load_keyboard_handler(); /* Initialize the function pointer that points to * the kbhit() equivalent, in this TTY case nttty_kbhit() @@ -338,7 +615,10 @@ int mode; /* Unable to set control handler */ cmode = 0; /* just to have a statement to break on for debugger */ } - get_scr_size(); + + LI = height; + CO = width; + console.cursor.X = console.cursor.Y = 0; really_move_cursor(); } @@ -363,32 +643,6 @@ nttty_kbhit() return pNHkbhit(hConIn, &ir); } -void -get_scr_size() -{ - int lines, cols; - - GetConsoleScreenBufferInfo(hConOut, &csbi); - - lines = csbi.srWindow.Bottom - (csbi.srWindow.Top + 1); - cols = csbi.srWindow.Right - (csbi.srWindow.Left + 1); - - LI = lines; - CO = min(cols, 80); - - if ((LI < 25) || (CO < 80)) { - COORD newcoord; - - LI = 25; - CO = 80; - - newcoord.Y = LI; - newcoord.X = CO; - - SetConsoleScreenBufferSize(hConOut, newcoord); - } -} - int tgetch() { @@ -440,6 +694,8 @@ really_move_cursor() console.cursor.Y = ttyDisplay->cury; } SetConsoleCursorPosition(hConOut, console.cursor); + + back_buffer_flip(); } void @@ -498,6 +754,7 @@ xputc_core(ch) char ch; { boolean inverse = FALSE; + cell_t cell; switch (ch) { case '\n': console.cursor.Y++; @@ -515,17 +772,19 @@ char ch; ttycolors[console.current_nhcolor]; if (console.current_nhattr[ATR_BOLD]) console.attr |= (inverse) ? - BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; - WriteConsoleOutputAttribute(hConOut, &console.attr, 1, console.cursor, &acount); + BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; + + cell.attribute = console.attr; if (has_unicode) { - /* Avoid bug in ANSI API on WinNT */ - WCHAR c2[2]; - int rc; - rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, &ch, 1, c2, 2); - WriteConsoleOutputCharacterW(hConOut, c2, rc, console.cursor, &ccount); + cell.characters[0] = cpConsole[ch].characters[0]; + cell.characters[1] = cpConsole[ch].characters[1]; + cell.count = cpConsole[ch].count; } else { - WriteConsoleOutputCharacterA(hConOut, &ch, 1, console.cursor, &ccount); + cell.characters[0] = ch; + cell.characters[1] = 0; + cell.count = 1; } + back_buffer_write(&cell, console.cursor.X, console.cursor.Y); console.cursor.X++; } } @@ -535,46 +794,11 @@ char ch; * for win32. It is used for glyphs only, not text. */ -/* CP437 to Unicode mapping according to the Unicode Consortium */ -static const WCHAR cp437[] = { - 0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022, - 0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C, - 0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8, - 0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC, - 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, - 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, - 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, - 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, - 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, - 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302, - 0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7, - 0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5, - 0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9, - 0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192, - 0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba, - 0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb, - 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510, - 0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f, - 0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567, - 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580, - 0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4, - 0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229, - 0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248, - 0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0 -}; - void g_putch(in_ch) int in_ch; { + cell_t cell; boolean inverse = FALSE; unsigned char ch = (unsigned char) in_ch; @@ -587,23 +811,24 @@ int in_ch; ttycolors[console.current_nhcolor]; if (console.current_nhattr[ATR_BOLD]) console.attr |= (inverse) ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY; - WriteConsoleOutputAttribute(hConOut, &console.attr, 1, console.cursor, &acount); - + cell.attribute = console.attr; + cell.characters[1] = 0; + cell.count = 1; if (has_unicode) - WriteConsoleOutputCharacterW(hConOut, &cp437[ch], 1, console.cursor, &ccount); + cell.characters[0] = cp437[ch]; else - WriteConsoleOutputCharacterA(hConOut, &ch, 1, console.cursor, &ccount); + cell.characters[0] = ch; + back_buffer_write(&cell, console.cursor.X, console.cursor.Y); } void cl_end() { - int cx; console.cursor.X = ttyDisplay->curx; console.cursor.Y = ttyDisplay->cury; - cx = CO - console.cursor.X; - FillConsoleOutputAttribute(hConOut, DEFTEXTCOLOR, cx, console.cursor, &acount); - FillConsoleOutputCharacter(hConOut, ' ', cx, console.cursor, &ccount); + + back_buffer_clear_to_end_of_line(console.cursor.X, console.cursor.Y); + tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury); } @@ -611,6 +836,10 @@ void raw_clear_screen() { if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { + + buffer_fill_to_end(&front_buffer, &clear_cell, 0, 0); + buffer_fill_to_end(&back_buffer, &clear_cell, 0, 0); + DWORD ccnt; COORD newcoord; @@ -621,6 +850,7 @@ raw_clear_screen() csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); FillConsoleOutputCharacter( hConOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); + } } @@ -651,11 +881,18 @@ cl_eos() { int cy = ttyDisplay->cury + 1; if (GetConsoleScreenBufferInfo(hConOut, &csbi)) { + + buffer_fill_to_end(&front_buffer, &clear_cell, ttyDisplay->curx, + ttyDisplay->cury); + buffer_fill_to_end(&back_buffer, &clear_cell, ttyDisplay->curx, + ttyDisplay->cury); + DWORD ccnt; COORD newcoord; newcoord.X = ttyDisplay->curx; newcoord.Y = ttyDisplay->cury; + FillConsoleOutputAttribute( hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, csbi.dwSize.X * csbi.dwSize.Y - cy, newcoord, &ccnt); @@ -1063,10 +1300,10 @@ VA_DECL(const char *, fmt) else { if(!init_ttycolor_completed) init_ttycolor(); - xputs(buf); if (ttyDisplay) curs(BASE_WINDOW, console.cursor.X + 1, console.cursor.Y); + really_move_cursor(); } VA_END(); return; From d2a7c8afa1c992ecf9782a1b54b6f215bcad680f Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 7 May 2018 08:41:54 -0400 Subject: [PATCH 10/25] some status data corrections --- src/botl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/botl.c b/src/botl.c index 5b573d856..68a38b62b 100644 --- a/src/botl.c +++ b/src/botl.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 botl.c $NHDT-Date: 1525563781 2018/05/05 23:43:01 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.90 $ */ +/* NetHack 3.6 botl.c $NHDT-Date: 1525696908 2018/05/07 12:41:48 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.91 $ */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /*-Copyright (c) Michael Allison, 2006. */ /* NetHack may be freely redistributed. See license for details. */ @@ -483,14 +483,14 @@ STATIC_DCL struct istat_s initblstats[MAXBLSTATS] = { INIT_BLSTAT("charisma", " Ch:%s", ANY_INT, 10, BL_CH), INIT_BLSTAT("alignment", " %s", ANY_STR, 40, BL_ALIGN), INIT_BLSTAT("score", " S:%s", ANY_LONG, 20, BL_SCORE), - INIT_BLSTAT("carrying-capacity", " %s", ANY_LONG, 20, BL_CAP), + INIT_BLSTAT("carrying-capacity", " %s", ANY_INT, 20, BL_CAP), INIT_BLSTAT("gold", " %s", ANY_LONG, 30, BL_GOLD), INIT_BLSTATP("power", " Pw:%s", ANY_INT, 10, BL_ENEMAX, BL_ENE), INIT_BLSTAT("power-max", "(%s)", ANY_INT, 10, BL_ENEMAX), - INIT_BLSTAT("experience-level", " Xp:%s", ANY_LONG, 10, BL_XP), + INIT_BLSTAT("experience-level", " Xp:%s", ANY_INT, 10, BL_XP), INIT_BLSTAT("armor-class", " AC:%s", ANY_INT, 10, BL_AC), INIT_BLSTAT("HD", " HD:%s", ANY_INT, 10, BL_HD), - INIT_BLSTAT("time", " T:%s", ANY_INT, 20, BL_TIME), + INIT_BLSTAT("time", " T:%s", ANY_LONG, 20, BL_TIME), INIT_BLSTAT("hunger", " %s", ANY_UINT, 40, BL_HUNGER), INIT_BLSTATP("hitpoints", " HP:%s", ANY_INT, 10, BL_HPMAX, BL_HP), INIT_BLSTAT("hitpoints-max", "(%s)", ANY_INT, 10, BL_HPMAX), @@ -630,7 +630,7 @@ bot_via_windowport() /* Experience */ blstats[idx][BL_XP].a.a_int = u.ulevel; - blstats[idx][BL_EXP].a.a_int = u.uexp; + blstats[idx][BL_EXP].a.a_long = u.uexp; /* Time (moves) */ blstats[idx][BL_TIME].a.a_long = moves; From b524c26da5aad614a47badafffe5d752d8e68182 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 7 May 2018 18:52:50 -0400 Subject: [PATCH 11/25] intermediate update to wintty.c as work continues --- win/tty/wintty.c | 305 +++++++++++++++++++++++++---------------------- 1 file changed, 165 insertions(+), 140 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index d0f364574..813351920 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -176,21 +176,7 @@ STATIC_DCL void FDECL(setup_racemenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL boolean NDECL(reset_role_filtering); - -#ifdef STATUS_HILITES -static long tty_condition_bits; -static struct tty_status_fields { - int color; - int attr; - coord loc; - boolean valid; -} tty_status[MAXBLSTATS], prev_tty_status[MAXBLSTATS]; -static int st_fld; -int hpbar_percent, hpbar_color; - -static int FDECL(condcolor, (long, unsigned long *)); -static int FDECL(condattr, (long, unsigned long *)); -#endif /* STATUS_HILITES */ +STATIC_DCL void FDECL(status_content, (winid, struct WinDesc *, const char *)); /* * A string containing all the default commands -- to add to a list @@ -2504,8 +2490,7 @@ const char *str; { register struct WinDesc *cw = 0; register char *ob; - register const char *nb; - register long i, j, n0; + register long i, n0; boolean attr_match = FALSE; /* Assume there's a real problem if the window is missing -- @@ -2536,55 +2521,7 @@ const char *str; break; case NHW_STATUS: - ob = &cw->data[cw->cury][j = cw->curx]; - if (context.botlx) - *ob = 0; - if (!cw->cury && (int) strlen(str) >= CO) { - /* the characters before "St:" are unnecessary */ - nb = index(str, ':'); - if (nb && nb > str + 2) - str = nb - 2; - } - nb = str; -#ifdef STATUS_HILITES - if (prev_tty_status[st_fld].valid - && tty_status[st_fld].loc.x == prev_tty_status[st_fld].loc.x - && tty_status[st_fld].loc.y == prev_tty_status[st_fld].loc.y - && tty_status[st_fld].color == prev_tty_status[st_fld].color - && tty_status[st_fld].attr == prev_tty_status[st_fld].attr) -#endif - attr_match = TRUE; - for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { - if (!*nb) { -#ifndef STATUS_HILITES - if (*ob || context.botlx) { -#else - if (context.botlx) { -#endif - /* last char printed may be in middle of line */ - tty_curs(WIN_STATUS, i, cw->cury); - cl_end(); - } - break; - } - if (*ob != *nb || !attr_match) { -#ifdef STATUS_HILITES - tty_curs(WIN_STATUS, - tty_status[st_fld].loc.x, - tty_status[st_fld].loc.y); -#endif - tty_putsym(WIN_STATUS, i, cw->cury, *nb); - } - if (*ob) - ob++; - } - - (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1); - cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */ -#ifndef STATUS_HILITES - cw->cury = (cw->cury + 1) % 2; - cw->curx = 0; -#endif + status_content(window, cw, str); break; case NHW_MAP: tty_curs(window, cw->curx + 1, cw->cury); @@ -3444,6 +3381,13 @@ char *posbar; } #endif /* POSITIONBAR */ + +/* + * +------------------+ + * | STATUS CODE | + * +------------------+ + */ + /* * The following data structures come from the genl_ routines in * src/windows.c and as such are considered to be on the window-port @@ -3455,6 +3399,20 @@ extern char *status_vals[MAXBLSTATS]; extern boolean status_activefields[MAXBLSTATS]; extern winid WIN_STATUS; +#ifdef STATUS_HILITES +static int FDECL(condcolor, (long, unsigned long *)); +static int FDECL(condattr, (long, unsigned long *)); +static long tty_condition_bits; +static struct tty_status_fields { + int color; + int attr; + coord loc; + boolean valid; +} tty_status[MAXBLSTATS], prev_tty_status[MAXBLSTATS]; +static int st_fld; +int hpbar_percent, hpbar_color; +#endif + void tty_status_init() { @@ -3477,6 +3435,143 @@ tty_status_init() genl_status_init(); } +void +status_content(window, cw, str) +winid window; +struct WinDesc *cw; +const char *str; +{ + char *ob; + long i, j, n0; + const char *nb; + boolean attr_match = FALSE; + + ob = &cw->data[cw->cury][j = cw->curx]; + if (context.botlx) + *ob = 0; + if (!cw->cury && (int) strlen(str) >= CO) { + /* the characters before "St:" are unnecessary */ + nb = index(str, ':'); + if (nb && nb > str + 2) + str = nb - 2; + } + nb = str; +#ifdef STATUS_HILITES + if (prev_tty_status[st_fld].valid + && tty_status[st_fld].loc.x == prev_tty_status[st_fld].loc.x + && tty_status[st_fld].loc.y == prev_tty_status[st_fld].loc.y + && tty_status[st_fld].color == prev_tty_status[st_fld].color + && tty_status[st_fld].attr == prev_tty_status[st_fld].attr) +#endif + attr_match = TRUE; + for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { + if (!*nb) { +#ifndef STATUS_HILITES + if (*ob || context.botlx) { +#else + if (context.botlx) { +#endif + /* last char printed may be in middle of line */ + tty_curs(WIN_STATUS, i, cw->cury); + cl_end(); + } + break; + } + if (*ob != *nb || !attr_match) { +#ifdef STATUS_HILITES + tty_curs(WIN_STATUS, + tty_status[st_fld].loc.x, + tty_status[st_fld].loc.y); +#endif + tty_putsym(WIN_STATUS, i, cw->cury, *nb); + } + if (*ob) + ob++; + } + + (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1); + cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */ +#ifndef STATUS_HILITES + cw->cury = (cw->cury + 1) % 2; + cw->curx = 0; +#endif + return; +} + +#ifdef STATUS_HILITES +/* new approach through status_update() only */ +#define Begin_Attr(m) \ + if (m) { \ + if ((m) & HL_BOLD) \ + term_start_attr(ATR_BOLD); \ + if ((m) & HL_INVERSE) \ + term_start_attr(ATR_INVERSE); \ + if ((m) & HL_ULINE) \ + term_start_attr(ATR_ULINE); \ + if ((m) & HL_BLINK) \ + term_start_attr(ATR_BLINK); \ + if ((m) & HL_DIM) \ + term_start_attr(ATR_DIM); \ + } + +#define End_Attr(m) \ + if (m) { \ + if ((m) & HL_DIM) \ + term_end_attr(ATR_DIM); \ + if ((m) & HL_BLINK) \ + term_end_attr(ATR_BLINK); \ + if ((m) & HL_ULINE) \ + term_end_attr(ATR_ULINE); \ + if ((m) & HL_INVERSE) \ + term_end_attr(ATR_INVERSE); \ + if ((m) & HL_BOLD) \ + term_end_attr(ATR_BOLD); \ + } + +#ifdef TEXTCOLOR +#define MaybeDisplayCond(bm,txt) \ + if (tty_condition_bits & (bm)) { \ + tty_putstr(WIN_STATUS, 0, " "); \ + if (iflags.hilite_delta) { \ + attrmask = condattr(bm, colormasks); \ + Begin_Attr(attrmask); \ + if ((coloridx = condcolor(bm, colormasks)) != NO_COLOR) \ + term_start_color(coloridx); \ + } \ + tty_putstr(WIN_STATUS, 0, txt); \ + if (iflags.hilite_delta) { \ + if (coloridx != NO_COLOR) \ + term_end_color(); \ + End_Attr(attrmask); \ + } \ + } +#else +#define MaybeDisplayCond(bm,txt) \ + if (tty_condition_bits & (bm)) { \ + tty_putstr(WIN_STATUS, 0, " "); \ + if (iflags.hilite_delta) { \ + attrmask = condattr(bm, colormasks); \ + Begin_Attr(attrmask); \ + } \ + tty_putstr(WIN_STATUS, 0, txt); \ + if (iflags.hilite_delta) { \ + End_Attr(attrmask); \ + } \ + } +#endif + +#define Status_Putstr(s) \ + tty_status[st_fld].loc.x = (xchar) cw->curx; \ + tty_status[st_fld].loc.y = (xchar) cw->cury; \ + tty_status[st_fld].valid = TRUE; \ + tty_putstr(WIN_STATUS, 0, s); + +/* + * tty_status_init() + * -- initialize the tty-specific data structures. + * -- call genl_status_init() to initialize the general data. + */ + /* * *_status_update() * -- update the value of a status field. @@ -3530,76 +3625,6 @@ tty_status_init() * See doc/window.doc for more details. */ - -/* new approach through status_update() only */ -#define Begin_Attr(m) \ - if (m) { \ - if ((m) & HL_BOLD) \ - term_start_attr(ATR_BOLD); \ - if ((m) & HL_INVERSE) \ - term_start_attr(ATR_INVERSE); \ - if ((m) & HL_ULINE) \ - term_start_attr(ATR_ULINE); \ - if ((m) & HL_BLINK) \ - term_start_attr(ATR_BLINK); \ - if ((m) & HL_DIM) \ - term_start_attr(ATR_DIM); \ - } - -#define End_Attr(m) \ - if (m) { \ - if ((m) & HL_DIM) \ - term_end_attr(ATR_DIM); \ - if ((m) & HL_BLINK) \ - term_end_attr(ATR_BLINK); \ - if ((m) & HL_ULINE) \ - term_end_attr(ATR_ULINE); \ - if ((m) & HL_INVERSE) \ - term_end_attr(ATR_INVERSE); \ - if ((m) & HL_BOLD) \ - term_end_attr(ATR_BOLD); \ - } - -#ifdef STATUS_HILITES - -#ifdef TEXTCOLOR -#define MaybeDisplayCond(bm,txt) \ - if (tty_condition_bits & (bm)) { \ - tty_putstr(WIN_STATUS, 0, " "); \ - if (iflags.hilite_delta) { \ - attrmask = condattr(bm, colormasks); \ - Begin_Attr(attrmask); \ - if ((coloridx = condcolor(bm, colormasks)) != NO_COLOR) \ - term_start_color(coloridx); \ - } \ - tty_putstr(WIN_STATUS, 0, txt); \ - if (iflags.hilite_delta) { \ - if (coloridx != NO_COLOR) \ - term_end_color(); \ - End_Attr(attrmask); \ - } \ - } -#else -#define MaybeDisplayCond(bm,txt) \ - if (tty_condition_bits & (bm)) { \ - tty_putstr(WIN_STATUS, 0, " "); \ - if (iflags.hilite_delta) { \ - attrmask = condattr(bm, colormasks); \ - Begin_Attr(attrmask); \ - } \ - tty_putstr(WIN_STATUS, 0, txt); \ - if (iflags.hilite_delta) { \ - End_Attr(attrmask); \ - } \ - } -#endif -#define status_putstr(s) \ - tty_status[st_fld].loc.x = (xchar) cw->curx; \ - tty_status[st_fld].loc.y = (xchar) cw->cury; \ - tty_status[st_fld].valid = TRUE; \ - tty_putstr(WIN_STATUS, 0, s); - - void tty_status_update(fldidx, ptr, chg, percent, color, colormasks) int fldidx, chg UNUSED, percent UNUSED, color; @@ -3678,7 +3703,7 @@ unsigned long *colormasks; text = status_vals[fldidx1]; if (iflags.hilite_delta) { if (*text == ' ') { - status_putstr(" "); + Status_Putstr(" "); text++; } /* multiple attributes can be in effect concurrently */ @@ -3689,7 +3714,7 @@ unsigned long *colormasks; #endif } - status_putstr(text); + Status_Putstr(text); if (iflags.hilite_delta) { #ifdef TEXTCOLOR @@ -3722,7 +3747,7 @@ unsigned long *colormasks; } } if (iflags.hilite_delta && iflags.wc2_hitpointbar) { - status_putstr("["); + Status_Putstr("["); #ifdef TEXTCOLOR coloridx = hpbar_color & 0x00FF; /* attridx = (hpbar_color & 0xFF00) >> 8; */ @@ -3778,7 +3803,7 @@ unsigned long *colormasks; /* putmixed() due to GOLD glyph */ putmixed(WIN_STATUS, 0, text); } else { - status_putstr(text); + Status_Putstr(text); } if (iflags.hilite_delta) { From e90b20a3a9bd5dedac96722b370a70da9c1c0d89 Mon Sep 17 00:00:00 2001 From: nhmall Date: Mon, 7 May 2018 20:20:36 -0400 Subject: [PATCH 12/25] optimization of output was ruining display effects --- sys/winnt/nttty.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 2ed5d7c14..9d1114498 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -252,6 +252,8 @@ cell_t undefined_cell; static boolean buffer_flipping_initialized = FALSE; +boolean do_immediate_flips = FALSE; + static void check_buffer_size(int width, int height); static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y); @@ -367,12 +369,18 @@ static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, cell_t * sentinel = buffer_get_cell(buffer, 0, buffer_height); while (dst != sentinel) *dst++ = clear_cell; + + if (do_immediate_flips && buffer == &back_buffer) + back_buffer_flip(); } static void back_buffer_write(cell_t * cell, int x, int y) { cell_t * dst = buffer_get_cell(&back_buffer, x, y); *dst = *cell; + + if (do_immediate_flips) + back_buffer_flip(); } static void back_buffer_clear_to_end_of_line(int x, int y) @@ -384,6 +392,9 @@ static void back_buffer_clear_to_end_of_line(int x, int y) sentinel = buffer_get_cell(&back_buffer, 0, y+1); while (cell != sentinel) *cell++ = clear_cell; + + if (do_immediate_flips) + back_buffer_flip(); } /* @@ -922,6 +933,7 @@ tty_delay_output() int k; goal = 50 + clock(); + back_buffer_flip(); while (goal > clock()) { k = junk; /* Do nothing */ } From 9bca6ecb8e1bf0f22b3765b3583a79c000223fe7 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 9 May 2018 13:12:11 -0400 Subject: [PATCH 13/25] tty status updates some status code cleanup It should be ready to merge tty-status changes into NetHack-3.6.0. --- win/tty/wintty.c | 619 ++++++++++++++++++++++++++--------------------- 1 file changed, 339 insertions(+), 280 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 813351920..ac3fe384f 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -1,4 +1,4 @@ -/* NetHack 3.6 wintty.c $NHDT-Date: 1525563766 2018/05/05 23:42:46 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.144 $ */ +/* NetHack 3.6 wintty.c $NHDT-Date: 1525885919 2018/05/09 17:11:59 $ $NHDT-Branch: tty-status $:$NHDT-Revision: 1.146 $ */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ @@ -176,7 +176,9 @@ STATIC_DCL void FDECL(setup_racemenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL boolean NDECL(reset_role_filtering); -STATIC_DCL void FDECL(status_content, (winid, struct WinDesc *, const char *)); +STATIC_DCL void FDECL(status_putstr, (winid, struct WinDesc *, const char *)); +STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P)); +STATIC_DCL void NDECL(render_status); /* * A string containing all the default commands -- to add to a list @@ -2504,7 +2506,11 @@ const char *str; if (str == (const char *) 0 || ((cw->flags & WIN_CANCELLED) && (cw->type != NHW_MESSAGE))) return; +#ifndef STATUS_HILITES if (cw->type != NHW_MESSAGE) +#else + if (cw->type != NHW_MESSAGE && cw->type != NHW_STATUS) +#endif str = compress_str(str); ttyDisplay->lastwin = window; @@ -2521,7 +2527,7 @@ const char *str; break; case NHW_STATUS: - status_content(window, cw, str); + status_putstr(window, cw, str); break; case NHW_MAP: tty_curs(window, cw->curx + 1, cw->cury); @@ -3393,7 +3399,6 @@ char *posbar; * src/windows.c and as such are considered to be on the window-port * "side" of things, rather than the NetHack-core "side" of things. */ - extern const char *status_fieldfmt[MAXBLSTATS]; extern char *status_vals[MAXBLSTATS]; extern boolean status_activefields[MAXBLSTATS]; @@ -3403,16 +3408,51 @@ extern winid WIN_STATUS; static int FDECL(condcolor, (long, unsigned long *)); static int FDECL(condattr, (long, unsigned long *)); static long tty_condition_bits; +static unsigned long *tty_colormasks; static struct tty_status_fields { int color; int attr; - coord loc; + int x, y; + size_t lth; boolean valid; -} tty_status[MAXBLSTATS], prev_tty_status[MAXBLSTATS]; + boolean redraw; +} tty_status[2][MAXBLSTATS]; static int st_fld; int hpbar_percent, hpbar_color; +struct condition_t { + long mask; + char *text[3]; /* 3 potential display values, progressively smaller */ +} conditions[] = { + /* The sequence order of these matters */ + { BL_MASK_STONE, {"Stone", "Ston", "Sto"}}, + { BL_MASK_SLIME, {"Slime", "Slim", "Slm"}}, + { BL_MASK_STRNGL, {"Strngl", "Stngl", "Str"}}, + { BL_MASK_FOODPOIS, {"FoodPois", "Fpois", "Poi"}}, + { BL_MASK_TERMILL, {"TermIll" , "Ill", "Ill"}}, + { BL_MASK_BLIND, {"Blind", "Blnd", "Bl"}}, + { BL_MASK_DEAF, {"Deaf", "Def", "Df"}}, + { BL_MASK_STUN, {"Stun", "Stun", "St"}}, + { BL_MASK_CONF, {"Conf", "Cnf", "Cn"}}, + { BL_MASK_HALLU, {"Hallu", "Hal", "Ha"}}, + { BL_MASK_LEV, {"Lev", "Lev", "Lv"}}, + { BL_MASK_FLY, {"Fly", "Fly", "Fl"}}, + { BL_MASK_RIDE, {"Ride", "Rid", "Ri"}}, +}; +enum statusfields fieldorder[2][15] = { + { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, + BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, + BL_FLUSH }, + { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, + BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, + BL_CAP, BL_CONDITION, BL_FLUSH } +}; #endif +/* + * tty_status_init() + * -- initialize the tty-specific data structures. + * -- call genl_status_init() to initialize the general data. + */ void tty_status_init() { @@ -3420,12 +3460,13 @@ tty_status_init() int i; for (i = 0; i < MAXBLSTATS; ++i) { - tty_status[i].color = NO_COLOR; /* no color */ - tty_status[i].attr = ATR_NONE; - tty_status[i].loc.x = 0; - tty_status[i].loc.y = 0; - tty_status[i].valid = FALSE; - prev_tty_status[i] = tty_status[i]; + tty_status[NOW][i].color = NO_COLOR; /* no color */ + tty_status[NOW][i].attr = ATR_NONE; + tty_status[NOW][i].x = 0; + tty_status[NOW][i].y = 0; + tty_status[NOW][i].valid = FALSE; + tty_status[NOW][i].redraw = FALSE; + tty_status[BEFORE][i] = tty_status[NOW][i]; } tty_condition_bits = 0L; hpbar_percent = 0, hpbar_color = NO_COLOR; @@ -3435,8 +3476,21 @@ tty_status_init() genl_status_init(); } -void -status_content(window, cw, str) +/* + * status_putstr() is not intended to be called directly + * by anything other than tty_putstr(). tty_putstr() + * does the prereq validations, and initializations of + * window and cw. + * + * Moving the status handling code here from tty_putstr() + * allows access to status data structures defined just + * above, rather than up top, with the additional bonus + * of having most status-related code bits fairly close + * together. + * + */ +static void +status_putstr(window, cw, str) winid window; struct WinDesc *cw; const char *str; @@ -3444,7 +3498,6 @@ const char *str; char *ob; long i, j, n0; const char *nb; - boolean attr_match = FALSE; ob = &cw->data[cw->cury][j = cw->curx]; if (context.botlx) @@ -3456,14 +3509,6 @@ const char *str; str = nb - 2; } nb = str; -#ifdef STATUS_HILITES - if (prev_tty_status[st_fld].valid - && tty_status[st_fld].loc.x == prev_tty_status[st_fld].loc.x - && tty_status[st_fld].loc.y == prev_tty_status[st_fld].loc.y - && tty_status[st_fld].color == prev_tty_status[st_fld].color - && tty_status[st_fld].attr == prev_tty_status[st_fld].attr) -#endif - attr_match = TRUE; for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { if (!*nb) { #ifndef STATUS_HILITES @@ -3477,14 +3522,20 @@ const char *str; } break; } - if (*ob != *nb || !attr_match) { -#ifdef STATUS_HILITES - tty_curs(WIN_STATUS, - tty_status[st_fld].loc.x, - tty_status[st_fld].loc.y); +#ifndef STATUS_HILITES + if (*ob != *nb) { +#else + if (*ob != *nb || tty_status[NOW][st_fld].redraw) { #endif tty_putsym(WIN_STATUS, i, cw->cury, *nb); } +#ifdef STATUS_HILITES + else { + /* tty_curs(window, x, y); */ + ttyDisplay->curx++; + cw->curx++; + } +#endif if (*ob) ob++; } @@ -3499,78 +3550,6 @@ const char *str; } #ifdef STATUS_HILITES -/* new approach through status_update() only */ -#define Begin_Attr(m) \ - if (m) { \ - if ((m) & HL_BOLD) \ - term_start_attr(ATR_BOLD); \ - if ((m) & HL_INVERSE) \ - term_start_attr(ATR_INVERSE); \ - if ((m) & HL_ULINE) \ - term_start_attr(ATR_ULINE); \ - if ((m) & HL_BLINK) \ - term_start_attr(ATR_BLINK); \ - if ((m) & HL_DIM) \ - term_start_attr(ATR_DIM); \ - } - -#define End_Attr(m) \ - if (m) { \ - if ((m) & HL_DIM) \ - term_end_attr(ATR_DIM); \ - if ((m) & HL_BLINK) \ - term_end_attr(ATR_BLINK); \ - if ((m) & HL_ULINE) \ - term_end_attr(ATR_ULINE); \ - if ((m) & HL_INVERSE) \ - term_end_attr(ATR_INVERSE); \ - if ((m) & HL_BOLD) \ - term_end_attr(ATR_BOLD); \ - } - -#ifdef TEXTCOLOR -#define MaybeDisplayCond(bm,txt) \ - if (tty_condition_bits & (bm)) { \ - tty_putstr(WIN_STATUS, 0, " "); \ - if (iflags.hilite_delta) { \ - attrmask = condattr(bm, colormasks); \ - Begin_Attr(attrmask); \ - if ((coloridx = condcolor(bm, colormasks)) != NO_COLOR) \ - term_start_color(coloridx); \ - } \ - tty_putstr(WIN_STATUS, 0, txt); \ - if (iflags.hilite_delta) { \ - if (coloridx != NO_COLOR) \ - term_end_color(); \ - End_Attr(attrmask); \ - } \ - } -#else -#define MaybeDisplayCond(bm,txt) \ - if (tty_condition_bits & (bm)) { \ - tty_putstr(WIN_STATUS, 0, " "); \ - if (iflags.hilite_delta) { \ - attrmask = condattr(bm, colormasks); \ - Begin_Attr(attrmask); \ - } \ - tty_putstr(WIN_STATUS, 0, txt); \ - if (iflags.hilite_delta) { \ - End_Attr(attrmask); \ - } \ - } -#endif - -#define Status_Putstr(s) \ - tty_status[st_fld].loc.x = (xchar) cw->curx; \ - tty_status[st_fld].loc.y = (xchar) cw->cury; \ - tty_status[st_fld].valid = TRUE; \ - tty_putstr(WIN_STATUS, 0, s); - -/* - * tty_status_init() - * -- initialize the tty-specific data structures. - * -- call genl_status_init() to initialize the general data. - */ /* * *_status_update() @@ -3627,63 +3606,152 @@ const char *str; void tty_status_update(fldidx, ptr, chg, percent, color, colormasks) -int fldidx, chg UNUSED, percent UNUSED, color; +int fldidx, chg UNUSED, percent, color; genericptr_t ptr; unsigned long *colormasks; { long *condptr = (long *) ptr; - int i, attrmask = 0; -#ifdef TEXTCOLOR - int coloridx = NO_COLOR; -#endif - struct WinDesc *cw = 0; - char *text = (char *) ptr; - static boolean oncearound = FALSE; /* prevent premature partial display */ - enum statusfields fieldorder[2][15] = { - { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, - BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, - BL_FLUSH }, - { BL_LEVELDESC, BL_GOLD, BL_HP, BL_HPMAX, BL_ENE, BL_ENEMAX, - BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, - BL_CAP, BL_CONDITION, BL_FLUSH } - }; - int attridx = 0; - st_fld = fldidx; + boolean do_color = FALSE; + boolean force_update = FALSE; - if (fldidx != BL_FLUSH) { - if (!status_activefields[fldidx]) - return; - switch (fldidx) { - case BL_CONDITION: - tty_condition_bits = *condptr; - oncearound = TRUE; +#ifdef TEXTCOLOR + do_color = TRUE; +#endif + + if (fldidx != BL_FLUSH && !status_activefields[fldidx]) + return; + + switch (fldidx) { + case BL_FLUSH: + force_update = TRUE; break; - default: + case BL_CONDITION: + tty_condition_bits = *condptr; + tty_colormasks = colormasks; + tty_status[NOW][fldidx].valid = TRUE; + break; + default: Sprintf(status_vals[fldidx], status_fieldfmt[fldidx] ? - status_fieldfmt[fldidx] : "%s", - text); -#ifdef TEXTCOLOR - tty_status[fldidx].color = (color & 0x00FF); -#else - tty_status[fldidx].color = NO_COLOR; -#endif - tty_status[fldidx].attr = (color & 0xFF00) >> 8; - - if (iflags.wc2_hitpointbar && fldidx == BL_HP) { - hpbar_percent = percent; -#ifdef TEXTCOLOR - hpbar_color = color; -#else - hpbar_color = NO_COLOR; -#endif - } - break; - } + status_fieldfmt[fldidx] : "%s", text); + tty_status[NOW][fldidx].color = do_color ? (color & 0x00FF) + : NO_COLOR; + tty_status[NOW][fldidx].attr = (color & 0xFF00) >> 8; + tty_status[NOW][fldidx].lth = strlen(status_vals[fldidx]); + tty_status[NOW][fldidx].valid = TRUE; + break; } - if (!oncearound) return; + /* Special additional processing for hitpointbar */ + if (iflags.wc2_hitpointbar && fldidx == BL_HP) { + hpbar_percent = percent; + hpbar_color = do_color ? (color & 0x00FF) : NO_COLOR; + } + + /* special case fixups */ + if (iflags.wc2_hitpointbar && fldidx == BL_TITLE) + tty_status[NOW][fldidx].lth += 2; /* [ and ] */ + if (fldidx == BL_GOLD) + tty_status[NOW][fldidx].lth -= 9; /* \GXXXXNNNN counts as 1 */ + + if (check_fields(force_update)) + render_status(); + return; +} + +/* + * This is the routine where we figure out where each field + * should be placed, and flag whether the on-screen details + * must be updated because they need to change. + * This is now done at an individual field case-by-case level. + */ +boolean +check_fields(forcefields) +boolean forcefields; +{ + int i, row, col; + boolean valid = TRUE, update_right; + + for (row = 0; row < 2; ++row) { + col = 1; + update_right = FALSE; + for (i = 0; fieldorder[row][i] != BL_FLUSH; ++i) { + int idx = fieldorder[row][i]; + + if (!status_activefields[idx]) + continue; + + if (!tty_status[NOW][idx].valid) + valid = FALSE; + + tty_status[NOW][idx].y = row; + tty_status[NOW][idx].x = col; + if (tty_status[NOW][idx].lth != tty_status[BEFORE][idx].lth) + update_right = TRUE; + /* + * status_putstr(), called from tty_putstr() checks + * whether individual tty cell text content matches what + * was already there and optimizes by leaving it be. + * Checking the text iself was sufficient back when the + * status lines were monochrome and of a single + * attribute style. + * + * With STATUS_HILITES, it is possible that the color + * needs to change even if the text is the same, so + * we flag that here by setting .redraw. + * Then, status_putstr() will see that flag setting + * and ensure that the tty cell content is updated. + */ + if (forcefields || update_right + || tty_status[NOW][idx].color != tty_status[BEFORE][idx].color + || tty_status[NOW][idx].attr != tty_status[BEFORE][idx].attr) + tty_status[NOW][idx].redraw = TRUE; + col += tty_status[NOW][idx].lth; + } + } + return valid; +} + +#define Begin_Attr(m) \ + if (m) { \ + if ((m) & HL_BOLD) \ + term_start_attr(ATR_BOLD); \ + if ((m) & HL_INVERSE) \ + term_start_attr(ATR_INVERSE); \ + if ((m) & HL_ULINE) \ + term_start_attr(ATR_ULINE); \ + if ((m) & HL_BLINK) \ + term_start_attr(ATR_BLINK); \ + if ((m) & HL_DIM) \ + term_start_attr(ATR_DIM); \ + } + +#define End_Attr(m) \ + if (m) { \ + if ((m) & HL_DIM) \ + term_end_attr(ATR_DIM); \ + if ((m) & HL_BLINK) \ + term_end_attr(ATR_BLINK); \ + if ((m) & HL_ULINE) \ + term_end_attr(ATR_ULINE); \ + if ((m) & HL_INVERSE) \ + term_end_attr(ATR_INVERSE); \ + if ((m) & HL_BOLD) \ + term_end_attr(ATR_BOLD); \ + } + +void +render_status(VOID_ARGS) +{ + long mask = 0L; + int i, c, row, shrinklvl = 0, attrmask = 0; + struct WinDesc *cw = 0; + boolean do_color = FALSE; + +#ifdef TEXTCOLOR + do_color = TRUE; +#endif if (WIN_STATUS == WIN_ERR || (cw = wins[WIN_STATUS]) == (struct WinDesc *) 0) { @@ -3691,147 +3759,138 @@ unsigned long *colormasks; return; } - curs(WIN_STATUS, 1, 0); - for (i = 0; fieldorder[0][i] != BL_FLUSH; ++i) { - int fldidx1 = fieldorder[0][i]; - if (status_activefields[fldidx1]) { - if (fldidx1 != BL_TITLE || !iflags.wc2_hitpointbar) { -#ifdef TEXTCOLOR - coloridx = tty_status[fldidx1].color; -#endif - attridx = tty_status[fldidx1].attr; - text = status_vals[fldidx1]; - if (iflags.hilite_delta) { - if (*text == ' ') { - Status_Putstr(" "); - text++; + for (row = 0; row < 2; ++row) { + curs(WIN_STATUS, 1, row); + for (i = 0; fieldorder[row][i] != BL_FLUSH; ++i) { + int fldidx = fieldorder[row][i]; + + if (status_activefields[fldidx]) { + int coloridx = tty_status[NOW][fldidx].color; + int attridx = tty_status[NOW][fldidx].attr; + int x = tty_status[NOW][fldidx].x; + int y = row; + char *text = status_vals[fldidx]; + boolean hitpointbar = (fldidx == BL_TITLE && iflags.wc2_hitpointbar); + + st_fld = fldidx; /* for status_putstr() */ + tty_curs(WIN_STATUS, x, y); + if (st_fld == BL_CONDITION) { + /* + * +-----------------+ + * | Condition Codes | + * +-----------------+ + */ + for (c = 0; c < SIZE(conditions); ++c) { + mask = conditions[c].mask; + if ((tty_condition_bits & mask) == mask) { + tty_putstr(WIN_STATUS, 0, " "); + if (iflags.hilite_delta) { + attrmask = condattr(mask, tty_colormasks); + Begin_Attr(attrmask); + if (do_color) { + coloridx = condcolor(mask, tty_colormasks); + if (coloridx != NO_COLOR) + term_start_color(coloridx); + } + } + tty_putstr(WIN_STATUS, 0, + conditions[c].text[shrinklvl]); + if (iflags.hilite_delta) { + if (do_color && coloridx != NO_COLOR) + term_end_color(); + End_Attr(attrmask); + } + } } - /* multiple attributes can be in effect concurrently */ - Begin_Attr(attridx); -#ifdef TEXTCOLOR - if (coloridx != NO_COLOR && coloridx != CLR_MAX) - term_start_color(coloridx); -#endif - } - - Status_Putstr(text); - - if (iflags.hilite_delta) { -#ifdef TEXTCOLOR - if (coloridx != NO_COLOR) - term_end_color(); -#endif - End_Attr(attridx); - } - } else { - /* hitpointbar using hp percent calculation */ - int bar_pos, bar_len; - char *bar2 = (char *)0; - char bar[MAXCO], savedch; - boolean twoparts = FALSE; - - text = status_vals[fldidx1]; - bar_len = strlen(text); - if (bar_len < MAXCO-1) { - Strcpy(bar, text); - bar_pos = (bar_len * hpbar_percent) / 100; - if (bar_pos < 1 && hpbar_percent > 0) - bar_pos = 1; - if (bar_pos >= bar_len && hpbar_percent < 100) - bar_pos = bar_len - 1; - if (bar_pos > 0 && bar_pos < bar_len) { - twoparts = TRUE; - bar2 = &bar[bar_pos]; - savedch = *bar2; - *bar2 = '\0'; - } - } - if (iflags.hilite_delta && iflags.wc2_hitpointbar) { - Status_Putstr("["); -#ifdef TEXTCOLOR - coloridx = hpbar_color & 0x00FF; - /* attridx = (hpbar_color & 0xFF00) >> 8; */ - if (coloridx != NO_COLOR) - term_start_color(coloridx); -#endif - term_start_attr(ATR_INVERSE); - tty_putstr(WIN_STATUS, 0, bar); - term_end_attr(ATR_INVERSE); -#ifdef TEXTCOLOR - if (coloridx != NO_COLOR) - term_end_color(); -#endif - if (twoparts) { - *bar2 = savedch; - tty_putstr(WIN_STATUS, 0, bar2); - } - tty_putstr(WIN_STATUS, 0, "]"); - } else - tty_putstr(WIN_STATUS, 0, text); - } - } - } - cl_end(); - curs(WIN_STATUS, 1, 1); - for (i = 0; fieldorder[1][i] != BL_FLUSH; ++i) { - int fldidx2 = fieldorder[1][i]; - - if (status_activefields[fldidx2]) { - if (fldidx2 != BL_CONDITION) { -#ifdef TEXTCOLOR - coloridx = tty_status[fldidx2].color; -#endif - attridx = tty_status[fldidx2].attr; - text = status_vals[fldidx2]; - if (iflags.hilite_delta) { - if (*text == ' ') { - tty_putstr(WIN_STATUS, 0, " "); - text++; - } - /* multiple attributes can be in effect concurrently */ - Begin_Attr(attridx); -#ifdef TEXTCOLOR - if (coloridx != NO_COLOR && coloridx != CLR_MAX) - term_start_color(coloridx); -#endif - } - - if (fldidx2 == BL_GOLD) { - tty_status[st_fld].loc.x = (xchar) cw->curx; - tty_status[st_fld].loc.y = (xchar) cw->cury; - tty_status[st_fld].valid = TRUE; \ + } else if (st_fld == BL_GOLD) { + /* + * +-----------+ + * | Gold | + * +-----------+ + */ /* putmixed() due to GOLD glyph */ putmixed(WIN_STATUS, 0, text); - } else { - Status_Putstr(text); - } + } else if (hitpointbar) { + /* + * +-------------------------+ + * | Title with Hitpoint Bar | + * +-------------------------+ + */ + /* hitpointbar using hp percent calculation */ + int bar_pos, bar_len; + char *bar2 = (char *)0; + char bar[MAXCO], savedch; + boolean twoparts = FALSE; - if (iflags.hilite_delta) { -#ifdef TEXTCOLOR - if (coloridx != NO_COLOR) - term_end_color(); -#endif - End_Attr(attridx); + bar_len = strlen(text); + if (bar_len < MAXCO-1) { + Strcpy(bar, text); + bar_pos = (bar_len * hpbar_percent) / 100; + if (bar_pos < 1 && hpbar_percent > 0) + bar_pos = 1; + if (bar_pos >= bar_len && hpbar_percent < 100) + bar_pos = bar_len - 1; + if (bar_pos > 0 && bar_pos < bar_len) { + twoparts = TRUE; + bar2 = &bar[bar_pos]; + savedch = *bar2; + *bar2 = '\0'; + } + } + if (iflags.hilite_delta && iflags.wc2_hitpointbar) { + tty_putstr(WIN_STATUS, 0, "["); + if (do_color && hpbar_color != NO_COLOR) + term_start_color(hpbar_color); + term_start_attr(ATR_INVERSE); + tty_putstr(WIN_STATUS, 0, bar); + term_end_attr(ATR_INVERSE); + if (do_color && hpbar_color != NO_COLOR) + term_end_color(); + if (twoparts) { + *bar2 = savedch; + tty_putstr(WIN_STATUS, 0, bar2); + } + tty_putstr(WIN_STATUS, 0, "]"); + } else { + tty_putstr(WIN_STATUS, 0, text); + } + } else { + /* + * +-----------------------------+ + * | Everything else that is not | + * | in a special case above | + * +-----------------------------+ + */ + if (iflags.hilite_delta) { + if (*text == ' ') { + tty_putstr(WIN_STATUS, 0, " "); + text++; + } + /* multiple attributes can be in effect concurrently */ + Begin_Attr(attridx); + if (do_color && coloridx != NO_COLOR + && coloridx != CLR_MAX) + term_start_color(coloridx); + } + tty_putstr(WIN_STATUS, 0, text); + if (iflags.hilite_delta) { + if (do_color && coloridx != NO_COLOR) + term_end_color(); + End_Attr(attridx); + } } - } else { - MaybeDisplayCond(BL_MASK_STONE, "Stone"); - MaybeDisplayCond(BL_MASK_SLIME, "Slime"); - MaybeDisplayCond(BL_MASK_STRNGL, "Strngl"); - MaybeDisplayCond(BL_MASK_FOODPOIS, "FoodPois"); - MaybeDisplayCond(BL_MASK_TERMILL, "TermIll"); - MaybeDisplayCond(BL_MASK_BLIND, "Blind"); - MaybeDisplayCond(BL_MASK_DEAF, "Deaf"); - MaybeDisplayCond(BL_MASK_STUN, "Stun"); - MaybeDisplayCond(BL_MASK_CONF, "Conf"); - MaybeDisplayCond(BL_MASK_HALLU, "Hallu"); - MaybeDisplayCond(BL_MASK_LEV, "Lev"); - MaybeDisplayCond(BL_MASK_FLY, "Fly"); - MaybeDisplayCond(BL_MASK_RIDE, "Ride"); + /* reset .redraw */ + tty_status[NOW][st_fld].redraw = FALSE; + /* + * Make a copy of the entire tty_status struct for comparison + * of current and previous. + */ + tty_status[BEFORE][st_fld] = tty_status[NOW][st_fld]; /* copy struct */ } - } - prev_tty_status[st_fld] = tty_status[st_fld]; /* copy struct */ + } + tty_curs(WIN_STATUS, cw->curx+1, cw->cury); + cl_end(); } - cl_end(); return; } From 778c8a56ab8c6dd15bfbdf747b5092f8b8ca3d7e Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 9 May 2018 13:25:46 -0400 Subject: [PATCH 14/25] remove a commented out code line --- win/tty/wintty.c | 1 - 1 file changed, 1 deletion(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index ac3fe384f..d58b211e3 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3531,7 +3531,6 @@ const char *str; } #ifdef STATUS_HILITES else { - /* tty_curs(window, x, y); */ ttyDisplay->curx++; cw->curx++; } From 4dd535cbd2bf9d05ab5a9245b85e6a954c6bf8f2 Mon Sep 17 00:00:00 2001 From: nhmall Date: Wed, 9 May 2018 18:47:19 -0400 Subject: [PATCH 15/25] cross platform testing --- win/tty/wintty.c | 1 + 1 file changed, 1 insertion(+) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index d58b211e3..96ec3b5f9 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3531,6 +3531,7 @@ const char *str; } #ifdef STATUS_HILITES else { + tty_curs(WIN_STATUS, i, cw->cury); ttyDisplay->curx++; cw->curx++; } From 702154529fb69af17972d0292d305acaf3a54eca Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 10 May 2018 10:05:29 -0400 Subject: [PATCH 16/25] provide some debug developer controls - part 1 --- include/extern.h | 2 +- include/flag.h | 11 ++++++ src/allmain.c | 89 +++++++++++++++++++++++++++++++++++++++++---- sys/share/pcmain.c | 7 +++- sys/unix/unixmain.c | 7 +++- sys/winnt/nttty.c | 8 ++-- 6 files changed, 108 insertions(+), 16 deletions(-) diff --git a/include/extern.h b/include/extern.h index b6f482515..4535f8769 100644 --- a/include/extern.h +++ b/include/extern.h @@ -26,7 +26,7 @@ E void NDECL(display_gamewindows); E void NDECL(newgame); E void FDECL(welcome, (BOOLEAN_P)); E time_t NDECL(get_realtime); -E boolean FDECL(argcheck, (int, char **, enum earlyarg)); +E int FDECL(argcheck, (int, char **, enum earlyarg)); /* ### apply.c ### */ diff --git a/include/flag.h b/include/flag.h index 5dd13b2ec..277b42cfe 100644 --- a/include/flag.h +++ b/include/flag.h @@ -221,6 +221,16 @@ enum getloc_filters { NUM_GFILTER }; +struct debug_flags { + boolean test; +#ifdef TTY_GRAPHICS + boolean ttystatus; +#endif +#ifdef WIN32 + boolean immediateflips; +#endif +}; + struct instance_flags { /* stuff that really isn't option or platform related. They are * set and cleared during the game to control the internal @@ -423,6 +433,7 @@ struct instance_flags { short mines_prize_type; /* luckstone */ short soko_prize_type1; /* bag of holding or */ short soko_prize_type2; /* amulet of reflection */ + struct debug_flags debug; }; /* diff --git a/src/allmain.c b/src/allmain.c index 6942aa232..569c6e456 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -6,6 +6,7 @@ /* various code that was replicated in *main.c */ #include "hack.h" +#include #ifndef NO_SIGNAL #include @@ -16,6 +17,7 @@ STATIC_DCL void NDECL(do_positionbar); #endif STATIC_DCL void FDECL(regen_hp, (int)); STATIC_DCL void FDECL(interrupt_multi, (const char *)); +STATIC_DCL void FDECL(debug_fields, (const char *)); void moveloop(resuming) @@ -752,11 +754,18 @@ const char *msg; */ static struct early_opt earlyopts[] = { - {ARG_DEBUG, "debug", 5, FALSE}, + {ARG_DEBUG, "debug", 5, TRUE}, {ARG_VERSION, "version", 4, TRUE}, }; -boolean +/* + * Returns: + * 0 = no match + * 1 = found and skip past this argument + * 2 = found and trigger immediate exit + */ + +int argcheck(argc, argv, e_arg) int argc; char *argv[]; @@ -774,7 +783,7 @@ enum earlyarg e_arg; if ((idx >= SIZE(earlyopts)) || (argc <= 1)) return FALSE; - for (i = 1; i < argc; ++i) { + for (i = 0; i < argc; ++i) { if (argv[i][0] != '-') continue; if (argv[i][1] == '-') { @@ -789,15 +798,20 @@ enum earlyarg e_arg; } if (match) { + const char *extended_opt = index(userea,':'); + + if (!extended_opt) + extended_opt = index(userea, '='); switch(e_arg) { case ARG_DEBUG: + if (extended_opt) { + extended_opt++; + debug_fields(extended_opt); + } + return 1; break; case ARG_VERSION: { boolean insert_into_pastebuf = FALSE; - const char *extended_opt = index(userea,':'); - - if (!extended_opt) - extended_opt = index(userea, '='); if (extended_opt) { extended_opt++; @@ -812,7 +826,7 @@ enum earlyarg e_arg; } } early_version_info(insert_into_pastebuf); - return TRUE; + return 2; break; } default: @@ -822,4 +836,63 @@ enum earlyarg e_arg; return FALSE; } +/* + * These are internal controls to aid developers with + * testing and debugging particular aspects of the code. + * They are not player options and the only place they + * are documented is right here. No gameplay is altered. + * + * test - test whether this parser is working + * ttystatus - TTY: + * immediateflips - WIN32: turn off display performance + * optimization so that display output + * can be debugged without buffering. + */ +void +debug_fields(opts) +const char *opts; +{ + char *op; + boolean negated = FALSE; + boolean retval = TRUE; + + while ((op = index(opts, ',')) != 0) { + *op++ = 0; + /* recurse */ + debug_fields(op); + } + if (strlen(opts) > BUFSZ / 2) + return; + + + /* strip leading and trailing white space */ + while (isspace((uchar) *opts)) + opts++; + op = eos((char *) opts); + while (--op >= opts && isspace((uchar) *op)) + *op = '\0'; + + if (!*opts) { + /* empty */ + return; + } + while ((*opts == '!') || !strncmpi(opts, "no", 2)) { + if (*opts == '!') + opts++; + else + opts += 2; + negated = !negated; + } + if (match_optname(opts, "test", 4, FALSE)) + iflags.debug.test = negated ? FALSE : TRUE; +#ifdef TTY_GRAPHICS + if (match_optname(opts, "ttystatus", 9, FALSE)) + iflags.debug.ttystatus = negated ? FALSE : TRUE; +#endif +#ifdef WIN32 + if (match_optname(opts, "immediateflips", 14, FALSE)) + iflags.debug.immediateflips = negated ? FALSE : TRUE; +#endif + return; +} /*allmain.c*/ diff --git a/sys/share/pcmain.c b/sys/share/pcmain.c index eea29f8de..6bb6cfc29 100644 --- a/sys/share/pcmain.c +++ b/sys/share/pcmain.c @@ -331,9 +331,14 @@ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);*/ Strcpy(hackdir, HACKDIR); #endif if (argc > 1) { - if (argcheck(argc, argv, ARG_VERSION)) + if (argcheck(argc, argv, ARG_VERSION) == 2) nethack_exit(EXIT_SUCCESS); + if (argcheck(argc, argv, ARG_DEBUG) == 1) { + argc--; + argv++; + } + if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index c856e758b..3c91b3e55 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -111,9 +111,14 @@ char *argv[]; dir = nh_getenv("HACKDIR"); if (argc > 1) { - if (argcheck(argc, argv, ARG_VERSION)) + if (argcheck(argc, argv, ARG_VERSION) == 2) exit(EXIT_SUCCESS); + if (argcheck(argc, argv, ARG_DEBUG) == 1) { + argc--; + argv++; + } + if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else diff --git a/sys/winnt/nttty.c b/sys/winnt/nttty.c index 9d1114498..4fbc11c63 100644 --- a/sys/winnt/nttty.c +++ b/sys/winnt/nttty.c @@ -252,8 +252,6 @@ cell_t undefined_cell; static boolean buffer_flipping_initialized = FALSE; -boolean do_immediate_flips = FALSE; - static void check_buffer_size(int width, int height); static cell_t * buffer_get_cell(console_buffer_t * buffer, int x, int y); @@ -370,7 +368,7 @@ static void buffer_fill_to_end(console_buffer_t * buffer, cell_t * src, while (dst != sentinel) *dst++ = clear_cell; - if (do_immediate_flips && buffer == &back_buffer) + if (iflags.debug.immediateflips && buffer == &back_buffer) back_buffer_flip(); } @@ -379,7 +377,7 @@ static void back_buffer_write(cell_t * cell, int x, int y) cell_t * dst = buffer_get_cell(&back_buffer, x, y); *dst = *cell; - if (do_immediate_flips) + if (iflags.debug.immediateflips) back_buffer_flip(); } @@ -393,7 +391,7 @@ static void back_buffer_clear_to_end_of_line(int x, int y) while (cell != sentinel) *cell++ = clear_cell; - if (do_immediate_flips) + if (iflags.debug.immediateflips) back_buffer_flip(); } From 8c2dc7bb1cf4fef8e7001c5cc2371a053c242b20 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 10 May 2018 18:48:02 -0400 Subject: [PATCH 17/25] add some logging to debug --- win/tty/wintty.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 96ec3b5f9..55f66ded3 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -179,6 +179,9 @@ STATIC_DCL boolean NDECL(reset_role_filtering); STATIC_DCL void FDECL(status_putstr, (winid, struct WinDesc *, const char *)); STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P)); STATIC_DCL void NDECL(render_status); +STATIC_DCL void FDECL(dump_tty_status, (const char *, int)); +STATIC_DCL void FDECL(dump_display_status, (const char *, int, + struct WinDesc *, const char *)); /* * A string containing all the default commands -- to add to a list @@ -3403,6 +3406,31 @@ extern const char *status_fieldfmt[MAXBLSTATS]; extern char *status_vals[MAXBLSTATS]; extern boolean status_activefields[MAXBLSTATS]; extern winid WIN_STATUS; +const char *fieldnames[] = { + "title", + "strength", + "dexterity", + "constitution", + "intelligence", + "wisdom", + "charisma", + "alignment", + "score", + "carrying-capacity", + "gold", + "power", + "power-max", + "experience-level", + "armor-class", + "HD", + "time", + "hunger", + "hitpoints", + "hitpoints-max", + "dungeon-level", + "experience", + "condition", +}; #ifdef STATUS_HILITES static int FDECL(condcolor, (long, unsigned long *)); @@ -3509,6 +3537,9 @@ const char *str; str = nb - 2; } nb = str; + if (iflags.debug.ttystatus) + dump_display_status("status_putstr (before)", st_fld, cw, str); + for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { if (!*nb) { #ifndef STATUS_HILITES @@ -3539,6 +3570,8 @@ const char *str; if (*ob) ob++; } + if (iflags.debug.ttystatus) + dump_display_status("status_putsr (after)", st_fld, cw, str); (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1); cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */ @@ -3654,7 +3687,11 @@ unsigned long *colormasks; tty_status[NOW][fldidx].lth += 2; /* [ and ] */ if (fldidx == BL_GOLD) tty_status[NOW][fldidx].lth -= 9; /* \GXXXXNNNN counts as 1 */ - + + /* debugging log */ + if (iflags.debug.ttystatus) + dump_tty_status("tty_status_update", fldidx); + if (check_fields(force_update)) render_status(); return; @@ -3703,10 +3740,22 @@ boolean forcefields; * Then, status_putstr() will see that flag setting * and ensure that the tty cell content is updated. */ + if (valid && iflags.debug.ttystatus) { + char buf[BUFSZ]; + + Sprintf(buf, "check_fields: forcefields=%s, name=%s\n" + "\t\t\"%s\"", + forcefields ? "TRUE" : "FALSE", + fieldnames[idx], + status_vals[idx]); + testinglog("ttystatus", buf, ""); + } + if (forcefields || update_right || tty_status[NOW][idx].color != tty_status[BEFORE][idx].color || tty_status[NOW][idx].attr != tty_status[BEFORE][idx].attr) tty_status[NOW][idx].redraw = TRUE; + if (iflags.debug.ttystatus) dump_tty_status("", idx); col += tty_status[NOW][idx].lth; } } @@ -3774,6 +3823,8 @@ render_status(VOID_ARGS) st_fld = fldidx; /* for status_putstr() */ tty_curs(WIN_STATUS, x, y); + if (iflags.debug.ttystatus) + dump_tty_status("render_status (before)", st_fld); if (st_fld == BL_CONDITION) { /* * +-----------------+ @@ -3881,6 +3932,8 @@ render_status(VOID_ARGS) } /* reset .redraw */ tty_status[NOW][st_fld].redraw = FALSE; + if (iflags.debug.ttystatus) + dump_tty_status("render_status (after)", st_fld); /* * Make a copy of the entire tty_status struct for comparison * of current and previous. @@ -3946,6 +3999,66 @@ unsigned long *bmarray; } return attr; } + +void +dump_display_status(descr, idx, cw, str) +const char *descr; +int idx; +struct WinDesc *cw; +const char *str; +{ + boolean buf[BUFSZ]; + const char *d2 = descr ? descr : "dump_Display_status"; + + Sprintf(buf, + "\t\t\"%s\"\n" + "\t\t%s = %d [%s], %s = %d, %s = %s\n" + "\t\t" + "%-17s = (%d,%d)\n" + "\t\t" + "%-17s = (%d,%d)\n" + "\t\t" + "%-17s = (%d,%d)\n", + str, + "idx", idx, fieldnames[idx], + "lth", tty_status[NOW][idx].lth, + "redraw",tty_status[NOW][idx].redraw ? "TRUE" : "FALSE", + "x,y", tty_status[NOW][idx].x, tty_status[NOW][idx].y, + "ttyDisplay->x,->y", ttyDisplay->curx, ttyDisplay->cury, + "cw->curx,->cury", cw->curx, cw->cury); + testinglog("ttystatus", d2, buf); + return; +} + +void +dump_tty_status(descr, idx) +const char *descr; +int idx; +{ + boolean buf[BUFSZ]; + const char *d2 = descr ? descr : "dump_status"; + + Sprintf(buf, + "\t\t%-6s = %s\n" + "\t\t%-6s = %d\n" + "\t\t%-6s = %d\n" + "\t\t%-6s = %X\n" + "\t\t%-6s = %d,%d\n" + "\t\t%-6s = %d\n" + "\t\t%-6s = %s\n" + "\t\t%-6s = %s\n", + "name", fieldnames[idx], + "idx", idx, + "color", tty_status[NOW][idx].color, + "attr", tty_status[NOW][idx].attr, + "x,y", tty_status[NOW][idx].x, tty_status[NOW][idx].y, + "lth", tty_status[NOW][idx].lth, + "valid", tty_status[NOW][idx].valid ? "TRUE" : "FALSE", + "redraw",tty_status[NOW][idx].redraw ? "TRUE" : "FALSE"); + testinglog("ttystatus", d2, buf); + return; +} + #endif /* STATUS_HILITES */ #endif /* TTY_GRAPHICS */ From 04c85aa59d23357cc9188def53fd8c5e0118c816 Mon Sep 17 00:00:00 2001 From: nhmall Date: Thu, 10 May 2018 18:54:58 -0400 Subject: [PATCH 18/25] update files.c with testinglog --- src/files.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/files.c b/src/files.c index 8a490d09e..cd5277acb 100644 --- a/src/files.c +++ b/src/files.c @@ -3542,7 +3542,7 @@ const char *dir UNUSED_if_not_OS2_CODEVIEW; /* ---------- END SCOREBOARD CREATION ----------- */ -/* ---------- BEGIN PANIC/IMPOSSIBLE LOG ----------- */ +/* ---------- BEGIN PANIC/IMPOSSIBLE/TESTING LOG ----------- */ /*ARGSUSED*/ void @@ -3579,7 +3579,31 @@ const char *reason; /* explanation */ return; } -/* ---------- END PANIC/IMPOSSIBLE LOG ----------- */ +/*ARGSUSED*/ +void +testinglog(filenm, type, reason) +const char *filenm; /* ad hoc file name */ +const char *type; +const char *reason; /* explanation */ +{ + FILE *lfile; + char fnbuf[BUFSZ]; + + if (!filenm) return; + Strcpy(fnbuf, filenm); + if (index(fnbuf, '.') == 0) + Strcat(fnbuf, ".log"); + lfile = fopen_datafile(fnbuf, "a", TROUBLEPREFIX); + if (lfile) { + time_t now = getnow(); + int uid = getuid(); + (void) fprintf(lfile, "%s\n%s\n", type, reason); + (void) fclose(lfile); + } + return; +} + +/* ---------- END PANIC/IMPOSSIBLE/TESTING LOG ----------- */ #ifdef SELF_RECOVER From dd04f5fcb551294e59853c58fbf0eb7d71d4936e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 May 2018 01:04:57 -0400 Subject: [PATCH 19/25] more tty-status updates --- include/extern.h | 2 + src/mapglyph.c | 135 ++++++++++++------------ win/tty/wintty.c | 262 +++++++++++++---------------------------------- 3 files changed, 147 insertions(+), 252 deletions(-) diff --git a/include/extern.h b/include/extern.h index 4535f8769..8ef6e617f 100644 --- a/include/extern.h +++ b/include/extern.h @@ -786,6 +786,7 @@ E void NDECL(read_wizkit); E int FDECL(read_sym_file, (int)); E int FDECL(parse_sym_line, (char *, int)); E void FDECL(paniclog, (const char *, const char *)); +E void FDECL(testinglog, (const char *, const char *, const char *)); E int FDECL(validate_prefix_locations, (char *)); #ifdef SELECTSAVED E char *FDECL(plname_from_file, (const char *)); @@ -1157,6 +1158,7 @@ E boolean FDECL(usmellmon, (struct permonst *)); E int FDECL(mapglyph, (int, int *, int *, unsigned *, int, int)); E char *FDECL(encglyph, (int)); +E char *FDECL(decode_mixed, (char *,const char *)); E void FDECL(genl_putmixed, (winid, int, const char *)); /* ### mcastu.c ### */ diff --git a/src/mapglyph.c b/src/mapglyph.c index 4ba4ee7e6..ca7e5ca33 100644 --- a/src/mapglyph.c +++ b/src/mapglyph.c @@ -247,6 +247,77 @@ int glyph; return encbuf; } +char * +decode_mixed(buf, str) +char *buf; +const char *str; +{ + static const char hex[] = "00112233445566778899aAbBcCdDeEfF"; + char *put = buf; + + if (!put || !str) + return ""; + + while (*str) { + if (*str == '\\') { + int rndchk, dcount, so, gv, ch = 0, oc = 0; + unsigned os = 0; + const char *dp, *save_str; + + save_str = str++; + switch (*str) { + case 'G': /* glyph value \GXXXXNNNN*/ + rndchk = dcount = 0; + for (++str; *str && ++dcount <= 4; ++str) + if ((dp = index(hex, *str)) != 0) + rndchk = (rndchk * 16) + ((int) (dp - hex) / 2); + else + break; + if (rndchk == context.rndencode) { + gv = dcount = 0; + for (; *str && ++dcount <= 4; ++str) + if ((dp = index(hex, *str)) != 0) + gv = (gv * 16) + ((int) (dp - hex) / 2); + else + break; + so = mapglyph(gv, &ch, &oc, &os, 0, 0); + *put++ = showsyms[so]; + /* 'str' is ready for the next loop iteration and '*str' + should not be copied at the end of this iteration */ + continue; + } else { + /* possible forgery - leave it the way it is */ + str = save_str; + } + break; +#if 0 + case 'S': /* symbol offset */ + so = rndchk = dcount = 0; + for (++str; *str && ++dcount <= 4; ++str) + if ((dp = index(hex, *str)) != 0) + rndchk = (rndchk * 16) + ((int) (dp - hex) / 2); + else + break; + if (rndchk == context.rndencode) { + dcount = 0; + for (; *str && ++dcount <= 2; ++str) + if ((dp = index(hex, *str)) != 0) + so = (so * 16) + ((int) (dp - hex) / 2); + else + break; + } + *put++ = showsyms[so]; + break; +#endif + case '\\': + break; + } + } + *put++ = *str++; + } + *put = '\0'; +} + /* * This differs from putstr() because the str parameter can * contain a sequence of characters representing: @@ -265,71 +336,9 @@ winid window; int attr; const char *str; { - static const char hex[] = "00112233445566778899aAbBcCdDeEfF"; char buf[BUFSZ]; - const char *cp = str; - char *put = buf; - - while (*cp) { - if (*cp == '\\') { - int rndchk, dcount, so, gv, ch = 0, oc = 0; - unsigned os = 0; - const char *dp, *save_cp; - - save_cp = cp++; - switch (*cp) { - case 'G': /* glyph value \GXXXXNNNN*/ - rndchk = dcount = 0; - for (++cp; *cp && ++dcount <= 4; ++cp) - if ((dp = index(hex, *cp)) != 0) - rndchk = (rndchk * 16) + ((int) (dp - hex) / 2); - else - break; - if (rndchk == context.rndencode) { - gv = dcount = 0; - for (; *cp && ++dcount <= 4; ++cp) - if ((dp = index(hex, *cp)) != 0) - gv = (gv * 16) + ((int) (dp - hex) / 2); - else - break; - so = mapglyph(gv, &ch, &oc, &os, 0, 0); - *put++ = showsyms[so]; - /* 'cp' is ready for the next loop iteration and '*cp' - should not be copied at the end of this iteration */ - continue; - } else { - /* possible forgery - leave it the way it is */ - cp = save_cp; - } - break; -#if 0 - case 'S': /* symbol offset */ - so = rndchk = dcount = 0; - for (++cp; *cp && ++dcount <= 4; ++cp) - if ((dp = index(hex, *cp)) != 0) - rndchk = (rndchk * 16) + ((int) (dp - hex) / 2); - else - break; - if (rndchk == context.rndencode) { - dcount = 0; - for (; *cp && ++dcount <= 2; ++cp) - if ((dp = index(hex, *cp)) != 0) - so = (so * 16) + ((int) (dp - hex) / 2); - else - break; - } - *put++ = showsyms[so]; - break; -#endif - case '\\': - break; - } - } - *put++ = *cp++; - } - *put = '\0'; /* now send it to the normal putstr */ - putstr(window, attr, buf); + putstr(window, attr, decode_mixed(buf, str)); } /*mapglyph.c*/ diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 55f66ded3..50d9c98ef 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -176,12 +176,9 @@ STATIC_DCL void FDECL(setup_racemenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL boolean NDECL(reset_role_filtering); -STATIC_DCL void FDECL(status_putstr, (winid, struct WinDesc *, const char *)); STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P)); STATIC_DCL void NDECL(render_status); -STATIC_DCL void FDECL(dump_tty_status, (const char *, int)); -STATIC_DCL void FDECL(dump_display_status, (const char *, int, - struct WinDesc *, const char *)); +STATIC_DCL void FDECL(tty_putstatusfield, (struct tty_status_fields *, const char *, int, int)); /* * A string containing all the default commands -- to add to a list @@ -2529,9 +2526,6 @@ const char *str; update_topl(str); break; - case NHW_STATUS: - status_putstr(window, cw, str); - break; case NHW_MAP: tty_curs(window, cw->curx + 1, cw->cury); term_start_attr(attr); @@ -3406,30 +3400,13 @@ extern const char *status_fieldfmt[MAXBLSTATS]; extern char *status_vals[MAXBLSTATS]; extern boolean status_activefields[MAXBLSTATS]; extern winid WIN_STATUS; + const char *fieldnames[] = { - "title", - "strength", - "dexterity", - "constitution", - "intelligence", - "wisdom", - "charisma", - "alignment", - "score", - "carrying-capacity", - "gold", - "power", - "power-max", - "experience-level", - "armor-class", - "HD", - "time", - "hunger", - "hitpoints", - "hitpoints-max", - "dungeon-level", - "experience", - "condition", + "title", "strength", "dexterity", "constitution", "intelligence", + "wisdom", "charisma", "alignment", "score", "carrying-capacity", + "gold", "power", "power-max", "experience-level", "armor-class", + "HD", "time", "hunger", "hitpoints", "hitpoints-max", + "dungeon-level", "experience", "condition", }; #ifdef STATUS_HILITES @@ -3438,6 +3415,7 @@ static int FDECL(condattr, (long, unsigned long *)); static long tty_condition_bits; static unsigned long *tty_colormasks; static struct tty_status_fields { + int idx; int color; int attr; int x, y; @@ -3488,6 +3466,7 @@ tty_status_init() int i; for (i = 0; i < MAXBLSTATS; ++i) { + tty_status[NOW][i].idx = -1; tty_status[NOW][i].color = NO_COLOR; /* no color */ tty_status[NOW][i].attr = ATR_NONE; tty_status[NOW][i].x = 0; @@ -3504,84 +3483,6 @@ tty_status_init() genl_status_init(); } -/* - * status_putstr() is not intended to be called directly - * by anything other than tty_putstr(). tty_putstr() - * does the prereq validations, and initializations of - * window and cw. - * - * Moving the status handling code here from tty_putstr() - * allows access to status data structures defined just - * above, rather than up top, with the additional bonus - * of having most status-related code bits fairly close - * together. - * - */ -static void -status_putstr(window, cw, str) -winid window; -struct WinDesc *cw; -const char *str; -{ - char *ob; - long i, j, n0; - const char *nb; - - ob = &cw->data[cw->cury][j = cw->curx]; - if (context.botlx) - *ob = 0; - if (!cw->cury && (int) strlen(str) >= CO) { - /* the characters before "St:" are unnecessary */ - nb = index(str, ':'); - if (nb && nb > str + 2) - str = nb - 2; - } - nb = str; - if (iflags.debug.ttystatus) - dump_display_status("status_putstr (before)", st_fld, cw, str); - - for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { - if (!*nb) { -#ifndef STATUS_HILITES - if (*ob || context.botlx) { -#else - if (context.botlx) { -#endif - /* last char printed may be in middle of line */ - tty_curs(WIN_STATUS, i, cw->cury); - cl_end(); - } - break; - } -#ifndef STATUS_HILITES - if (*ob != *nb) { -#else - if (*ob != *nb || tty_status[NOW][st_fld].redraw) { -#endif - tty_putsym(WIN_STATUS, i, cw->cury, *nb); - } -#ifdef STATUS_HILITES - else { - tty_curs(WIN_STATUS, i, cw->cury); - ttyDisplay->curx++; - cw->curx++; - } -#endif - if (*ob) - ob++; - } - if (iflags.debug.ttystatus) - dump_display_status("status_putsr (after)", st_fld, cw, str); - - (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1); - cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */ -#ifndef STATUS_HILITES - cw->cury = (cw->cury + 1) % 2; - cw->curx = 0; -#endif - return; -} - #ifdef STATUS_HILITES /* @@ -3662,6 +3563,7 @@ unsigned long *colormasks; case BL_CONDITION: tty_condition_bits = *condptr; tty_colormasks = colormasks; + tty_status[NOW][fldidx].idx = fldidx; tty_status[NOW][fldidx].valid = TRUE; break; default: @@ -3672,6 +3574,7 @@ unsigned long *colormasks; : NO_COLOR; tty_status[NOW][fldidx].attr = (color & 0xFF00) >> 8; tty_status[NOW][fldidx].lth = strlen(status_vals[fldidx]); + tty_status[NOW][fldidx].idx = fldidx; tty_status[NOW][fldidx].valid = TRUE; break; } @@ -3797,6 +3700,7 @@ render_status(VOID_ARGS) int i, c, row, shrinklvl = 0, attrmask = 0; struct WinDesc *cw = 0; boolean do_color = FALSE; + struct tty_status_fields *nullfield = (struct tty_status_fields *)0; #ifdef TEXTCOLOR do_color = TRUE; @@ -3821,10 +3725,7 @@ render_status(VOID_ARGS) char *text = status_vals[fldidx]; boolean hitpointbar = (fldidx == BL_TITLE && iflags.wc2_hitpointbar); - st_fld = fldidx; /* for status_putstr() */ - tty_curs(WIN_STATUS, x, y); - if (iflags.debug.ttystatus) - dump_tty_status("render_status (before)", st_fld); + st_fld = fldidx; if (st_fld == BL_CONDITION) { /* * +-----------------+ @@ -3832,9 +3733,9 @@ render_status(VOID_ARGS) * +-----------------+ */ for (c = 0; c < SIZE(conditions); ++c) { - mask = conditions[c].mask; + mask = conditions[c].mask; if ((tty_condition_bits & mask) == mask) { - tty_putstr(WIN_STATUS, 0, " "); + tty_putstatusfield(nullfield, " ", x++, y); if (iflags.hilite_delta) { attrmask = condattr(mask, tty_colormasks); Begin_Attr(attrmask); @@ -3844,8 +3745,9 @@ render_status(VOID_ARGS) term_start_color(coloridx); } } - tty_putstr(WIN_STATUS, 0, - conditions[c].text[shrinklvl]); + tty_putstatusfield(nullfield, + conditions[c].text[shrinklvl], x, y); + x += (int) strlen(conditions[c].text[shrinklvl]); if (iflags.hilite_delta) { if (do_color && coloridx != NO_COLOR) term_end_color(); @@ -3853,14 +3755,18 @@ render_status(VOID_ARGS) } } } + tty_curs(WIN_STATUS, x, y); + cl_end(); } else if (st_fld == BL_GOLD) { + char buf[BUFSZ]; /* * +-----------+ * | Gold | * +-----------+ */ - /* putmixed() due to GOLD glyph */ - putmixed(WIN_STATUS, 0, text); + /* decode_mixed() due to GOLD glyph */ + tty_putstatusfield(nullfield, + decode_mixed(buf, text), x, y); } else if (hitpointbar) { /* * +-------------------------+ @@ -3888,22 +3794,26 @@ render_status(VOID_ARGS) *bar2 = '\0'; } } - if (iflags.hilite_delta && iflags.wc2_hitpointbar) { - tty_putstr(WIN_STATUS, 0, "["); + if (iflags.hilite_delta) { + tty_putstatusfield(nullfield, "[", x++, y); if (do_color && hpbar_color != NO_COLOR) term_start_color(hpbar_color); term_start_attr(ATR_INVERSE); - tty_putstr(WIN_STATUS, 0, bar); + tty_putstatusfield(nullfield, bar, x, y); + x += (int) strlen(bar); term_end_attr(ATR_INVERSE); if (do_color && hpbar_color != NO_COLOR) term_end_color(); if (twoparts) { *bar2 = savedch; - tty_putstr(WIN_STATUS, 0, bar2); + tty_putstatusfield(nullfield, bar2, x, y); + x += (int) strlen(bar2); + tty_curs(WIN_STATUS, x, y); } - tty_putstr(WIN_STATUS, 0, "]"); + tty_putstatusfield(nullfield, "]", x++, y); } else { - tty_putstr(WIN_STATUS, 0, text); + tty_putstatusfield(&tty_status[NOW][fldidx], + (char *)0, x, y); } } else { /* @@ -3914,7 +3824,7 @@ render_status(VOID_ARGS) */ if (iflags.hilite_delta) { if (*text == ' ') { - tty_putstr(WIN_STATUS, 0, " "); + tty_putstatusfield(nullfield, " ", x++, y); text++; } /* multiple attributes can be in effect concurrently */ @@ -3923,7 +3833,8 @@ render_status(VOID_ARGS) && coloridx != CLR_MAX) term_start_color(coloridx); } - tty_putstr(WIN_STATUS, 0, text); + tty_putstatusfield(&tty_status[NOW][fldidx], + text, x, y); if (iflags.hilite_delta) { if (do_color && coloridx != NO_COLOR) term_end_color(); @@ -3932,8 +3843,6 @@ render_status(VOID_ARGS) } /* reset .redraw */ tty_status[NOW][st_fld].redraw = FALSE; - if (iflags.debug.ttystatus) - dump_tty_status("render_status (after)", st_fld); /* * Make a copy of the entire tty_status struct for comparison * of current and previous. @@ -3941,12 +3850,45 @@ render_status(VOID_ARGS) tty_status[BEFORE][st_fld] = tty_status[NOW][st_fld]; /* copy struct */ } } - tty_curs(WIN_STATUS, cw->curx+1, cw->cury); - cl_end(); } return; } +void +tty_putstatusfield(fld, val, x, y) +struct tty_status_fields *fld; +const char *val; +int x,y; +{ + int i, ncols, lth; + struct WinDesc *cw = 0; + const char *text = (char *)0; + + if ((cw = wins[NHW_STATUS]) == (struct WinDesc *) 0) + panic("Invalid WinDesc\n"); + + ncols = cw->cols; + if (val) { + text = val; + lth = strlen(text); + } else if (fld) { + text = status_vals[fld->idx]; + lth = fld->lth; + } + if (!text) return; + + print_vt_code2(AVTC_SELECT_WINDOW, NHW_STATUS); + + tty_curs(NHW_STATUS, x, y); + for (i = 0; i < lth; ++i) { + if ((i + x ) < ncols) { + (void) putchar(*text++); + ttyDisplay->curx++; + cw->curx++; + } + } +} + #ifdef TEXTCOLOR /* * Return what color this condition should @@ -4000,67 +3942,9 @@ unsigned long *bmarray; return attr; } -void -dump_display_status(descr, idx, cw, str) -const char *descr; -int idx; -struct WinDesc *cw; -const char *str; -{ - boolean buf[BUFSZ]; - const char *d2 = descr ? descr : "dump_Display_status"; - - Sprintf(buf, - "\t\t\"%s\"\n" - "\t\t%s = %d [%s], %s = %d, %s = %s\n" - "\t\t" - "%-17s = (%d,%d)\n" - "\t\t" - "%-17s = (%d,%d)\n" - "\t\t" - "%-17s = (%d,%d)\n", - str, - "idx", idx, fieldnames[idx], - "lth", tty_status[NOW][idx].lth, - "redraw",tty_status[NOW][idx].redraw ? "TRUE" : "FALSE", - "x,y", tty_status[NOW][idx].x, tty_status[NOW][idx].y, - "ttyDisplay->x,->y", ttyDisplay->curx, ttyDisplay->cury, - "cw->curx,->cury", cw->curx, cw->cury); - testinglog("ttystatus", d2, buf); - return; -} - -void -dump_tty_status(descr, idx) -const char *descr; -int idx; -{ - boolean buf[BUFSZ]; - const char *d2 = descr ? descr : "dump_status"; - - Sprintf(buf, - "\t\t%-6s = %s\n" - "\t\t%-6s = %d\n" - "\t\t%-6s = %d\n" - "\t\t%-6s = %X\n" - "\t\t%-6s = %d,%d\n" - "\t\t%-6s = %d\n" - "\t\t%-6s = %s\n" - "\t\t%-6s = %s\n", - "name", fieldnames[idx], - "idx", idx, - "color", tty_status[NOW][idx].color, - "attr", tty_status[NOW][idx].attr, - "x,y", tty_status[NOW][idx].x, tty_status[NOW][idx].y, - "lth", tty_status[NOW][idx].lth, - "valid", tty_status[NOW][idx].valid ? "TRUE" : "FALSE", - "redraw",tty_status[NOW][idx].redraw ? "TRUE" : "FALSE"); - testinglog("ttystatus", d2, buf); - return; -} - #endif /* STATUS_HILITES */ #endif /* TTY_GRAPHICS */ /*wintty.c*/ + From d0e508241b23938d25963553cdec6b25d075e077 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 May 2018 01:07:54 -0400 Subject: [PATCH 20/25] missing return value --- src/mapglyph.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/mapglyph.c b/src/mapglyph.c index ca7e5ca33..587d317c8 100644 --- a/src/mapglyph.c +++ b/src/mapglyph.c @@ -316,6 +316,7 @@ const char *str; *put++ = *str++; } *put = '\0'; + return buf; } /* From a3ba46d73278625522155148238ab6971f287c12 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 May 2018 01:10:43 -0400 Subject: [PATCH 21/25] remove some debug code --- win/tty/wintty.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 50d9c98ef..ad29a4650 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3591,10 +3591,6 @@ unsigned long *colormasks; if (fldidx == BL_GOLD) tty_status[NOW][fldidx].lth -= 9; /* \GXXXXNNNN counts as 1 */ - /* debugging log */ - if (iflags.debug.ttystatus) - dump_tty_status("tty_status_update", fldidx); - if (check_fields(force_update)) render_status(); return; @@ -3630,35 +3626,16 @@ boolean forcefields; if (tty_status[NOW][idx].lth != tty_status[BEFORE][idx].lth) update_right = TRUE; /* - * status_putstr(), called from tty_putstr() checks - * whether individual tty cell text content matches what - * was already there and optimizes by leaving it be. - * Checking the text iself was sufficient back when the - * status lines were monochrome and of a single - * attribute style. - * * With STATUS_HILITES, it is possible that the color * needs to change even if the text is the same, so * we flag that here by setting .redraw. * Then, status_putstr() will see that flag setting * and ensure that the tty cell content is updated. */ - if (valid && iflags.debug.ttystatus) { - char buf[BUFSZ]; - - Sprintf(buf, "check_fields: forcefields=%s, name=%s\n" - "\t\t\"%s\"", - forcefields ? "TRUE" : "FALSE", - fieldnames[idx], - status_vals[idx]); - testinglog("ttystatus", buf, ""); - } - if (forcefields || update_right || tty_status[NOW][idx].color != tty_status[BEFORE][idx].color || tty_status[NOW][idx].attr != tty_status[BEFORE][idx].attr) tty_status[NOW][idx].redraw = TRUE; - if (iflags.debug.ttystatus) dump_tty_status("", idx); col += tty_status[NOW][idx].lth; } } From ba057ef3de1815eb3f01d076f3601d64931fbb0c Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 May 2018 02:18:42 -0400 Subject: [PATCH 22/25] condition shrinkage when required --- win/tty/wintty.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index ad29a4650..ffc8ccadb 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -179,6 +179,7 @@ STATIC_DCL boolean NDECL(reset_role_filtering); STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P)); STATIC_DCL void NDECL(render_status); STATIC_DCL void FDECL(tty_putstatusfield, (struct tty_status_fields *, const char *, int, int)); +STATIC_DCL int FDECL(set_cond_shrinklvl, (int, int)); /* * A string containing all the default commands -- to add to a list @@ -3676,7 +3677,7 @@ render_status(VOID_ARGS) long mask = 0L; int i, c, row, shrinklvl = 0, attrmask = 0; struct WinDesc *cw = 0; - boolean do_color = FALSE; + boolean do_color = FALSE, fit = FALSE; struct tty_status_fields *nullfield = (struct tty_status_fields *)0; #ifdef TEXTCOLOR @@ -3709,6 +3710,7 @@ render_status(VOID_ARGS) * | Condition Codes | * +-----------------+ */ + shrinklvl = set_cond_shrinklvl(x, cw->cols); for (c = 0; c < SIZE(conditions); ++c) { mask = conditions[c].mask; if ((tty_condition_bits & mask) == mask) { @@ -3866,6 +3868,33 @@ int x,y; } } +int +set_cond_shrinklvl(col, ncols) +int col, ncols; +{ + long mask = 0L; + int j, c, x, avail, shrinklvl = 0; + boolean fitting = FALSE; + + avail = ncols - col; + /* determine appropriate shrinklvl required */ + for (j = 0; j < 3 && !fitting; ++j) { + x = 0; + for (c = 0; c < SIZE(conditions); ++c) { + mask = conditions[c].mask; + if ((tty_condition_bits & mask) == mask) { + x++; /* for spacer */ + x += (int) strlen(conditions[c].text[shrinklvl]); + } + } + if (x < avail) + fitting = TRUE; + else if (shrinklvl < 2) + shrinklvl++; + } + return shrinklvl; +} + #ifdef TEXTCOLOR /* * Return what color this condition should From 9a87064ccae39289dd26f0b64b2020c76471d50e Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 May 2018 06:57:34 -0400 Subject: [PATCH 23/25] some build fixes for compile issues reported --- include/extern.h | 2 +- include/wintty.h | 12 +++++++++ src/allmain.c | 1 - src/mapglyph.c | 2 +- win/tty/wintty.c | 63 +++++++++++++++++++++++++++++++++--------------- 5 files changed, 58 insertions(+), 22 deletions(-) diff --git a/include/extern.h b/include/extern.h index 8ef6e617f..96a5ade8b 100644 --- a/include/extern.h +++ b/include/extern.h @@ -1158,7 +1158,7 @@ E boolean FDECL(usmellmon, (struct permonst *)); E int FDECL(mapglyph, (int, int *, int *, unsigned *, int, int)); E char *FDECL(encglyph, (int)); -E char *FDECL(decode_mixed, (char *,const char *)); +E const char *FDECL(decode_mixed, (char *,const char *)); E void FDECL(genl_putmixed, (winid, int, const char *)); /* ### mcastu.c ### */ diff --git a/include/wintty.h b/include/wintty.h index 1f270128f..4ff0ddb3c 100644 --- a/include/wintty.h +++ b/include/wintty.h @@ -69,6 +69,18 @@ struct DisplayDesc { #endif /* WINDOW_STRUCTS */ +#ifdef STATUS_HILITES +struct tty_status_fields { + int idx; + int color; + int attr; + int x, y; + size_t lth; + boolean valid; + boolean redraw; +}; +#endif + #define MAXWIN 20 /* maximum number of windows, cop-out */ /* tty dependent window types */ diff --git a/src/allmain.c b/src/allmain.c index 569c6e456..2c1364d75 100644 --- a/src/allmain.c +++ b/src/allmain.c @@ -854,7 +854,6 @@ const char *opts; { char *op; boolean negated = FALSE; - boolean retval = TRUE; while ((op = index(opts, ',')) != 0) { *op++ = 0; diff --git a/src/mapglyph.c b/src/mapglyph.c index 587d317c8..04ef068e9 100644 --- a/src/mapglyph.c +++ b/src/mapglyph.c @@ -247,7 +247,7 @@ int glyph; return encbuf; } -char * +const char * decode_mixed(buf, str) char *buf; const char *str; diff --git a/win/tty/wintty.c b/win/tty/wintty.c index ffc8ccadb..821859efa 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -176,10 +176,13 @@ STATIC_DCL void FDECL(setup_racemenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_gendmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL void FDECL(setup_algnmenu, (winid, BOOLEAN_P, int, int, int)); STATIC_DCL boolean NDECL(reset_role_filtering); +#ifdef STATUS_HILITES STATIC_DCL boolean FDECL(check_fields, (BOOLEAN_P)); STATIC_DCL void NDECL(render_status); -STATIC_DCL void FDECL(tty_putstatusfield, (struct tty_status_fields *, const char *, int, int)); +STATIC_DCL void FDECL(tty_putstatusfield, (struct tty_status_fields *, + const char *, int, int)); STATIC_DCL int FDECL(set_cond_shrinklvl, (int, int)); +#endif /* * A string containing all the default commands -- to add to a list @@ -2494,7 +2497,6 @@ const char *str; register struct WinDesc *cw = 0; register char *ob; register long i, n0; - boolean attr_match = FALSE; /* Assume there's a real problem if the window is missing -- * probably a panic message @@ -2507,11 +2509,7 @@ const char *str; if (str == (const char *) 0 || ((cw->flags & WIN_CANCELLED) && (cw->type != NHW_MESSAGE))) return; -#ifndef STATUS_HILITES if (cw->type != NHW_MESSAGE) -#else - if (cw->type != NHW_MESSAGE && cw->type != NHW_STATUS) -#endif str = compress_str(str); ttyDisplay->lastwin = window; @@ -2526,7 +2524,39 @@ const char *str; #endif update_topl(str); break; +#ifndef STATUS_HILITES + case NHW_STATUS: + ob = &cw->data[cw->cury][j = cw->curx]; + if (context.botlx) + *ob = 0; + if (!cw->cury && (int) strlen(str) >= CO) { + /* the characters before "St:" are unnecessary */ + nb = index(str, ':'); + if (nb && nb > str + 2) + str = nb - 2; + } + nb = str; + for (i = cw->curx + 1, n0 = cw->cols; i < n0; i++, nb++) { + if (!*nb) { + if (*ob || context.botlx) { + /* last char printed may be in middle of line */ + tty_curs(WIN_STATUS, i, cw->cury); + cl_end(); + } + break; + } + if (*ob != *nb) + tty_putsym(WIN_STATUS, i, cw->cury, *nb); + if (*ob) + ob++; + } + (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1); + cw->data[cw->cury][cw->cols - 1] = '\0'; /* null terminate */ + cw->cury = (cw->cury + 1) % 2; + cw->curx = 0; + break; +#endif /* STATUS_HILITES */ case NHW_MAP: tty_curs(window, cw->curx + 1, cw->cury); term_start_attr(attr); @@ -3415,20 +3445,15 @@ static int FDECL(condcolor, (long, unsigned long *)); static int FDECL(condattr, (long, unsigned long *)); static long tty_condition_bits; static unsigned long *tty_colormasks; -static struct tty_status_fields { - int idx; - int color; - int attr; - int x, y; - size_t lth; - boolean valid; - boolean redraw; -} tty_status[2][MAXBLSTATS]; +static struct tty_status_fields + tty_status[2][MAXBLSTATS]; /* 2: first index is for current + and previous */ static int st_fld; -int hpbar_percent, hpbar_color; -struct condition_t { +static int hpbar_percent, hpbar_color; +static struct condition_t { long mask; - char *text[3]; /* 3 potential display values, progressively smaller */ + const char *text[3]; /* 3: potential display values, progressively + * smaller */ } conditions[] = { /* The sequence order of these matters */ { BL_MASK_STONE, {"Stone", "Ston", "Sto"}}, @@ -3445,7 +3470,7 @@ struct condition_t { { BL_MASK_FLY, {"Fly", "Fly", "Fl"}}, { BL_MASK_RIDE, {"Ride", "Rid", "Ri"}}, }; -enum statusfields fieldorder[2][15] = { +static enum statusfields fieldorder[2][15] = { /* 2: two status lines */ { BL_TITLE, BL_STR, BL_DX, BL_CO, BL_IN, BL_WI, BL_CH, BL_ALIGN, BL_SCORE, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH, BL_FLUSH }, From 3598fcc92999289663d005d981678a469e2ef352 Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 May 2018 14:10:52 -0400 Subject: [PATCH 24/25] more status handling updates Suppress unneeded spaces from a couple of fields BL_LEVELDESC - trailing spaces. BL_CAP - it only contains a space --- include/wintty.h | 1 + win/tty/wintty.c | 152 ++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 133 insertions(+), 20 deletions(-) diff --git a/include/wintty.h b/include/wintty.h index 4ff0ddb3c..a4a6625a5 100644 --- a/include/wintty.h +++ b/include/wintty.h @@ -77,6 +77,7 @@ struct tty_status_fields { int x, y; size_t lth; boolean valid; + boolean dirty; boolean redraw; }; #endif diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 821859efa..4562788db 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -182,6 +182,7 @@ STATIC_DCL void NDECL(render_status); STATIC_DCL void FDECL(tty_putstatusfield, (struct tty_status_fields *, const char *, int, int)); STATIC_DCL int FDECL(set_cond_shrinklvl, (int, int)); +STATIC_DCL boolean NDECL(check_windowdata); #endif /* @@ -3448,7 +3449,6 @@ static unsigned long *tty_colormasks; static struct tty_status_fields tty_status[2][MAXBLSTATS]; /* 2: first index is for current and previous */ -static int st_fld; static int hpbar_percent, hpbar_color; static struct condition_t { long mask; @@ -3478,7 +3478,21 @@ static enum statusfields fieldorder[2][15] = { /* 2: two status lines */ BL_AC, BL_XP, BL_EXP, BL_HD, BL_TIME, BL_HUNGER, BL_CAP, BL_CONDITION, BL_FLUSH } }; +static boolean windowdata_init = FALSE; +/* This controls whether to skip fields that aren't + * flagged as requiring updating during the current + * render_status(). + * + * Hopefully that can be confirmed as working correctly + * for all platforms eventually and the conditional + * setting below can be removed. + */ +#if defined(UNIX) +static int do_field_opt = 0; +#else +static int do_field_opt = 1; #endif +#endif /* STATUS_HILITES */ /* * tty_status_init() @@ -3497,7 +3511,8 @@ tty_status_init() tty_status[NOW][i].attr = ATR_NONE; tty_status[NOW][i].x = 0; tty_status[NOW][i].y = 0; - tty_status[NOW][i].valid = FALSE; + tty_status[NOW][i].valid = FALSE; + tty_status[NOW][i].dirty = FALSE; tty_status[NOW][i].redraw = FALSE; tty_status[BEFORE][i] = tty_status[NOW][i]; } @@ -3587,12 +3602,14 @@ unsigned long *colormasks; force_update = TRUE; break; case BL_CONDITION: + tty_status[NOW][fldidx].idx = fldidx; tty_condition_bits = *condptr; tty_colormasks = colormasks; - tty_status[NOW][fldidx].idx = fldidx; tty_status[NOW][fldidx].valid = TRUE; + tty_status[NOW][fldidx].dirty = TRUE; break; default: + tty_status[NOW][fldidx].idx = fldidx; Sprintf(status_vals[fldidx], status_fieldfmt[fldidx] ? status_fieldfmt[fldidx] : "%s", text); @@ -3600,8 +3617,9 @@ unsigned long *colormasks; : NO_COLOR; tty_status[NOW][fldidx].attr = (color & 0xFF00) >> 8; tty_status[NOW][fldidx].lth = strlen(status_vals[fldidx]); - tty_status[NOW][fldidx].idx = fldidx; tty_status[NOW][fldidx].valid = TRUE; + tty_status[NOW][fldidx].dirty = TRUE; + break; } @@ -3611,12 +3629,33 @@ unsigned long *colormasks; hpbar_color = do_color ? (color & 0x00FF) : NO_COLOR; } - /* special case fixups */ + /* The core botl engine sends a single blank to the window port + for carrying-capacity when its unused. Let's suppress that */ + if (tty_status[NOW][fldidx].lth == 1 && + status_vals[fldidx][0] == ' ') { + status_vals[fldidx][0] = '\0'; + tty_status[NOW][fldidx].lth = 0; + } + + /* The core botl engine sends BL_LEVELDESC with trailing blanks + included. Let's suppress one of the trailing blanks */ + if (fldidx == BL_LEVELDESC) { + char *lastchar = eos(status_vals[fldidx]); + lastchar--; + while (lastchar && *lastchar == ' ' + && lastchar >= status_vals[fldidx]) { + *lastchar-- = '\0'; + tty_status[NOW][fldidx].lth--; + } + } + + /* Some other special case fixups */ if (iflags.wc2_hitpointbar && fldidx == BL_TITLE) tty_status[NOW][fldidx].lth += 2; /* [ and ] */ if (fldidx == BL_GOLD) tty_status[NOW][fldidx].lth -= 9; /* \GXXXXNNNN counts as 1 */ + if (check_fields(force_update)) render_status(); return; @@ -3632,8 +3671,11 @@ boolean check_fields(forcefields) boolean forcefields; { - int i, row, col; - boolean valid = TRUE, update_right; + int c, i, row, col; + boolean valid = TRUE, matchprev = FALSE, update_right; + + if (!windowdata_init && !check_windowdata()) + return FALSE; for (row = 0; row < 2; ++row) { col = 1; @@ -3649,16 +3691,44 @@ boolean forcefields; tty_status[NOW][idx].y = row; tty_status[NOW][idx].x = col; + + /* evaluate */ if (tty_status[NOW][idx].lth != tty_status[BEFORE][idx].lth) update_right = TRUE; + + /* + * Check values against those already on the dislay. + * - Is the additional processing time for this worth it? + */ + matchprev = FALSE; + if (do_field_opt && tty_status[NOW][idx].dirty) { + /* compare values */ + const char *ob, *nb; /* old byte, new byte */ + + c = col - 1; + ob = &wins[WIN_STATUS]->data[row][c]; + nb = status_vals[idx]; + while (*nb && c < wins[WIN_STATUS]->cols) { + if (*nb != *ob) + break; + nb++; + ob++; + c++; + } + if (!*nb && c > col - 1) + matchprev = TRUE; + } + /* * With STATUS_HILITES, it is possible that the color * needs to change even if the text is the same, so * we flag that here by setting .redraw. - * Then, status_putstr() will see that flag setting + * Then, render_status() will see that flag setting * and ensure that the tty cell content is updated. - */ - if (forcefields || update_right + * After the field has been updated, render_status() + * will also clear .redraw. + */ + if (forcefields || update_right || !matchprev || tty_status[NOW][idx].color != tty_status[BEFORE][idx].color || tty_status[NOW][idx].attr != tty_status[BEFORE][idx].attr) tty_status[NOW][idx].redraw = TRUE; @@ -3711,7 +3781,7 @@ render_status(VOID_ARGS) if (WIN_STATUS == WIN_ERR || (cw = wins[WIN_STATUS]) == (struct WinDesc *) 0) { - paniclog("status", "WIN_ERR on status window."); + paniclog("render_status", "WIN_ERR on status window."); return; } @@ -3728,8 +3798,17 @@ render_status(VOID_ARGS) char *text = status_vals[fldidx]; boolean hitpointbar = (fldidx == BL_TITLE && iflags.wc2_hitpointbar); - st_fld = fldidx; - if (st_fld == BL_CONDITION) { + if (do_field_opt && !tty_status[NOW][fldidx].redraw) + continue; + + /* + * Ignore zero length fields. check_fields() didn't count + * them in either. + */ + if (!tty_status[NOW][fldidx].lth) + continue; + + if (fldidx == BL_CONDITION) { /* * +-----------------+ * | Condition Codes | @@ -3761,7 +3840,7 @@ render_status(VOID_ARGS) } tty_curs(WIN_STATUS, x, y); cl_end(); - } else if (st_fld == BL_GOLD) { + } else if (fldidx == BL_GOLD) { char buf[BUFSZ]; /* * +-----------+ @@ -3845,26 +3924,32 @@ render_status(VOID_ARGS) End_Attr(attridx); } } - /* reset .redraw */ - tty_status[NOW][st_fld].redraw = FALSE; + /* reset .redraw and .dirty now that they've been rendered */ + tty_status[NOW][fldidx].dirty = FALSE; + tty_status[NOW][fldidx].redraw = FALSE; /* * Make a copy of the entire tty_status struct for comparison * of current and previous. */ - tty_status[BEFORE][st_fld] = tty_status[NOW][st_fld]; /* copy struct */ + tty_status[BEFORE][fldidx] = tty_status[NOW][fldidx]; /* copy struct */ } } } return; } +/* + * This is what places a field on the tty display. + * If val isn't null, it will be used rather than + * fld (it takes precedence). + */ void tty_putstatusfield(fld, val, x, y) struct tty_status_fields *fld; const char *val; int x,y; { - int i, ncols, lth; + int i, n, ncols, lth; struct WinDesc *cw = 0; const char *text = (char *)0; @@ -3885,10 +3970,13 @@ int x,y; tty_curs(NHW_STATUS, x, y); for (i = 0; i < lth; ++i) { - if ((i + x ) < ncols) { - (void) putchar(*text++); + n = i + x; + if (n < ncols && *text) { + (void) putchar(*text); ttyDisplay->curx++; cw->curx++; + cw->data[y][n-1] = *text; + text++; } } } @@ -3920,6 +4008,30 @@ int col, ncols; return shrinklvl; } +/* + * Ensure the underlying status window data start out + * blank and null-terminated. + */ +boolean +check_windowdata(VOID_ARGS) +{ + if (WIN_STATUS == WIN_ERR || wins[WIN_STATUS] == (struct WinDesc *) 0) { + paniclog("check_windowdata", " null status window."); + return FALSE; + } else if (!windowdata_init) { + int i, n = wins[WIN_STATUS]->cols; + + for (i = 0; i < wins[WIN_STATUS]->cols; ++i) + wins[WIN_STATUS]->data[0][i] = ' '; + wins[WIN_STATUS]->data[0][n - 1] = '\0'; /* null terminate */ + for (i = 0; i < wins[WIN_STATUS]->cols; ++i) + wins[WIN_STATUS]->data[1][i] = ' '; + wins[WIN_STATUS]->data[0][n - 1] = '\0'; /* null terminate */ + windowdata_init = TRUE; + } + return TRUE; +} + #ifdef TEXTCOLOR /* * Return what color this condition should From 149fc5a4dd2854f3ee757d5575379f86da425eae Mon Sep 17 00:00:00 2001 From: nhmall Date: Sat, 12 May 2018 14:42:19 -0400 Subject: [PATCH 25/25] empty field suppression caught condition values unintentionally --- win/tty/wintty.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/win/tty/wintty.c b/win/tty/wintty.c index 4562788db..dbfc6d863 100644 --- a/win/tty/wintty.c +++ b/win/tty/wintty.c @@ -3631,8 +3631,8 @@ unsigned long *colormasks; /* The core botl engine sends a single blank to the window port for carrying-capacity when its unused. Let's suppress that */ - if (tty_status[NOW][fldidx].lth == 1 && - status_vals[fldidx][0] == ' ') { + if (tty_status[NOW][fldidx].lth == 1 + && status_vals[fldidx][0] == ' ') { status_vals[fldidx][0] = '\0'; tty_status[NOW][fldidx].lth = 0; } @@ -3805,7 +3805,7 @@ render_status(VOID_ARGS) * Ignore zero length fields. check_fields() didn't count * them in either. */ - if (!tty_status[NOW][fldidx].lth) + if (!tty_status[NOW][fldidx].lth && fldidx != BL_CONDITION) continue; if (fldidx == BL_CONDITION) {