2009-05-26 14:13:08 +00:00
|
|
|
/* Residual - A 3D game interpreter
|
2008-06-13 14:57:47 +00:00
|
|
|
*
|
|
|
|
* Residual is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the AUTHORS
|
|
|
|
* file distributed with this source distribution.
|
2006-04-02 14:20:45 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
* This library 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
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*
|
|
|
|
* $URL$
|
|
|
|
* $Id$
|
|
|
|
*
|
|
|
|
*/
|
2003-08-22 05:53:29 +00:00
|
|
|
|
2009-06-18 11:52:26 +00:00
|
|
|
#include "engines/grim/grim.h"
|
2009-05-24 19:13:58 +00:00
|
|
|
#include "engines/grim/textobject.h"
|
2009-06-23 05:15:20 +00:00
|
|
|
#include "engines/grim/savegame.h"
|
|
|
|
#include "engines/grim/lua.h"
|
2003-08-22 05:53:29 +00:00
|
|
|
|
2009-05-25 06:49:57 +00:00
|
|
|
namespace Grim {
|
|
|
|
|
2009-05-10 15:48:40 +00:00
|
|
|
Common::String parseMsgText(const char *msg, char *msgId);
|
2005-03-19 21:48:23 +00:00
|
|
|
|
2005-03-20 16:48:26 +00:00
|
|
|
TextObjectDefaults sayLineDefaults;
|
|
|
|
TextObjectDefaults printLineDefaults;
|
2009-05-10 12:17:41 +00:00
|
|
|
TextObjectDefaults blastTextDefaults;
|
2005-03-20 16:48:26 +00:00
|
|
|
|
2008-09-10 08:10:06 +00:00
|
|
|
TextObject::TextObject(bool blastDraw) :
|
2005-04-05 13:50:54 +00:00
|
|
|
_created(false), _x(0), _y(0), _width(0), _height(0), _justify(0),
|
2005-08-10 08:33:45 +00:00
|
|
|
_numberLines(1), _disabled(false), _font(NULL), _textBitmap(NULL),
|
2007-01-29 18:42:58 +00:00
|
|
|
_bitmapWidthPtr(NULL), _textObjectHandle(NULL) {
|
2005-04-03 11:33:28 +00:00
|
|
|
memset(_textID, 0, sizeof(_textID));
|
2005-03-20 13:51:40 +00:00
|
|
|
_fgColor._vals[0] = 0;
|
|
|
|
_fgColor._vals[1] = 0;
|
|
|
|
_fgColor._vals[2] = 0;
|
2008-09-10 08:10:06 +00:00
|
|
|
_blastDraw = blastDraw;
|
2005-03-20 13:51:40 +00:00
|
|
|
}
|
2005-03-19 21:48:23 +00:00
|
|
|
|
2005-04-05 13:50:54 +00:00
|
|
|
void TextObject::setText(char *text) {
|
|
|
|
if (strlen(text) < sizeof(_textID))
|
|
|
|
strcpy(_textID, text);
|
|
|
|
else {
|
2009-06-01 19:09:09 +00:00
|
|
|
error("Text ID exceeded maximum length (%d): %s", (int)sizeof(_textID), text);
|
2005-04-05 13:50:54 +00:00
|
|
|
// this should be good enough to still be unique
|
|
|
|
// but for debug purposes lets make this crash the program so we know about it
|
|
|
|
strncpy(_textID, text, sizeof(_textID));
|
|
|
|
_textID[sizeof(_textID)] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-20 13:51:40 +00:00
|
|
|
TextObject::~TextObject() {
|
|
|
|
destroyBitmap();
|
|
|
|
}
|
|
|
|
|
2009-06-23 05:15:20 +00:00
|
|
|
void TextObject::saveState(SaveGame *savedState) {
|
|
|
|
int32 size;
|
|
|
|
PointerId ptr;
|
|
|
|
|
|
|
|
size = strlen(_textID);
|
|
|
|
savedState->writeLESint32(size);
|
|
|
|
savedState->write(_textID, size);
|
|
|
|
ptr = makeIdFromPointer(_font);
|
|
|
|
savedState->writeLEUint32(ptr.low);
|
|
|
|
savedState->writeLEUint32(ptr.hi);
|
|
|
|
savedState->writeLEUint32(_blastDraw);
|
|
|
|
savedState->writeLEUint32(_disabled);
|
|
|
|
savedState->writeLEUint32(_justify);
|
|
|
|
savedState->writeLEUint32(_width);
|
|
|
|
savedState->writeLEUint32(_height);
|
|
|
|
savedState->writeLEUint32(_x);
|
|
|
|
savedState->writeLEUint32(_y);
|
|
|
|
savedState->writeLEUint32(_fgColor.red());
|
|
|
|
savedState->writeLEUint32(_fgColor.green());
|
|
|
|
savedState->writeLEUint32(_fgColor.blue());
|
|
|
|
}
|
|
|
|
|
2005-03-20 16:48:26 +00:00
|
|
|
void TextObject::setDefaults(TextObjectDefaults *defaults) {
|
|
|
|
_x = defaults->x;
|
|
|
|
_y = defaults->x;
|
|
|
|
_font = defaults->font;
|
|
|
|
_fgColor = defaults->fgColor;
|
|
|
|
_justify = defaults->justify;
|
2005-04-05 13:50:54 +00:00
|
|
|
_disabled = defaults->disabled;
|
2005-03-20 13:51:40 +00:00
|
|
|
}
|
|
|
|
|
2005-05-05 21:23:17 +00:00
|
|
|
int TextObject::getBitmapWidth() {
|
2008-09-10 11:16:57 +00:00
|
|
|
if (!_bitmapWidthPtr)
|
2005-05-05 21:23:17 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
int width = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < _numberLines; i++) {
|
|
|
|
if (_bitmapWidthPtr[i] > width)
|
|
|
|
width = _bitmapWidthPtr[i];
|
|
|
|
}
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TextObject::getBitmapHeight() {
|
|
|
|
uint height = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < _numberLines; i++) {
|
2007-01-29 18:42:58 +00:00
|
|
|
height += _font->getHeight();
|
2005-05-05 21:23:17 +00:00
|
|
|
}
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
2005-04-05 04:33:56 +00:00
|
|
|
int TextObject::getTextCharPosition(int pos) {
|
|
|
|
int width = 0;
|
2009-05-10 15:48:40 +00:00
|
|
|
Common::String msg = parseMsgText(_textID, NULL);
|
2005-04-05 04:33:56 +00:00
|
|
|
for (int i = 0; (msg[i] != '\0') && (i < pos); ++i) {
|
2007-01-29 18:42:58 +00:00
|
|
|
width += _font->getCharWidth(msg[i]);
|
2005-04-05 04:33:56 +00:00
|
|
|
}
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
2005-03-20 13:51:40 +00:00
|
|
|
void TextObject::createBitmap() {
|
|
|
|
if (_created)
|
|
|
|
destroyBitmap();
|
|
|
|
|
2009-05-10 15:48:40 +00:00
|
|
|
Common::String msg = parseMsgText(_textID, NULL);
|
|
|
|
Common::String message;
|
2005-04-05 13:50:54 +00:00
|
|
|
char *c = (char *)msg.c_str();
|
2005-03-19 21:48:23 +00:00
|
|
|
|
2005-04-05 13:50:54 +00:00
|
|
|
// remove spaces (NULL_TEXT) from the end of the string,
|
|
|
|
// while this helps make the string unique it screws up
|
|
|
|
// text justification
|
2009-05-10 15:48:40 +00:00
|
|
|
for (int i = (int)msg.size() - 1; c[i] == TEXT_NULL; i--)
|
|
|
|
msg.deleteLastChar();
|
2005-08-21 13:59:38 +00:00
|
|
|
|
|
|
|
// remove char of id 13 from the end of the string,
|
2009-05-10 15:48:40 +00:00
|
|
|
for (int i = (int)msg.size() - 1; c[i] == 13; i--)
|
|
|
|
msg.deleteLastChar();
|
2005-04-05 13:50:54 +00:00
|
|
|
|
2005-05-05 21:23:17 +00:00
|
|
|
// format the output message to incorporate line wrapping
|
|
|
|
// (if necessary) for the text object
|
2009-08-04 14:44:48 +00:00
|
|
|
const int left = 10;
|
|
|
|
const int right = 630;
|
|
|
|
const int maxWidth = 620;
|
|
|
|
int stringWidth = 0;
|
|
|
|
|
|
|
|
for (int i = 0; i < (int)msg.size(); i++)
|
|
|
|
stringWidth += MAX(_font->getCharWidth(msg[i]), _font->getCharDataWidth(msg[i]));
|
|
|
|
|
|
|
|
_numberLines = (stringWidth / maxWidth) + 1;
|
|
|
|
int numberCharsPerLine = (msg.size() / _numberLines) + 1;
|
|
|
|
|
2009-10-17 12:48:23 +00:00
|
|
|
int cline = 1;
|
2009-08-04 14:44:48 +00:00
|
|
|
int lineWidth = 0;
|
|
|
|
int maxLineWidth = 0;
|
|
|
|
for (int i = 0; i < (int)msg.size(); i++) {
|
2007-01-29 18:42:58 +00:00
|
|
|
lineWidth += MAX(_font->getCharWidth(msg[i]), _font->getCharDataWidth(msg[i]));
|
2009-10-17 12:48:23 +00:00
|
|
|
if (i + 1 == numberCharsPerLine * cline) {
|
2009-08-04 14:44:48 +00:00
|
|
|
if (lineWidth > maxLineWidth)
|
|
|
|
maxLineWidth = lineWidth;
|
|
|
|
|
2009-10-17 12:48:23 +00:00
|
|
|
++cline;
|
2005-05-05 21:23:17 +00:00
|
|
|
lineWidth = 0;
|
2009-08-04 14:44:48 +00:00
|
|
|
|
|
|
|
if (message.contains(' ')) {
|
|
|
|
while (msg[i] != ' ' && i > 0) {
|
|
|
|
message.deleteLastChar();
|
|
|
|
--i;
|
|
|
|
}
|
|
|
|
} else if (msg[i] != ' ') { // if it is an unique word
|
|
|
|
message.deleteLastChar();
|
|
|
|
message += '-';
|
|
|
|
--i;
|
|
|
|
}
|
2005-05-05 21:23:17 +00:00
|
|
|
message += '\n';
|
|
|
|
_numberLines++;
|
2009-08-04 14:44:48 +00:00
|
|
|
|
2005-05-05 21:23:17 +00:00
|
|
|
continue; // don't add the space back
|
|
|
|
}
|
2009-08-04 14:44:48 +00:00
|
|
|
|
|
|
|
if (lineWidth > maxLineWidth)
|
|
|
|
maxLineWidth = lineWidth;
|
|
|
|
if (_justify == RJUSTIFY && (_x - maxLineWidth < left))
|
|
|
|
setX(-_x + maxLineWidth + 2 * left);
|
|
|
|
else if (_justify == LJUSTIFY && (_x + maxLineWidth > right))
|
|
|
|
setX((- maxLineWidth / 2) + right);
|
|
|
|
else if (_justify == CENTER) {
|
|
|
|
if (_x - maxLineWidth / 2 < left)
|
|
|
|
setX(-_x + maxLineWidth + 2 * left);
|
|
|
|
else if (_x + maxLineWidth / 2 > right)
|
|
|
|
setX((- maxLineWidth / 2) + right);
|
|
|
|
}
|
2005-05-05 21:23:17 +00:00
|
|
|
message += msg[i];
|
2005-03-19 21:48:23 +00:00
|
|
|
}
|
2009-08-04 14:44:48 +00:00
|
|
|
|
2009-05-07 19:06:31 +00:00
|
|
|
_textObjectHandle = (GfxBase::TextObjectHandle **)malloc(sizeof(long) * _numberLines);
|
2008-03-10 23:06:07 +00:00
|
|
|
_bitmapWidthPtr = new int[_numberLines];
|
2005-05-05 21:23:17 +00:00
|
|
|
|
|
|
|
for (int j = 0; j < _numberLines; j++) {
|
2009-05-10 15:48:40 +00:00
|
|
|
int nextLinePos, cutLen;
|
|
|
|
const char *pos = strchr(message.c_str(), '\n');
|
|
|
|
if (pos) {
|
|
|
|
nextLinePos = pos - message.c_str();
|
|
|
|
cutLen = nextLinePos + 1;
|
|
|
|
} else {
|
|
|
|
nextLinePos = message.size();
|
|
|
|
cutLen = nextLinePos;
|
|
|
|
}
|
|
|
|
Common::String currentLine(message.c_str(), message.c_str() + nextLinePos);
|
2005-05-05 21:23:17 +00:00
|
|
|
|
|
|
|
_bitmapWidthPtr[j] = 0;
|
2009-05-10 15:48:40 +00:00
|
|
|
for (unsigned int i = 0; i < currentLine.size(); ++i) {
|
2008-09-28 15:23:15 +00:00
|
|
|
_bitmapWidthPtr[j] += MAX(_font->getCharWidth(currentLine[i]), _font->getCharDataWidth(currentLine[i]));
|
2005-05-05 21:23:17 +00:00
|
|
|
}
|
|
|
|
|
2007-01-29 18:42:58 +00:00
|
|
|
_textBitmap = new uint8[_font->getHeight() * (_bitmapWidthPtr[j] + 1)];
|
2009-04-07 12:58:30 +00:00
|
|
|
memset(_textBitmap, 0, _font->getHeight() * (_bitmapWidthPtr[j] + 1));
|
2005-05-05 21:23:17 +00:00
|
|
|
|
|
|
|
// Fill bitmap
|
2007-01-29 18:42:58 +00:00
|
|
|
int startOffset = 0;
|
2009-10-17 12:48:23 +00:00
|
|
|
for (unsigned int d = 0; d < currentLine.size(); d++) {
|
|
|
|
int ch = currentLine[d];
|
2007-01-29 18:42:58 +00:00
|
|
|
int8 startingLine = _font->getCharStartingLine(ch) + _font->getBaseOffsetY();
|
|
|
|
int32 charDataWidth = _font->getCharDataWidth(ch);
|
|
|
|
int32 charWidth = _font->getCharWidth(ch);
|
|
|
|
int8 startingCol = _font->getCharStartingCol(ch);
|
|
|
|
for (int line = 0; line < _font->getCharDataHeight(ch); line++) {
|
|
|
|
int offset = startOffset + ((_bitmapWidthPtr[j] + 1) * (line + startingLine));
|
|
|
|
for (int r = 0; r < charDataWidth; r++) {
|
|
|
|
const byte pixel = *(_font->getCharData(ch) + r + (charDataWidth * line));
|
|
|
|
byte *dst = _textBitmap + offset + startingCol + r;
|
2008-09-28 15:23:15 +00:00
|
|
|
if (*dst == 0 && pixel != 0)
|
2007-01-29 18:42:58 +00:00
|
|
|
_textBitmap[offset + startingCol + r] = pixel;
|
2005-05-05 21:23:17 +00:00
|
|
|
}
|
2007-01-29 18:42:58 +00:00
|
|
|
if (line + startingLine >= _font->getHeight())
|
|
|
|
break;
|
2005-03-19 21:48:23 +00:00
|
|
|
}
|
2007-01-29 18:42:58 +00:00
|
|
|
startOffset += charWidth;
|
2005-03-19 21:48:23 +00:00
|
|
|
}
|
2007-01-29 18:42:58 +00:00
|
|
|
|
|
|
|
_textObjectHandle[j] = g_driver->createTextBitmap(_textBitmap, _bitmapWidthPtr[j] + 1, _font->getHeight(), _fgColor);
|
2005-05-05 21:23:17 +00:00
|
|
|
delete[] _textBitmap;
|
2009-05-10 15:48:40 +00:00
|
|
|
for (int count = 0; count < cutLen; count++)
|
|
|
|
message.deleteChar(0);
|
2005-03-19 21:48:23 +00:00
|
|
|
}
|
2005-03-20 13:51:40 +00:00
|
|
|
_created = true;
|
2003-08-22 05:53:29 +00:00
|
|
|
}
|
|
|
|
|
2005-03-20 13:51:40 +00:00
|
|
|
void TextObject::destroyBitmap() {
|
2005-04-05 13:50:54 +00:00
|
|
|
_created = false;
|
2005-03-20 13:51:40 +00:00
|
|
|
if (_textObjectHandle) {
|
2005-05-05 21:23:17 +00:00
|
|
|
for (int i = 0; i < _numberLines; i++) {
|
|
|
|
g_driver->destroyTextBitmap(_textObjectHandle[i]);
|
2008-07-13 15:42:45 +00:00
|
|
|
delete _textObjectHandle[i];
|
2005-05-05 21:23:17 +00:00
|
|
|
}
|
|
|
|
free(_textObjectHandle);
|
2005-03-20 13:51:40 +00:00
|
|
|
_textObjectHandle = NULL;
|
|
|
|
}
|
2005-05-05 21:23:17 +00:00
|
|
|
if (_bitmapWidthPtr) {
|
2008-03-10 23:06:07 +00:00
|
|
|
delete[] _bitmapWidthPtr;
|
2005-05-05 21:23:17 +00:00
|
|
|
_bitmapWidthPtr = NULL;
|
|
|
|
}
|
2005-03-19 21:48:23 +00:00
|
|
|
}
|
2005-01-02 13:34:50 +00:00
|
|
|
|
2003-08-22 05:53:29 +00:00
|
|
|
void TextObject::draw() {
|
2005-05-05 21:23:17 +00:00
|
|
|
int height = 0;
|
|
|
|
|
2009-05-24 19:44:47 +00:00
|
|
|
if (!_created || _disabled)
|
2005-04-05 13:50:54 +00:00
|
|
|
return;
|
2005-05-05 21:23:17 +00:00
|
|
|
// render multi-line (wrapped) text
|
|
|
|
for (int i = 0; i < _numberLines; i++) {
|
|
|
|
int y;
|
|
|
|
|
2008-09-10 08:10:06 +00:00
|
|
|
if (_blastDraw)
|
2009-04-07 12:01:07 +00:00
|
|
|
y = _y + 5;
|
|
|
|
else {
|
2009-04-08 09:14:31 +00:00
|
|
|
if (_font->getHeight() == 21) // talk_font,verb_font
|
2009-04-07 12:01:07 +00:00
|
|
|
y = _y - 6;
|
2009-04-08 09:14:31 +00:00
|
|
|
else if (_font->getHeight() == 26) // special_font
|
2009-04-07 12:01:07 +00:00
|
|
|
y = _y - 12;
|
2009-04-08 09:14:31 +00:00
|
|
|
else if (_font->getHeight() == 13) // computer_font
|
2009-04-07 12:01:07 +00:00
|
|
|
y = _y - 6;
|
2009-04-08 09:14:31 +00:00
|
|
|
else if (_font->getHeight() == 19) // pt_font
|
|
|
|
y = _y - 9;
|
2009-04-07 12:01:07 +00:00
|
|
|
else
|
|
|
|
y = _y;
|
|
|
|
}
|
2008-09-10 08:10:06 +00:00
|
|
|
|
2005-05-05 21:23:17 +00:00
|
|
|
if (y < 0)
|
|
|
|
y = 0;
|
2009-05-09 17:47:28 +00:00
|
|
|
|
2005-05-05 21:23:17 +00:00
|
|
|
if (_justify == LJUSTIFY || _justify == NONE)
|
|
|
|
g_driver->drawTextBitmap(_x, height + y, _textObjectHandle[i]);
|
|
|
|
else if (_justify == CENTER) {
|
2007-01-29 18:42:58 +00:00
|
|
|
int x = _x - (_bitmapWidthPtr[i] / 2);
|
2005-05-05 21:23:17 +00:00
|
|
|
if (x < 0)
|
|
|
|
x = 0;
|
|
|
|
|
|
|
|
g_driver->drawTextBitmap(x, height + y, _textObjectHandle[i]);
|
|
|
|
} else if (_justify == RJUSTIFY) {
|
2007-01-29 18:42:58 +00:00
|
|
|
int x = (_x - getBitmapWidth());
|
2005-05-05 21:23:17 +00:00
|
|
|
if (x < 0)
|
|
|
|
x = 0;
|
|
|
|
|
2007-01-29 18:42:58 +00:00
|
|
|
g_driver->drawTextBitmap(x, height + y, _textObjectHandle[i]);
|
2009-05-25 19:21:58 +00:00
|
|
|
} else if (gDebugLevel == DEBUG_WARN || gDebugLevel == DEBUG_ALL)
|
2009-05-31 07:33:18 +00:00
|
|
|
warning("TextObject::draw: Unknown justification code (%d)", _justify);
|
2005-05-05 21:23:17 +00:00
|
|
|
|
2007-01-29 18:42:58 +00:00
|
|
|
height += _font->getHeight();
|
2005-05-05 21:23:17 +00:00
|
|
|
}
|
2003-08-22 05:53:29 +00:00
|
|
|
}
|
2009-05-25 06:49:57 +00:00
|
|
|
|
|
|
|
} // end of namespace Grim
|