Patch #1003866 (SCUMM: New text rendering code (fixes various bugs))

svn-id: r14521
This commit is contained in:
Max Horn 2004-08-08 22:10:38 +00:00
parent f8cc6c2241
commit 835ef5f012
14 changed files with 151 additions and 306 deletions

22
NEWS
View file

@ -2,20 +2,26 @@ For a more comprehensive changelog for the latest experimental CVS code, see:
http://scummvm.sourceforge.net/daily/ChangeLog http://scummvm.sourceforge.net/daily/ChangeLog
0.?? 0.??
New Games:
- Added SAGA engine (for the games and "I Have No Mouth and I Must Scream"
and "Inherit the Earth")
General: General:
- Added support for FLAC (losless) encoded audio files - Added support for FLAC (losless) encoded audio files
- Added an 'On Screen Display' to the SDL backend - Added an 'On Screen Display' to the SDL backend
- Rewrote the backend API partially - Partially rewrote the backend API
- Comments in config files are preserved now - Comments in config files are preserved now
- Updated AdvMame scalers based on scale2x 2.0 - AdvMame3x looks nicer now - Updated AdvMame scalers based on scale2x 2.0 - AdvMame3x looks nicer now,
- Added MMX i386 assembler HQ2x and HQ3x scalers and AdvMame2x is MMX accelerated
- Alt-x and Ctrl-z quit keys disabled in favour of Ctrl-q on non - Added MMX i386 assembler versions of the HQ2x and HQ3x scalers
Mac OS X unices (including Linux) - Alt-x and Ctrl-z quit keys disabled in favour of Ctrl-q on unix like
operating systems, like Linux (exception: Mac OS X still uses Cmd-q)
SCUMM: SCUMM:
- Old zak256 target removed, use zakTowns instead - Old zak256 target removed, use zakTowns instead
- Added support for the special container file format used in mac version - Added support for the special container file format used in the macintosh
(thus you do not have to use rescumm anymore) versions of some games (thus you do not have to use rescumm anymore)
- Partially rewrote the text engine, fixing various bugs
Queen: Queen:
- Various fixes [TODO: Somebody of the Queen team please fill this in] - Various fixes [TODO: Somebody of the Queen team please fill this in]
@ -43,7 +49,7 @@ For a more comprehensive changelog for the latest experimental CVS code, see:
same file handle, e.g. in the Sam & Max intro when using monster.sog. same file handle, e.g. in the Sam & Max intro when using monster.sog.
SCUMM: SCUMM:
- Many SCUMM game engine fixes. - As usual: many SCUMM game engine fixes.
- Added graphics decoders for 3DO Humongous Entertainment games - Added graphics decoders for 3DO Humongous Entertainment games
- Numerous Humongous Entertainment games fixes - Numerous Humongous Entertainment games fixes
- Fixed bug in Full Throttle, so battle difficulty matches original - Fixed bug in Full Throttle, so battle difficulty matches original

9
TODO
View file

