aboutsummaryrefslogtreecommitdiff
path: root/engines/drascula/graphics.cpp
diff options
context:
space:
mode:
authorThierry Crozat2016-04-08 02:04:13 +0100
committerThierry Crozat2016-04-08 02:04:28 +0100
commitd256f18952623f7d7a720ed52327fe2a1f5a8004 (patch)
tree7f115066bdce7b4f89366d5e00c39c1d3c2ca539 /engines/drascula/graphics.cpp
parentf624a15b4b1ac985331981e95a96b2adb7d9d021 (diff)
downloadscummvm-rg350-d256f18952623f7d7a720ed52327fe2a1f5a8004.tar.gz
scummvm-rg350-d256f18952623f7d7a720ed52327fe2a1f5a8004.tar.bz2
scummvm-rg350-d256f18952623f7d7a720ed52327fe2a1f5a8004.zip
DRASCULA: Fix text alignment to be faithful to the original
The changes in this commit should provide an identical text placement to the original. In addition to using the original source code as reference I have checked that is the case by comparing with DosBox for the intro of the Spanish and English versions as well as for parts of the game with the English version. I added comments for the obscure parts (such as the original adding a space at the end of the last line of text when splitting a string into several lines, thus impacting how that last line is aligned).
Diffstat (limited to 'engines/drascula/graphics.cpp')
-rw-r--r--engines/drascula/graphics.cpp102
1 files changed, 66 insertions, 36 deletions
diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp
index 5e37d2c3b0..4ed949cc99 100644
--- a/engines/drascula/graphics.cpp
+++ b/engines/drascula/graphics.cpp
@@ -319,31 +319,42 @@ int DrasculaEngine::print_abc_opc(const char *said, int screenY, int game) {
}
bool DrasculaEngine::textFitsCentered(char *text, int x) {
- int half_len = strlen(text) * CHAR_WIDTH / 2;
- // Clip center between 60 and 255
- x = CLIP<int>(x, 60, 259);
- // We want a text centered on x thats fits on screen
- // CHAR_WIDTH is even so x - length / 2 + length is always equal to x + length / 2
- return (x - half_len >= 2 && x + half_len <= 317);
+ int halfLen = (strlen(text) / 2) * CHAR_WIDTH;
+
+ // See comment in centerText()
+ if (x > 160)
+ x = 315 - x;
+ return (halfLen <= x);
}
void DrasculaEngine::centerText(const char *message, int textX, int textY) {
char msg[200];
- char messageLine[200];
- char tmpMessageLine[200];
- *messageLine = 0;
- *tmpMessageLine = 0;
- char *curWord;
- int curLine = 0;
- int x = 0;
- // original starts printing 4 lines above textY
- int y = CLIP<int>(textY - (4 * CHAR_HEIGHT), 0, 320);
-
Common::strlcpy(msg, message, 200);
+
+ // We make sure to have a width of at least 120 pixels by clipping the center.
+ // In theory since the screen width is 320 I would expect something like this:
+ // x = CLIP<int>(x, 60, 260);
+ // return (x - halfLen >= 0 && x + halfLen <= 319);
+
+ // The engines does things differently though. It tries to clips text at 315 instead of 319.
+ // And instead of testing the upper bound if x is greater than 160 it takes the complement to 315
+ // and test only the lower bounds. However since 160 is not the middle of 315, we end up having
+ // text that can go beyond 315 (up to 320) if x is in [159, 160].
+ // Also note that if the numbers of characters is odd, there is one more character to the right
+ // than to the left as it computes the half length with an integer division by two BEFORE multiplying
+ // by CHAR_WIDTH. Thus in theory we may end up with one character out of the screen!
+ // Be faithfull to the original and do the same though.
+
+ textX = CLIP<int>(textX, 60, 255);
// If the message fits on screen as-is, just print it here
if (textFitsCentered(msg, textX)) {
- x = CLIP<int>(textX, 60, 259) - strlen(msg) * CHAR_WIDTH / 2;
+ int x = textX - (strlen(msg) / 2) * CHAR_WIDTH - 1;
+ // The original starts to draw (nbLines + 2) lines above textY, except if there is a single line
+ // in which case it starts drawing at (nbLines + 3) above textY.
+ // Also clip to the screen height although the original does not do it.
+ int y = textY - 4 * CHAR_HEIGHT;
+ y = CLIP<int>(y, 0, 200 - CHAR_HEIGHT);
print_abc(msg, x, y);
return;
}
@@ -354,42 +365,61 @@ void DrasculaEngine::centerText(const char *message, int textX, int textY) {
// with the German translation.
if (!strchr(msg, ' ')) {
int len = strlen(msg);
- x = CLIP<int>(textX - len * CHAR_WIDTH / 2, 2, 317 - len * CHAR_WIDTH);
+ int x = CLIP<int>(textX - (len / 2) * CHAR_WIDTH - 1, 0, 319 - len * CHAR_WIDTH);
+ int y = textY - 4 * CHAR_HEIGHT;
+ y = CLIP<int>(y, 0, 200 - CHAR_HEIGHT);
print_abc(msg, x, y);
return;
}
// Message doesn't fit on screen, split it
-
+ char messageLines[15][41]; // screenWidth/charWidth = 320/8 = 40. Thus lines can have up to 41 characters with the null terminator (despite the original allocating only 40 characters here).
+ int curLine = 0;
+ char messageCurLine[50];
+ char tmpMessageCurLine[50];
+ *messageCurLine = 0;
+ *tmpMessageCurLine = 0;
// Get a word from the message
- curWord = strtok(msg, " ");
+ char* curWord = strtok(msg, " ");
while (curWord != NULL) {
// Check if the word and the current line fit on screen
- if (tmpMessageLine[0] != '\0')
- Common::strlcat(tmpMessageLine, " ", 200);
- Common::strlcat(tmpMessageLine, curWord, 200);
- if (textFitsCentered(tmpMessageLine, textX)) {
+ if (tmpMessageCurLine[0] != '\0')
+ Common::strlcat(tmpMessageCurLine, " ", 50);
+ Common::strlcat(tmpMessageCurLine, curWord, 50);
+ if (textFitsCentered(tmpMessageCurLine, textX)) {
// Line fits, so add the word to the current message line
- strcpy(messageLine, tmpMessageLine);
+ strcpy(messageCurLine, tmpMessageCurLine);
} else {
- // Line doesn't fit, so show the current line on screen and
- // create a new one
- // If it goes off screen, print_abc will adjust it
- x = CLIP<int>(textX, 60, 259) - strlen(messageLine) * CHAR_WIDTH / 2;
- print_abc(messageLine, x, y + curLine * (CHAR_HEIGHT + 2));
- Common::strlcpy(messageLine, curWord, 200);
- Common::strlcpy(tmpMessageLine, curWord, 200);
- curLine++;
+ // Line does't fit. Store the current line and start a new line.
+ Common::strlcpy(messageLines[curLine++], messageCurLine, 41);
+ Common::strlcpy(messageCurLine, curWord, 50);
+ Common::strlcpy(tmpMessageCurLine, curWord, 50);
}
// Get next word
curWord = strtok(NULL, " ");
-
if (curWord == NULL) {
- x = CLIP<int>(textX, 60, 259) - strlen(messageLine) * CHAR_WIDTH / 2;
- print_abc(messageLine, x, y + curLine * (CHAR_HEIGHT + 2));
+ // The original has an interesting bug that if we split the text on several lines
+ // a space is added at the end (which impacts the alignment, and may even cause the line
+ // to become too long).
+ Common::strlcat(messageCurLine, " ", 50);
+ if (!textFitsCentered(messageCurLine, textX)) {
+ messageCurLine[strlen(messageCurLine) - 1] = '\0';
+ Common::strlcpy(messageLines[curLine++], messageCurLine, 41);
+ strcpy(messageLines[curLine++], " ");
+ } else
+ Common::strlcpy(messageLines[curLine++], messageCurLine, 41);
}
}
+
+ // The original starts to draw (nbLines + 2) lines above textY.
+ // Also clip to the screen height although the original does not do it.
+ int y = textY - (curLine + 2) * CHAR_HEIGHT;
+ y = CLIP<int>(y, 0, 200 - curLine * (CHAR_HEIGHT + 2) + 2);
+ for (int line = 0 ; line < curLine ; ++line, y += CHAR_HEIGHT + 2) {
+ int textHalfLen = (strlen(messageLines[line]) / 2) * CHAR_WIDTH;
+ print_abc(messageLines[line], textX - textHalfLen - 1, y);
+ }
}
void DrasculaEngine::screenSaver() {