moved CharsetRendere into its own header/source file; changed Scumm::_charset into a pointer, to make it possible to use different implementations of it

svn-id: r6147
This commit is contained in:
Max Horn
2002-12-25 21:04:47 +00:00
parent f1808d20ac
commit fca9ec09e7
14 changed files with 655 additions and 588 deletions
+128 -491
View File
@@ -23,374 +23,11 @@
#include "stdafx.h"
#include "scumm.h"
#include "actor.h"
#include "charset.h"
#include "dialogs.h"
#include "verbs.h"
#include "scumm/sound.h"
void CharsetRenderer::setCurID(byte id) {
_curId = id;
_fontPtr = getFontPtr(id);
}
byte *CharsetRenderer::getFontPtr(byte id)
{
byte *ptr = _vm->getResourceAddress(rtCharset, id);
assert(ptr);
if (_vm->_features & GF_SMALL_HEADER)
ptr += 17;
else
ptr += 29;
return ptr;
}
// do spacing for variable width old-style font
int CharsetRenderer::getSpacing(byte chr, byte *charset)
{
int spacing = 0;
if (_vm->_features & GF_OLD256) {
spacing = *(charset - 11 + chr);
} else {
int offs = READ_LE_UINT32(charset + chr * 4 + 4);
if (offs) {
spacing = charset[offs];
if (charset[offs + 2] >= 0x80) {
spacing += charset[offs + 2] - 0x100;
} else {
spacing += charset[offs + 2];
}
}
}
// FIXME - this fixes the inventory icons in Zak256/Indy3
// see bug #613109.
// chars 1,2: up arrow chars 3,4: down arrow
if ((_vm->_gameId == GID_ZAK256 || _vm->_gameId == GID_INDY3_256)
&& (chr >= 1 && chr <= 4))
spacing = 6;
return spacing;
}
int CharsetRenderer::getStringWidth(int arg, byte *text, int pos)
{
byte *ptr;
int width;
byte chr;
width = 1;
ptr = _fontPtr;
while ((chr = text[pos++]) != 0) {
if (chr == 0xD)
break;
if (chr == '@')
continue;
if (chr == 254 || chr == 255) {
chr = text[pos++];
if (chr == 3) // 'WAIT'
break;
if (chr == 8) { // 'Verb on next line'
if (arg == 1)
break;
while (text[pos] == ' ')
text[pos++] = '@';
continue;
}
if (chr == 10 || chr == 21 || chr == 12 || chr == 13) {
pos += 2;
continue;
}
if (chr == 9 || chr == 1 || chr == 2) // 'Newline'
break;
if (chr == 14) {
int set = text[pos] | (text[pos + 1] << 8);
pos += 2;
ptr = getFontPtr(set);
continue;
}
}
width += getSpacing(chr, ptr);
}
return width;
}
void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth)
{
int lastspace = -1;
int curw = 1;
byte *ptr;
byte chr;
ptr = _fontPtr;
while ((chr = str[pos++]) != 0) {
if (chr == '@')
continue;
if (chr == 254)
chr = 255;
if (chr == 255) {
chr = str[pos++];
if (chr == 3) // 'Wait'
break;
if (chr == 8) { // 'Verb on next line'
if (a == 1) {
curw = 1;
} else {
while (str[pos] == ' ')
str[pos++] = '@';
}
continue;
}
if (chr == 10 || chr == 21 || chr == 12 || chr == 13) {
pos += 2;
continue;
}
if (chr == 1) { // 'Newline'
curw = 1;
continue;
}
if (chr == 2) // 'Don't terminate with \n'
break;
if (chr == 14) {
int set = str[pos] | (str[pos + 1] << 8);
pos += 2;
ptr = getFontPtr(set);
continue;
}
}
if (chr == ' ')
lastspace = pos - 1;
curw += getSpacing(chr, ptr);
if (lastspace == -1)
continue;
if (curw > maxwidth) {
str[lastspace] = 0xD;
curw = 1;
pos = lastspace + 1;
lastspace = -1;
}
}
}
void CharsetRenderer::printCharOld(int chr)
{ // Indy3 / Zak256
VirtScreen *vs;
byte *char_ptr, *dest_ptr;
unsigned int buffer = 0, mask = 0, x = 0, y = 0;
unsigned char color;
_vm->checkRange(_vm->_maxCharsets - 1, 0, _curId, "Printing with bad charset %d");
if ((vs = _vm->findVirtScreen(_top)) == NULL)
return;
if (chr == '@')
return;
if (_firstChar) {
_strLeft = _left;
_strTop = _top;
_strRight = _left;
_strBottom = _top;
_firstChar = false;
}
char_ptr = _fontPtr + 207 + (chr + 1) * 8;
dest_ptr = vs->screenPtr + vs->xstart + (_top - vs->topline) * _vm->_realWidth + _left;
_vm->updateDirtyRect(vs->number, _left, _left + 8, _top - vs->topline, _top - vs->topline + 8, 0);
for (y = 0; y < 8; y++) {
for (x = 0; x < 8; x++) {
if ((mask >>= 1) == 0) {
buffer = *char_ptr++;
mask = 0x80;
}
color = ((buffer & mask) != 0);
if (color)
*(dest_ptr + y * _vm->_realWidth + x) = _color;
}
}
// FIXME
_left += getSpacing(chr, _fontPtr);
if (_left > _strRight)
_strRight = _left;
if (_top + 8 > _strBottom)
_strBottom = _top + 8;
}
void CharsetRenderer::printChar(int chr)
{
int width, height;
int d;
VirtScreen *vs;
_vm->checkRange(_vm->_maxCharsets - 1, 1, _curId, "Printing with bad charset %d");
if ((vs = _vm->findVirtScreen(_top)) == NULL)
return;
if (chr == '@')
return;
_bpp = *_fontPtr;
_colorMap[1] = _color;
_charOffs = READ_LE_UINT32(_fontPtr + chr * 4 + 4);
if (!_charOffs)
return;
assert(_charOffs < 0x10000);
_charPtr = _fontPtr + _charOffs;
width = _charPtr[0];
height = _charPtr[1];
if (_firstChar) {
_strLeft = 0;
_strTop = 0;
_strRight = 0;
_strBottom = 0;
}
if (_disableOffsX) {
_offsX = 0;
} else {
d = _charPtr[2];
if (d >= 0x80)
d -= 0x100;
_offsX = d;
}
d = _charPtr[3];
if (d >= 0x80)
d -= 0x100;
_offsY = d;
_top += _offsY;
_left += _offsX;
if (_left + width > _right + 1 || _left < 0) {
_left += width;
_top -= _offsY;
return;
}
_disableOffsX = false;
if (_firstChar) {
_strLeft = _left;
_strTop = _top;
_strRight = _left;
_strBottom = _top;
_firstChar = false;
}
if (_left < _strLeft)
_strLeft = _left;
if (_top < _strTop)
_strTop = _top;
int drawTop = _top - vs->topline;
if (drawTop < 0)
drawTop = 0;
int bottom = drawTop + height + _offsY;
_vm->updateDirtyRect(vs->number, _left, _left + width, drawTop, bottom, 0);
if (vs->number != 0)
_blitAlso = false;
if (vs->number == 0 && !_blitAlso)
_hasMask = true;
_virtScreenHeight = vs->height;
_charPtr += 4;
byte *mask = _vm->getResourceAddress(rtBuffer, 9)
+ drawTop * _vm->gdi._numStrips + _left / 8 + _vm->_screenStartStrip;
byte *dst = vs->screenPtr + vs->xstart + drawTop * _vm->_realWidth + _left;
bool useMask = (vs->number == 0 && !_ignoreCharsetMask);
if (_blitAlso) {
byte *back = dst;
dst = _vm->getResourceAddress(rtBuffer, vs->number + 5)
+ vs->xstart + drawTop * _vm->_realWidth + _left;
drawBits(dst, mask, drawTop, width, height, useMask);
_vm->blit(back, dst, width, height);
} else {
drawBits(dst, mask, drawTop, width, height, useMask);
}
_left += width;
if (_left > _strRight)
_strRight = _left;
if (_top + height > _strBottom)
_strBottom = _top + height;
_top -= _offsY;
}
void CharsetRenderer::drawBits(byte *dst, byte *mask, int drawTop, int width, int height, bool useMask)
{
byte maskmask;
int y, x;
int maskpos;
int color;
byte numbits, bits;
bits = *_charPtr++;
numbits = 8;
y = 0;
for (y = 0; y < height && y + drawTop < _virtScreenHeight; y++) {
maskmask = revBitMask[_left & 7];
maskpos = 0;
for (x = 0; x < width; x++) {
int myMask = (0xFF << (8 - _bpp)) & 0xFF;
int myColor = (bits & myMask) >> (8 - _bpp);
color = (bits >> (8 - _bpp)) & 0xFF;
assert(color == myColor);
if (color) {
if (useMask) {
mask[maskpos] |= maskmask;
}
*dst = _colorMap[color];
}
dst++;
bits <<= _bpp;
numbits -= _bpp;
if (numbits == 0) {
bits = *_charPtr++;
numbits = 8;
}
maskmask >>= 1;
if (maskmask == 0) {
maskmask = 0x80;
maskpos++;
}
}
dst += _vm->_realWidth - width;
mask += _vm->gdi._numStrips;
}
}
void Scumm::unkMessage1()
{
byte buffer[100];
@@ -494,28 +131,28 @@ void Scumm::CHARSET_1()
}
}
_charset._top = _string[0].ypos;
_charset._startLeft = _charset._left = _string[0].xpos;
_charset->_top = _string[0].ypos;
_charset->_startLeft = _charset->_left = _string[0].xpos;
if (a && a->charset)
_charset.setCurID(a->charset);
_charset->setCurID(a->charset);
else
_charset.setCurID(_string[0].charset);
_charset->setCurID(_string[0].charset);
_charset._center = _string[0].center;
_charset._right = _string[0].right;
_charset._color = _charsetColor;
_charset->_center = _string[0].center;
_charset->_right = _string[0].right;
_charset->_color = _charsetColor;
if (!(_features & GF_OLD256)) // FIXME
for (i = 0; i < 4; i++)
_charset._colorMap[i] = _charsetData[_charset.getCurID()][i];
_charset->_colorMap[i] = _charsetData[_charset->getCurID()][i];
if (_keepText) {
_charset._strLeft = gdi._mask_left;
_charset._strRight = gdi._mask_right;
_charset._strTop = gdi._mask_top;
_charset._strBottom = gdi._mask_bottom;
_charset->_strLeft = gdi._mask_left;
_charset->_strRight = gdi._mask_right;
_charset->_strTop = gdi._mask_top;
_charset->_strBottom = gdi._mask_bottom;
}
if (_talkDelay)
@@ -555,23 +192,23 @@ void Scumm::CHARSET_1()
restoreCharsetBg();
}
t = _charset._right - _string[0].xpos - 1;
if (_charset._center) {
if (t > _charset._nextLeft)
t = _charset._nextLeft;
t = _charset->_right - _string[0].xpos - 1;
if (_charset->_center) {
if (t > _charset->_nextLeft)
t = _charset->_nextLeft;
t <<= 1;
}
buffer = _charset._buffer + _charset._bufPos;
_charset.addLinebreaks(0, buffer, 0, t);
buffer = _charset->_buffer + _charset->_bufPos;
_charset->addLinebreaks(0, buffer, 0, t);
if (_charset._center) {
_charset._nextLeft -= _charset.getStringWidth(0, buffer, 0) >> 1;
if (_charset._nextLeft < 0)
_charset._nextLeft = 0;
if (_charset->_center) {
_charset->_nextLeft -= _charset->getStringWidth(0, buffer, 0) >> 1;
if (_charset->_nextLeft < 0)
_charset->_nextLeft = 0;
}
_charset._disableOffsX = _charset._firstChar = !_keepText;
_charset->_disableOffsX = _charset->_firstChar = !_keepText;
do {
c = *buffer++;
@@ -585,16 +222,16 @@ void Scumm::CHARSET_1()
if (c == 13) {
newLine:;
if (_features & GF_OLD256) {
_charset._nextTop = 8;
_charset._nextLeft = 0;
_charset->_nextTop = 8;
_charset->_nextLeft = 0;
continue;
} else {
_charset._nextLeft = _string[0].xpos;
if (_charset._center) {
_charset._nextLeft -= _charset.getStringWidth(0, buffer, 0) >> 1;
_charset->_nextLeft = _string[0].xpos;
if (_charset->_center) {
_charset->_nextLeft -= _charset->getStringWidth(0, buffer, 0) >> 1;
}
_charset._nextTop += _charset.getFontPtr()[1];
_charset._disableOffsX = true;
_charset->_nextTop += _charset->getFontPtr()[1];
_charset->_disableOffsX = true;
continue;
}
}
@@ -603,20 +240,20 @@ void Scumm::CHARSET_1()
c = 0xFF;
if (c != 0xFF) {
_charset._left = _charset._nextLeft;
_charset._top = _charset._nextTop;
_charset->_left = _charset->_nextLeft;
_charset->_top = _charset->_nextTop;
if (_features & GF_OLD256)
_charset.printCharOld(c);
_charset->printCharOld(c);
else if (!(_features & GF_AFTER_V6)) {
if (!(_haveMsg == 0xFE && _noSubtitles))
_charset.printChar(c);
_charset->printChar(c);
} else {
if (!((_haveMsg == 0xFE || _haveMsg == 0xFF) && _noSubtitles))
_charset.printChar(c);
_charset->printChar(c);
}
_charset._nextLeft = _charset._left;
_charset._nextTop = _charset._top;
_charset->_nextLeft = _charset->_left;
_charset->_nextTop = _charset->_top;
_talkDelay += _vars[VAR_CHARINC];
continue;
}
@@ -654,21 +291,21 @@ void Scumm::CHARSET_1()
color = *buffer++;
color |= *buffer++ << 8;
if (color == 0xFF)
_charset._color = _charsetColor;
_charset->_color = _charsetColor;
else
_charset._color = color;
_charset->_color = color;
break;
case 13:
buffer += 2;
break;
case 14: {
int oldy = _charset.getFontPtr()[1];
int oldy = _charset->getFontPtr()[1];
_charset.setCurID(*buffer++);
_charset->setCurID(*buffer++);
buffer += 2;
for (i = 0; i < 4; i++)
_charset._colorMap[i] = _charsetData[_charset.getCurID()][i];
_charset._nextTop -= _charset.getFontPtr()[1] - oldy;
_charset->_colorMap[i] = _charsetData[_charset->getCurID()][i];
_charset->_nextTop -= _charset->getFontPtr()[1] - oldy;
break;
}
default:
@@ -689,12 +326,12 @@ void Scumm::CHARSET_1()
if (a && has_anim)
a->startAnimActor(frme != -1 ? frme : a->talkFrame1);
_charset._bufPos = buffer - _charset._buffer;
_charset->_bufPos = buffer - _charset->_buffer;
gdi._mask_left = _charset._strLeft;
gdi._mask_right = _charset._strRight;
gdi._mask_top = _charset._strTop;
gdi._mask_bottom = _charset._strBottom;
gdi._mask_left = _charset->_strLeft;
gdi._mask_right = _charset->_strRight;
gdi._mask_top = _charset->_strTop;
gdi._mask_bottom = _charset->_strBottom;
}
void Scumm::description()
@@ -702,22 +339,22 @@ void Scumm::description()
int c;
byte *buffer;
buffer = _charset._buffer;
buffer = _charset->_buffer;
_string[0].ypos = camera._cur.y + 88;
_string[0].xpos = (_realWidth / 2) - (_charset.getStringWidth(0, buffer, 0) >> 1);
_string[0].xpos = (_realWidth / 2) - (_charset->getStringWidth(0, buffer, 0) >> 1);
if (_string[0].xpos < 0)
_string[0].xpos = 0;
_charset._bufPos = 0;
_charset._top = _string[0].ypos;
_charset._startLeft = _charset._left = _string[0].xpos;
_charset._right = _realWidth - 1;
_charset._center = false;
_charset._color = 15;
_charset._disableOffsX = _charset._firstChar = true;
_charset.setCurID(3);
_charset._nextLeft = _string[0].xpos;
_charset._nextTop = _string[0].ypos;
_charset->_bufPos = 0;
_charset->_top = _string[0].ypos;
_charset->_startLeft = _charset->_left = _string[0].xpos;
_charset->_right = _realWidth - 1;
_charset->_center = false;
_charset->_color = 15;
_charset->_disableOffsX = _charset->_firstChar = true;
_charset->setCurID(3);
_charset->_nextLeft = _string[0].xpos;
_charset->_nextTop = _string[0].ypos;
// FIXME: _talkdelay = 1 - display description, not correct ego actor talking,
// 0 - no display, correct ego actor talking
_talkDelay = 0;
@@ -731,19 +368,19 @@ void Scumm::description()
break;
}
if (c != 0xFF) {
_charset._left = _charset._nextLeft;
_charset._top = _charset._nextTop;
_charset.printChar(c);
_charset._nextLeft = _charset._left;
_charset._nextTop = _charset._top;
_charset->_left = _charset->_nextLeft;
_charset->_top = _charset->_nextTop;
_charset->printChar(c);
_charset->_nextLeft = _charset->_left;
_charset->_nextTop = _charset->_top;
continue;
}
} while (1);
gdi._mask_left = _charset._strLeft;
gdi._mask_right = _charset._strRight;
gdi._mask_top = _charset._strTop;
gdi._mask_bottom = _charset._strBottom;
gdi._mask_left = _charset->_strLeft;
gdi._mask_right = _charset->_strRight;
gdi._mask_top = _charset->_strTop;
gdi._mask_bottom = _charset->_strBottom;
}
void Scumm::drawDescString(byte *msg)
@@ -753,21 +390,21 @@ void Scumm::drawDescString(byte *msg)
buf = _msgPtrToAdd = buffer;
addMessageToStack(msg);
_charset._bufPos = 0;
_charset._top = _string[0].ypos;
_charset._startLeft = _charset._left = _string[0].xpos;
_charset._right = _realWidth - 1;
_charset._center = _string[0].center;
_charset._color = _string[0].color;
_charset._disableOffsX = _charset._firstChar = true;
_charset.setCurID(_string[0].charset);
_charset._nextLeft = _string[0].xpos;
_charset._nextTop = _string[0].ypos;
_charset->_bufPos = 0;
_charset->_top = _string[0].ypos;
_charset->_startLeft = _charset->_left = _string[0].xpos;
_charset->_right = _realWidth - 1;
_charset->_center = _string[0].center;
_charset->_color = _string[0].color;
_charset->_disableOffsX = _charset->_firstChar = true;
_charset->setCurID(_string[0].charset);
_charset->_nextLeft = _string[0].xpos;
_charset->_nextTop = _string[0].ypos;
// Center text
_charset._nextLeft -= _charset.getStringWidth(0, buffer, 0) >> 1;
if (_charset._nextLeft < 0)
_charset._nextLeft = 0;
_charset->_nextLeft -= _charset->getStringWidth(0, buffer, 0) >> 1;
if (_charset->_nextLeft < 0)
_charset->_nextLeft = 0;
_talkDelay = 1;
@@ -780,19 +417,19 @@ void Scumm::drawDescString(byte *msg)
break;
}
if (c != 0xFF) {
_charset._left = _charset._nextLeft;
_charset._top = _charset._nextTop;
_charset.printChar(c);
_charset._nextLeft = _charset._left;
_charset._nextTop = _charset._top;
_charset->_left = _charset->_nextLeft;
_charset->_top = _charset->_nextTop;
_charset->printChar(c);
_charset->_nextLeft = _charset->_left;
_charset->_nextTop = _charset->_top;
continue;
}
} while (1);
gdi._mask_left = _charset._strLeft;
gdi._mask_right = _charset._strRight;
gdi._mask_top = _charset._strTop;
gdi._mask_bottom = _charset._strBottom;
gdi._mask_left = _charset->_strLeft;
gdi._mask_right = _charset->_strRight;
gdi._mask_top = _charset->_strTop;
gdi._mask_bottom = _charset->_strBottom;
}
void Scumm::drawString(int a)
@@ -806,19 +443,19 @@ void Scumm::drawString(int a)
_msgPtrToAdd = buf;
_messagePtr = addMessageToStack(_messagePtr);
_charset._top = _string[a].ypos;
_charset._startLeft = _charset._left = _string[a].xpos;
_charset._right = _string[a].right;
_charset._center = _string[a].center;
_charset._color = _string[a].color;
_charset._disableOffsX = _charset._firstChar = true;
_charset.setCurID(_string[a].charset);
_charset->_top = _string[a].ypos;
_charset->_startLeft = _charset->_left = _string[a].xpos;
_charset->_right = _string[a].right;
_charset->_center = _string[a].center;
_charset->_color = _string[a].color;
_charset->_disableOffsX = _charset->_firstChar = true;
_charset->setCurID(_string[a].charset);
if (!(_features & GF_OLD256)) {
for (i = 0; i < 4; i++)
_charset._colorMap[i] = _charsetData[_charset.getCurID()][i];
_charset->_colorMap[i] = _charsetData[_charset->getCurID()][i];
fontHeight = _charset.getFontPtr()[1];
fontHeight = _charset->getFontPtr()[1];
}
_msgPtrToAdd = buf;
@@ -836,12 +473,12 @@ void Scumm::drawString(int a)
}
if (space)
*space = '\0';
if (_charset._center) {
_charset._left -= _charset.getStringWidth(a, buf, 0) >> 1;
if (_charset->_center) {
_charset->_left -= _charset->getStringWidth(a, buf, 0) >> 1;
}
if (!(_features & GF_AFTER_V7))
_charset._ignoreCharsetMask = true;
_charset->_ignoreCharsetMask = true;
// In Full Throttle (and other games?), verb text should always mask
@@ -868,55 +505,55 @@ void Scumm::drawString(int a)
break;
case 1:
case 8:
if (_charset._center) {
_charset._left = _charset._startLeft - _charset.getStringWidth(a, buf, i);
if (_charset->_center) {
_charset->_left = _charset->_startLeft - _charset->getStringWidth(a, buf, i);
} else {
_charset._left = _charset._startLeft;
_charset->_left = _charset->_startLeft;
}
_charset._top += fontHeight;
_charset->_top += fontHeight;
break;
case 12:
color = buf[i] + (buf[i + 1] << 8);
i += 2;
if (color == 0xFF)
_charset._color = _string[a].color;
_charset->_color = _string[a].color;
else
_charset._color = color;
_charset->_color = color;
break;
}
} else {
if (a == 1 && (_features & GF_AFTER_V6)) {
if (_string[a].no_talk_anim == 0)
_charset._blitAlso = true;
_charset->_blitAlso = true;
}
if (_features & GF_OLD256)
_charset.printCharOld(chr);
_charset->printCharOld(chr);
else
_charset.printChar(chr);
_charset._blitAlso = false;
_charset->printChar(chr);
_charset->_blitAlso = false;
}
}
_charset._ignoreCharsetMask = false;
_charset->_ignoreCharsetMask = false;
if (a == 0) {
_charset._nextLeft = _charset._left;
_charset._nextTop = _charset._top;
_charset->_nextLeft = _charset->_left;
_charset->_nextTop = _charset->_top;
}
_string[a].xpos = _charset._strRight + 8; // Indy3: Fixes Grail Diary text positioning
_string[a].xpos = _charset->_strRight + 8; // Indy3: Fixes Grail Diary text positioning
if (_features & GF_AFTER_V7) {
_charset._hasMask = true;
if (_charset._strLeft < gdi._mask_left)
gdi._mask_left = _charset._strLeft;
if (_charset._strRight > gdi._mask_right)
gdi._mask_right = _charset._strRight;
if (_charset._strTop < gdi._mask_top)
gdi._mask_top = _charset._strTop;
if (_charset._strBottom > gdi._mask_bottom)
gdi._mask_bottom = _charset._strBottom;
_charset->_hasMask = true;
if (_charset->_strLeft < gdi._mask_left)
gdi._mask_left = _charset->_strLeft;
if (_charset->_strRight > gdi._mask_right)
gdi._mask_right = _charset->_strRight;
if (_charset->_strTop < gdi._mask_top)
gdi._mask_top = _charset->_strTop;
if (_charset->_strBottom > gdi._mask_bottom)
gdi._mask_bottom = _charset->_strBottom;
}
}
@@ -1118,7 +755,7 @@ void Scumm::initCharset(int charsetno)
_string[1].t_charset = charsetno;
for (i = 0; i < 16; i++)
_charset._colorMap[i] = _charsetData[_charset.getCurID()][i];
_charset->_colorMap[i] = _charsetData[_charset->getCurID()][i];
}
void Scumm::loadLanguageBundle() {
File file;