aboutsummaryrefslogtreecommitdiff
path: root/engines/sword1/text.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sword1/text.cpp')
-rw-r--r--engines/sword1/text.cpp191
1 files changed, 191 insertions, 0 deletions
diff --git a/engines/sword1/text.cpp b/engines/sword1/text.cpp
new file mode 100644
index 0000000000..d7e14073e9
--- /dev/null
+++ b/engines/sword1/text.cpp
@@ -0,0 +1,191 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "sword1/text.h"
+#include "sword1/resman.h"
+#include "sword1/objectman.h"
+#include "common/util.h"
+#include "sword1/swordres.h"
+#include "sword1/sworddefs.h"
+
+namespace Sword1 {
+
+#define OVERLAP 3
+#define SPACE ' '
+#define BORDER_COL 200
+#define LETTER_COL 193
+#define NO_COL 0 // sprite background - 0 for transparency
+#define MAX_LINES 30
+
+
+Text::Text(ObjectMan *pObjMan, ResMan *pResMan, bool czechVersion) {
+ _objMan = pObjMan;
+ _resMan = pResMan;
+ _textCount = 0;
+ _fontId = (czechVersion) ? CZECH_GAME_FONT : GAME_FONT;
+ _font = (uint8*)_resMan->openFetchRes(_fontId);
+
+ _joinWidth = charWidth( SPACE ) - 2 * OVERLAP;
+ _charHeight = FROM_LE_16(_resMan->fetchFrame(_font, 0)->height); // all chars have the same height
+ _textBlocks[0] = _textBlocks[1] = NULL;
+}
+
+Text::~Text(void) {
+ if (_textBlocks[0])
+ free(_textBlocks[0]);
+ if (_textBlocks[1])
+ free(_textBlocks[1]);
+ //_resMan->resClose(_fontId); => wiped automatically by _resMan->flush();
+}
+
+uint32 Text::lowTextManager(uint8 *ascii, int32 width, uint8 pen) {
+ _textCount++;
+ if (_textCount > MAX_TEXT_OBS)
+ error("Text::lowTextManager: MAX_TEXT_OBS exceeded!");
+ uint32 textObjId = (TEXT_sect * ITM_PER_SEC) - 1;
+ do {
+ textObjId++;
+ } while (_objMan->fetchObject(textObjId)->o_status);
+ // okay, found a free text object
+
+ _objMan->fetchObject(textObjId)->o_status = STAT_FORE;
+ makeTextSprite((uint8)textObjId, ascii, (uint16)width, pen);
+
+ return textObjId;
+}
+
+void Text::makeTextSprite(uint8 slot, uint8 *text, uint16 maxWidth, uint8 pen) {
+ LineInfo lines[MAX_LINES];
+ uint16 numLines = analyzeSentence(text, maxWidth, lines);
+
+ uint16 sprWidth = 0;
+ uint16 lineCnt;
+ for (lineCnt = 0; lineCnt < numLines; lineCnt++)
+ if (lines[lineCnt].width > sprWidth)
+ sprWidth = lines[lineCnt].width;
+ uint16 sprHeight = _charHeight * numLines;
+ uint32 sprSize = sprWidth * sprHeight;
+ assert(!_textBlocks[slot]); // if this triggers, the speechDriver failed to call Text::releaseText.
+ _textBlocks[slot] = (FrameHeader*)malloc(sprSize + sizeof(FrameHeader));
+
+ memcpy( _textBlocks[slot]->runTimeComp, "Nu ", 4);
+ _textBlocks[slot]->compSize = 0;
+ _textBlocks[slot]->width = TO_LE_16(sprWidth);
+ _textBlocks[slot]->height = TO_LE_16(sprHeight);
+ _textBlocks[slot]->offsetX = 0;
+ _textBlocks[slot]->offsetY = 0;
+
+ uint8 *linePtr = ((uint8*)_textBlocks[slot]) + sizeof(FrameHeader);
+ memset(linePtr, NO_COL, sprSize);
+ for (lineCnt = 0; lineCnt < numLines; lineCnt++) {
+ uint8 *sprPtr = linePtr + (sprWidth - lines[lineCnt].width) / 2; // center the text
+ for (uint16 pos = 0; pos < lines[lineCnt].length; pos++)
+ sprPtr += copyChar(*text++, sprPtr, sprWidth, pen) - OVERLAP;
+ text++; // skip space at the end of the line
+ linePtr += _charHeight * sprWidth;
+ }
+}
+
+uint16 Text::charWidth(uint8 ch) {
+ if (ch < SPACE)
+ ch = 64;
+ return FROM_LE_16(_resMan->fetchFrame(_font, ch - SPACE)->width);
+}
+
+uint16 Text::analyzeSentence(uint8 *text, uint16 maxWidth, LineInfo *line) {
+ uint16 lineNo = 0;
+
+ bool firstWord = true;
+ while (*text) {
+ uint16 wordWidth = 0;
+ uint16 wordLength = 0;
+
+ while ((*text != SPACE) && *text) {
+ wordWidth += charWidth(*text) - OVERLAP;
+ wordLength++;
+ text++;
+ }
+ if (*text == SPACE)
+ text++;
+
+ wordWidth += OVERLAP; // no overlap on final letter of word!
+ if ( firstWord ) { // first word on first line, so no separating SPACE needed
+ line[0].width = wordWidth;
+ line[0].length = wordLength;
+ firstWord = false;
+ } else {
+ // see how much extra space this word will need to fit on current line
+ // (with a separating space character - also overlapped)
+ uint16 spaceNeeded = _joinWidth + wordWidth;
+
+ if (line[lineNo].width + spaceNeeded <= maxWidth ) {
+ line[lineNo].width += spaceNeeded;
+ line[lineNo].length += 1 + wordLength; // NB. space+word characters
+ } else { // put word (without separating SPACE) at start of next line
+ lineNo++;
+ assert( lineNo < MAX_LINES );
+ line[lineNo].width = wordWidth;
+ line[lineNo].length = wordLength;
+ }
+ }
+ }
+ return lineNo+1; // return no of lines
+}
+
+uint16 Text::copyChar(uint8 ch, uint8 *sprPtr, uint16 sprWidth, uint8 pen) {
+ FrameHeader *chFrame = _resMan->fetchFrame(_font, ch - SPACE);
+ uint8 *chData = ((uint8*)chFrame) + sizeof(FrameHeader);
+ uint8 *dest = sprPtr;
+ for (uint16 cnty = 0; cnty < FROM_LE_16(chFrame->height); cnty++) {
+ for (uint16 cntx = 0; cntx < FROM_LE_16(chFrame->width); cntx++) {
+ if (*chData == LETTER_COL)
+ dest[cntx] = pen;
+ else if ((*chData == BORDER_COL) && (!dest[cntx])) // don't do a border if there's already a color underneath (chars can overlap)
+ dest[cntx] = BORDER_COL;
+ chData++;
+ }
+ dest += sprWidth;
+ }
+ return FROM_LE_16(chFrame->width);
+}
+
+FrameHeader *Text::giveSpriteData(uint32 textTarget) {
+ // textTarget is the resource ID of the Compact linking the textdata.
+ // that's 0x950000 for slot 0 and 0x950001 for slot 1. easy, huh? :)
+ textTarget &= ITM_ID;
+ assert(textTarget <= 1);
+
+ return _textBlocks[textTarget];
+}
+
+void Text::releaseText(uint32 id) {
+ id &= ITM_ID;
+ assert(id <= 1);
+ if (_textBlocks[id]) {
+ free(_textBlocks[id]);
+ _textBlocks[id] = NULL;
+ _textCount--;
+ }
+}
+
+} // End of namespace Sword1