From 17bf3daa5b900d1dc514ad58e3935ce584424b8d Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Sun, 14 Jan 2024 17:06:56 -0800 Subject: [PATCH 1/6] add basic letter alignment for text display --- src/brogue/IO.c | 42 ++++++++++++++++++++++---------- src/brogue/Rogue.h | 10 +++++++- src/platform/null-platform.c | 3 ++- src/platform/platform.h | 3 ++- src/platform/platformdependent.c | 5 ++-- src/platform/sdl2-platform.c | 5 ++-- src/platform/tiles.c | 14 ++++++++++- src/platform/tiles.h | 4 ++- 8 files changed, 64 insertions(+), 22 deletions(-) diff --git a/src/brogue/IO.c b/src/brogue/IO.c index a467f36e..12cce977 100644 --- a/src/brogue/IO.c +++ b/src/brogue/IO.c @@ -857,7 +857,9 @@ void commitDraws() { || lastPlotted->foreColorComponents[2] != curr->foreColorComponents[2] || lastPlotted->backColorComponents[0] != curr->backColorComponents[0] || lastPlotted->backColorComponents[1] != curr->backColorComponents[1] - || lastPlotted->backColorComponents[2] != curr->backColorComponents[2]; + || lastPlotted->backColorComponents[2] != curr->backColorComponents[2] + || lastPlotted->textInfo.mode != curr->textInfo.mode + || lastPlotted->textInfo.startColumn != curr->textInfo.startColumn; if (!needsUpdate) { continue; @@ -869,7 +871,8 @@ void commitDraws() { curr->foreColorComponents[2], curr->backColorComponents[0], curr->backColorComponents[1], - curr->backColorComponents[2] + curr->backColorComponents[2], + curr->textInfo ); *lastPlotted = *curr; } @@ -888,7 +891,8 @@ void refreshScreen() { curr->foreColorComponents[2], curr->backColorComponents[0], curr->backColorComponents[1], - curr->backColorComponents[2] + curr->backColorComponents[2], + curr->textInfo ); // Remember that it was previously plotted, so that // commitDraws still knows when it needs updates. @@ -1748,7 +1752,11 @@ void colorMultiplierFromDungeonLight(short x, short y, color *editColor) { editColor->colorDances = false; } +/// Calls `plotCharWithColorAndTextInfo` with a default `CellTextInfo` config. void plotCharWithColor(enum displayGlyph inputChar, windowpos loc, const color *cellForeColor, const color *cellBackColor) { + plotCharWithColorAndTextInfo(inputChar, loc, cellForeColor, cellBackColor, (CellTextInfo) { .mode = 0 }); +} +void plotCharWithColorAndTextInfo(enum displayGlyph inputChar, windowpos loc, const color *cellForeColor, const color *cellBackColor, CellTextInfo textInfo) { short oldRNG; short foreRed = cellForeColor->red, @@ -1806,6 +1814,9 @@ void plotCharWithColor(enum displayGlyph inputChar, windowpos loc, const color * target->backColorComponents[0] = backRed; target->backColorComponents[1] = backGreen; target->backColorComponents[2] = backBlue; + if (textInfo.mode != 0) { + target->textInfo = textInfo; + } restoreRNG; } @@ -1946,12 +1957,10 @@ void clearDisplayBuffer(screenDisplayBuffer *dbuf) { for (i=0; icells[i][j].character = ' '; - for (k=0; k<3; k++) { - dbuf->cells[i][j].foreColorComponents[k] = 0; - dbuf->cells[i][j].backColorComponents[k] = 0; - } - dbuf->cells[i][j].opacity = 0; + dbuf->cells[i][j] = (cellDisplayBuffer) { + // All other fields will be zeroed. + .character = ' ', + }; } } } @@ -1994,7 +2003,7 @@ void overlayDisplayBuffer(const screenDisplayBuffer *overBuf) { tempColor = colorFromComponents(displayBuffer.cells[i][j].backColorComponents); applyColorAverage(&backColor, &tempColor, 100 - overBuf->cells[i][j].opacity); - plotCharWithColor(character, (windowpos){ i, j }, &foreColor, &backColor); + plotCharWithColorAndTextInfo(character, (windowpos){ i, j }, &foreColor, &backColor, overBuf->cells[i][j].textInfo); } } } @@ -3239,6 +3248,10 @@ static void drawMessageArchive(char messages[MESSAGE_ARCHIVE_LINES][COLS*2], sho dbuf.cells[mapToWindowX(j)][i].foreColorComponents[k] = dbuf.cells[mapToWindowX(j)][i].foreColorComponents[k] * fadePercent / 100; } } + dbuf.cells[mapToWindowX(j)][i].textInfo = (CellTextInfo) { + .mode = 1, // text + .startColumn = mapToWindowX(0), + }; } } @@ -3630,9 +3643,12 @@ void updateMessageDisplay() { } } - plotCharWithColor(displayedMessage[i][m], (windowpos){ mapToWindowX(j), MESSAGE_LINES - i - 1 }, - &messageColor, - &black); + plotCharWithColorAndTextInfo( + displayedMessage[i][m], (windowpos){ mapToWindowX(j), MESSAGE_LINES - i - 1 }, + &messageColor, + &black, + (CellTextInfo) { .mode = 1, .startColumn = mapToWindowX(0) } + ); } for (; j < DCOLS; j++) { plotCharWithColor(' ', (windowpos){ mapToWindowX(j), MESSAGE_LINES - i - 1 }, &black, &black); diff --git a/src/brogue/Rogue.h b/src/brogue/Rogue.h index 4e71ce2f..f03859cd 100644 --- a/src/brogue/Rogue.h +++ b/src/brogue/Rogue.h @@ -1283,12 +1283,18 @@ enum dungeonLayers { NUMBER_TERRAIN_LAYERS }; +typedef struct CellTextInfo { + int mode; + int startColumn; +} CellTextInfo; + // keeps track of graphics so we only redraw if the cell has changed: typedef struct cellDisplayBuffer { enum displayGlyph character; char foreColorComponents[3]; char backColorComponents[3]; char opacity; + CellTextInfo textInfo; } cellDisplayBuffer; typedef struct screenDisplayBuffer { @@ -2884,7 +2890,8 @@ extern "C" { void plotChar(enum displayGlyph inputChar, short xLoc, short yLoc, short backRed, short backGreen, short backBlue, - short foreRed, short foreGreen, short foreBlue); + short foreRed, short foreGreen, short foreBlue, + CellTextInfo textInfo); typedef struct PauseBehavior { /// If `interuptForMouseMove` is true, then the pause function will return `true` @@ -2956,6 +2963,7 @@ extern "C" { void hiliteCell(short x, short y, const color *hiliteColor, short hiliteStrength, boolean distinctColors); void colorMultiplierFromDungeonLight(short x, short y, color *editColor); void plotCharWithColor(enum displayGlyph inputChar, windowpos loc, const color *cellForeColor, const color *cellBackColor); + void plotCharWithColorAndTextInfo(enum displayGlyph inputChar, windowpos loc, const color *cellForeColor, const color *cellBackColor, CellTextInfo textInfo); void plotCharToBuffer(enum displayGlyph inputChar, windowpos loc, const color *foreColor, const color *backColor, screenDisplayBuffer *dbuf); void plotForegroundChar(enum displayGlyph inputChar, short x, short y, const color *foreColor, boolean affectedByLighting); void commitDraws(void); diff --git a/src/platform/null-platform.c b/src/platform/null-platform.c index 0c2309c9..9809715c 100644 --- a/src/platform/null-platform.c +++ b/src/platform/null-platform.c @@ -15,7 +15,8 @@ static void null_nextKeyOrMouseEvent(rogueEvent *returnEvent, boolean textInput, static void null_plotChar(enum displayGlyph ch, short xLoc, short yLoc, short foreRed, short foreGreen, short foreBlue, - short backRed, short backGreen, short backBlue) { + short backRed, short backGreen, short backBlue, + CellTextInfo textInfo) { return; } diff --git a/src/platform/platform.h b/src/platform/platform.h index 2c3ecad7..c27a88e2 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -58,7 +58,8 @@ struct brogueConsole { enum displayGlyph inputChar, short x, short y, short foreRed, short foreGreen, short foreBlue, - short backRed, short backGreen, short backBlue + short backRed, short backGreen, short backBlue, + CellTextInfo textInfo ); void (*remap)(const char *, const char *); diff --git a/src/platform/platformdependent.c b/src/platform/platformdependent.c index c7de4287..aeb9c6e4 100644 --- a/src/platform/platformdependent.c +++ b/src/platform/platformdependent.c @@ -224,8 +224,9 @@ boolean isEnvironmentGlyph(enum displayGlyph glyph) { void plotChar(enum displayGlyph inputChar, short xLoc, short yLoc, short foreRed, short foreGreen, short foreBlue, - short backRed, short backGreen, short backBlue) { - currentConsole.plotChar(inputChar, xLoc, yLoc, foreRed, foreGreen, foreBlue, backRed, backGreen, backBlue); + short backRed, short backGreen, short backBlue, + CellTextInfo textInfo) { + currentConsole.plotChar(inputChar, xLoc, yLoc, foreRed, foreGreen, foreBlue, backRed, backGreen, backBlue, textInfo); } boolean shiftKeyIsDown() { diff --git a/src/platform/sdl2-platform.c b/src/platform/sdl2-platform.c index 7181e126..f8f0b942 100644 --- a/src/platform/sdl2-platform.c +++ b/src/platform/sdl2-platform.c @@ -390,11 +390,12 @@ static void _plotChar( enum displayGlyph inputChar, short x, short y, short foreRed, short foreGreen, short foreBlue, - short backRed, short backGreen, short backBlue + short backRed, short backGreen, short backBlue, + CellTextInfo textInfo ) { updateTile(y, x, fontIndex(inputChar), foreRed, foreGreen, foreBlue, - backRed, backGreen, backBlue); + backRed, backGreen, backBlue, textInfo); } diff --git a/src/platform/tiles.c b/src/platform/tiles.c index 96312073..82e857cf 100644 --- a/src/platform/tiles.c +++ b/src/platform/tiles.c @@ -35,6 +35,7 @@ typedef struct ScreenTile { short foreRed, foreGreen, foreBlue; // foreground color (0..100) short backRed, backGreen, backBlue; // background color (0..100) short charIndex; // index of the glyph to draw + CellTextInfo textInfo; short needsRefresh; // true if the tile has changed since the last screen refresh, else false } ScreenTile; @@ -589,7 +590,8 @@ static void createTextures(SDL_Renderer *renderer, int outputWidth, int outputHe /// void updateTile(int row, int column, short charIndex, short foreRed, short foreGreen, short foreBlue, - short backRed, short backGreen, short backBlue) + short backRed, short backGreen, short backBlue, + CellTextInfo textInfo) { screenTiles[row][column] = (ScreenTile){ .foreRed = foreRed, @@ -599,6 +601,7 @@ void updateTile(int row, int column, short charIndex, .backGreen = backGreen, .backBlue = backBlue, .charIndex = charIndex, + .textInfo = textInfo, .needsRefresh = 1 }; } @@ -692,6 +695,8 @@ void updateScreen() { continue; // this tile uses another texture and gets painted at another step } + int textMode = tile->textInfo.mode; + int tileRow = tile->charIndex / 16; int tileColumn = tile->charIndex % 16; @@ -712,6 +717,13 @@ void updateScreen() { dest.x = x * outputWidth / COLS; dest.y = y * outputHeight / ROWS; + if (textMode == 1) { + // If it's text, then we want to compress the letters + // so the spacing between consecutive letters is more + // natural and readable. + dest.x -= outputWidth * (x - tile->textInfo.startColumn) / 5 / COLS; + } + // blend the foreground if (SDL_SetTextureColorMod(Textures[step], round(2.55 * tile->foreRed), diff --git a/src/platform/tiles.h b/src/platform/tiles.h index 21296ac8..cb4fb4d8 100644 --- a/src/platform/tiles.h +++ b/src/platform/tiles.h @@ -2,12 +2,14 @@ #define __TILES_H__ #include +#include "Rogue.h" void initTiles(void); void resizeWindow(int width, int height); void updateTile(int row, int column, short charIndex, short foreRed, short foreGreen, short foreBlue, - short backRed, short backGreen, short backBlue); + short backRed, short backGreen, short backBlue, + CellTextInfo textInfo); void updateScreen(void); SDL_Surface *captureScreen(void); From ec269050ff52caf51e60b9357f4995a1c0ce7427 Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Mon, 15 Jan 2024 12:02:06 -0800 Subject: [PATCH 2/6] extend letter alignment logic --- src/brogue/Buttons.c | 3 +++ src/brogue/IO.c | 47 ++++++++++++++++++++++++++++++++++++++++--- src/brogue/MainMenu.c | 11 +++++++++- src/brogue/Rogue.h | 9 +++++++-- src/platform/tiles.c | 26 +++++++++++++++++++++--- 5 files changed, 87 insertions(+), 9 deletions(-) diff --git a/src/brogue/Buttons.c b/src/brogue/Buttons.c index 3428c54f..fcb6109a 100644 --- a/src/brogue/Buttons.c +++ b/src/brogue/Buttons.c @@ -115,6 +115,9 @@ void drawButton(brogueButton *button, enum buttonDrawStates highlight, screenDis if (dbuf) { // Only buffers can have opacity set. dbuf->cells[button->x + i][button->y].opacity = opacity; + dbuf->cells[button->x + i][button->y].textInfo = (CellTextInfo) { .mode = 1, .firstColumn = button->x }; + } else { + displayBuffer.cells[button->x + i][button->y].textInfo = (CellTextInfo) { .mode = 1, .firstColumn = button->x }; } } } diff --git a/src/brogue/IO.c b/src/brogue/IO.c index 12cce977..4e3d90b7 100644 --- a/src/brogue/IO.c +++ b/src/brogue/IO.c @@ -859,7 +859,7 @@ void commitDraws() { || lastPlotted->backColorComponents[1] != curr->backColorComponents[1] || lastPlotted->backColorComponents[2] != curr->backColorComponents[2] || lastPlotted->textInfo.mode != curr->textInfo.mode - || lastPlotted->textInfo.startColumn != curr->textInfo.startColumn; + || lastPlotted->textInfo.firstColumn != curr->textInfo.firstColumn; if (!needsUpdate) { continue; @@ -1821,6 +1821,37 @@ void plotCharWithColorAndTextInfo(enum displayGlyph inputChar, windowpos loc, co restoreRNG; } +void plotCharToBufferWithTextInfo(enum displayGlyph inputChar, windowpos loc, const color *foreColor, const color *backColor, CellTextInfo textInfo, screenDisplayBuffer *dbuf) { + short oldRNG; + + if (!dbuf) { + plotCharWithColorAndTextInfo(inputChar, loc, foreColor, backColor, textInfo); + return; + } + + brogueAssert(locIsInWindow(loc)); + if (!locIsInWindow(loc)) { + return; + } + + oldRNG = rogue.RNG; + rogue.RNG = RNG_COSMETIC; + //assureCosmeticRNG; + + cellDisplayBuffer* cell = &dbuf->cells[loc.window_x][loc.window_y]; + cell->foreColorComponents[0] = foreColor->red + rand_range(0, foreColor->redRand) + rand_range(0, foreColor->rand); + cell->foreColorComponents[1] = foreColor->green + rand_range(0, foreColor->greenRand) + rand_range(0, foreColor->rand); + cell->foreColorComponents[2] = foreColor->blue + rand_range(0, foreColor->blueRand) + rand_range(0, foreColor->rand); + cell->backColorComponents[0] = backColor->red + rand_range(0, backColor->redRand) + rand_range(0, backColor->rand); + cell->backColorComponents[1] = backColor->green + rand_range(0, backColor->greenRand) + rand_range(0, backColor->rand); + cell->backColorComponents[2] = backColor->blue + rand_range(0, backColor->blueRand) + rand_range(0, backColor->rand); + cell->character = inputChar; + if (textInfo.mode != 0) { + cell->textInfo = textInfo; + } + restoreRNG; +} + void plotCharToBuffer(enum displayGlyph inputChar, windowpos loc, const color *foreColor, const color *backColor, screenDisplayBuffer *dbuf) { short oldRNG; @@ -3250,7 +3281,7 @@ static void drawMessageArchive(char messages[MESSAGE_ARCHIVE_LINES][COLS*2], sho } dbuf.cells[mapToWindowX(j)][i].textInfo = (CellTextInfo) { .mode = 1, // text - .startColumn = mapToWindowX(0), + .firstColumn = mapToWindowX(0), }; } } @@ -3647,7 +3678,7 @@ void updateMessageDisplay() { displayedMessage[i][m], (windowpos){ mapToWindowX(j), MESSAGE_LINES - i - 1 }, &messageColor, &black, - (CellTextInfo) { .mode = 1, .startColumn = mapToWindowX(0) } + (CellTextInfo) { .mode = 1, .firstColumn = mapToWindowX(0) } ); } for (; j < DCOLS; j++) { @@ -4054,6 +4085,16 @@ short printStringWithWrapping(const char *theString, short x, short y, short wid if (locIsInWindow((windowpos){ px, py })) { plotCharToBuffer(printString[i], (windowpos){ px, py }, &fColor, backColor, dbuf); + CellTextInfo textInfo = (CellTextInfo) { + .mode = 2, // TEXT_CENTER + .firstColumn = x + 1, + .lastColumn = x + width-1, + }; + if (dbuf) { + dbuf->cells[px][py].textInfo = textInfo; + } else { + displayBuffer.cells[px][py].textInfo = textInfo; + } } px++; diff --git a/src/brogue/MainMenu.c b/src/brogue/MainMenu.c index ca58a544..839e292e 100644 --- a/src/brogue/MainMenu.c +++ b/src/brogue/MainMenu.c @@ -890,14 +890,23 @@ void mainBrogueJunction() { initializeLaunchArguments(&rogue.nextGame, rogue.nextGamePath, &rogue.nextGameSeed); do { + // In between menus and games, zero out the textinfo. + for (int x = 0; x < COLS; x++) { + for (int y = 0; y < ROWS; y++) { + displayBuffer.cells[x][y].textInfo = (CellTextInfo) { .mode = 0 }; + } + } rogue.gameHasEnded = false; rogue.playbackFastForward = false; rogue.playbackMode = false; switch (rogue.nextGame) { - case NG_NOTHING: + case NG_NOTHING: { // Run the main menu to get a decision out of the player. + const SavedDisplayBuffer rbuf = saveDisplayBuffer(); titleMenu(); + restoreDisplayBuffer(&rbuf); break; + } case NG_GAME_VARIANT: rogue.nextGame = NG_NOTHING; initializeGameVariant(); diff --git a/src/brogue/Rogue.h b/src/brogue/Rogue.h index f03859cd..a5e666f4 100644 --- a/src/brogue/Rogue.h +++ b/src/brogue/Rogue.h @@ -1284,8 +1284,12 @@ enum dungeonLayers { }; typedef struct CellTextInfo { - int mode; - int startColumn; + /// 0 : Normal terminal output + /// 1 : Left-aligned text [startColumn must be set] + /// 2 : Middle-aligned text [startColumn and endColumn must be set] + int8_t mode; + int8_t firstColumn; // first column (x coordinate) of text (inclusive) + int8_t lastColumn; // last column (x coordinate) of text (inclusive) } CellTextInfo; // keeps track of graphics so we only redraw if the cell has changed: @@ -2965,6 +2969,7 @@ extern "C" { void plotCharWithColor(enum displayGlyph inputChar, windowpos loc, const color *cellForeColor, const color *cellBackColor); void plotCharWithColorAndTextInfo(enum displayGlyph inputChar, windowpos loc, const color *cellForeColor, const color *cellBackColor, CellTextInfo textInfo); void plotCharToBuffer(enum displayGlyph inputChar, windowpos loc, const color *foreColor, const color *backColor, screenDisplayBuffer *dbuf); + void plotCharToBufferWithTextInfo(enum displayGlyph inputChar, windowpos loc, const color *foreColor, const color *backColor, CellTextInfo textInfo, screenDisplayBuffer *dbuf); void plotForegroundChar(enum displayGlyph inputChar, short x, short y, const color *foreColor, boolean affectedByLighting); void commitDraws(void); void dumpLevelToScreen(void); diff --git a/src/platform/tiles.c b/src/platform/tiles.c index 82e857cf..8b55596b 100644 --- a/src/platform/tiles.c +++ b/src/platform/tiles.c @@ -696,9 +696,10 @@ void updateScreen() { } int textMode = tile->textInfo.mode; + int charIndex = tile->charIndex; - int tileRow = tile->charIndex / 16; - int tileColumn = tile->charIndex % 16; + int tileRow = charIndex / 16; + int tileColumn = charIndex % 16; if (tileEmpty[tileRow][tileColumn] && !(tileRow == 21 && tileColumn == 1)) { // wall top (procedural) @@ -721,8 +722,27 @@ void updateScreen() { // If it's text, then we want to compress the letters // so the spacing between consecutive letters is more // natural and readable. - dest.x -= outputWidth * (x - tile->textInfo.startColumn) / 5 / COLS; + dest.x -= outputWidth * (x - tile->textInfo.firstColumn) / 5 / COLS; } + if (textMode == 2) { + int offsetForLetter = outputWidth * (x - tile->textInfo.firstColumn) / 5 / COLS; + int offsetForEnd = outputWidth * (tile->textInfo.lastColumn - tile->textInfo.firstColumn) / 5 / COLS; + // `offsetForLetter` is zero for the first letter, and increases for each + // subsequent letter in the line. + dest.x -= offsetForLetter; + // `offsetForEnd` is a constant for all text in the same contiguous span. + // By adding half its value back, we shift the text over so that the first + // letter and the last letter in the span are shifted equally for kerning, + // so that spacing on both sides is uniform. + dest.x += offsetForEnd / 2; + } + + // int diff = abs(tile->foreRed - tile->backRed) + abs(tile->foreGreen - tile->backGreen) + abs(tile->foreBlue - tile->backBlue); + // if (diff < 100) { + // tile->foreRed = 100; + // tile->foreGreen = 100; + // tile->foreBlue = 100; + // } // blend the foreground if (SDL_SetTextureColorMod(Textures[step], From c216b11098808fb2654308d39a8d1ab6568c176d Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Sat, 20 Jan 2024 16:14:17 -0800 Subject: [PATCH 3/6] fix logic for updating textinfo --- src/brogue/IO.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/brogue/IO.c b/src/brogue/IO.c index 4e3d90b7..7d2d3149 100644 --- a/src/brogue/IO.c +++ b/src/brogue/IO.c @@ -1814,9 +1814,9 @@ void plotCharWithColorAndTextInfo(enum displayGlyph inputChar, windowpos loc, co target->backColorComponents[0] = backRed; target->backColorComponents[1] = backGreen; target->backColorComponents[2] = backBlue; - if (textInfo.mode != 0) { - target->textInfo = textInfo; - } + // if (textInfo.mode != 0 || inputChar != ' ') { + target->textInfo = textInfo; + // } restoreRNG; } @@ -1846,9 +1846,8 @@ void plotCharToBufferWithTextInfo(enum displayGlyph inputChar, windowpos loc, co cell->backColorComponents[1] = backColor->green + rand_range(0, backColor->greenRand) + rand_range(0, backColor->rand); cell->backColorComponents[2] = backColor->blue + rand_range(0, backColor->blueRand) + rand_range(0, backColor->rand); cell->character = inputChar; - if (textInfo.mode != 0) { - cell->textInfo = textInfo; - } + + cell->textInfo = textInfo; restoreRNG; } @@ -1877,6 +1876,7 @@ void plotCharToBuffer(enum displayGlyph inputChar, windowpos loc, const color *f cell->backColorComponents[1] = backColor->green + rand_range(0, backColor->greenRand) + rand_range(0, backColor->rand); cell->backColorComponents[2] = backColor->blue + rand_range(0, backColor->blueRand) + rand_range(0, backColor->rand); cell->character = inputChar; + cell->textInfo = (CellTextInfo) { .mode = 0 }; restoreRNG; } @@ -2020,6 +2020,8 @@ void overlayDisplayBuffer(const screenDisplayBuffer *overBuf) { enum displayGlyph character; backColor = colorFromComponents(overBuf->cells[i][j].backColorComponents); + CellTextInfo displayTextInfo = displayBuffer.cells[i][j].textInfo; + // character and fore color: if (overBuf->cells[i][j].character == ' ') { // Blank cells in the overbuf take the character from the screen. character = displayBuffer.cells[i][j].character; @@ -2028,13 +2030,17 @@ void overlayDisplayBuffer(const screenDisplayBuffer *overBuf) { } else { character = overBuf->cells[i][j].character; foreColor = colorFromComponents(overBuf->cells[i][j].foreColorComponents); + displayTextInfo = overBuf->cells[i][j].textInfo; + } + if (overBuf->cells[i][j].opacity > 90) { + displayTextInfo = overBuf->cells[i][j].textInfo; } // back color: tempColor = colorFromComponents(displayBuffer.cells[i][j].backColorComponents); applyColorAverage(&backColor, &tempColor, 100 - overBuf->cells[i][j].opacity); - plotCharWithColorAndTextInfo(character, (windowpos){ i, j }, &foreColor, &backColor, overBuf->cells[i][j].textInfo); + plotCharWithColorAndTextInfo(character, (windowpos){ i, j }, &foreColor, &backColor, displayTextInfo); } } } From d5f44b9ff25a9ec7535c7a70d2acb1dab8570024 Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Sat, 20 Jan 2024 18:52:28 -0800 Subject: [PATCH 4/6] center button text --- src/brogue/Buttons.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/brogue/Buttons.c b/src/brogue/Buttons.c index fcb6109a..17934ee8 100644 --- a/src/brogue/Buttons.c +++ b/src/brogue/Buttons.c @@ -77,6 +77,12 @@ void drawButton(brogueButton *button, enum buttonDrawStates highlight, screenDis short symbolNumber = 0; + CellTextInfo buttonTextInfo = (CellTextInfo) { + .mode = 2, + .firstColumn = button->x, + .lastColumn = button->x + width - 1, + }; + for (int i = 0, textLoc = 0; i < width && i + button->x < COLS; i++, textLoc++) { while (button->text[textLoc] == COLOR_ESCAPE) { textLoc = decodeMessageColor(button->text, textLoc, &fColorBase); @@ -115,9 +121,9 @@ void drawButton(brogueButton *button, enum buttonDrawStates highlight, screenDis if (dbuf) { // Only buffers can have opacity set. dbuf->cells[button->x + i][button->y].opacity = opacity; - dbuf->cells[button->x + i][button->y].textInfo = (CellTextInfo) { .mode = 1, .firstColumn = button->x }; + dbuf->cells[button->x + i][button->y].textInfo = buttonTextInfo; } else { - displayBuffer.cells[button->x + i][button->y].textInfo = (CellTextInfo) { .mode = 1, .firstColumn = button->x }; + displayBuffer.cells[button->x + i][button->y].textInfo = buttonTextInfo; } } } From 35f25e0137c3c128d48d2af4e9cffad8290a7b09 Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Sat, 20 Jan 2024 19:08:09 -0800 Subject: [PATCH 5/6] center various texts --- src/brogue/IO.c | 77 +++++++++++++++++++++++++++++++--------------- src/brogue/Rogue.h | 5 ++- 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/src/brogue/IO.c b/src/brogue/IO.c index 7d2d3149..fbd28bd6 100644 --- a/src/brogue/IO.c +++ b/src/brogue/IO.c @@ -2883,8 +2883,8 @@ boolean getInputTextString(char *inputText, return true; } -void displayCenteredAlert(char *message) { - printString(message, (COLS - strLenWithoutEscapes(message)) / 2, ROWS / 2, &teal, &black, 0); +void displayCenteredAlert(const char *message) { + printStringCentered(message, (COLS - strLenWithoutEscapes(message)) / 2, ROWS / 2, &teal, &black, 0); } // Flashes a message on the screen starting at (x, y) lasting for the given time (in ms) and with the given colors. @@ -3565,9 +3565,9 @@ void message(const char *msg, unsigned long flags) { // Only used for the "you die..." message, to enable posthumous inventory viewing. void displayMoreSignWithoutWaitingForAcknowledgment() { if (strLenWithoutEscapes(displayedMessage[0]) < DCOLS - 8 || messagesUnconfirmed > 0) { - printString("--MORE--", COLS - 8, MESSAGE_LINES-1, &black, &white, 0); + printStringCentered("--MORE--", COLS - 8, MESSAGE_LINES-1, &black, &white, 0); } else { - printString("--MORE--", COLS - 8, MESSAGE_LINES, &black, &white, 0); + printStringCentered("--MORE--", COLS - 8, MESSAGE_LINES, &black, &white, 0); } } @@ -3579,11 +3579,11 @@ void displayMoreSign() { } if (strLenWithoutEscapes(displayedMessage[0]) < DCOLS - 8 || messagesUnconfirmed > 0) { - printString("--MORE--", COLS - 8, MESSAGE_LINES-1, &black, &white, 0); + printStringCentered("--MORE--", COLS - 8, MESSAGE_LINES-1, &black, &white, 0); waitForAcknowledgment(); - printString(" ", COLS - 8, MESSAGE_LINES-1, &black, &black, 0); + printStringCentered(" ", COLS - 8, MESSAGE_LINES-1, &black, &black, 0); } else { - printString("--MORE--", COLS - 8, MESSAGE_LINES, &black, &white, 0); + printStringCentered("--MORE--", COLS - 8, MESSAGE_LINES, &black, &white, 0); waitForAcknowledgment(); for (i=1; i<=8; i++) { refreshDungeonCell((pos){ DCOLS - i, 0 }); @@ -3799,15 +3799,15 @@ void refreshSideBar(short focusX, short focusY, boolean focusedEntityMustGoFirst // Header information for playback mode. if (rogue.playbackMode) { - printString(" -- PLAYBACK -- ", 0, printY++, &white, &black, 0); + printStringCentered(" -- PLAYBACK -- ", 0, printY++, &white, &black, 0); if (rogue.howManyTurns > 0) { sprintf(buf, "Turn %li/%li", rogue.playerTurnNumber, rogue.howManyTurns); printProgressBar(0, printY++, buf, rogue.playerTurnNumber, rogue.howManyTurns, &darkPurple, false); } if (rogue.playbackOOS) { - printString(" [OUT OF SYNC] ", 0, printY++, &badMessageColor, &black, 0); + printStringCentered(" [OUT OF SYNC] ", 0, printY++, &badMessageColor, &black, 0); } else if (rogue.playbackPaused) { - printString(" [PAUSED] ", 0, printY++, &gray, &black, 0); + printStringCentered(" [PAUSED] ", 0, printY++, &gray, &black, 0); } printString(" ", 0, printY++, &white, &black, 0); } @@ -3947,7 +3947,7 @@ void refreshSideBar(short focusX, short focusY, boolean focusedEntityMustGoFirst printString(" ", 0, i, &white, &black, 0); } sprintf(buf, " -- Depth: %i --%s ", rogue.depthLevel, (rogue.depthLevel < 10 ? " " : "")); - printString(buf, 0, ROWS - 1, &white, &black, 0); + printStringCentered(buf, 0, ROWS - 1, &white, &black, 0); } else if (!focusedEntityMustGoFirst) { // Failed to get the focusMonst printed on the screen. Try again, this time with the focus first. refreshSideBar(focusX, focusY, true); @@ -3961,6 +3961,11 @@ void printString(const char *theString, short x, short y, const color *foreColor color fColor = *foreColor; + CellTextInfo textInfo = (CellTextInfo) { + .mode = 1, + .firstColumn = x, + }; + for (i=0; theString[i] != '\0' && x < COLS; i++, x++) { while (theString[i] == COLOR_ESCAPE) { i = decodeMessageColor(theString, i, &fColor); @@ -3969,7 +3974,29 @@ void printString(const char *theString, short x, short y, const color *foreColor } } - plotCharToBuffer(theString[i], (windowpos){ x, y }, &fColor, backColor, dbuf); + plotCharToBufferWithTextInfo(theString[i], (windowpos){ x, y }, &fColor, backColor, textInfo, dbuf); + } +} + +// The same as `printString`, but centers the text when performing letter spacing adjustments. +void printStringCentered(const char *theString, short x, short y, const color *foreColor, const color *backColor, screenDisplayBuffer *dbuf) { + color fColor = *foreColor; + + CellTextInfo textInfo = (CellTextInfo) { + .mode = 2, + .firstColumn = x, + .lastColumn = x + strLenWithoutEscapes(theString) - 1, + }; + + for (int i=0; theString[i] != '\0' && x < COLS; i++, x++) { + while (theString[i] == COLOR_ESCAPE) { + i = decodeMessageColor(theString, i, &fColor); + if (!theString[i]) { + return; + } + } + + plotCharToBufferWithTextInfo(theString[i], (windowpos){ x, y }, &fColor, backColor, textInfo, dbuf); } } @@ -4651,7 +4678,7 @@ short printMonsterInfo(creature *monst, short y, boolean dim, boolean highlight) } else if (player.status[STATUS_NUTRITION] > 0) { printProgressBar(0, y++, "Nutrition (Faint)", player.status[STATUS_NUTRITION], STOMACH_SIZE, &blueBar, dim); } else if (y < ROWS - 1) { - printString(" STARVING ", 0, y++, &badMessageColor, &black, NULL); + printStringCentered(" STARVING ", 0, y++, &badMessageColor, &black, NULL); } } @@ -4698,35 +4725,35 @@ short printMonsterInfo(creature *monst, short y, boolean dim, boolean highlight) && monst->newPowerCount == monst->totalPowerCount && y < ROWS - 1 && (!player.status[STATUS_HALLUCINATING] || rogue.playbackOmniscience )) { - printString(" Negated ", 0, y++, (dim ? &darkPink : &pink), &black, 0); + printStringCentered(" Negated ", 0, y++, (dim ? &darkPink : &pink), &black, 0); } if (player.status[STATUS_HALLUCINATING] && !rogue.playbackOmniscience && y < ROWS - 1) { - printString(hallucinationStrings[rand_range(0, 9)], 0, y++, (dim ? &darkGray : &gray), &black, 0); + printStringCentered(hallucinationStrings[rand_range(0, 9)], 0, y++, (dim ? &darkGray : &gray), &black, 0); } else if (monst->bookkeepingFlags & MB_CAPTIVE && y < ROWS - 1) { - printString(" (Captive) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); + printStringCentered(" (Captive) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); } else if ((monst->info.flags & MONST_RESTRICTED_TO_LIQUID) && !cellHasTMFlag(monst->loc.x, monst->loc.y, TM_ALLOWS_SUBMERGING)) { - printString(" (Helpless) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); + printStringCentered(" (Helpless) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); } else if (monst->creatureState == MONSTER_SLEEPING && y < ROWS - 1) { - printString(" (Sleeping) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); + printStringCentered(" (Sleeping) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); } else if ((monst->creatureState == MONSTER_ALLY) && y < ROWS - 1) { - printString(" (Ally) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); + printStringCentered(" (Ally) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); } else if (monst->creatureState == MONSTER_FLEEING && y < ROWS - 1) { - printString(" (Fleeing) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); + printStringCentered(" (Fleeing) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); } else if ((monst->creatureState == MONSTER_WANDERING) && y < ROWS - 1) { if ((monst->bookkeepingFlags & MB_FOLLOWER) && monst->leader && (monst->leader->info.flags & MONST_IMMOBILE)) { // follower of an immobile leader -- i.e. a totem - printString(" (Worshiping) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); + printStringCentered(" (Worshiping) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); } else if ((monst->bookkeepingFlags & MB_FOLLOWER) && monst->leader && (monst->leader->bookkeepingFlags & MB_CAPTIVE)) { // actually a captor/torturer - printString(" (Guarding) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); + printStringCentered(" (Guarding) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); } else { - printString(" (Wandering) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); + printStringCentered(" (Wandering) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); } } else if (monst->ticksUntilTurn > max(0, player.ticksUntilTurn) + player.movementSpeed) { - printString(" (Off balance) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); + printStringCentered(" (Off balance) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); } else if ((monst->creatureState == MONSTER_TRACKING_SCENT) && y < ROWS - 1) { - printString(" (Hunting) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); + printStringCentered(" (Hunting) ", 0, y++, (dim ? &darkGray : &gray), &black, 0); } } } else if (monst == &player) { diff --git a/src/brogue/Rogue.h b/src/brogue/Rogue.h index a5e666f4..84f938a9 100644 --- a/src/brogue/Rogue.h +++ b/src/brogue/Rogue.h @@ -2942,7 +2942,7 @@ extern "C" { short x, short y, short width, boolean includeButtons); void funkyFade(screenDisplayBuffer *displayBuf, const color *colorStart, const color *colorEnd, short stepCount, short x, short y, boolean invert); - void displayCenteredAlert(char *message); + void displayCenteredAlert(const char *message); void flashMessage(char *message, short x, short y, int time, const color *fColor, const color *bColor); void flashTemporaryAlert(char *message, int time); void highlightScreenCell(short x, short y, const color *highlightColor, short strength); @@ -2991,7 +2991,10 @@ extern "C" { void flashForeground(short *x, short *y, const color **flashColor, short *flashStrength, short count, short frames); void flashCell(const color *theColor, short frames, short x, short y); void colorFlash(const color *theColor, unsigned long reqTerrainFlags, unsigned long reqTileFlags, short frames, short maxRadius, short x, short y); + // Prints the specified formatted string to the screen, starting at the coordinates (x, y). void printString(const char *theString, short x, short y, const color *foreColor, const color* backColor, screenDisplayBuffer *dbuf); + // The same as `printString`, but centers the text when performing letter spacing adjustments. + void printStringCentered(const char *theString, short x, short y, const color *foreColor, const color* backColor, screenDisplayBuffer *dbuf); short wrapText(char *to, const char *sourceText, short width); short printStringWithWrapping(const char *theString, short x, short y, short width, const color *foreColor, const color *backColor, screenDisplayBuffer *dbuf); From 81850eda16287cea6562bbe47fb797843dccda1b Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Sun, 21 Jan 2024 14:45:13 -0800 Subject: [PATCH 6/6] fix misplaced text --- src/brogue/IO.c | 57 ++++++++++++++++++++++++---------------------- src/brogue/Rogue.h | 1 + 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/brogue/IO.c b/src/brogue/IO.c index fbd28bd6..6f9082d7 100644 --- a/src/brogue/IO.c +++ b/src/brogue/IO.c @@ -1814,9 +1814,7 @@ void plotCharWithColorAndTextInfo(enum displayGlyph inputChar, windowpos loc, co target->backColorComponents[0] = backRed; target->backColorComponents[1] = backGreen; target->backColorComponents[2] = backBlue; - // if (textInfo.mode != 0 || inputChar != ' ') { target->textInfo = textInfo; - // } restoreRNG; } @@ -2186,6 +2184,7 @@ void funkyFade(screenDisplayBuffer *displayBuf, const color *colorStart, } for (n=(invert ? stepCount - 1 : 0); (invert ? n >= 0 : n <= stepCount); n += (invert ? -1 : 1)) { + const boolean lastIteration = invert ? n == 0 : n == stepCount-1; for (i=0; i