diff options
Diffstat (limited to 'engines/sword1/text.cpp')
-rw-r--r-- | engines/sword1/text.cpp | 191 |
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 |