@ -230,15 +230,6 @@ SCUMM
details details
* V7-8 games: Implement smooth horizontal scrolling (instead of scrolling in * V7-8 games: Implement smooth horizontal scrolling (instead of scrolling in
increments of 8 pixels). See bug #629417. increments of 8 pixels). See bug #629417.
* COMI (maybe V7 games, too?): "Fix" CHARSET_1 behaviour when the room scrolls.
In particular, when text is drawn via CHARSET_1 and then scrolling takes
place, the text scrolls, too - but it really should stay fixed. There are
several ways to do this that I can think of. One would be to use an overlay
screen (i.e. use virtscreen 3, which isn't used at all currently) to draw
the text; then "compose" that screen over the main screen.
Or constantly (well, at least whenever the camera moves) redraw the text.
That would require buffering the text; maybe the blast text code could be
reused for this...
* Add tool and support for compress *.la* file resources (ex. sounds) to fit * Add tool and support for compress *.la* file resources (ex. sounds) to fit
on small devices on small devices
* Fix codec44 for nut fonts * Fix codec44 for nut fonts

View file

@ -385,7 +385,7 @@ void AkosRenderer::codec1_genericDecode() {
return; return;
} }
} else { } else {
masked = (y < 0 || y >= _outheight) || (v1.mask_ptr && ((mask[0] | mask[v1.imgbufoffs]) & maskbit)); masked = (y < 0 || y >= _outheight) || (v1.mask_ptr && (*mask & maskbit));
if (color && !masked && !skip_column) { if (color && !masked && !skip_column) {
pcolor = palette[color]; pcolor = palette[color];
@ -781,8 +781,7 @@ byte AkosRenderer::codec1(int xmoveCur, int ymoveCur) {
v1.destptr = _outptr + v1.y * _outwidth + v1.x; v1.destptr = _outptr + v1.y * _outwidth + v1.x;
v1.mask_ptr = _vm->getMaskBuffer(0, v1.y, 0); v1.mask_ptr = _vm->getMaskBuffer(0, v1.y, _zbuf);
v1.imgbufoffs = _vm->gdi._imgBufOffs[_zbuf];
codec1_genericDecode(); codec1_genericDecode();
@ -847,9 +846,7 @@ byte AkosRenderer::codec5(int xmoveCur, int ymoveCur) {
} }
bdd.y = _actorY + ymoveCur; bdd.y = _actorY + ymoveCur;
if (_zbuf != 0) {
bdd.maskPtr = _vm->getMaskBuffer(0, 0, _zbuf); bdd.maskPtr = _vm->getMaskBuffer(0, 0, _zbuf);
}
_vm->drawBomp(bdd, !_mirror); _vm->drawBomp(bdd, !_mirror);
_vm->_bompActorPalettePtr = NULL; _vm->_bompActorPalettePtr = NULL;
@ -930,7 +927,7 @@ void AkosRenderer::akos16Decompress(byte *dest, int32 pitch, const byte *src, in
int32 numskip_before, int32 numskip_after, byte transparency, int maskLeft, int maskTop, int zBuf) { int32 numskip_before, int32 numskip_after, byte transparency, int maskLeft, int maskTop, int zBuf) {
byte *tmp_buf = akos16.buffer; byte *tmp_buf = akos16.buffer;
int maskpitch; int maskpitch;
byte *maskptr = 0, *charsetMask = 0; byte *maskptr;
const byte maskbit = revBitMask[maskLeft & 7]; const byte maskbit = revBitMask[maskLeft & 7];
if (dir < 0) { if (dir < 0) {
@ -946,19 +943,13 @@ void AkosRenderer::akos16Decompress(byte *dest, int32 pitch, const byte *src, in
maskpitch = _numStrips; maskpitch = _numStrips;
charsetMask = _vm->getMaskBuffer(maskLeft, maskTop, 0);
if (zBuf != 0)
maskptr = _vm->getMaskBuffer(maskLeft, maskTop, zBuf); maskptr = _vm->getMaskBuffer(maskLeft, maskTop, zBuf);
assert(t_height > 0); assert(t_height > 0);
assert(t_width > 0); assert(t_width > 0);
while (t_height--) { while (t_height--) {
akos16DecodeLine(tmp_buf, t_width, dir); akos16DecodeLine(tmp_buf, t_width, dir);
bompApplyMask(akos16.buffer, charsetMask, maskbit, t_width, transparency);
if (maskptr) {
bompApplyMask(akos16.buffer, maskptr, maskbit, t_width, transparency); bompApplyMask(akos16.buffer, maskptr, maskbit, t_width, transparency);
maskptr += maskpitch;
}
bool HE7Check = (_vm->_heversion == 70); bool HE7Check = (_vm->_heversion == 70);
bompApplyShadow(_shadow_mode, _shadow_table, akos16.buffer, dest, t_width, transparency, HE7Check); bompApplyShadow(_shadow_mode, _shadow_table, akos16.buffer, dest, t_width, transparency, HE7Check);
@ -966,7 +957,7 @@ void AkosRenderer::akos16Decompress(byte *dest, int32 pitch, const byte *src, in
akos16SkipData(numskip_after); akos16SkipData(numskip_after);
} }
dest += pitch; dest += pitch;
charsetMask += maskpitch; maskptr += maskpitch;
} }
} }

View file

@ -97,7 +97,6 @@ protected:
int skip_width; int skip_width;
byte *destptr; byte *destptr;
const byte *mask_ptr; const byte *mask_ptr;
int imgbufoffs;
} v1; } v1;
public: public:

View file

@ -199,7 +199,6 @@ void ScummEngine::drawBomp(const BompDrawData &bd, bool mirror) {
const byte *src; const byte *src;
byte *dst; byte *dst;
byte *mask = 0; byte *mask = 0;
byte *charset_mask;
Common::Rect clip; Common::Rect clip;
byte *scalingYPtr = bd.scalingYPtr; byte *scalingYPtr = bd.scalingYPtr;
byte skip_y_bits = 0x80; byte skip_y_bits = 0x80;
@ -234,10 +233,7 @@ void ScummEngine::drawBomp(const BompDrawData &bd, bool mirror) {
const byte maskbit = revBitMask[(bd.x + clip.left) & 7]; const byte maskbit = revBitMask[(bd.x + clip.left) & 7];
// Always mask against the charset mask // Mask against any additionally imposed mask
charset_mask = getMaskBuffer(bd.x + clip.left, bd.y, 0);
// Also mask against any additionally imposed mask
if (bd.maskPtr) { if (bd.maskPtr) {
mask = bd.maskPtr + (bd.y * gdi._numStrips) + ((bd.x + clip.left) / 8); mask = bd.maskPtr + (bd.y * gdi._numStrips) + ((bd.x + clip.left) / 8);
} }
@ -310,7 +306,6 @@ void ScummEngine::drawBomp(const BompDrawData &bd, bool mirror) {
// Replace the parts of the line which are masked with the transparency color // Replace the parts of the line which are masked with the transparency color
if (bd.maskPtr) if (bd.maskPtr)
bompApplyMask(line_ptr, mask, maskbit, width, 255); bompApplyMask(line_ptr, mask, maskbit, width, 255);
bompApplyMask(line_ptr, charset_mask, maskbit, width, 255);
// Apply custom color map, if available // Apply custom color map, if available
if (_bompActorPalettePtr) if (_bompActorPalettePtr)
@ -324,7 +319,6 @@ void ScummEngine::drawBomp(const BompDrawData &bd, bool mirror) {
// Advance to the next line // Advance to the next line
pos_y++; pos_y++;
mask += gdi._numStrips; mask += gdi._numStrips;
charset_mask += gdi._numStrips;
dst += bd.outwidth; dst += bd.outwidth;
} }
} }

View file

@ -944,7 +944,7 @@ void CharsetRendererV3::setColor(byte color)
void CharsetRendererV3::printChar(int chr) { void CharsetRendererV3::printChar(int chr) {
// Indy3 / Zak256 / Loom // Indy3 / Zak256 / Loom
VirtScreen *vs; VirtScreen *vs;
byte *char_ptr, *dest_ptr, *mask_ptr; byte *char_ptr, *dest_ptr;
int width, height; int width, height;
int drawTop; int drawTop;
@ -972,8 +972,6 @@ void CharsetRendererV3::printChar(int chr) {
drawTop = _top - vs->topline; drawTop = _top - vs->topline;
char_ptr = _fontPtr + chr * 8; char_ptr = _fontPtr + chr * 8;
dest_ptr = vs->screenPtr + vs->xstart + drawTop * vs->width + _left;
mask_ptr = _vm->getMaskBuffer(_left, drawTop, 0);
_vm->markRectAsDirty(vs->number, _left, _left + width, drawTop, drawTop + height); _vm->markRectAsDirty(vs->number, _left, _left + width, drawTop, drawTop + height);
@ -981,8 +979,13 @@ void CharsetRendererV3::printChar(int chr) {
_hasMask = true; _hasMask = true;
_textScreenID = vs->number; _textScreenID = vs->number;
} }
if (_ignoreCharsetMask || !vs->hasTwoBuffers) {
dest_ptr = vs->screenPtr + vs->xstart + drawTop * vs->width + _left;
} else {
dest_ptr = (byte *)_vm->gdi._textSurface.pixels + drawTop * _vm->gdi._textSurface.pitch + _left;
}
drawBits1(vs, dest_ptr, char_ptr, mask_ptr, drawTop, 8, 8); drawBits1(vs, dest_ptr, char_ptr, drawTop, 8, 8);
if (_str.left > _left) if (_str.left > _left)
_str.left = _left; _str.left = _left;
@ -1085,24 +1088,29 @@ void CharsetRendererClassic::printChar(int chr) {
_vm->markRectAsDirty(vs->number, _left, _left + width, drawTop, drawTop + height + offsY); _vm->markRectAsDirty(vs->number, _left, _left + width, drawTop, drawTop + height + offsY);
byte *dst;
byte *back;
if (!_ignoreCharsetMask) { if (!_ignoreCharsetMask) {
_hasMask = true; _hasMask = true;
_textScreenID = vs->number; _textScreenID = vs->number;
} }
if (_ignoreCharsetMask || !vs->hasTwoBuffers) {
dst = vs->screenPtr + vs->xstart + drawTop * vs->width + _left;
} else {
dst = (byte *)_vm->gdi._textSurface.pixels + drawTop * _vm->gdi._textSurface.pitch + _left;
}
byte *mask = _vm->getMaskBuffer(_left, drawTop, 0); back = dst;
byte *dst = vs->screenPtr + vs->xstart + drawTop * vs->width + _left;
byte *back = dst;
if (_blitAlso && vs->hasTwoBuffers) { if (_blitAlso && vs->hasTwoBuffers) {
dst = vs->backBuf + vs->xstart + drawTop * vs->width + _left; dst = vs->backBuf + vs->xstart + drawTop * vs->width + _left;
} }
if (is2byte) { if (is2byte) {
drawBits1(vs, dst, charPtr, mask, drawTop, origWidth, origHeight); drawBits1(vs, dst, charPtr, drawTop, origWidth, origHeight);
} else { } else {
byte bpp = *_fontPtr; byte bpp = *_fontPtr;
drawBitsN(vs, dst, charPtr, mask, bpp, drawTop, origWidth, origHeight); drawBitsN(vs, dst, charPtr, bpp, drawTop, origWidth, origHeight);
} }
if (_blitAlso && vs->hasTwoBuffers) { if (_blitAlso && vs->hasTwoBuffers) {
@ -1128,30 +1136,21 @@ void CharsetRendererClassic::printChar(int chr) {
_top -= offsY; _top -= offsY;
} }
void CharsetRendererClassic::drawBitsN(VirtScreen *vs, byte *dst, const byte *src, byte *mask, byte bpp, int drawTop, int width, int height) { void CharsetRendererClassic::drawBitsN(VirtScreen *vs, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height) {
byte maskmask;
int y, x; int y, x;
int maskpos;
int color; int color;
byte numbits, bits; byte numbits, bits;
bool useMask = (vs->number == kMainVirtScreen && !_ignoreCharsetMask);
assert(bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8); assert(bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8);
bits = *src++; bits = *src++;
numbits = 8; numbits = 8;
for (y = 0; y < height && y + drawTop < vs->height; y++) { for (y = 0; y < height && y + drawTop < vs->height; y++) {
maskmask = revBitMask[_left & 7];
maskpos = 0;
for (x = 0; x < width; x++) { for (x = 0; x < width; x++) {
color = (bits >> (8 - bpp)) & 0xFF; color = (bits >> (8 - bpp)) & 0xFF;
if (color && y + drawTop >= 0) { if (color && y + drawTop >= 0) {
*dst = _vm->_charsetColorMap[color]; *dst = _vm->_charsetColorMap[color];
if (useMask) {
mask[maskpos] |= maskmask;
}
} }
dst++; dst++;
bits <<= bpp; bits <<= bpp;
@ -1160,28 +1159,16 @@ void CharsetRendererClassic::drawBitsN(VirtScreen *vs, byte *dst, const byte *sr
bits = *src++; bits = *src++;
numbits = 8; numbits = 8;
} }
maskmask >>= 1;
if (maskmask == 0) {
maskmask = 0x80;
maskpos++;
}
} }
dst += vs->width - width; dst += vs->width - width;
mask += _vm->gdi._numStrips;
} }
} }
void CharsetRendererCommon::drawBits1(VirtScreen *vs, byte *dst, const byte *src, byte *mask, int drawTop, int width, int height) { void CharsetRendererCommon::drawBits1(VirtScreen *vs, byte *dst, const byte *src, int drawTop, int width, int height) {
byte maskmask;
int y, x; int y, x;
int maskpos;
byte bits = 0; byte bits = 0;
bool useMask = (vs->number == kMainVirtScreen && !_ignoreCharsetMask);
for (y = 0; y < height && y + drawTop < vs->height; y++) { for (y = 0; y < height && y + drawTop < vs->height; y++) {
maskmask = revBitMask[_left & 7];
maskpos = 0;
for (x = 0; x < width; x++) { for (x = 0; x < width; x++) {
if ((x % 8) == 0) if ((x % 8) == 0)
bits = *src++; bits = *src++;
@ -1192,30 +1179,11 @@ void CharsetRendererCommon::drawBits1(VirtScreen *vs, byte *dst, const byte *src
*(dst + vs->width + 1) = _shadowColor; *(dst + vs->width + 1) = _shadowColor;
} }
*dst = _color; *dst = _color;
if (useMask) {
mask[maskpos] |= maskmask;
if (_dropShadow) {
mask[maskpos + _vm->gdi._numStrips] |= maskmask;
if (maskmask == 1) {
mask[maskpos + 1] |= 0x80;
mask[maskpos + _vm->gdi._numStrips + 1] |= 0x80;
} else {
mask[maskpos] |= (maskmask >> 1);
mask[maskpos + _vm->gdi._numStrips] |= (maskmask >> 1);
}
}
}
} }
dst++; dst++;
maskmask >>= 1;
if (maskmask == 0) {
maskmask = 0x80;
maskpos++;
}
} }
dst += vs->width - width; dst += vs->width - width;
mask += _vm->gdi._numStrips;
} }
} }
@ -1293,12 +1261,23 @@ void CharsetRendererNut::printChar(int chr) {
shadow.right = _left + width + 2; shadow.right = _left + width + 2;
shadow.bottom = _top + height + 2; shadow.bottom = _top + height + 2;
Graphics::Surface s;
if (!_ignoreCharsetMask) { if (!_ignoreCharsetMask) {
_hasMask = true; _hasMask = true;
_textScreenID = kMainVirtScreen; _textScreenID = kMainVirtScreen;
} }
if (_ignoreCharsetMask) {
VirtScreen *vs = &_vm->virtscr[kMainVirtScreen];
s.pixels = vs->screenPtr + vs->xstart + _vm->_screenTop * vs->width;
s.w = vs->width;
s.h = vs->height;
s.pitch = vs->width;
s.bytesPerPixel = 1;
} else {
s = _vm->gdi._textSurface;
}
_current->drawShadowChar(chr, _left, _top, _color, !_ignoreCharsetMask, _curId != 3); _current->drawShadowChar(s, chr, _left, _top, _color, _curId != 3);
_vm->markRectAsDirty(kMainVirtScreen, shadow); _vm->markRectAsDirty(kMainVirtScreen, shadow);
if (_str.left > _left) if (_str.left > _left)

View file

@ -69,7 +69,6 @@ public:
void restoreCharsetBg(); void restoreCharsetBg();
void clearCharsetMask(); void clearCharsetMask();
bool hasCharsetMask(int left, int top, int right, int bottom);
virtual void printChar(int chr) = 0; virtual void printChar(int chr) = 0;
@ -88,7 +87,7 @@ class CharsetRendererCommon : public CharsetRenderer {
protected: protected:
byte *_fontPtr; byte *_fontPtr;
void drawBits1(VirtScreen *vs, byte *dst, const byte *src, byte *mask, int drawTop, int width, int height); void drawBits1(VirtScreen *vs, byte *dst, const byte *src, int drawTop, int width, int height);
public: public:
CharsetRendererCommon(ScummEngine *vm) : CharsetRenderer(vm) {} CharsetRendererCommon(ScummEngine *vm) : CharsetRenderer(vm) {}
@ -102,7 +101,7 @@ class CharsetRendererClassic : public CharsetRendererCommon {
protected: protected:
int getCharWidth(byte chr); int getCharWidth(byte chr);
void drawBitsN(VirtScreen *vs, byte *dst, const byte *src, byte *mask, byte bpp, int drawTop, int width, int height); void drawBitsN(VirtScreen *vs, byte *dst, const byte *src, byte bpp, int drawTop, int width, int height);
public: public:
CharsetRendererClassic(ScummEngine *vm) : CharsetRendererCommon(vm) {} CharsetRendererClassic(ScummEngine *vm) : CharsetRendererCommon(vm) {}

View file

@ -284,8 +284,7 @@ byte CostumeRenderer::mainRoutine(int xmoveCur, int ymoveCur) {
v1.destptr = _outptr + v1.y * _outwidth + v1.x; v1.destptr = _outptr + v1.y * _outwidth + v1.x;
v1.mask_ptr = _vm->getMaskBuffer(0, v1.y, 0); v1.mask_ptr = _vm->getMaskBuffer(0, v1.y, _zbuf);
v1.imgbufoffs = _vm->gdi._imgBufOffs[_zbuf];
CHECK_HEAP CHECK_HEAP
@ -350,7 +349,7 @@ static const int v1MMActorPalatte2[25] = {
}; };
#define MASK_AT(xoff) \ #define MASK_AT(xoff) \
(mask && (mask[((v1.x + xoff) / 8) + v1.imgbufoffs] & revBitMask[(v1.x + xoff) & 7])) (mask && (mask[((v1.x + xoff) / 8)] & revBitMask[(v1.x + xoff) & 7]))
#define LINE(c,p) \ #define LINE(c,p) \
pcolor = (color >> c) & 3; \ pcolor = (color >> c) & 3; \
if (pcolor) { \ if (pcolor) { \
@ -467,7 +466,7 @@ void CostumeRenderer::proc3() {
do { do {
if (_scaleY == 255 || *scaleytab++ < _scaleY) { if (_scaleY == 255 || *scaleytab++ < _scaleY) {
masked = (y < 0 || y >= _outheight) || (v1.mask_ptr && ((mask[0] | mask[v1.imgbufoffs]) & maskbit)); masked = (y < 0 || y >= _outheight) || (v1.mask_ptr && (mask[0] & maskbit));
if (color && !masked) { if (color && !masked) {
// FIXME: Fully implement _shadow_mode.in Sam & Max // FIXME: Fully implement _shadow_mode.in Sam & Max
@ -536,7 +535,7 @@ void CostumeRenderer::proc3_ami() {
len = *src++; len = *src++;
do { do {
if (_scaleY == 255 || cost_scaleTable[_scaleIndexY] < _scaleY) { if (_scaleY == 255 || cost_scaleTable[_scaleIndexY] < _scaleY) {
masked = (y < 0 || y >= _outheight) || (v1.mask_ptr && ((mask[0] | mask[v1.imgbufoffs]) & maskbit)); masked = (y < 0 || y >= _outheight) || (v1.mask_ptr && (mask[0] & maskbit));
if (color && v1.x >= 0 && v1.x < _outwidth && !masked) { if (color && v1.x >= 0 && v1.x < _outwidth && !masked) {
*dst = _palette[color]; *dst = _palette[color];

View file

@ -156,49 +156,12 @@ static const TransitionEffect transitionEffects[5] = {
}; };
#endif #endif
static inline void copy8PixelsWithMasking(byte *dst, const byte *src, byte maskbits) {
if (!(maskbits & 0x80))
dst[0] = src[0];
if (!(maskbits & 0x40))
dst[1] = src[1];
if (!(maskbits & 0x20))
dst[2] = src[2];
if (!(maskbits & 0x10))
dst[3] = src[3];
if (!(maskbits & 0x08))
dst[4] = src[4];
if (!(maskbits & 0x04))
dst[5] = src[5];
if (!(maskbits & 0x02))
dst[6] = src[6];
if (!(maskbits & 0x01))
dst[7] = src[7];
}
static inline void clear8PixelsWithMasking(byte *dst, const byte color, byte maskbits) {
if (!(maskbits & 0x80))
dst[0] = color;
if (!(maskbits & 0x40))
dst[1] = color;
if (!(maskbits & 0x20))
dst[2] = color;
if (!(maskbits & 0x10))
dst[3] = color;
if (!(maskbits & 0x08))
dst[4] = color;
if (!(maskbits & 0x04))
dst[5] = color;
if (!(maskbits & 0x02))
dst[6] = color;
if (!(maskbits & 0x01))
dst[7] = color;
}
#pragma mark - #pragma mark -
#pragma mark --- Virtual Screens --- #pragma mark --- Virtual Screens ---
#pragma mark - #pragma mark -
#define CHARSET_MASK_TRANSPARENCY 254
Gdi::Gdi(ScummEngine *vm) { Gdi::Gdi(ScummEngine *vm) {
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
@ -206,6 +169,9 @@ Gdi::Gdi(ScummEngine *vm) {
_roomPalette = vm->_roomPalette; _roomPalette = vm->_roomPalette;
if ((vm->_features & GF_AMIGA) && (vm->_version >= 4)) if ((vm->_features & GF_AMIGA) && (vm->_version >= 4))
_roomPalette += 16; _roomPalette += 16;
_compositeBuf = 0;
_textSurface.pixels = 0;
} }
void ScummEngine::initScreens(int b, int h) { void ScummEngine::initScreens(int b, int h) {
@ -235,8 +201,26 @@ void ScummEngine::initScreens(int b, int h) {
_screenB = b; _screenB = b;
_screenH = h; _screenH = h;
gdi.init();
} }
void Gdi::init() {
const int size = _vm->_screenWidth * _vm->_screenHeight;
free(_compositeBuf);
free(_textSurface.pixels);
_compositeBuf = (byte *)malloc(size);
_textSurface.pixels = malloc(size);
memset(_compositeBuf, CHARSET_MASK_TRANSPARENCY, size);
memset(_textSurface.pixels, CHARSET_MASK_TRANSPARENCY, size);
_textSurface.w = _vm->_screenWidth;
_textSurface.h = _vm->_screenHeight;
_textSurface.pitch = _vm->_screenWidth;
_textSurface.bytesPerPixel = 1;
}
void ScummEngine::initVirtScreen(VirtScreenNumber slot, int number, int top, int width, int height, bool twobufs, void ScummEngine::initVirtScreen(VirtScreenNumber slot, int number, int top, int width, int height, bool twobufs,
bool scrollable) { bool scrollable) {
VirtScreen *vs = &virtscr[slot]; VirtScreen *vs = &virtscr[slot];
@ -246,7 +230,7 @@ void ScummEngine::initVirtScreen(VirtScreenNumber slot, int number, int top, int
assert(slot >= 0 && slot < 4); assert(slot >= 0 && slot < 4);
if (_version >= 7) { if (_version >= 7) {
if (slot == 0 && (_roomHeight != 0)) if (slot == kMainVirtScreen && (_roomHeight != 0))
height = _roomHeight; height = _roomHeight;
} }
@ -431,8 +415,7 @@ void Gdi::updateDirtyScreen(VirtScreen *vs) {
* specified by top/bottom coordinate in the virtual screen. * specified by top/bottom coordinate in the virtual screen.
*/ */
void Gdi::drawStripToScreen(VirtScreen *vs, int x, int width, int top, int bottom) { void Gdi::drawStripToScreen(VirtScreen *vs, int x, int width, int top, int bottom) {
byte *ptr; const int height = bottom - top;
int height;
if (bottom <= top) if (bottom <= top)
return; return;
@ -442,11 +425,33 @@ void Gdi::drawStripToScreen(VirtScreen *vs, int x, int width, int top, int botto
assert(top >= 0 && bottom <= vs->height); // Paranoia checks assert(top >= 0 && bottom <= vs->height); // Paranoia checks
height = bottom - top;
// We don't clip height and width here, rather we rely on the backend to // We don't clip height and width here, rather we rely on the backend to
// perform any needed clipping. // perform any needed clipping.
ptr = vs->screenPtr + (x + vs->xstart) + top * vs->width; const int y = vs->topline + top - _vm->_screenTop;
_vm->_system->copyRectToScreen(ptr, vs->width, x, vs->topline + top - _vm->_screenTop, width, height); const byte *src = vs->screenPtr + (x + vs->xstart) + top * vs->width;
assert(_textSurface.pixels);
assert(_compositeBuf);
Common::Rect r(x, y, x+width, y+height);
r.clip(Common::Rect(_textSurface.w, _textSurface.h));
// TODO: is this enough clipping?
byte *dst = _compositeBuf + x + y * _vm->_screenWidth;
const byte *text = (byte *)_textSurface.pixels + x + y * _textSurface.pitch;
for (int h = 0; h < r.height(); ++h) {
for (int w = 0; w < r.width(); ++w) {
if (text[w] == CHARSET_MASK_TRANSPARENCY)
dst[w] = src[w];
else
dst[w] = text[w];
}
src += vs->width;
dst += _vm->_screenWidth;
text += _textSurface.pitch;
}
_vm->_system->copyRectToScreen(_compositeBuf + x + y * _vm->_screenWidth, _vm->_screenWidth, x, y, width, height);
} }
#pragma mark - #pragma mark -
@ -633,14 +638,12 @@ void ScummEngine::restoreBG(Common::Rect rect, byte backColor) {
// be optimized to (rect.right - rect.left) / 8 and // be optimized to (rect.right - rect.left) / 8 and
// thus to width / 8, but that's not the case since // thus to width / 8, but that's not the case since
// we are dealing with integer math here. // we are dealing with integer math here.
const int mask_width = ((rect.right + 7) / 8) - (rect.left / 8); const int mask_width = rect.width();
byte *mask = (byte *)gdi._textSurface.pixels + gdi._textSurface.pitch * rect.top + rect.left;
byte *mask = getMaskBuffer(rect.left, rect.top, 0); while (height--) {
memset(mask, CHARSET_MASK_TRANSPARENCY, mask_width);
do { mask += gdi._textSurface.pitch;
memset(mask, 0, mask_width); }
mask += gdi._numStrips;
} while (--height);
} }
} else { } else {
while (height--) { while (height--) {
@ -663,9 +666,7 @@ void CharsetRenderer::restoreCharsetBg() {
// restoreBG(), but was changed to only restore those parts which are // restoreBG(), but was changed to only restore those parts which are
// currently covered by the charset mask. // currently covered by the charset mask.
// Loop over first three virtual screens
VirtScreen *vs = &_vm->virtscr[_textScreenID]; VirtScreen *vs = &_vm->virtscr[_textScreenID];
if (!vs->height) if (!vs->height)
return; return;
@ -677,27 +678,8 @@ void CharsetRenderer::restoreCharsetBg() {
const byte *backBuf = vs->backBuf + vs->xstart; const byte *backBuf = vs->backBuf + vs->xstart;
if (vs->number == kMainVirtScreen) { if (vs->number == kMainVirtScreen) {
// Restore from back buffer, but only those parts which are // Clean out the charset mask
// currently covered by the charset mask. In addition, we memset(_vm->gdi._textSurface.pixels, CHARSET_MASK_TRANSPARENCY, _vm->gdi._textSurface.pitch * _vm->gdi._textSurface.h);
// clean out the charset mask
const int mask_width = _vm->gdi._numStrips;
byte *mask = _vm->getMaskBuffer(0, 0, 0);
assert(vs->width == 8 * _vm->gdi._numStrips);
int height = vs->height;
while (height--) {
for (int w = 0; w < mask_width; ++w) {
const byte maskbits = mask[w];
if (maskbits) {
copy8PixelsWithMasking(screenBuf + w*8, backBuf + w*8, ~maskbits);
mask[w] = 0;
}
}
screenBuf += vs->width;
backBuf += vs->width;
mask += _vm->gdi._numStrips;
}
} else { } else {
// Restore from back buffer // Restore from back buffer
_vm->blit(screenBuf, backBuf, vs->width, vs->height); _vm->blit(screenBuf, backBuf, vs->width, vs->height);
@ -713,10 +695,6 @@ void CharsetRenderer::clearCharsetMask() {
memset(_vm->getResourceAddress(rtBuffer, 9), 0, _vm->gdi._imgBufOffs[1]); memset(_vm->getResourceAddress(rtBuffer, 9), 0, _vm->gdi._imgBufOffs[1]);
} }
bool CharsetRenderer::hasCharsetMask(int left, int top, int right, int bottom) {
return _hasMask;
}
byte *ScummEngine::getMaskBuffer(int x, int y, int z) { byte *ScummEngine::getMaskBuffer(int x, int y, int z) {
return gdi.getMaskBuffer(x / 8, y, z) + _screenStartStrip; return gdi.getMaskBuffer(x / 8, y, z) + _screenStartStrip;
} }
@ -1170,22 +1148,13 @@ void Gdi::drawBitmap(const byte *ptr, VirtScreen *vs, int x, int y, const int wi
} }
} }
mask_ptr = getMaskBuffer(x, y);
CHECK_HEAP; CHECK_HEAP;
if (vs->hasTwoBuffers) { if (vs->hasTwoBuffers) {
if (_vm->_charset->hasCharsetMask(sx * 8, y, (sx + 1) * 8, bottom)) {
if (flag & dbClear || !lightsOn)
clear8ColWithMasking(backbuff_ptr, height, mask_ptr);
else
draw8ColWithMasking(backbuff_ptr, bgbak_ptr, height, mask_ptr);
} else {
if (flag & dbClear || !lightsOn) if (flag & dbClear || !lightsOn)
clear8Col(backbuff_ptr, height); clear8Col(backbuff_ptr, height);
else else
draw8Col(backbuff_ptr, bgbak_ptr, height); draw8Col(backbuff_ptr, bgbak_ptr, height);
} }
}
CHECK_HEAP; CHECK_HEAP;
if (_vm->_version == 1) { if (_vm->_version == 1) {
@ -1304,16 +1273,12 @@ void Gdi::resetBackground(int top, int bottom, int strip) {
vs->bdirty[strip] = bottom; vs->bdirty[strip] = bottom;
offs = top * vs->width + vs->xstart + strip * 8; offs = top * vs->width + vs->xstart + strip * 8;
byte *mask_ptr = _vm->getMaskBuffer(strip * 8, top, 0);
bgbak_ptr = vs->backBuf + offs; bgbak_ptr = vs->backBuf + offs;
backbuff_ptr = vs->screenPtr + offs; backbuff_ptr = vs->screenPtr + offs;
numLinesToProcess = bottom - top; numLinesToProcess = bottom - top;
if (numLinesToProcess) { if (numLinesToProcess) {
if (_vm->isLightOn()) { if (_vm->isLightOn()) {
if (_vm->_charset->hasCharsetMask(strip * 8, top, (strip + 1) * 8, bottom))
draw8ColWithMasking(backbuff_ptr, bgbak_ptr, numLinesToProcess, mask_ptr);
else
draw8Col(backbuff_ptr, bgbak_ptr, numLinesToProcess); draw8Col(backbuff_ptr, bgbak_ptr, numLinesToProcess);
} else { } else {
clear8Col(backbuff_ptr, numLinesToProcess); clear8Col(backbuff_ptr, numLinesToProcess);
@ -1654,47 +1619,6 @@ bool Gdi::decompressBitmap(byte *bgbak_ptr, const byte *src, int numLinesToProce
return useOrDecompress; return useOrDecompress;
} }
void Gdi::draw8ColWithMasking(byte *dst, const byte *src, int height, byte *mask) {
byte maskbits;
do {
maskbits = *mask;
if (maskbits) {
copy8PixelsWithMasking(dst, src, maskbits);
} else {
#if defined(SCUMM_NEED_ALIGNMENT)
memcpy(dst, src, 8);
#else
((uint32 *)dst)[0] = ((const uint32 *)src)[0];
((uint32 *)dst)[1] = ((const uint32 *)src)[1];
#endif
}
src += _vm->_screenWidth;
dst += _vm->_screenWidth;
mask += _numStrips;
} while (--height);
}
void Gdi::clear8ColWithMasking(byte *dst, int height, byte *mask) {
byte maskbits;
do {
maskbits = *mask;
if (maskbits) {
clear8PixelsWithMasking(dst, 0, maskbits);
} else {
#if defined(SCUMM_NEED_ALIGNMENT)
memset(dst, 0, 8);
#else
((uint32 *)dst)[0] = 0;
((uint32 *)dst)[1] = 0;
#endif
}
dst += _vm->_screenWidth;
mask += _numStrips;
} while (--height);
}
void Gdi::draw8Col(byte *dst, const byte *src, int height) { void Gdi::draw8Col(byte *dst, const byte *src, int height) {
do { do {
#if defined(SCUMM_NEED_ALIGNMENT) #if defined(SCUMM_NEED_ALIGNMENT)

View file

@ -24,6 +24,7 @@
#define GFX_H #define GFX_H
#include "common/rect.h" #include "common/rect.h"
#include "graphics/surface.h"
namespace Scumm { namespace Scumm {
@ -217,7 +218,11 @@ public:
Gdi(ScummEngine *vm); Gdi(ScummEngine *vm);
Graphics::Surface _textSurface;
protected: protected:
byte *_compositeBuf;
byte *_roomPalette; byte *_roomPalette;
byte _decomp_shr, _decomp_mask; byte _decomp_shr, _decomp_mask;
byte _transparentColor; byte _transparentColor;
@ -251,9 +256,7 @@ protected:
void decodeStrip3DO(byte *dst, const byte *src, int height, byte transpCheck); void decodeStrip3DO(byte *dst, const byte *src, int height, byte transpCheck);
void decodeStripHE(byte *dst, const byte *src, int height, byte transpCheck); void decodeStripHE(byte *dst, const byte *src, int height, byte transpCheck);
void draw8ColWithMasking(byte *dst, const byte *src, int height, byte *mask);
void draw8Col(byte *dst, const byte *src, int height); void draw8Col(byte *dst, const byte *src, int height);
void clear8ColWithMasking(byte *dst, int height, byte *mask);
void clear8Col(byte *dst, int height); void clear8Col(byte *dst, int height);
void decompressMaskImgOr(byte *dst, const byte *src, int height); void decompressMaskImgOr(byte *dst, const byte *src, int height);
void decompressMaskImg(byte *dst, const byte *src, int height); void decompressMaskImg(byte *dst, const byte *src, int height);
@ -261,9 +264,11 @@ protected:
void drawStripToScreen(VirtScreen *vs, int x, int w, int t, int b); void drawStripToScreen(VirtScreen *vs, int x, int w, int t, int b);
void updateDirtyScreen(VirtScreen *vs); void updateDirtyScreen(VirtScreen *vs);
byte *getMaskBuffer(int x, int y, int z = 0); byte *getMaskBuffer(int x, int y, int z);
public: public:
void init();
void drawBitmap(const byte *ptr, VirtScreen *vs, int x, int y, const int width, const int height, void drawBitmap(const byte *ptr, VirtScreen *vs, int x, int y, const int width, const int height,
int stripnr, int numstrip, byte flag, StripTable *table = 0); int stripnr, int numstrip, byte flag, StripTable *table = 0);
void drawBitmapV2Helper(const byte *ptr, VirtScreen *vs, int x, int y, const int width, const int height, void drawBitmapV2Helper(const byte *ptr, VirtScreen *vs, int x, int y, const int width, const int height,

View file

@ -239,16 +239,13 @@ int NutRenderer::getCharHeight(byte c) {
return _chars[c].height; return _chars[c].height;
} }
void NutRenderer::drawShadowChar(int c, int x, int y, byte color, bool useMask, bool showShadow) { void NutRenderer::drawShadowChar(const Graphics::Surface &s, int c, int x, int y, byte color, bool showShadow) {
debug(8, "NutRenderer::drawShadowChar('%c', %d, %d, %d, %d, %d) called", c, x, y, (int)color, useMask, showShadow); debug(8, "NutRenderer::drawShadowChar('%c', %d, %d, %d, %d) called", c, x, y, (int)color, showShadow);
if (!_loaded) { if (!_loaded) {
warning("NutRenderer::drawShadowChar() Font is not loaded"); warning("NutRenderer::drawShadowChar() Font is not loaded");
return; return;
} }
VirtScreen *vs = &_vm->virtscr[kMainVirtScreen];
byte *dst, *mask = NULL;
// HACK: we draw the character a total of 7 times: 6 times shifted // HACK: we draw the character a total of 7 times: 6 times shifted
// and in black for the shadow, and once in the right color and position. // and in black for the shadow, and once in the right color and position.
// This way we achieve the exact look as the original CMI had. However, // This way we achieve the exact look as the original CMI had. However,
@ -268,18 +265,10 @@ void NutRenderer::drawShadowChar(int c, int x, int y, byte color, bool useMask,
y += offsetY[i]; y += offsetY[i];
color = cTable[i]; color = cTable[i];
if (y >= vs->height || x >= vs->width) {
continue;
}
dst = vs->screenPtr + y * vs->width + x + vs->xstart;
if (useMask)
mask = _vm->getMaskBuffer(x, y, 0);
if (c >= 256 && _vm->_CJKMode) if (c >= 256 && _vm->_CJKMode)
draw2byte(dst, mask, c, x, y - _vm->_screenTop, color); draw2byte(s, c, x, y, color);
else else
drawChar(dst, mask, (byte)c, x, y - _vm->_screenTop, color); drawChar(s, (byte)c, x, y, color);
x -= offsetX[i]; x -= offsetX[i];
y -= offsetY[i]; y -= offsetY[i];
@ -318,15 +307,13 @@ void NutRenderer::drawFrame(byte *dst, int c, int x, int y) {
} }
} }
void NutRenderer::drawChar(byte *dst, byte *mask, byte c, int x, int y, byte color) { void NutRenderer::drawChar(const Graphics::Surface &s, byte c, int x, int y, byte color) {
const int width = MIN(_chars[c].width, _vm->_screenWidth - x); byte *dst = (byte *)s.pixels + y * s.pitch + x;
const int height = MIN(_chars[c].height, _vm->_screenHeight - y); const int width = MIN(_chars[c].width, s.w - x);
const int height = MIN(_chars[c].height, s.h - y);
const byte *src = _chars[c].src; const byte *src = _chars[c].src;
const int srcPitch = _chars[c].width; const int srcPitch = _chars[c].width;
byte maskmask;
int maskpos;
const int minX = x < 0 ? -x : 0; const int minX = x < 0 ? -x : 0;
const int minY = y < 0 ? -y : 0; const int minY = y < 0 ? -y : 0;
@ -336,75 +323,47 @@ void NutRenderer::drawChar(byte *dst, byte *mask, byte c, int x, int y, byte col
if (minY) { if (minY) {
src += minY * srcPitch; src += minY * srcPitch;
dst += minY * _vm->_screenWidth; dst += minY * s.pitch;
if (mask)
mask += minY * _vm->gdi._numStrips;
} }
for (int ty = minY; ty < height; ty++) { for (int ty = minY; ty < height; ty++) {
maskmask = revBitMask[(x + minX) & 7];
maskpos = (x%8 + minX) / 8;
for (int tx = minX; tx < width; tx++) { for (int tx = minX; tx < width; tx++) {
if (src[tx] != 0) { if (src[tx] != 0) {
dst[tx] = color; dst[tx] = color;
if (mask)
mask[maskpos] |= maskmask;
}
maskmask >>= 1;
if (maskmask == 0) {
maskmask = 0x80;
maskpos++;
} }
} }
src += srcPitch; src += srcPitch;
dst += _vm->_screenWidth; dst += s.pitch;
if (mask)
mask += _vm->gdi._numStrips;
} }
} }
void NutRenderer::draw2byte(byte *dst, byte *mask, int c, int x, int y, byte color) { void NutRenderer::draw2byte(const Graphics::Surface &s, int c, int x, int y, byte color) {
if (!_loaded) { if (!_loaded) {
debug(2, "NutRenderer::draw2byte() Font is not loaded"); debug(2, "NutRenderer::draw2byte() Font is not loaded");
return; return;
} }
byte *dst = (byte *)s.pixels + y * s.pitch + x;
const int width = _vm->_2byteWidth; const int width = _vm->_2byteWidth;
const int height = MIN(_vm->_2byteHeight, _vm->_screenHeight - y); const int height = MIN(_vm->_2byteHeight, s.h - y);
byte *src = _vm->get2byteCharPtr(c); byte *src = _vm->get2byteCharPtr(c);
byte bits = 0; byte bits = 0;
byte maskmask;
int maskpos;
if (height <= 0 || width <= 0) { if (height <= 0 || width <= 0) {
return; return;
} }
for (int ty = 0; ty < height; ty++) { for (int ty = 0; ty < height; ty++) {
maskmask = revBitMask[x & 7];
maskpos = 0;
for (int tx = 0; tx < width; tx++) { for (int tx = 0; tx < width; tx++) {
if ((tx & 7) == 0) if ((tx & 7) == 0)
bits = *src++; bits = *src++;
if (x + tx < 0 || x + tx >= _vm->_screenWidth || y + ty < 0) if (x + tx < 0 || x + tx >= s.w || y + ty < 0)
continue; continue;
if (bits & revBitMask[tx & 7]) { if (bits & revBitMask[tx & 7]) {
dst[tx] = color; dst[tx] = color;
if (mask) {
mask[maskpos] |= maskmask;
} }
} }
dst += s.pitch;
maskmask >>= 1;
if (maskmask == 0) {
maskmask = 0x80;
maskpos++;
}
}
dst += _vm->_screenWidth;
if (mask)
mask += _vm->gdi._numStrips;
} }
} }

View file

@ -22,6 +22,7 @@
#define NUT_RENDERER_H #define NUT_RENDERER_H
#include "common/file.h" #include "common/file.h"
#include "graphics/surface.h"
namespace Scumm { namespace Scumm {
@ -43,8 +44,8 @@ protected:
int32 decodeCodec44(byte *dst, const byte *src, uint32 length); int32 decodeCodec44(byte *dst, const byte *src, uint32 length);
void drawChar(byte *dst, byte *mask, byte c, int x, int y, byte color); void drawChar(const Graphics::Surface &s, byte c, int x, int y, byte color);
void draw2byte(byte *dst, byte *mask, int c, int x, int y, byte color); void draw2byte(const Graphics::Surface &s, int c, int x, int y, byte color);
public: public:
NutRenderer(ScummEngine *vm); NutRenderer(ScummEngine *vm);
@ -54,7 +55,7 @@ public:
bool loadFont(const char *filename); bool loadFont(const char *filename);
void drawFrame(byte *dst, int c, int x, int y); void drawFrame(byte *dst, int c, int x, int y);
void drawShadowChar(int c, int x, int y, byte color, bool useMask, bool showShadow); void drawShadowChar(const Graphics::Surface &s, int c, int x, int y, byte color, bool showShadow);
int getCharWidth(byte c); int getCharWidth(byte c);
int getCharHeight(byte c); int getCharHeight(byte c);

View file

@ -2652,13 +2652,13 @@ void ScummEngine::initRoomSubBlocks() {
// Transparent color // Transparent color
if (_features & GF_OLD_BUNDLE) if (_features & GF_OLD_BUNDLE)
gdi._transparentColor = 255; // TODO - FIXME gdi._transparentColor = 255;
else { else {
ptr = findResourceData(MKID('TRNS'), roomptr); ptr = findResourceData(MKID('TRNS'), roomptr);
if (ptr) if (ptr)
gdi._transparentColor = ptr[0]; gdi._transparentColor = ptr[0];
else if (_version == 8) else if (_version == 8)
gdi._transparentColor = 5; // FIXME gdi._transparentColor = 5;
else else
gdi._transparentColor = 255; gdi._transparentColor = 255;
} }

View file

@ -419,8 +419,6 @@ void ScummEngine::drawVerb(int verb, int mode) {
} }
void ScummEngine::restoreVerbBG(int verb) { void ScummEngine::restoreVerbBG(int verb) {
if (_version >= 7)
return;
VerbSlot *vs; VerbSlot *vs;