diff options
author | Max Horn | 2002-08-21 16:07:07 +0000 |
---|---|---|
committer | Max Horn | 2002-08-21 16:07:07 +0000 |
commit | ce46866403fdcc479cf9d67e4d430409b15dadc3 (patch) | |
tree | 75ebfaa1ed13f549959d76d3ce101c3e66f5451b /scumm/string.cpp | |
parent | 662256f25dbe43abf67077a804e225738765f009 (diff) | |
download | scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.tar.gz scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.tar.bz2 scummvm-rg350-ce46866403fdcc479cf9d67e4d430409b15dadc3.zip |
Initial revision
svn-id: r4785
Diffstat (limited to 'scumm/string.cpp')
-rw-r--r-- | scumm/string.cpp | 1056 |
1 files changed, 1056 insertions, 0 deletions
diff --git a/scumm/string.cpp b/scumm/string.cpp new file mode 100644 index 0000000000..00f1cdd04d --- /dev/null +++ b/scumm/string.cpp @@ -0,0 +1,1056 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001 Ludvig Strigeus + * Copyright (C) 2001/2002 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * $Header$ + * + */ + +#include "stdafx.h" +#include "scumm.h" +#include "actor.h" + +int CharsetRenderer::getStringWidth(int arg, byte *text, int pos) +{ + byte *ptr; + int width, offs, w; + byte chr; + + width = 1; + ptr = _vm->getResourceAddress(rtCharset, _curId) + 29; + if (_vm->_features & GF_SMALL_HEADER) + ptr -= 12; + + while ((chr = text[pos++]) != 0) { + if (chr == 0xD) + break; + if (chr == '@') + continue; + if (chr == 254) + chr = 255; + if (chr == 255) { + chr = text[pos++]; + if (chr == 3) + break; + if (chr == 8) { + 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) + break; + if (chr == 14) { + int set = text[pos] | (text[pos + 1] << 8); + pos += 2; + ptr = _vm->getResourceAddress(rtCharset, set) + 29; + if (_vm->_features & GF_SMALL_HEADER) + ptr -= 12; + continue; + } + } + if (_vm->_features & GF_OLD256) { + width += 8; + } else { + offs = READ_LE_UINT32(ptr + chr * 4 + 4); + if (offs) { + if (ptr[offs + 2] >= 0x80) { + w = ptr[offs + 2] - 0x100; + } else { + w = ptr[offs + 2]; + } + width += ptr[offs] + w; + } + } + } + return width; +} + +void CharsetRenderer::addLinebreaks(int a, byte *str, int pos, int maxwidth) +{ + int lastspace = -1; + int curw = 1; + int offs, w; + byte *ptr; + byte chr; + + ptr = _vm->getResourceAddress(rtCharset, _curId) + 29; + if (_vm->_features & GF_SMALL_HEADER) + ptr -= 12; + + while ((chr = str[pos++]) != 0) { + if (chr == '@') + continue; + if (chr == 254) + chr = 255; + if (chr == 255) { + chr = str[pos++]; + if (chr == 3) + break; + if (chr == 8) { + 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) { + curw = 1; + continue; + } + if (chr == 2) + break; + if (chr == 14) { + int set = str[pos] | (str[pos + 1] << 8); + pos += 2; + ptr = _vm->getResourceAddress(rtCharset, set) + 29; + if (_vm->_features & GF_SMALL_HEADER) + ptr -= 12; + continue; + } + } + + if (chr == ' ') + lastspace = pos - 1; + if (_vm->_features & GF_OLD256) { + curw += getSpacing(chr); + } else { + offs = READ_LE_UINT32(ptr + chr * 4 + 4); + if (offs) { + if (ptr[offs + 2] >= 0x80) { + w = ptr[offs + 2] - 0x100; + } else { + w = ptr[offs + 2]; + } + curw += w + ptr[offs]; + } + } + if (lastspace == -1) + continue; + if (curw > maxwidth) { + str[lastspace] = 0xD; + curw = 1; + pos = lastspace + 1; + lastspace = -1; + } + } +} + +void Scumm::unkMessage1() +{ + byte buffer[100]; + _msgPtrToAdd = buffer; + _messagePtr = addMessageToStack(_messagePtr); + + if (buffer[0] == 0xFF && buffer[1] == 10) { + uint32 a, b; + + a = buffer[2] | (buffer[3] << 8) | (buffer[6] << 16) | (buffer[7] << 24); + b = buffer[10] | (buffer[11] << 8) | (buffer[14] << 16) | (buffer[15] << 24); +// if (_saveSound != 1) + _sound->talkSound(a, b, 1); + } +// warning("unkMessage1(\"%s\")", buffer); +} + +void Scumm::unkMessage2() +{ + byte buf[100], *tmp; + + _msgPtrToAdd = buf; + tmp = _messagePtr = addMessageToStack(_messagePtr); + + if (string[3].color == 0) + string[3].color = 4; + + warning("unkMessage2(\"%s\")", buf); + _messagePtr = tmp; +} + + +void Scumm::CHARSET_1() +{ + int s, i, t, c; + int frme; + Actor *a; + byte *buffer; + + if (!_haveMsg) + return; + + // FIXME: This Zak check fixes several hangs (Yak hang, and opening + // 'secret room while walking' hang. It doesn't do the camera check + // when the talk target isn't an actor. The question is, can we make + // this a more general case? Does it really need to be Zak specific? + if (!(_features & GF_AFTER_V7) && !(_gameId==GID_ZAK256 && _vars[VAR_TALK_ACTOR] == 0xFF)) { + if ((camera._dest.x >> 3) != (camera._cur.x >> 3) || camera._cur.x != camera._last.x) + return; + } + + a = NULL; + if (_vars[VAR_TALK_ACTOR] != 0xFF) + a = derefActorSafe(_vars[VAR_TALK_ACTOR], "CHARSET_1"); + + if (a && string[0].overhead != 0) { + if (!(_features & GF_AFTER_V6)) { + string[0].xpos = a->x - camera._cur.x + 160; + + if (_vars[VAR_V5_TALK_STRING_Y] < 0) { + s = (a->scaley * (int)_vars[VAR_V5_TALK_STRING_Y]) / 0xFF; + string[0].ypos = ((_vars[VAR_V5_TALK_STRING_Y] - s) >> 1) + s - a->elevation + a->y; + } else { + string[0].ypos = _vars[VAR_V5_TALK_STRING_Y]; + } + if (string[0].ypos < 1) + string[0].ypos = 1; + + if (string[0].xpos < 80) + string[0].xpos = 80; + if (string[0].xpos > 240) + string[0].xpos = 240; + } else { + s = a->scaley * a->new_1 / 0xFF; + string[0].ypos = ((a->new_1 - s) >> 1) + s - a->elevation + a->y; + if (string[0].ypos < 1) + string[0].ypos = 1; + + if (string[0].ypos < camera._cur.y - 100) + + string[0].ypos = camera._cur.y - 100; + + s = a->scalex * a->new_2 / 0xFF; + string[0].xpos = ((a->new_2 - s) >> 1) + s + a->x - camera._cur.x + 160; + if (string[0].xpos < 80) + string[0].xpos = 80; + if (string[0].xpos > 240) + string[0].xpos = 240; + } + } + + charset._top = string[0].ypos; + charset._left = string[0].xpos; + charset._left2 = string[0].xpos; + charset._curId = string[0].charset; + + if (a && a->charset) + charset._curId = a->charset; + + charset._center = string[0].center; + charset._right = string[0].right; + charset._color = _charsetColor; + _bkColor = 0; + + if (!(_features & GF_OLD256)) // FIXME + for (i = 0; i < 4; i++) + if (_features & GF_SMALL_HEADER) + charset._colorMap[i] = _charsetData[charset._curId][i - 12]; + else + charset._colorMap[i] = _charsetData[charset._curId][i]; + + if (_keepText) { + charset._strLeft = gdi._mask_left; + charset._strRight = gdi._mask_right; + charset._strTop = gdi._mask_top; + charset._strBottom = gdi._mask_bottom; + } + + if (_talkDelay) + return; + + if (_haveMsg != 0xFF && _haveMsg != 0xFE) { + if (_sound->_sfxMode == 0) + stopTalk(); + return; + } + + if (a && !string[0].no_talk_anim) { + a->startAnimActor(a->talkFrame1); + _useTalkAnims = true; + } + + _talkDelay = _defaultTalkDelay; + + if (!_keepText) { + if (_features & GF_OLD256) { + gdi._mask_left = string[0].xpos; + gdi._mask_top = string[0].ypos; + gdi._mask_bottom = string[0].ypos + 8; + gdi._mask_right = 320; + if (string[0].ypos <= 16) // If we are cleaning the text line, clean 2 lines. + gdi._mask_bottom = 16; + } + restoreCharsetBg(); + charset._xpos2 = string[0].xpos; + charset._ypos2 = string[0].ypos; + } + + t = charset._right - string[0].xpos - 1; + if (charset._center) { + if (t > charset._xpos2) + t = charset._xpos2; + t <<= 1; + } + + buffer = charset._buffer + charset._bufPos; + charset.addLinebreaks(0, buffer, 0, t); + + _lastXstart = virtscr[0].xstart; + if (charset._center) { + charset._xpos2 -= charset.getStringWidth(0, buffer, 0) >> 1; + if (charset._xpos2 < 0) + charset._xpos2 = 0; + } + + charset._disableOffsX = charset._unk12 = !_keepText; + + do { + c = *buffer++; + if (c == 0) { + // End of text reached, set _haveMsg to 1 so that the text will be + // removed next time CHARSET_1 is called. + _haveMsg = 1; + _keepText = false; + break; + } + if (c == 13) { + newLine:; + if (_features & GF_OLD256) { + charset._ypos2 = 8; + charset._xpos2 = 0; + continue; + } else { + charset._xpos2 = string[0].xpos; + if (charset._center) { + charset._xpos2 -= charset.getStringWidth(0, buffer, 0) >> 1; + } + if (_features & GF_SMALL_HEADER) + charset._ypos2 += getResourceAddress(rtCharset, charset._curId)[18]; + else + charset._ypos2 += getResourceAddress(rtCharset, charset._curId)[30]; + charset._disableOffsX = 1; + continue; + } + } + + if (c == 0xFE) + c = 0xFF; + + if (c != 0xFF) { + charset._left = charset._xpos2; + charset._top = charset._ypos2; + if (_features & GF_OLD256) + charset.printCharOld(c); + else if (!(_features & GF_AFTER_V6)) { +// if (!_vars[VAR_V5_CHARFLAG]) { /* FIXME */ + if (!(_haveMsg == 0xFE && _noSubtitles)) + charset.printChar(c); +// } + } else { + if (!(_haveMsg == 0xFE && _noSubtitles)) + charset.printChar(c); + } + + charset._xpos2 = charset._left; + charset._ypos2 = charset._top; + _talkDelay += _vars[VAR_CHARINC]; + continue; + } + + c = *buffer++; + if (c == 3) { + if (_haveMsg != 0xFE) + _haveMsg = 0xFF; + _keepText = false; + break; + } else if (c == 1) { + goto newLine; + } else if (c == 2) { + _haveMsg = 0; + _keepText = true; + break; + } else if (c == 9) { + frme = *buffer++; + frme |= *buffer++ << 8; + if (a) + a->startAnimActor(frme); + } else if (c == 10) { + uint32 tmpA, tmpB; + + tmpA = buffer[0] | (buffer[1] << 8) | (buffer[4] << 16) | (buffer[5] << 24); + tmpB = buffer[8] | (buffer[9] << 8) | (buffer[12] << 16) | (buffer[13] << 24); + _sound->talkSound(tmpA, tmpB, 2); + buffer += 14; + + // Set flag that speech variant exist of this msg + if (_haveMsg == 0xFF) + _haveMsg = 0xFE; + } else if (c == 14) { + int oldy = getResourceAddress(rtCharset, charset._curId)[30]; + + charset._curId = *buffer++; + buffer += 2; + for (i = 0; i < 4; i++) + if (_features & GF_SMALL_HEADER) + charset._colorMap[i] = _charsetData[charset._curId][i - 12]; + else + charset._colorMap[i] = _charsetData[charset._curId][i]; + charset._ypos2 -= getResourceAddress(rtCharset, charset._curId)[30] - oldy; + } else if (c == 12) { + int color; + color = *buffer++; + color |= *buffer++ << 8; + if (color == 0xFF) + charset._color = _charsetColor; + else + charset._color = color; + } else if (c == 13) { + buffer += 2; + } else { + warning("CHARSET_1: invalid code %d", c); + } + } while (1); + + 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; +} + +void Scumm::description() +{ + int c; + byte *buffer; + + buffer = charset._buffer + charset._bufPos; + string[0].ypos = camera._cur.y + 88; + string[0].xpos = 160 - (charset.getStringWidth(0, buffer, 0) >> 1); + if (string[0].xpos < 0) + string[0].xpos = 0; + + charset._top = string[0].ypos; + charset._left = string[0].xpos; + charset._left2 = string[0].xpos; + charset._right = 319; + charset._xpos2 = string[0].xpos; + charset._ypos2 = string[0].ypos; + charset._disableOffsX = charset._unk12 = 1; + charset._curId = 3; + charset._center = false; + charset._color = 15; + _bkColor = 0; + _talkDelay = 1; + + restoreCharsetBg(); + + _lastXstart = virtscr[0].xstart; + + do { + c = *buffer++; + if (c == 0) { + _haveMsg = 1; + break; + } + if (c != 0xFF) { + charset._left = charset._xpos2; + charset._top = charset._ypos2; + charset.printChar(c); + charset._xpos2 = charset._left; + charset._ypos2 = 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; +} + +void Scumm::drawString(int a) +{ + byte buf[256]; + byte *charsetptr, *space; + int i; + byte byte1 = 0, chr; + uint color; + + _msgPtrToAdd = buf; + _messagePtr = addMessageToStack(_messagePtr); + + charset._left2 = charset._left = string[a].xpos; + charset._top = string[a].ypos; + charset._curId = string[a].charset; + charset._center = string[a].center; + charset._right = string[a].right; + charset._color = string[a].color; + _bkColor = 0; + charset._unk12 = 1; + charset._disableOffsX = 1; + + if (!(_features & GF_OLD256)) { + charsetptr = getResourceAddress(rtCharset, charset._curId); + assert(charsetptr); + charsetptr += 29; + if (_features & GF_SMALL_HEADER) + charsetptr -= 12; + + for (i = 0; i < 4; i++) + if (_features & GF_SMALL_HEADER) + charset._colorMap[i] = _charsetData[charset._curId][i - 12]; + else + charset._colorMap[i] = _charsetData[charset._curId][i]; + + byte1 = charsetptr[1]; + } + + _msgPtrToAdd = buf; + + /* trim from the right */ + space = NULL; + while (*_msgPtrToAdd) { + if (*_msgPtrToAdd == ' ') { + if (!space) + space = _msgPtrToAdd; + } else { + space = NULL; + } + _msgPtrToAdd++; + } + if (space) + *space = '\0'; + if (charset._center) { + charset._left -= charset.getStringWidth(a, buf, 0) >> 1; + } + + charset._ignoreCharsetMask = 1; + + if (!buf[0]) { + buf[0] = ' '; + buf[1] = 0; + } + + for (i = 0; (chr = buf[i++]) != 0;) { + if (chr == 254) + chr = 255; + if (chr == 255) { + chr = buf[i++]; + switch (chr) { + case 9: + case 10: + case 13: + case 14: + i += 2; + break; + case 1: + case 8: + if (charset._center) { + charset._left = charset._left2 - charset.getStringWidth(a, buf, i); + } else { + charset._left = charset._left2; + } + charset._top += byte1; + break; + case 12: + color = buf[i] + (buf[i + 1] << 8); + i += 2; + if (color == 0xFF) + charset._color = string[a].color; + else + charset._color = color; + break; + } + } else { + if (a == 1 && (_features & GF_AFTER_V6)) + + if (string[a].no_talk_anim == 0) + charset._blitAlso = true; + if (_features & GF_OLD256) + charset.printCharOld(chr); + else + charset.printChar(chr); + charset._blitAlso = false; + } + } + + charset._ignoreCharsetMask = 0; + + if (a == 0) { + charset._xpos2 = charset._left; + charset._ypos2 = charset._top; + } +} + +byte *Scumm::addMessageToStack(byte *msg) +{ + int num, numorg; + byte *ptr, chr; + + numorg = num = _numInMsgStack; + ptr = getResourceAddress(rtTemp, 6); + + if (ptr == NULL) + error("Message stack not allocated"); + + if (msg == NULL) { + warning("Bad message in addMessageToStack, ignoring"); + return NULL; + } + + while ((chr = *msg++) != 0) { + if (num > 500) + error("Message stack overflow"); + + ptr[num++] = chr; + + if (chr == 255) { + ptr[num++] = chr = *msg++; + + if (chr != 1 && chr != 2 && chr != 3 && chr != 8) { + ptr[num++] = chr = *msg++; + ptr[num++] = chr = *msg++; + } + } + } + ptr[num++] = 0; + + _numInMsgStack = num; + num = numorg; + + while (1) { + ptr = getResourceAddress(rtTemp, 6); + chr = ptr[num++]; + if (chr == 0) + break; + if (chr == 0xFF) { + chr = ptr[num++]; + switch (chr) { + case 4: + unkAddMsgToStack2(READ_LE_UINT16(ptr + num)); + num += 2; + break; + case 5: + unkAddMsgToStack3(READ_LE_UINT16(ptr + num)); + num += 2; + break; + case 6: + unkAddMsgToStack4(READ_LE_UINT16(ptr + num)); + num += 2; + break; + case 7: + unkAddMsgToStack5(READ_LE_UINT16(ptr + num)); + num += 2; + break; + case 9: +//#if defined(DOTT) + case 10: + case 12: + case 13: + case 14: +//#endif + *_msgPtrToAdd++ = 0xFF; + *_msgPtrToAdd++ = chr; + *_msgPtrToAdd++ = ptr[num++]; + *_msgPtrToAdd++ = ptr[num++]; + break; + default: + *_msgPtrToAdd++ = 0xFF; + *_msgPtrToAdd++ = chr; + } + } else { + if (chr != '@') { + *_msgPtrToAdd++ = chr; + } + } + } + *_msgPtrToAdd = 0; + _numInMsgStack = numorg; + + return msg; +} + +void Scumm::unkAddMsgToStack2(int var) +{ + int num, max; + byte flag; + + num = readVar(var); + if (num < 0) { + *_msgPtrToAdd++ = '-'; + num = -num; + } + + flag = 0; + max = 10000; + do { + if (num >= max || flag) { + *_msgPtrToAdd++ = num / max + '0'; + num -= (num / max) * max; + flag = 1; + } + max /= 10; + if (max == 1) + flag = 1; + } while (max); +} + +void Scumm::unkAddMsgToStack3(int var) +{ + int num, i; + + num = readVar(var); + if (num) { + for (i = 1; i < _maxVerbs; i++) { + if (num == _verbs[i].verbid && !_verbs[i].type && !_verbs[i].saveid) { + addMessageToStack(getResourceAddress(rtVerb, i)); + break; + } + } + } else { + addMessageToStack((byte *)""); + } +} + +void Scumm::unkAddMsgToStack4(int var) +{ + int num; + + num = readVar(var); + if (num) { + addMessageToStack(getObjOrActorName(num)); + } else { + addMessageToStack((byte *)""); + } +} + +void Scumm::unkAddMsgToStack5(int var) +{ + byte *ptr; + + if (_features & GF_AFTER_V6 || _gameId == GID_INDY3_256) + var = readVar(var); + + if (var) { + ptr = getStringAddress(var); + if (ptr) { + addMessageToStack(ptr); + return; + } + } + addMessageToStack((byte *)""); +} + +void Scumm::initCharset(int charsetno) +{ + int i; + + if (_features & GF_OLD256) + charsetno = !charsetno; + + if (_features & GF_SMALL_HEADER) + loadCharset(charsetno); + else if (!getResourceAddress(rtCharset, charsetno)) + loadCharset(charsetno); + + string[0].t_charset = charsetno; + string[1].t_charset = charsetno; + + for (i = 0; i < 0x10; i++) + if (_features & GF_SMALL_HEADER) + charset._colorMap[i] = _charsetData[charset._curId][i - 12]; + else + charset._colorMap[i] = _charsetData[charset._curId][i]; +} + +void CharsetRenderer::printCharOld(int chr) +{ // Loom3 / 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 (_unk12) { + _strLeft = _left; + _strTop = _top; + _strRight = _left; + _strBottom = _top; + _unk12 = 0; + } + char_ptr = _vm->getResourceAddress(rtCharset, _curId) + 224 + (chr + 1) * 8; + dest_ptr = vs->screenPtr + vs->xstart + (_top - vs->topline) * 320 + _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 * 320 + x) = _color; + } + } + + _left += getSpacing(chr); + + if (_left > _strRight) + _strRight = _left; + + if (_top + 8 > _strBottom) + _strBottom = _top + 8; + +} + + +void CharsetRenderer::printChar(int chr) +{ + int d, right; + VirtScreen *vs; + + _vm->checkRange(_vm->_maxCharsets - 1, 1, _curId, "Printing with bad charset %d"); + if ((vs = _vm->findVirtScreen(_top)) == NULL) + return; + + if (chr == '@') + return; + + _ptr = _vm->getResourceAddress(rtCharset, _curId) + 29; + if (_vm->_features & GF_SMALL_HEADER) + _ptr -= 12; + + _bpp = _unk2 = *_ptr; + _invNumBits = 8 - _bpp; + _bitMask = 0xFF << _invNumBits; + _colorMap[1] = _color; + + _charOffs = READ_LE_UINT32(_ptr + chr * 4 + 4); + + if (!_charOffs) + return; + + assert(_charOffs < 0x10000); + + _charPtr = _ptr + _charOffs; + + _width = _charPtr[0]; + _height = _charPtr[1]; + if (_unk12) { + _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; + + right = _left + _width; + + if (right > _right + 1 || _left < 0) { + _left = right; + _top -= _offsY; + return; + } + + _disableOffsX = 0; + + if (_unk12) { + _strLeft = _left; + _strTop = _top; + _strRight = _left; + _strBottom = _top; + _unk12 = 0; + } + + if (_left < _strLeft) + _strLeft = _left; + + if (_top < _strTop) + _strTop = _top; + + _drawTop = _top - vs->topline; + if (_drawTop < 0) + _drawTop = 0; + + _bottom = _drawTop + _height + _offsY; + + _vm->updateDirtyRect(vs->number, _left, right, _drawTop, _bottom, 0); + +#if defined(OLD) + if (vs->number == 0) + _hasMask = true; +#else + if (vs->number != 0) + _blitAlso = false; + if (vs->number == 0 && _blitAlso == 0) + _hasMask = true; +#endif + + _dest_ptr = _backbuff_ptr = vs->screenPtr + vs->xstart + _drawTop * 320 + _left; + +#if !defined(OLD) + if (_blitAlso) { +#else + if (1) { +#endif + _dest_ptr = _bgbak_ptr = _vm->getResourceAddress(rtBuffer, vs->number + 5) + + vs->xstart + _drawTop * 320 + _left; + } + + _mask_ptr = _vm->getResourceAddress(rtBuffer, 9) + + _drawTop * 40 + _left / 8 + _vm->_screenStartStrip; + + _revBitMask = revBitMask[_left & 7]; + + _virtScreenHeight = vs->height; + _charPtr += 4; + + drawBits(); + +#if !defined(OLD) + if (_blitAlso) + blit(_backbuff_ptr, _bgbak_ptr, _width, _height); +#endif + + _left += _width; + if (_left > _strRight) + _strRight = _left; + + if (_top + _height > _strBottom) + _strBottom = _top + _height; + + _top -= _offsY; +} + +void CharsetRenderer::drawBits() +{ + bool usemask; + byte *dst, *mask, maskmask; + int y, x; + int maskpos; + int color; + byte numbits, bits; + + usemask = (_vm->_curVirtScreen->number == 0 && _ignoreCharsetMask == 0); + + bits = *_charPtr++; + numbits = 8; + + dst = _dest_ptr; + mask = _mask_ptr; + y = 0; + + for (y = 0; y < _height && y + _drawTop < _virtScreenHeight;) { + maskmask = _revBitMask; + maskpos = 0; + + for (x = 0; x < _width; x++) { + color = (bits & _bitMask) >> _invNumBits; + if (color) { + if (usemask) { + mask[maskpos] |= maskmask; + } + *dst = _colorMap[color]; + } + dst++; + bits <<= _bpp; + if ((numbits -= _bpp) == 0) { + bits = *_charPtr++; + numbits = 8; + } + if ((maskmask >>= 1) == 0) { + maskmask = 0x80; + maskpos++; + } + } + dst = (_dest_ptr += 320); + mask += 40; + y++; + } +} + +int CharsetRenderer::getSpacing(char chr) +{ + int space; + + if (_curId == 1) { // do spacing for variable width old-style font + switch (chr) { + case '.': + space = 1; + break; + case 'i': + case '\'': + case 'I': + case '!': + space = 2; + break; + case 'l': + space = 3; + break; + case ' ': + space = 4; + break; + case 'W': + case 'w': + case 'N': + case 'M': + case 'm': + space = 8; + break; + default: + space = 6; + } + } else + space = 7; + return space; +} |