SCUMM: (SCUMM7/8) - reorganize font rendering - second part
- Attach actor talk texts to the appropriate text renderer and get rid of redundant code. - Cleanup subtitle text handling. - Fix handling of ^codes. - Fix more regressions from last commit. - Correct some x/y positioning.
This commit is contained in:
parent
1f56132725
commit
0256e92c25
10 changed files with 164 additions and 448 deletions
|
@ -1965,21 +1965,39 @@ void CharsetRendererMac::setColor(byte color) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_SCUMM_7_8
|
#ifdef ENABLE_SCUMM_7_8
|
||||||
int CharsetRendererV7::draw2byte(byte *buffer, Common::Rect &clipRect, int x, int y, int pitch, int16 col, uint16 chr) {
|
int CharsetRendererV7::draw2byte(byte*, Common::Rect &clipRect, int x, int y, int pitch, int16 col, uint16 chr) {
|
||||||
if (!prepareDraw(chr))
|
if (_vm->isScummvmKorTarget()) {
|
||||||
|
enableShadow(true);
|
||||||
|
_charPtr = _vm->get2byteCharPtr(chr);
|
||||||
|
_origWidth = _width = _vm->_2byteWidth;
|
||||||
|
_origHeight = _height = _vm->_2byteHeight;
|
||||||
|
_offsX = _offsY = 0;
|
||||||
|
} else if (!prepareDraw(chr)) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_color = col;
|
||||||
VirtScreen &vs = _vm->_virtscr[kMainVirtScreen];
|
VirtScreen &vs = _vm->_virtscr[kMainVirtScreen];
|
||||||
drawBits1(vs, x + vs.xstart, y, _charPtr, MAX<int>(clipRect.top, y), _width - 1, _height);
|
drawBits1(vs, x + vs.xstart, y, _charPtr, MAX<int>(clipRect.top, y), _origWidth, _origHeight);
|
||||||
return _width;
|
|
||||||
|
return _origWidth + _spacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CharsetRendererV7::drawChar(byte *buffer, Common::Rect &clipRect, int x, int y, int pitch, int16 col, byte chr) {
|
int CharsetRendererV7::drawChar(byte *buffer, Common::Rect &clipRect, int x, int y, int pitch, int16 col, byte chr) {
|
||||||
if (!prepareDraw(chr))
|
if (!prepareDraw(chr))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (_vm->isScummvmKorTarget()) {
|
||||||
|
_origWidth = _width;
|
||||||
|
_origHeight = _height;
|
||||||
|
}
|
||||||
|
|
||||||
|
_width = getCharWidth(chr);
|
||||||
|
|
||||||
|
_vm->_charsetColorMap[1] = col;
|
||||||
VirtScreen &vs = _vm->_virtscr[kMainVirtScreen];
|
VirtScreen &vs = _vm->_virtscr[kMainVirtScreen];
|
||||||
drawBitsN(vs, buffer + y * vs.pitch + x, _charPtr, _vm->_bytesPerPixel, y, _origWidth, _origHeight);
|
drawBitsN(vs, buffer + (y + _offsY) * vs.pitch + vs.xstart + x, _charPtr, *_fontPtr, y, _origWidth, _origHeight);
|
||||||
|
|
||||||
return _width;
|
return _width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2027,7 +2045,7 @@ int CharsetRendererNut::getCharHeight(uint16 chr) const {
|
||||||
|
|
||||||
int CharsetRendererNut::getCharWidth(uint16 chr) const {
|
int CharsetRendererNut::getCharWidth(uint16 chr) const {
|
||||||
assert(_current);
|
assert(_current);
|
||||||
return _current->getCharWidth(chr);
|
return _current->getCharWidth(chr & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CharsetRendererNut::getFontHeight() const {
|
int CharsetRendererNut::getFontHeight() const {
|
||||||
|
@ -2035,122 +2053,6 @@ int CharsetRendererNut::getFontHeight() const {
|
||||||
return _current->getFontHeight();
|
return _current->getFontHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
int CharsetRendererNut::getStringWidth(int arg, const byte *text, uint strLenMax) {
|
|
||||||
// SCUMM7 games actually use the same implemention (minus the strLenMax parameter). If
|
|
||||||
// any text placement bugs in one of these games come up it might be worth to look at
|
|
||||||
// that. Or simply for the fact that we could get rid of SmushFont::getStringWidth()...
|
|
||||||
if (!strLenMax)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int maxWidth = 0;
|
|
||||||
int width = 0;
|
|
||||||
|
|
||||||
while (*text && strLenMax) {
|
|
||||||
while (text[0] == '^') {
|
|
||||||
switch (text[1]) {
|
|
||||||
case 'f':
|
|
||||||
// We should change the font on the fly at this point
|
|
||||||
// which would result in a different width result.
|
|
||||||
// This has never been observed in the game though, and
|
|
||||||
// as such, we don't handle it.
|
|
||||||
text += 4;
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
text += 5;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
error("CharsetRenderer::getStringWidth(): Invalid escape code in text string");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is2ByteCharacter(_vm->_language, *text)) {
|
|
||||||
width += _vm->_2byteWidth + (_vm->_language != Common::JA_JPN ? 1 : 0);
|
|
||||||
++text;
|
|
||||||
--strLenMax;
|
|
||||||
} else if (*text == '\n') {
|
|
||||||
maxWidth = MAX<int>(width, maxWidth);
|
|
||||||
width = 0;
|
|
||||||
} else if (*text != '\r' && *text != _vm->_newLineCharacter) {
|
|
||||||
width += getCharWidth(*text);
|
|
||||||
}
|
|
||||||
|
|
||||||
++text;
|
|
||||||
--strLenMax;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MAX<int>(width, maxWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CharsetRendererNut::printChar(int chr, bool ignoreCharsetMask) {
|
|
||||||
/*Common::Rect shadow;
|
|
||||||
|
|
||||||
assert(_current);
|
|
||||||
if (chr == '@')
|
|
||||||
return;
|
|
||||||
|
|
||||||
shadow.left = _left;
|
|
||||||
shadow.top = _top;
|
|
||||||
|
|
||||||
if (_firstChar) {
|
|
||||||
_str.left = (shadow.left >= 0) ? shadow.left : 0;
|
|
||||||
_str.top = (shadow.top >= 0) ? shadow.top : 0;
|
|
||||||
_str.right = _str.left;
|
|
||||||
_str.bottom = _str.top;
|
|
||||||
_firstChar = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int width = _current->getCharWidth(chr);
|
|
||||||
int height = _current->getCharHeight(chr);
|
|
||||||
|
|
||||||
bool is2byte = chr >= 256 && _vm->_useCJKMode;
|
|
||||||
if (is2byte) {
|
|
||||||
width = _vm->_2byteWidth;
|
|
||||||
if (_vm->_game.id == GID_CMI)
|
|
||||||
height++; // One extra pixel for the shadow
|
|
||||||
}
|
|
||||||
|
|
||||||
shadow.right = _left + width;
|
|
||||||
shadow.bottom = _top + height;
|
|
||||||
|
|
||||||
Graphics::Surface s;
|
|
||||||
if (!ignoreCharsetMask) {
|
|
||||||
_hasMask = true;
|
|
||||||
_textScreenID = kMainVirtScreen;
|
|
||||||
}
|
|
||||||
|
|
||||||
int drawTop = _top;
|
|
||||||
if (ignoreCharsetMask) {
|
|
||||||
VirtScreen *vs = &_vm->_virtscr[kMainVirtScreen];
|
|
||||||
s = *vs;
|
|
||||||
s.setPixels(vs->getPixels(0, 0));
|
|
||||||
} else {
|
|
||||||
s = _vm->_textSurface;
|
|
||||||
drawTop -= _vm->_screenTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::Rect clipRect(s.w, s.h);
|
|
||||||
if (chr >= 256 && _vm->_useCJKMode)
|
|
||||||
_current->draw2byte((uint8*)s.getBasePtr(0, 0), clipRect, _left, drawTop, s.pitch, _color, chr);
|
|
||||||
else
|
|
||||||
_current->drawChar((uint8*)s.getBasePtr(0, 0), clipRect, _left, drawTop, s.pitch, _color, (byte)chr);
|
|
||||||
_vm->markRectAsDirty(kMainVirtScreen, shadow);
|
|
||||||
|
|
||||||
if (_str.left > _left)
|
|
||||||
_str.left = _left;
|
|
||||||
|
|
||||||
// Original keeps glyph width and character dimensions separately
|
|
||||||
if ((_vm->_language == Common::ZH_TWN || _vm->_language == Common::KO_KOR) && is2byte)
|
|
||||||
width++;
|
|
||||||
|
|
||||||
_left += width;
|
|
||||||
|
|
||||||
if (_str.right < shadow.right)
|
|
||||||
_str.right = shadow.right;
|
|
||||||
|
|
||||||
if (_str.bottom < shadow.bottom)
|
|
||||||
_str.bottom = shadow.bottom;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
int CharsetRendererNut::draw2byte(byte *buffer, Common::Rect &clipRect, int x, int y, int pitch, int16 col, uint16 chr) {
|
int CharsetRendererNut::draw2byte(byte *buffer, Common::Rect &clipRect, int x, int y, int pitch, int16 col, uint16 chr) {
|
||||||
assert(_current);
|
assert(_current);
|
||||||
return _current->draw2byte(buffer, clipRect, x, y, pitch, col, chr);
|
return _current->draw2byte(buffer, clipRect, x, y, pitch, col, chr);
|
||||||
|
|
|
@ -310,15 +310,20 @@ public:
|
||||||
#ifdef ENABLE_SCUMM_7_8
|
#ifdef ENABLE_SCUMM_7_8
|
||||||
class CharsetRendererV7 : public CharsetRendererClassic, public GlyphRenderer_v7 {
|
class CharsetRendererV7 : public CharsetRendererClassic, public GlyphRenderer_v7 {
|
||||||
public:
|
public:
|
||||||
CharsetRendererV7(ScummEngine *vm) : CharsetRendererClassic(vm) {}
|
CharsetRendererV7(ScummEngine *vm) : CharsetRendererClassic(vm), _spacing(vm->_useCJKMode && vm->_language != Common::JA_JPN ? 1 : 0) {}
|
||||||
~CharsetRendererV7() override {};
|
~CharsetRendererV7() override {};
|
||||||
|
|
||||||
|
void printChar(int chr, bool ignoreCharsetMask) override { error("CharsetRendererV7::printChar(): Unexpected legacy function call"); }
|
||||||
|
|
||||||
int draw2byte(byte *buffer, Common::Rect &clipRect, int x, int y, int pitch, int16 col, uint16 chr) override;
|
int draw2byte(byte *buffer, Common::Rect &clipRect, int x, int y, int pitch, int16 col, uint16 chr) override;
|
||||||
int drawChar(byte *buffer, Common::Rect &clipRect, int x, int y, int pitch, int16 col, byte chr) override;
|
int drawChar(byte *buffer, Common::Rect &clipRect, int x, int y, int pitch, int16 col, byte chr) override;
|
||||||
int getCharWidth(uint16 chr) const override { return CharsetRendererClassic::getCharWidth(chr); }
|
int getCharWidth(uint16 chr) const override { return ((chr & 0x80) && _vm->_useCJKMode) ? _vm->_2byteWidth + _spacing : CharsetRendererClassic::getCharWidth(chr); }
|
||||||
int getCharHeight(uint16 chr) const override { return ((chr & 0x80) && _vm->_useCJKMode) ? _vm->_2byteHeight + 1 : _fontHeight; }
|
int getCharHeight(uint16 chr) const override { return ((chr & 0x80) && _vm->_useCJKMode) ? _vm->_2byteHeight + 1 : _fontHeight; }
|
||||||
int getFontHeight() const override { return _fontHeight; }
|
int getFontHeight() const override { return _fontHeight; }
|
||||||
int setFont(int) override { return 0; }
|
int setFont(int) override { return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int _spacing;
|
||||||
};
|
};
|
||||||
|
|
||||||
class CharsetRendererNut : public CharsetRenderer, public GlyphRenderer_v7 {
|
class CharsetRendererNut : public CharsetRenderer, public GlyphRenderer_v7 {
|
||||||
|
@ -326,7 +331,7 @@ public:
|
||||||
CharsetRendererNut(ScummEngine *vm);
|
CharsetRendererNut(ScummEngine *vm);
|
||||||
~CharsetRendererNut() override;
|
~CharsetRendererNut() override;
|
||||||
|
|
||||||
void printChar(int chr, bool ignoreCharsetMask) override;
|
void printChar(int chr, bool ignoreCharsetMask) override { error("CharsetRendererNut::printChar(): Unexpected legacy function call"); }
|
||||||
|
|
||||||
void setCurID(int32 id) override;
|
void setCurID(int32 id) override;
|
||||||
int setFont(int id) override;
|
int setFont(int id) override;
|
||||||
|
|
|
@ -33,14 +33,28 @@ NutRenderer::NutRenderer(ScummEngine *vm, const char *filename) :
|
||||||
_maxCharSize(0),
|
_maxCharSize(0),
|
||||||
_fontHeight(0),
|
_fontHeight(0),
|
||||||
_charBuffer(0),
|
_charBuffer(0),
|
||||||
_decodedData(0) {
|
_decodedData(0),
|
||||||
memset(_chars, 0, sizeof(_chars));
|
_2byteColorTable(0),
|
||||||
loadFont(filename);
|
_2byteShadowXOffsetTable(0),
|
||||||
|
_2byteShadowYOffsetTable(0),
|
||||||
|
_2byteMainColor(0),
|
||||||
|
_spacing(vm->_useCJKMode && vm->_language != Common::JA_JPN ? 1 : 0),
|
||||||
|
_2byteSteps(vm->_game.version == 8 ? 4 : 2) {
|
||||||
|
static const int8 cjkShadowOffsetsX[4] = { -1, 0, 1, 0 };
|
||||||
|
static const int8 cjkShadowOffsetsY[4] = { 0, 1, 0, 0 };
|
||||||
|
_2byteShadowXOffsetTable = &cjkShadowOffsetsX[ARRAYSIZE(cjkShadowOffsetsX) - _2byteSteps];
|
||||||
|
_2byteShadowYOffsetTable = &cjkShadowOffsetsY[ARRAYSIZE(cjkShadowOffsetsY) - _2byteSteps];
|
||||||
|
_2byteColorTable = new uint8[_2byteSteps];
|
||||||
|
memset(_2byteColorTable, 0, _2byteSteps);
|
||||||
|
_2byteMainColor = &_2byteColorTable[_2byteSteps - 1];
|
||||||
|
memset(_chars, 0, sizeof(_chars));
|
||||||
|
loadFont(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
NutRenderer::~NutRenderer() {
|
NutRenderer::~NutRenderer() {
|
||||||
delete[] _charBuffer;
|
delete[] _charBuffer;
|
||||||
delete[] _decodedData;
|
delete[] _decodedData;
|
||||||
|
delete[] _2byteColorTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void smush_decode_codec1(byte *dst, const byte *src, int left, int top, int width, int height, int pitch);
|
void smush_decode_codec1(byte *dst, const byte *src, int left, int top, int width, int height, int pitch);
|
||||||
|
@ -260,7 +274,7 @@ void NutRenderer::loadFont(const char *filename) {
|
||||||
|
|
||||||
int NutRenderer::getCharWidth(byte c) const {
|
int NutRenderer::getCharWidth(byte c) const {
|
||||||
if (c >= 0x80 && _vm->_useCJKMode)
|
if (c >= 0x80 && _vm->_useCJKMode)
|
||||||
return _vm->_2byteWidth / 2;
|
return _vm->_2byteWidth + _spacing;
|
||||||
|
|
||||||
if (c >= _numChars)
|
if (c >= _numChars)
|
||||||
error("invalid character in NutRenderer::getCharWidth : %d (%d)", c, _numChars);
|
error("invalid character in NutRenderer::getCharWidth : %d (%d)", c, _numChars);
|
||||||
|
@ -369,6 +383,9 @@ int NutRenderer::drawChar(byte *buffer, Common::Rect &clipRect, int x, int y, in
|
||||||
dst += minY * pitch;
|
dst += minY * pitch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (minX)
|
||||||
|
dst += minX;
|
||||||
|
|
||||||
char color = (col != -1) ? col : 1;
|
char color = (col != -1) ? col : 1;
|
||||||
|
|
||||||
if (_vm->_game.version == 7) {
|
if (_vm->_game.version == 7) {
|
||||||
|
@ -426,39 +443,33 @@ int NutRenderer::draw2byte(byte *buffer, Common::Rect &clipRect, int x, int y, i
|
||||||
int height = MIN((int)_vm->_2byteHeight, clipRect.bottom - y);
|
int height = MIN((int)_vm->_2byteHeight, clipRect.bottom - y);
|
||||||
int minX = x < clipRect.left ? clipRect.left - x : 0;
|
int minX = x < clipRect.left ? clipRect.left - x : 0;
|
||||||
int minY = y < clipRect.top ? clipRect.top - y : 0;
|
int minY = y < clipRect.top ? clipRect.top - y : 0;
|
||||||
|
*_2byteMainColor = col;
|
||||||
|
|
||||||
if (width <= 0 || height <= 0)
|
if (width <= 0 || height <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const byte *src = _vm->get2byteCharPtr(chr);
|
const byte *src = _vm->get2byteCharPtr(chr);
|
||||||
byte bits = 0;
|
|
||||||
|
|
||||||
if (width <= 0 || height <= 0)
|
if (width <= 0 || height <= 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (minY) {
|
if (minY) {
|
||||||
src += minY * _vm->_2byteWidth;
|
src += ((minY * _vm->_2byteWidth) >> 3);
|
||||||
buffer += minY * pitch;
|
buffer += (minY * pitch);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ShadowMode {
|
if (minX) {
|
||||||
kNone,
|
src += (minX >> 3);
|
||||||
kNormalShadowMode,
|
buffer += minX;
|
||||||
kCJKv7ShadowMode,
|
}
|
||||||
kCJKv8ShadowMode
|
|
||||||
};
|
|
||||||
|
|
||||||
ShadowMode shadowMode = _vm->_useCJKMode ? (_vm->_game.version == 8 ? kCJKv8ShadowMode : kCJKv7ShadowMode) : kNone;
|
|
||||||
|
|
||||||
int shadowOffsetXTable[4] = { -1, 0, 1, 0 };
|
|
||||||
int shadowOffsetYTable[4] = { 0, 1, 0, 0 };
|
|
||||||
int shadowOffsetColorTable[4] = { 0, 0, 0, col };
|
|
||||||
|
|
||||||
|
byte bits = *src;
|
||||||
const byte *origSrc = src;
|
const byte *origSrc = src;
|
||||||
for (int shadowIdx = (shadowMode == kCJKv8ShadowMode) ? 0 : (shadowMode == kCJKv7ShadowMode ? 2 : 3); shadowIdx < 4; shadowIdx++) {
|
|
||||||
int offX = MAX<int>(x + shadowOffsetXTable[shadowIdx], clipRect.left);
|
for (int step = 0; step < _2byteSteps; ++step) {
|
||||||
int offY = MAX<int>(y + shadowOffsetYTable[shadowIdx], clipRect.top);
|
int offX = MAX<int>(x + _2byteShadowXOffsetTable[step], clipRect.left);
|
||||||
byte drawColor = shadowOffsetColorTable[shadowIdx];
|
int offY = MAX<int>(y + _2byteShadowYOffsetTable[step], clipRect.top);
|
||||||
|
byte drawColor = _2byteColorTable[step];
|
||||||
|
|
||||||
src = origSrc;
|
src = origSrc;
|
||||||
byte *dst = buffer + pitch * offY + offX;
|
byte *dst = buffer + pitch * offY + offX;
|
||||||
|
@ -469,99 +480,14 @@ int NutRenderer::draw2byte(byte *buffer, Common::Rect &clipRect, int x, int y, i
|
||||||
continue;
|
continue;
|
||||||
if ((i % 8) == 0)
|
if ((i % 8) == 0)
|
||||||
bits = *src++;
|
bits = *src++;
|
||||||
if (bits & revBitMask(i % 8)) {
|
if (bits & revBitMask(i % 8))
|
||||||
if (shadowMode == kNormalShadowMode) {
|
|
||||||
dst[i + 1] = 0;
|
|
||||||
dst[pitch + i] = 0;
|
|
||||||
dst[pitch + i + 1] = 0;
|
|
||||||
}
|
|
||||||
dst[i] = drawColor;
|
dst[i] = drawColor;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
dst += pitch;
|
dst += pitch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return width + 1;
|
|
||||||
|
return width + _spacing;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
void NutRenderer::drawChar(const Graphics::Surface &s, byte c, int x, int y, byte color) {
|
|
||||||
// FIXME: This gets passed a const destination Surface. Intuitively this
|
|
||||||
// should never get written to. But sadly it does... For now we simply
|
|
||||||
// cast the const qualifier away.
|
|
||||||
byte *dst = (byte *)const_cast<void *>(s.getBasePtr(x, y));
|
|
||||||
const int width = MIN((int)_chars[c].width, s.w - x);
|
|
||||||
const int height = MIN((int)_chars[c].height, s.h - y);
|
|
||||||
const byte *src = unpackChar(c);
|
|
||||||
int srcPitch = _chars[c].width;
|
|
||||||
|
|
||||||
const int minX = x < 0 ? -x : 0;
|
|
||||||
const int minY = y < 0 ? -y : 0;
|
|
||||||
|
|
||||||
if (height <= 0 || width <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (minY) {
|
|
||||||
src += minY * srcPitch;
|
|
||||||
dst += minY * s.pitch;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int ty = minY; ty < height; ty++) {
|
|
||||||
for (int tx = minX; tx < width; tx++) {
|
|
||||||
if (src[tx] != _chars[c].transparency) {
|
|
||||||
if (src[tx] == 1) {
|
|
||||||
dst[tx] = color;
|
|
||||||
} else {
|
|
||||||
dst[tx] = src[tx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
src += srcPitch;
|
|
||||||
dst += s.pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void NutRenderer::draw2byte(const Graphics::Surface &s, int c, int x, int y, byte color) {
|
|
||||||
const int width = _vm->_2byteWidth;
|
|
||||||
const int height = MIN(_vm->_2byteHeight, s.h - y);
|
|
||||||
const byte *src = _vm->get2byteCharPtr(c);
|
|
||||||
byte bits = 0;
|
|
||||||
|
|
||||||
if (height <= 0 || width <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int shadowOffsetXTable[4] = {-1, 0, 1, 0};
|
|
||||||
int shadowOffsetYTable[4] = {0, 1, 0, 0};
|
|
||||||
int shadowOffsetColorTable[4] = {0, 0, 0, color};
|
|
||||||
int shadowIdx = (_vm->_useCJKMode && _vm->_game.id == GID_CMI) ? 0 : 3;
|
|
||||||
|
|
||||||
const byte *origSrc = src;
|
|
||||||
|
|
||||||
for (; shadowIdx < 4; shadowIdx++) {
|
|
||||||
int offX = x + shadowOffsetXTable[shadowIdx];
|
|
||||||
int offY = y + shadowOffsetYTable[shadowIdx];
|
|
||||||
byte drawColor = shadowOffsetColorTable[shadowIdx];
|
|
||||||
|
|
||||||
// FIXME: This gets passed a const destination Surface. Intuitively this
|
|
||||||
// should never get written to. But sadly it does... For now we simply
|
|
||||||
// cast the const qualifier away.
|
|
||||||
byte *dst = (byte *)const_cast<void *>(s.getBasePtr(offX, offY));
|
|
||||||
src = origSrc;
|
|
||||||
|
|
||||||
for (int ty = 0; ty < height; ty++) {
|
|
||||||
for (int tx = 0; tx < width; tx++) {
|
|
||||||
if ((tx & 7) == 0)
|
|
||||||
bits = *src++;
|
|
||||||
if (offX + tx < 0 || offX + tx >= s.w || offY + ty < 0)
|
|
||||||
continue;
|
|
||||||
if (bits & revBitMask(tx % 8)) {
|
|
||||||
dst[tx] = drawColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dst += s.pitch;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
} // End of namespace Scumm
|
} // End of namespace Scumm
|
||||||
|
|
|
@ -41,12 +41,19 @@ protected:
|
||||||
int _numChars;
|
int _numChars;
|
||||||
int _maxCharSize;
|
int _maxCharSize;
|
||||||
int _fontHeight;
|
int _fontHeight;
|
||||||
|
int _spacing;
|
||||||
byte *_charBuffer;
|
byte *_charBuffer;
|
||||||
byte *_decodedData;
|
byte *_decodedData;
|
||||||
byte *_paletteMap;
|
byte *_paletteMap;
|
||||||
byte _bpp;
|
byte _bpp;
|
||||||
byte _palette[16];
|
byte _palette[16];
|
||||||
|
|
||||||
|
const int8 *_2byteShadowXOffsetTable;
|
||||||
|
const int8 *_2byteShadowYOffsetTable;
|
||||||
|
uint8 *_2byteColorTable;
|
||||||
|
uint8 *_2byteMainColor;
|
||||||
|
const int _2byteSteps;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
uint16 width;
|
uint16 width;
|
||||||
uint16 height;
|
uint16 height;
|
||||||
|
|
|
@ -1076,6 +1076,8 @@ ScummEngine_v7::ScummEngine_v7(OSystem *syst, const DetectorResult &dr)
|
||||||
clearSubtitleQueue();
|
clearSubtitleQueue();
|
||||||
|
|
||||||
_textV7 = NULL;
|
_textV7 = NULL;
|
||||||
|
_defaultTextClipRect = Common::Rect(_screenWidth, _screenHeight);
|
||||||
|
_wrappedTextClipRect = Common::Rect(10, 10, _screenWidth - 10, _screenHeight - 10);
|
||||||
|
|
||||||
_game.features |= GF_NEW_COSTUMES;
|
_game.features |= GF_NEW_COSTUMES;
|
||||||
}
|
}
|
||||||
|
@ -2980,7 +2982,6 @@ void ScummEngine::restart() {
|
||||||
// subclass which is implemented using a memory buffer (i.e. no actual file is
|
// subclass which is implemented using a memory buffer (i.e. no actual file is
|
||||||
// created). Then to restart we just have to load that pseudo save state.
|
// created). Then to restart we just have to load that pseudo save state.
|
||||||
|
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// Reset some stuff
|
// Reset some stuff
|
||||||
|
|
|
@ -66,6 +66,9 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TextRenderer_v7 *_textV7;
|
TextRenderer_v7 *_textV7;
|
||||||
|
Common::Rect _defaultTextClipRect;
|
||||||
|
Common::Rect _wrappedTextClipRect;
|
||||||
|
|
||||||
int _verbLineSpacing;
|
int _verbLineSpacing;
|
||||||
bool _existLanguageFile;
|
bool _existLanguageFile;
|
||||||
char *_languageBuffer;
|
char *_languageBuffer;
|
||||||
|
@ -80,10 +83,18 @@ protected:
|
||||||
byte charset;
|
byte charset;
|
||||||
byte text[256];
|
byte text[256];
|
||||||
bool actorSpeechMsg;
|
bool actorSpeechMsg;
|
||||||
|
bool center;
|
||||||
|
bool wrap;
|
||||||
};
|
};
|
||||||
#else
|
#else
|
||||||
struct SubtitleText : TextObject {
|
struct SubtitleText : TextObject {
|
||||||
|
void clear() {
|
||||||
|
TextObject::clear();
|
||||||
|
actorSpeechMsg = center = wrap = false;
|
||||||
|
}
|
||||||
bool actorSpeechMsg;
|
bool actorSpeechMsg;
|
||||||
|
bool center;
|
||||||
|
bool wrap;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -94,7 +105,7 @@ protected:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void processSubtitleQueue();
|
void processSubtitleQueue();
|
||||||
void addSubtitleToQueue(const byte *text, const Common::Point &pos, byte color, byte charset);
|
void addSubtitleToQueue(const byte *text, const Common::Point &pos, byte color, byte charset, bool center, bool wrap);
|
||||||
void clearSubtitleQueue();
|
void clearSubtitleQueue();
|
||||||
void CHARSET_1() override;
|
void CHARSET_1() override;
|
||||||
bool isSmushActive() { return _smushActive; }
|
bool isSmushActive() { return _smushActive; }
|
||||||
|
@ -128,7 +139,7 @@ protected:
|
||||||
int getObjectIdFromOBIM(const byte *obim) override;
|
int getObjectIdFromOBIM(const byte *obim) override;
|
||||||
|
|
||||||
void createTextRenderer(GlyphRenderer_v7 *gr) override;
|
void createTextRenderer(GlyphRenderer_v7 *gr) override;
|
||||||
void enqueueText(const byte *text, int x, int y, byte color, byte charset, bool center, bool wrapped = false);
|
void enqueueText(const byte *text, int x, int y, byte color, byte charset, bool center, bool wrap = false);
|
||||||
void drawBlastTexts() override;
|
void drawBlastTexts() override;
|
||||||
void actorTalk(const byte *msg) override;
|
void actorTalk(const byte *msg) override;
|
||||||
void translateText(const byte *text, byte *trans_buff) override;
|
void translateText(const byte *text, byte *trans_buff) override;
|
||||||
|
|
|
@ -627,26 +627,24 @@ void SmushPlayer::handleTextResource(uint32 subType, int32 subSize, Common::Seek
|
||||||
string2[0] = 0;
|
string2[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *str2 = str;
|
|
||||||
while (str[0] == '^') {
|
while (str[0] == '^') {
|
||||||
switch (str[1]) {
|
switch (str[1]) {
|
||||||
case 'f':
|
case 'f':
|
||||||
{
|
|
||||||
fontId = str[3] - '0';
|
fontId = str[3] - '0';
|
||||||
str += 4;
|
str += 4;
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
case 'c':
|
case 'c':
|
||||||
{
|
|
||||||
color = str[4] - '0' + 10 *(str[3] - '0');
|
color = str[4] - '0' + 10 *(str[3] - '0');
|
||||||
str += 5;
|
str += 5;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error("invalid escape code in text string");
|
error("invalid escape code in text string");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
str = str2;
|
|
||||||
|
if (_vm->_game.id == GID_CMI && string2[0] != 0)
|
||||||
|
str = string2;
|
||||||
|
|
||||||
// This is a hack from the original COMI CJK interpreter. Its purpose is to avoid
|
// This is a hack from the original COMI CJK interpreter. Its purpose is to avoid
|
||||||
// ugly combinations of two byte characters (rendered with the respective special
|
// ugly combinations of two byte characters (rendered with the respective special
|
||||||
// font) and standard one byte (NUT font) characters (see bug #11947).
|
// font) and standard one byte (NUT font) characters (see bug #11947).
|
||||||
|
@ -658,60 +656,11 @@ void SmushPlayer::handleTextResource(uint32 subType, int32 subSize, Common::Seek
|
||||||
SmushFont *sf = getFont(fontId);
|
SmushFont *sf = getFont(fontId);
|
||||||
assert(sf != NULL);
|
assert(sf != NULL);
|
||||||
|
|
||||||
|
// The hack that used to be here to prevent bug #2220 is no longer necessary and
|
||||||
// The HACK that used to be here to prevent bug #2220 is no longer necessary and
|
|
||||||
// has been removed. The font renderer can handle all ^codes it encounters (font
|
// has been removed. The font renderer can handle all ^codes it encounters (font
|
||||||
// changes on the fly will be ignored for Smush texts, since our code design does
|
// changes on the fly will be ignored for Smush texts, since our code design does
|
||||||
// not permit it and the feature isn't used anyway).
|
// not permit it and the feature isn't used anyway).
|
||||||
|
|
||||||
// HACK. This is to prevent bug #2220. In updated Win95 dig
|
|
||||||
// there is such line:
|
|
||||||
//
|
|
||||||
// ^f01^c001LEAD TESTER
|
|
||||||
// Chris Purvis
|
|
||||||
// ^f01
|
|
||||||
// ^f01^c001WINDOWS COMPATIBILITY
|
|
||||||
// Chip Hinnenberg
|
|
||||||
// ^f01^c001WINDOWS TESTING
|
|
||||||
// Jim Davison
|
|
||||||
// Lynn Selk
|
|
||||||
//
|
|
||||||
// i.e. formatting exists not in the first line only
|
|
||||||
// We just strip that off and assume that neither font
|
|
||||||
// nor font color was altered. Proper fix would be to feed
|
|
||||||
// drawString() with each line sequentally
|
|
||||||
/* char *string3 = NULL, *sptr2;
|
|
||||||
const char *sptr;
|
|
||||||
|
|
||||||
if (strchr(str, '^')) {
|
|
||||||
string3 = (char *)malloc(strlen(str) + 1);
|
|
||||||
|
|
||||||
for (sptr = str, sptr2 = string3; *sptr;) {
|
|
||||||
if (*sptr == '^') {
|
|
||||||
switch (sptr[1]) {
|
|
||||||
case 'f':
|
|
||||||
sptr += 4;
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
sptr += 5;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
error("invalid escape code in text string");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (TextRenderer_v7::is2ByteCharacter(_vm->_language, *sptr))
|
|
||||||
*sptr2++ = *sptr++;
|
|
||||||
*sptr2++ = *sptr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*sptr2++ = *sptr++; // copy zero character
|
|
||||||
str = string3;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if (_vm->_game.id == GID_CMI && string2[0] != 0) {
|
|
||||||
str = string2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// flags:
|
// flags:
|
||||||
// bit 0 - center 0x01
|
// bit 0 - center 0x01
|
||||||
// bit 1 - not used (align right) 0x02
|
// bit 1 - not used (align right) 0x02
|
||||||
|
@ -743,7 +692,6 @@ void SmushPlayer::handleTextResource(uint32 subType, int32 subSize, Common::Seek
|
||||||
}
|
}
|
||||||
|
|
||||||
free(string);
|
free(string);
|
||||||
//free(string3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *SmushPlayer::getString(int id) {
|
const char *SmushPlayer::getString(int id) {
|
||||||
|
|
|
@ -677,12 +677,12 @@ void ScummEngine::CHARSET_1() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c == 13) {
|
if (c == 13) {
|
||||||
#ifdef ENABLE_SCUMM_7_8
|
/*#ifdef ENABLE_SCUMM_7_8
|
||||||
if (_game.version >= 7 && subtitleLine != subtitleBuffer) {
|
if (_game.version >= 7 && subtitleLine != subtitleBuffer) {
|
||||||
((ScummEngine_v7 *)this)->addSubtitleToQueue(subtitleBuffer, subtitlePos, _charsetColor, _charset->getCurID());
|
((ScummEngine_v7 *)this)->addSubtitleToQueue(subtitleBuffer, subtitlePos, _charsetColor, _charset->getCurID());
|
||||||
subtitleLine = subtitleBuffer;
|
subtitleLine = subtitleBuffer;
|
||||||
}
|
}
|
||||||
#endif
|
#endif*/
|
||||||
if (!newLine())
|
if (!newLine())
|
||||||
break;
|
break;
|
||||||
continue;
|
continue;
|
||||||
|
@ -762,12 +762,12 @@ void ScummEngine::CHARSET_1() {
|
||||||
if (_game.platform == Common::kPlatformFMTowns && (c == 0 || c == 2 || c == 3))
|
if (_game.platform == Common::kPlatformFMTowns && (c == 0 || c == 2 || c == 3))
|
||||||
memcpy(&_curStringRect, &_charset->_str, sizeof(Common::Rect));
|
memcpy(&_curStringRect, &_charset->_str, sizeof(Common::Rect));
|
||||||
#endif
|
#endif
|
||||||
|
/*
|
||||||
#ifdef ENABLE_SCUMM_7_8
|
#ifdef ENABLE_SCUMM_7_8
|
||||||
if (_game.version >= 7 && subtitleLine != subtitleBuffer) {
|
if (_game.version >= 7 && subtitleLine != subtitleBuffer) {
|
||||||
((ScummEngine_v7 *)this)->addSubtitleToQueue(subtitleBuffer, subtitlePos, _charsetColor, _charset->getCurID());
|
((ScummEngine_v7 *)this)->addSubtitleToQueue(subtitleBuffer, subtitlePos, _charsetColor, _charset->getCurID());
|
||||||
}
|
}
|
||||||
#endif
|
#endif*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScummEngine::drawString(int a, const byte *msg) {
|
void ScummEngine::drawString(int a, const byte *msg) {
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
namespace Scumm {
|
namespace Scumm {
|
||||||
|
|
||||||
TextRenderer_v7::TextRenderer_v7(ScummEngine *vm, GlyphRenderer_v7 *gr)
|
TextRenderer_v7::TextRenderer_v7(ScummEngine *vm, GlyphRenderer_v7 *gr)
|
||||||
: _gameId(vm->_game.id), _lang(vm->_language), _2byteCharWidth(vm->_2byteWidth), _screenWidth(vm->_screenWidth), _useCJKMode(vm->_useCJKMode), _lineBreakMarker(vm->_newLineCharacter), _gr(gr) {
|
: _gameId(vm->_game.id), _lang(vm->_language), _2byteCharWidth(vm->_2byteWidth), _screenWidth(vm->_screenWidth), _useCJKMode(vm->_useCJKMode), _spacing(vm->_language != Common::JA_JPN ? 1 : 0), _lineBreakMarker(vm->_newLineCharacter), _gr(gr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int TextRenderer_v7::getStringWidth(const char *str, uint numBytesMax) {
|
int TextRenderer_v7::getStringWidth(const char *str, uint numBytesMax) {
|
||||||
|
@ -47,22 +47,25 @@ int TextRenderer_v7::getStringWidth(const char *str, uint numBytesMax) {
|
||||||
int font = _gr->setFont(-1);
|
int font = _gr->setFont(-1);
|
||||||
|
|
||||||
while (*str && numBytesMax) {
|
while (*str && numBytesMax) {
|
||||||
while (str[0] == '^') {
|
if (*str == '^') {
|
||||||
switch (str[1]) {
|
if (str[1] == 'f') {
|
||||||
case 'f':
|
|
||||||
_gr->setFont(str[3] - '0');
|
_gr->setFont(str[3] - '0');
|
||||||
str += 4;
|
str += 4;
|
||||||
break;
|
numBytesMax -= 4;
|
||||||
case 'c':
|
continue;
|
||||||
|
} else if (str[1] == 'c') {
|
||||||
str += 5;
|
str += 5;
|
||||||
break;
|
numBytesMax -= 5;
|
||||||
default:
|
continue;
|
||||||
error("CharsetRenderer::getStringWidth(): Invalid escape code in text string");
|
} else if (str[1] == 'l') {
|
||||||
|
str += 2;
|
||||||
|
numBytesMax -= 2;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is2ByteCharacter(_lang, *str)) {
|
if (is2ByteCharacter(_lang, *str)) {
|
||||||
width += _2byteCharWidth + (_lang != Common::JA_JPN ? 1 : 0);
|
width += _2byteCharWidth + _spacing;
|
||||||
++str;
|
++str;
|
||||||
--numBytesMax;
|
--numBytesMax;
|
||||||
} else if (*str == '\n') {
|
} else if (*str == '\n') {
|
||||||
|
@ -91,17 +94,20 @@ int TextRenderer_v7::getStringHeight(const char *str, uint numBytesMax) {
|
||||||
int font = _gr->setFont(-1);
|
int font = _gr->setFont(-1);
|
||||||
|
|
||||||
while (*str && numBytesMax) {
|
while (*str && numBytesMax) {
|
||||||
while (str[0] == '^') {
|
if (*str == '^') {
|
||||||
switch (str[1]) {
|
if (str[1] == 'f') {
|
||||||
case 'f':
|
|
||||||
_gr->setFont(str[3] - '0');
|
_gr->setFont(str[3] - '0');
|
||||||
str += 4;
|
str += 4;
|
||||||
break;
|
numBytesMax -= 4;
|
||||||
case 'c':
|
continue;
|
||||||
|
} else if (str[1] == 'c') {
|
||||||
str += 5;
|
str += 5;
|
||||||
break;
|
numBytesMax -= 5;
|
||||||
default:
|
continue;
|
||||||
error("CharsetRenderer::getStringWidth(): Invalid escape code in text string");
|
} else if (str[1] == 'l') {
|
||||||
|
str += 2;
|
||||||
|
numBytesMax -= 2;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,18 +137,21 @@ void TextRenderer_v7::drawSubstring(const char *str, uint numBytesMax, byte *buf
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; str[i] != 0 && numBytesMax; ++i) {
|
for (int i = 0; str[i] != 0 && numBytesMax; ++i) {
|
||||||
while (str[i] == '^') {
|
if (str[i] == '^') {
|
||||||
switch (str[i + 1]) {
|
if (str[i + 1] == 'f') {
|
||||||
case 'f':
|
|
||||||
_gr->setFont(str[i + 3] - '0');
|
_gr->setFont(str[i + 3] - '0');
|
||||||
|
i += 3;
|
||||||
|
numBytesMax -= 4;
|
||||||
|
continue;
|
||||||
|
} else if (str[i + 1] == 'c') {
|
||||||
|
col = str[i + 4] - '0' + 10 *(str[i + 3] - '0');
|
||||||
i += 4;
|
i += 4;
|
||||||
break;
|
numBytesMax -= 5;
|
||||||
case 'c':
|
continue;
|
||||||
col = str[4] - '0' + 10 *(str[3] - '0');
|
} else if (str[i + 1] == 'l') {
|
||||||
i += 5;
|
i++;
|
||||||
break;
|
numBytesMax -= 2;
|
||||||
default:
|
continue;
|
||||||
error("CharsetRenderer::getStringWidth(): Invalid escape code in text string");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +206,7 @@ void TextRenderer_v7::drawString(const char *str, byte *buffer, Common::Rect &cl
|
||||||
|
|
||||||
_gr->setFont(font);
|
_gr->setFont(font);
|
||||||
|
|
||||||
clipRect.left = center ? x - maxWidth : x;
|
clipRect.left = center ? x - maxWidth / 2: x;
|
||||||
clipRect.right = MIN<int>(clipRect.right, clipRect.left + maxWidth);
|
clipRect.right = MIN<int>(clipRect.right, clipRect.left + maxWidth);
|
||||||
clipRect.top = y2;
|
clipRect.top = y2;
|
||||||
clipRect.bottom = y;
|
clipRect.bottom = y;
|
||||||
|
@ -334,7 +343,7 @@ void ScummEngine_v7::createTextRenderer(GlyphRenderer_v7 *gr) {
|
||||||
_textV7 = new TextRenderer_v7(this, gr);
|
_textV7 = new TextRenderer_v7(this, gr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScummEngine_v7::enqueueText(const byte *text, int x, int y, byte color, byte charset, bool center, bool wrapped) {
|
void ScummEngine_v7::enqueueText(const byte *text, int x, int y, byte color, byte charset, bool center, bool wrap) {
|
||||||
assert(_blastTextQueuePos + 1 <= ARRAYSIZE(_blastTextQueue));
|
assert(_blastTextQueuePos + 1 <= ARRAYSIZE(_blastTextQueue));
|
||||||
|
|
||||||
if (_useCJKMode) {
|
if (_useCJKMode) {
|
||||||
|
@ -347,7 +356,9 @@ void ScummEngine_v7::enqueueText(const byte *text, int x, int y, byte color, byt
|
||||||
|
|
||||||
BlastText &bt = _blastTextQueue[_blastTextQueuePos];
|
BlastText &bt = _blastTextQueue[_blastTextQueuePos];
|
||||||
convertMessageToString(text, bt.text, sizeof(bt.text));
|
convertMessageToString(text, bt.text, sizeof(bt.text));
|
||||||
if (!*bt.text)
|
|
||||||
|
// The original DIG interpreter expressly checks for " " strings here. And the game also sends these quite frequently...
|
||||||
|
if (!bt.text[0] || (bt.text[0] == (byte)' ' && !bt.text[1]))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_blastTextQueuePos++;
|
_blastTextQueuePos++;
|
||||||
|
@ -356,13 +367,11 @@ void ScummEngine_v7::enqueueText(const byte *text, int x, int y, byte color, byt
|
||||||
bt.color = color;
|
bt.color = color;
|
||||||
bt.charset = charset;
|
bt.charset = charset;
|
||||||
bt.center = center;
|
bt.center = center;
|
||||||
bt.wrap = wrapped;
|
bt.wrap = wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScummEngine_v7::drawBlastTexts() {
|
void ScummEngine_v7::drawBlastTexts() {
|
||||||
VirtScreen *vs = &_virtscr[kMainVirtScreen];
|
VirtScreen *vs = &_virtscr[kMainVirtScreen];
|
||||||
Common::Rect _defaultTextClipRect = Common::Rect(vs->w, vs->h);
|
|
||||||
Common::Rect _wrappedTextClipRect = _game.id == GID_CMI ? Common::Rect(10, 10, 630, 470) : _defaultTextClipRect;
|
|
||||||
|
|
||||||
for (int i = 0; i < _blastTextQueuePos; i++) {
|
for (int i = 0; i < _blastTextQueuePos; i++) {
|
||||||
BlastText &bt = _blastTextQueue[i];
|
BlastText &bt = _blastTextQueue[i];
|
||||||
|
@ -371,10 +380,10 @@ void ScummEngine_v7::drawBlastTexts() {
|
||||||
|
|
||||||
if (bt.wrap) {
|
if (bt.wrap) {
|
||||||
bt.rect = _wrappedTextClipRect;
|
bt.rect = _wrappedTextClipRect;
|
||||||
_textV7->drawStringWrap((const char*)bt.text, (byte*)vs->getPixels(0, 0), bt.rect, bt.xpos, bt.ypos, vs->pitch, bt.color, bt.center);
|
_textV7->drawStringWrap((const char*)bt.text, (byte*)vs->getBasePtr(0, 0), bt.rect, bt.xpos, bt.ypos, vs->pitch, bt.color, bt.center);
|
||||||
} else {
|
} else {
|
||||||
bt.rect = _defaultTextClipRect;
|
bt.rect = _defaultTextClipRect;
|
||||||
_textV7->drawString((const char*)bt.text, (byte*)vs->getPixels(0, 0), bt.rect, bt.xpos, bt.ypos, vs->pitch, bt.color, bt.center);
|
_textV7->drawString((const char*)bt.text, (byte*)vs->getBasePtr(0, 0), bt.rect, bt.xpos, bt.ypos, vs->pitch, bt.color, bt.center);
|
||||||
}
|
}
|
||||||
|
|
||||||
markRectAsDirty(vs->number, bt.rect);
|
markRectAsDirty(vs->number, bt.rect);
|
||||||
|
@ -400,11 +409,11 @@ void ScummEngine_v7::processSubtitleQueue() {
|
||||||
if (!st->actorSpeechMsg && (!ConfMan.getBool("subtitles") || VAR(VAR_VOICE_MODE) == 0))
|
if (!st->actorSpeechMsg && (!ConfMan.getBool("subtitles") || VAR(VAR_VOICE_MODE) == 0))
|
||||||
// no subtitles and there's a speech variant of the message, don't display the text
|
// no subtitles and there's a speech variant of the message, don't display the text
|
||||||
continue;
|
continue;
|
||||||
enqueueText(st->text, st->xpos, st->ypos, st->color, st->charset, false);
|
enqueueText(st->text, st->xpos, st->ypos, st->color, st->charset, st->center, st->wrap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScummEngine_v7::addSubtitleToQueue(const byte *text, const Common::Point &pos, byte color, byte charset) {
|
void ScummEngine_v7::addSubtitleToQueue(const byte *text, const Common::Point &pos, byte color, byte charset, bool center, bool wrap) {
|
||||||
if (text[0] && strcmp((const char *)text, " ") != 0) {
|
if (text[0] && strcmp((const char *)text, " ") != 0) {
|
||||||
assert(_subtitleQueuePos < ARRAYSIZE(_subtitleQueue));
|
assert(_subtitleQueuePos < ARRAYSIZE(_subtitleQueue));
|
||||||
SubtitleText *st = &_subtitleQueue[_subtitleQueuePos];
|
SubtitleText *st = &_subtitleQueue[_subtitleQueuePos];
|
||||||
|
@ -420,6 +429,8 @@ void ScummEngine_v7::addSubtitleToQueue(const byte *text, const Common::Point &p
|
||||||
st->color = color;
|
st->color = color;
|
||||||
st->charset = charset;
|
st->charset = charset;
|
||||||
st->actorSpeechMsg = _haveActorSpeechMsg;
|
st->actorSpeechMsg = _haveActorSpeechMsg;
|
||||||
|
st->center = center;
|
||||||
|
st->wrap = wrap;
|
||||||
++_subtitleQueuePos;
|
++_subtitleQueuePos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -435,10 +446,6 @@ void ScummEngine_v7::CHARSET_1() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte subtitleBuffer[2048];
|
|
||||||
byte *subtitleLine = subtitleBuffer;
|
|
||||||
Common::Point subtitlePos;
|
|
||||||
|
|
||||||
processSubtitleQueue();
|
processSubtitleQueue();
|
||||||
|
|
||||||
if (!_haveMsg)
|
if (!_haveMsg)
|
||||||
|
@ -452,21 +459,20 @@ void ScummEngine_v7::CHARSET_1() {
|
||||||
if (a && _string[0].overhead) {
|
if (a && _string[0].overhead) {
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
_string[0].xpos = a->getPos().x - _virtscr[kMainVirtScreen].xstart;
|
_string[0].xpos = a->getPos().x + _screenWidth / 2 - camera._cur.x;
|
||||||
s = a->_scalex * a->_talkPosX / 255;
|
s = a->_scalex * a->_talkPosX / 255;
|
||||||
_string[0].xpos += (a->_talkPosX - s) / 2 + s;
|
_string[0].xpos += (a->_talkPosX - s) / 2 + s;
|
||||||
|
|
||||||
_string[0].ypos = a->getPos().y - a->getElevation() - _screenTop;
|
int yyy1 = a->getPos().y;
|
||||||
|
int yyy2 = a->getElevation();
|
||||||
|
|
||||||
|
_string[0].ypos = a->getPos().y - a->getElevation() + _screenHeight / 2 - camera._cur.y;
|
||||||
s = a->_scaley * a->_talkPosY / 255;
|
s = a->_scaley * a->_talkPosY / 255;
|
||||||
_string[0].ypos += (a->_talkPosY - s) / 2 + s;
|
_string[0].ypos += (a->_talkPosY - s) / 2 + s;
|
||||||
}
|
}
|
||||||
|
|
||||||
_charset->setColor(_charsetColor);
|
_charset->setColor(_charsetColor);
|
||||||
|
_charset->setCurID(_string[0].charset);
|
||||||
if (a && a->_charset)
|
|
||||||
_charset->setCurID(a->_charset);
|
|
||||||
else
|
|
||||||
_charset->setCurID(_string[0].charset);
|
|
||||||
|
|
||||||
if (_talkDelay)
|
if (_talkDelay)
|
||||||
return;
|
return;
|
||||||
|
@ -482,110 +488,19 @@ void ScummEngine_v7::CHARSET_1() {
|
||||||
a->runActorTalkScript(a->_talkStartFrame);
|
a->runActorTalkScript(a->_talkStartFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_keepText) {
|
if (!_keepText)
|
||||||
clearSubtitleQueue();
|
clearSubtitleQueue();
|
||||||
_nextLeft = _string[0].xpos;
|
|
||||||
_nextTop = _string[0].ypos + _screenTop;
|
|
||||||
}
|
|
||||||
|
|
||||||
_charset->_disableOffsX = _charset->_firstChar = !_keepText;
|
|
||||||
|
|
||||||
_talkDelay = VAR(VAR_DEFAULT_TALK_DELAY);
|
_talkDelay = VAR(VAR_DEFAULT_TALK_DELAY);
|
||||||
for (int i = _charsetBufPos; _charsetBuffer[i]; ++i) {
|
int newPos = _charsetBufPos;
|
||||||
|
while (_charsetBuffer[newPos++])
|
||||||
_talkDelay += VAR(VAR_CHARINC);
|
_talkDelay += VAR(VAR_CHARINC);
|
||||||
}
|
|
||||||
|
|
||||||
if (_string[0].wrapping) {
|
Common::Point subtitlePos(_string[0].xpos, _string[0].ypos);
|
||||||
_charset->addLinebreaks(0, _charsetBuffer, _charsetBufPos, _screenWidth - 20);
|
addSubtitleToQueue(_charsetBuffer + _charsetBufPos, subtitlePos, _charsetColor, _charset->getCurID(), _string[0].center, _string[0].wrapping);
|
||||||
|
_charsetBufPos = newPos;
|
||||||
|
|
||||||
struct { int pos, w; } substring[10];
|
_haveMsg = VAR(VAR_HAVE_MSG) = (_game.version == 8 && _string[0].no_talk_anim) ? 2 : 1;
|
||||||
int count = 0;
|
|
||||||
int maxLineWidth = 0;
|
|
||||||
int lastPos = 0;
|
|
||||||
int code = 0;
|
|
||||||
while (handleNextCharsetCode(a, &code)) {
|
|
||||||
if (code == 13 || code == 0) {
|
|
||||||
*subtitleLine++ = '\0';
|
|
||||||
assert(count < 10);
|
|
||||||
substring[count].w = _charset->getStringWidth(0, subtitleBuffer + lastPos);
|
|
||||||
if (maxLineWidth < substring[count].w) {
|
|
||||||
maxLineWidth = substring[count].w;
|
|
||||||
}
|
|
||||||
substring[count].pos = lastPos;
|
|
||||||
++count;
|
|
||||||
lastPos = subtitleLine - subtitleBuffer;
|
|
||||||
} else {
|
|
||||||
*subtitleLine++ = code;
|
|
||||||
*subtitleLine = '\0';
|
|
||||||
}
|
|
||||||
if (code == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int h = count * _charset->getFontHeight();
|
|
||||||
h += _charset->getFontHeight() / 2;
|
|
||||||
subtitlePos.y = _string[0].ypos;
|
|
||||||
if (subtitlePos.y + h > _screenHeight - 10) {
|
|
||||||
subtitlePos.y = _screenHeight - 10 - h;
|
|
||||||
}
|
|
||||||
if (subtitlePos.y < 10) {
|
|
||||||
subtitlePos.y = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < count; ++i) {
|
|
||||||
subtitlePos.x = _string[0].xpos;
|
|
||||||
if (_string[0].center) {
|
|
||||||
if (subtitlePos.x + maxLineWidth / 2 > _screenWidth - 10) {
|
|
||||||
subtitlePos.x = _screenWidth - 10 - maxLineWidth / 2;
|
|
||||||
}
|
|
||||||
if (subtitlePos.x - maxLineWidth / 2 < 10) {
|
|
||||||
subtitlePos.x = 10 + maxLineWidth / 2;
|
|
||||||
}
|
|
||||||
subtitlePos.x -= substring[i].w / 2;
|
|
||||||
} else {
|
|
||||||
if (subtitlePos.x + maxLineWidth > _screenWidth - 10) {
|
|
||||||
subtitlePos.x = _screenWidth - 10 - maxLineWidth;
|
|
||||||
}
|
|
||||||
if (subtitlePos.x - maxLineWidth < 10) {
|
|
||||||
subtitlePos.x = 10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (subtitlePos.y < _screenHeight - 10) {
|
|
||||||
addSubtitleToQueue(subtitleBuffer + substring[i].pos, subtitlePos, _charsetColor, _charset->getCurID());
|
|
||||||
}
|
|
||||||
subtitlePos.y += _charset->getFontHeight();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int code = 0;
|
|
||||||
subtitlePos.y = _string[0].ypos;
|
|
||||||
if (subtitlePos.y < 10) {
|
|
||||||
subtitlePos.y = 10;
|
|
||||||
}
|
|
||||||
while (handleNextCharsetCode(a, &code)) {
|
|
||||||
if (code == 13 || code == 0) {
|
|
||||||
subtitlePos.x = _string[0].xpos;
|
|
||||||
if (_string[0].center) {
|
|
||||||
subtitlePos.x -= _charset->getStringWidth(0, subtitleBuffer) / 2;
|
|
||||||
}
|
|
||||||
if (subtitlePos.x < 10) {
|
|
||||||
subtitlePos.x = 10;
|
|
||||||
}
|
|
||||||
if (subtitlePos.y < _screenHeight - 10) {
|
|
||||||
addSubtitleToQueue(subtitleBuffer, subtitlePos, _charsetColor, _charset->getCurID());
|
|
||||||
subtitlePos.y += _charset->getFontHeight();
|
|
||||||
}
|
|
||||||
subtitleLine = subtitleBuffer;
|
|
||||||
} else {
|
|
||||||
*subtitleLine++ = code;
|
|
||||||
}
|
|
||||||
*subtitleLine = '\0';
|
|
||||||
if (code == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_haveMsg = (_game.version == 8) ? 2 : 1;
|
|
||||||
_keepText = false;
|
_keepText = false;
|
||||||
_string[0] = saveStr;
|
_string[0] = saveStr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,7 @@ private:
|
||||||
const Common::Language _lang;
|
const Common::Language _lang;
|
||||||
const byte _gameId;
|
const byte _gameId;
|
||||||
const bool _useCJKMode;
|
const bool _useCJKMode;
|
||||||
|
const int _spacing;
|
||||||
const byte _2byteCharWidth;
|
const byte _2byteCharWidth;
|
||||||
const byte _lineBreakMarker;
|
const byte _lineBreakMarker;
|
||||||
const uint16 _screenWidth;
|
const uint16 _screenWidth;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue