got rid of _curVirtScreen and VirtScreen::unk1; added some comments to gfx.cpp; added a hack to enable smooth scrolling in V7 games (note: when I say hack, I mean it, it is buggy as hell and not enabled by default, use at your own risk and don't report problems with it, it's disabled by default)

svn-id: r6037
This commit is contained in:
Max Horn 2002-12-21 01:11:42 +00:00
parent f2fe67fbdb
commit 50f7ffbeb6
5 changed files with 64 additions and 48 deletions

View file

@ -32,6 +32,26 @@
#endif #endif
// If you wan to try buggy hacked smooth scrolling support in The Dig, enable
// the following preprocessor flag by uncommenting it.
//
// Note: This is purely experimental, NOT WORKING COMPLETLY and very buggy.
// Please do not make reports about problems with it - this is only in CVS
// to get it fixed and so that really interested parties can experiment it.
// It is NOT FIT FOR GENERAL USAGE!. You have been warned.
//
// Doing this correctly will be quite some more complicated. Basically, with smooth
// scrolling, the virtual screen strips don't match the display screen strips.
// Hence we either have to draw partial strips - but that'd be rather cumbersome.
// Or the much simple (and IMHO more elegant) solution is to simply use a screen pitch
// that is 8 pixel wider than the real screen width, and always draw one strip more than
// needed to the backbuf. This will still require quite some code to be changed but
// should otherwise be relatively easy to understand, and using VirtScreen::pitch
// will actually clean up the code.
//
// #define V7_SMOOTH_SCROLLING_HACK
enum { enum {
kScrolltime = 500, // ms scrolling is supposed to take kScrolltime = 500, // ms scrolling is supposed to take
kPictureDelay = 20 kPictureDelay = 20
@ -159,8 +179,6 @@ void Scumm::initVirtScreen(int slot, int number, int top, int width, int height,
{ {
VirtScreen *vs = &virtscr[slot]; VirtScreen *vs = &virtscr[slot];
int size; int size;
int i;
byte *ptr;
assert(height >= 0); assert(height >= 0);
assert(slot >= 0 && slot < 4); assert(slot >= 0 && slot < 4);
@ -171,7 +189,6 @@ void Scumm::initVirtScreen(int slot, int number, int top, int width, int height,
} }
vs->number = slot; vs->number = slot;
vs->unk1 = 0;
vs->width = _realWidth; vs->width = _realWidth;
vs->topline = top; vs->topline = top;
vs->height = height; vs->height = height;
@ -182,18 +199,17 @@ void Scumm::initVirtScreen(int slot, int number, int top, int width, int height,
vs->size = size; vs->size = size;
vs->backBuf = NULL; vs->backBuf = NULL;
if ((vs->scrollable) && (_features & GF_AFTER_V7)) { if (vs->scrollable) {
size += _realWidth * 8; if (_features & GF_AFTER_V7) {
} else { size += _realWidth * 8;
size += _realWidth * 4; } else {
size += _realWidth * 4;
}
} }
createResource(rtBuffer, slot + 1, size); createResource(rtBuffer, slot + 1, size);
vs->screenPtr = getResourceAddress(rtBuffer, slot + 1); vs->screenPtr = getResourceAddress(rtBuffer, slot + 1);
memset(vs->screenPtr, 0, size); // reset background
ptr = vs->screenPtr;
for (i = 0; i < size; i++) // reset background ?
*ptr++ = 0;
if (twobufs) { if (twobufs) {
createResource(rtBuffer, slot + 5, size); createResource(rtBuffer, slot + 5, size);
@ -211,10 +227,10 @@ VirtScreen *Scumm::findVirtScreen(int y)
for (i = 0; i < 3; i++, vs++) { for (i = 0; i < 3; i++, vs++) {
if (y >= vs->topline && y < vs->topline + vs->height) { if (y >= vs->topline && y < vs->topline + vs->height) {
return _curVirtScreen = vs; return vs;
} }
} }
return _curVirtScreen = NULL; return NULL;
} }
void Scumm::updateDirtyRect(int virt, int left, int right, int top, int bottom, uint32 dirtybits) void Scumm::updateDirtyRect(int virt, int left, int right, int top, int bottom, uint32 dirtybits)
@ -237,14 +253,19 @@ void Scumm::updateDirtyRect(int virt, int left, int right, int top, int bottom,
right = vs->width; right = vs->width;
if (virt == 0 && dirtybits) { if (virt == 0 && dirtybits) {
rp = (right >> 3) + _screenStartStrip;
lp = (left >> 3) + _screenStartStrip; lp = (left >> 3) + _screenStartStrip;
if (lp < 0) if (lp < 0)
lp = 0; lp = 0;
if (_features & GF_AFTER_V7) { if (_features & GF_AFTER_V7) {
#ifdef V7_SMOOTH_SCROLLING_HACK
rp = (right + vs->xstart) >> 3;
#else
rp = (right >> 3) + _screenStartStrip;
#endif
if (rp > 409) if (rp > 409)
rp = 409; rp = 409;
} else { } else {
rp = (right >> 3) + _screenStartStrip;
if (rp >= 200) if (rp >= 200)
rp = 200; rp = 200;
} }
@ -306,8 +327,8 @@ void Scumm::drawDirtyScreenParts()
} else { } else {
vs = &virtscr[0]; vs = &virtscr[0];
src = vs->screenPtr + _screenStartStrip * 8 + _screenTop * _realWidth; src = vs->screenPtr + vs->xstart + _screenTop * _realWidth;
_system->copy_rect(src, _realWidth, 0, vs->topline, _realWidth, vs->height); _system->copy_rect(src, _realWidth, 0, vs->topline, _realWidth, vs->height - _screenTop);
for (i = 0; i < gdi._numStrips; i++) { for (i = 0; i < gdi._numStrips; i++) {
vs->tdirty[i] = (byte)vs->height; vs->tdirty[i] = (byte)vs->height;
@ -330,14 +351,16 @@ void Scumm::updateDirtyScreen(int slot)
gdi.updateDirtyScreen(&virtscr[slot]); gdi.updateDirtyScreen(&virtscr[slot]);
} }
// Blit the data from the given VirtScreen to the display. If the camera moved,
// a full blit is done, otherwise only the visible dirty areas are updated.
void Gdi::updateDirtyScreen(VirtScreen *vs) void Gdi::updateDirtyScreen(VirtScreen *vs)
{ {
if (vs->height == 0) if (vs->height == 0)
return; return;
if (_vm->_features & GF_AFTER_V7 && (_vm->camera._cur.y != _vm->camera._last.y)) if (_vm->_features & GF_AFTER_V7 && (_vm->camera._cur.y != _vm->camera._last.y)) {
drawStripToScreen(vs, 0, _numStrips << 3, 0, vs->height); drawStripToScreen(vs, 0, _numStrips << 3, 0, vs->height);
else { } else {
int i; int i;
int start, w, top, bottom; int start, w, top, bottom;
@ -352,6 +375,8 @@ void Gdi::updateDirtyScreen(VirtScreen *vs)
vs->tdirty[i] = (byte)vs->height; vs->tdirty[i] = (byte)vs->height;
vs->bdirty[i] = 0; vs->bdirty[i] = 0;
if (i != (_numStrips - 1) && vs->bdirty[i + 1] == (byte)bottom && vs->tdirty[i + 1] == (byte)top) { if (i != (_numStrips - 1) && vs->bdirty[i + 1] == (byte)bottom && vs->tdirty[i + 1] == (byte)top) {
// Simple optimizations: if two or more neighbouring strips form one bigger rectangle,
// blit them all at once.
w += 8; w += 8;
continue; continue;
} }
@ -366,6 +391,7 @@ void Gdi::updateDirtyScreen(VirtScreen *vs)
} }
} }
// Blit the specified rectangle from the given virtual screen to the display.
void Gdi::drawStripToScreen(VirtScreen *vs, int x, int w, int t, int b) void Gdi::drawStripToScreen(VirtScreen *vs, int x, int w, int t, int b)
{ {
byte *ptr; byte *ptr;
@ -395,6 +421,7 @@ void Gdi::clearUpperMask()
memset(_vm->getResourceAddress(rtBuffer, 9), 0, _imgBufOffs[1] - _imgBufOffs[0]); memset(_vm->getResourceAddress(rtBuffer, 9), 0, _imgBufOffs[1] - _imgBufOffs[0]);
} }
// Reset the background behind an actor or blast object
void Gdi::resetBackground(int top, int bottom, int strip) void Gdi::resetBackground(int top, int bottom, int strip)
{ {
VirtScreen *vs = &_vm->virtscr[0]; VirtScreen *vs = &_vm->virtscr[0];
@ -569,6 +596,8 @@ void Scumm::drawFlashlight()
_flashlightIsDrawn = true; _flashlightIsDrawn = true;
} }
// Redraw background as needed, i.e. the left/right sides if scrolling took place etc.
// Note that this only updated the virtual screen, not the actual display.
void Scumm::redrawBGAreas() void Scumm::redrawBGAreas()
{ {
int i; int i;
@ -581,6 +610,7 @@ void Scumm::redrawBGAreas()
val = 0; val = 0;
// Redraw parts of the background which are marked as dirty.
if (!_fullRedraw && _BgNeedsRedraw) { if (!_fullRedraw && _BgNeedsRedraw) {
for (i = 0; i != gdi._numStrips; i++) { for (i = 0; i != gdi._numStrips; i++) {
if (gfxUsageBits[_screenStartStrip + i] & 0x80000000) { if (gfxUsageBits[_screenStartStrip + i] & 0x80000000) {
@ -626,19 +656,11 @@ void Scumm::redrawBGStrip(int start, int num)
assert(s >= 0 && (size_t) s < sizeof(gfxUsageBits) / sizeof(gfxUsageBits[0])); assert(s >= 0 && (size_t) s < sizeof(gfxUsageBits) / sizeof(gfxUsageBits[0]));
_curVirtScreen = &virtscr[0];
for (int i = 0; i < num; i++) for (int i = 0; i < num; i++)
gfxUsageBits[s + i] |= 0x80000000; gfxUsageBits[s + i] |= 0x80000000;
/*if (_curVirtScreen->height < _scrHeight) {
warning("Screen Y size %d < Room height %d",
_curVirtScreen->height,
_scrHeight);
} */
gdi.drawBitmap(getResourceAddress(rtRoom, _roomResource) + _IM00_offs, gdi.drawBitmap(getResourceAddress(rtRoom, _roomResource) + _IM00_offs,
_curVirtScreen, s, 0, _curVirtScreen->height, s, num, 0); &virtscr[0], s, 0, virtscr[0].height, s, num, 0);
} }
void Scumm::restoreCharsetBg() void Scumm::restoreCharsetBg()
@ -765,7 +787,6 @@ void Gdi::drawBitmap(byte *ptr, VirtScreen *vs, int x, int y, const int h,
byte *zplane_list[6]; byte *zplane_list[6];
int bottom; int bottom;
byte twobufs;
int numzbuf; int numzbuf;
int sx; int sx;
bool lightsOn; bool lightsOn;
@ -815,8 +836,6 @@ void Gdi::drawBitmap(byte *ptr, VirtScreen *vs, int x, int y, const int h,
warning("Gdi::drawBitmap, strip drawn to %d below window bottom %d", bottom, vs->height); warning("Gdi::drawBitmap, strip drawn to %d below window bottom %d", bottom, vs->height);
} }
twobufs = vs->alloctwobuffers;
_vertStripNextInc = h * _vm->_realWidth - 1; _vertStripNextInc = h * _vm->_realWidth - 1;
do { do {
@ -838,7 +857,7 @@ void Gdi::drawBitmap(byte *ptr, VirtScreen *vs, int x, int y, const int h,
vs->bdirty[sx] = bottom; vs->bdirty[sx] = bottom;
backbuff_ptr = vs->screenPtr + (y * _numStrips + x) * 8; backbuff_ptr = vs->screenPtr + (y * _numStrips + x) * 8;
if (twobufs) if (vs->alloctwobuffers)
bgbak_ptr = _vm->getResourceAddress(rtBuffer, vs->number + 5) + (y * _numStrips + x) * 8; bgbak_ptr = _vm->getResourceAddress(rtBuffer, vs->number + 5) + (y * _numStrips + x) * 8;
else else
bgbak_ptr = backbuff_ptr; bgbak_ptr = backbuff_ptr;
@ -851,7 +870,7 @@ void Gdi::drawBitmap(byte *ptr, VirtScreen *vs, int x, int y, const int h,
decompressBitmap(bgbak_ptr, smap_ptr + READ_LE_UINT32(smap_ptr + stripnr * 4 + 8), h); decompressBitmap(bgbak_ptr, smap_ptr + READ_LE_UINT32(smap_ptr + stripnr * 4 + 8), h);
CHECK_HEAP; CHECK_HEAP;
if (twobufs) { if (vs->alloctwobuffers) {
if (_vm->hasCharsetMask(sx << 3, y, (sx + 1) << 3, bottom)) { if (_vm->hasCharsetMask(sx << 3, y, (sx + 1) << 3, bottom)) {
if (flag & dbClear || !lightsOn) if (flag & dbClear || !lightsOn)
clear8ColWithMasking(backbuff_ptr, h, _mask_ptr); clear8ColWithMasking(backbuff_ptr, h, _mask_ptr);
@ -1954,8 +1973,6 @@ void Scumm::cameraMoved()
_screenStartStrip = (camera._cur.x - (_realWidth / 2)) >> 3; _screenStartStrip = (camera._cur.x - (_realWidth / 2)) >> 3;
_screenEndStrip = _screenStartStrip + gdi._numStrips - 1; _screenEndStrip = _screenStartStrip + gdi._numStrips - 1;
virtscr[0].xstart = _screenStartStrip << 3;
_screenTop = camera._cur.y - (_realHeight / 2); _screenTop = camera._cur.y - (_realHeight / 2);
if (_features & GF_AFTER_V7) { if (_features & GF_AFTER_V7) {
@ -1966,6 +1983,11 @@ void Scumm::cameraMoved()
_screenLeft = _screenStartStrip << 3; _screenLeft = _screenStartStrip << 3;
} }
#ifdef V7_SMOOTH_SCROLLING_HACK
virtscr[0].xstart = _screenLeft;
#else
virtscr[0].xstart = _screenStartStrip << 3;
#endif
} }
void Scumm::panCameraTo(int x, int y) void Scumm::panCameraTo(int x, int y)

View file

@ -42,7 +42,6 @@ struct CameraData { /* Camera state data */
struct VirtScreen { /* Virtual screen areas */ struct VirtScreen { /* Virtual screen areas */
int number; int number;
uint16 unk1;
uint16 topline; uint16 topline;
uint16 width, height; uint16 width, height;
uint16 size; uint16 size;

View file

@ -336,8 +336,6 @@ void Scumm::drawObject(int obj, int arg)
if (_BgNeedsRedraw) if (_BgNeedsRedraw)
arg = 0; arg = 0;
_curVirtScreen = &virtscr[0];
od = &_objs[obj]; od = &_objs[obj];
xpos = od->x_pos >> 3; xpos = od->x_pos >> 3;
@ -386,7 +384,7 @@ void Scumm::drawObject(int obj, int arg)
// the inventory and conversation icons. // the inventory and conversation icons.
if ((_features & GF_AFTER_V7 || _gameId == GID_SAMNMAX) && getClass(od->obj_nr, 22)) if ((_features & GF_AFTER_V7 || _gameId == GID_SAMNMAX) && getClass(od->obj_nr, 22))
flags |= Gdi::dbDrawMaskOnAll; flags |= Gdi::dbDrawMaskOnAll;
gdi.drawBitmap(ptr, _curVirtScreen, x, ypos, height, x - xpos, numstrip, flags); gdi.drawBitmap(ptr, &virtscr[0], x, ypos, height, x - xpos, numstrip, flags);
} }
} }

View file

@ -219,7 +219,7 @@ protected:
int _offsX, _offsY; int _offsX, _offsY;
int _virtScreenHeight; int _virtScreenHeight;
void drawBits(byte *dst, byte *mask, int drawTop, int width, int height); void drawBits(byte *dst, byte *mask, int drawTop, int width, int height, bool useMask);
public: public:
byte _colorMap[16]; byte _colorMap[16];
@ -406,7 +406,6 @@ public:
int _curVerbSlot; int _curVerbSlot;
int _curPalIndex; int _curPalIndex;
byte _currentRoom; byte _currentRoom;
VirtScreen *_curVirtScreen;
bool _egoPositioned; bool _egoPositioned;
int _keyPressed; int _keyPressed;

View file

@ -320,17 +320,18 @@ void CharsetRenderer::printChar(int chr)
+ drawTop * _vm->gdi._numStrips + _left / 8 + _vm->_screenStartStrip; + drawTop * _vm->gdi._numStrips + _left / 8 + _vm->_screenStartStrip;
byte *dst = vs->screenPtr + vs->xstart + drawTop * _vm->_realWidth + _left; byte *dst = vs->screenPtr + vs->xstart + drawTop * _vm->_realWidth + _left;
bool useMask = (vs->number == 0 && !_ignoreCharsetMask);
if (_blitAlso) { if (_blitAlso) {
byte *back = dst; byte *back = dst;
dst = _vm->getResourceAddress(rtBuffer, vs->number + 5) dst = _vm->getResourceAddress(rtBuffer, vs->number + 5)
+ vs->xstart + drawTop * _vm->_realWidth + _left; + vs->xstart + drawTop * _vm->_realWidth + _left;
drawBits(dst, mask, drawTop, width, height); drawBits(dst, mask, drawTop, width, height, useMask);
_vm->blit(back, dst, width, height); _vm->blit(back, dst, width, height);
} else { } else {
drawBits(dst, mask, drawTop, width, height); drawBits(dst, mask, drawTop, width, height, useMask);
} }
_left += width; _left += width;
@ -343,17 +344,14 @@ void CharsetRenderer::printChar(int chr)
_top -= _offsY; _top -= _offsY;
} }
void CharsetRenderer::drawBits(byte *dst, byte *mask, int drawTop, int width, int height) void CharsetRenderer::drawBits(byte *dst, byte *mask, int drawTop, int width, int height, bool useMask)
{ {
bool usemask;
byte maskmask; byte maskmask;
int y, x; int y, x;
int maskpos; int maskpos;
int color; int color;
byte numbits, bits; byte numbits, bits;
usemask = (_vm->_curVirtScreen->number == 0 && !_ignoreCharsetMask);
bits = *_charPtr++; bits = *_charPtr++;
numbits = 8; numbits = 8;
@ -370,7 +368,7 @@ void CharsetRenderer::drawBits(byte *dst, byte *mask, int drawTop, int width, in
assert(color == myColor); assert(color == myColor);
if (color) { if (color) {
if (usemask) { if (useMask) {
mask[maskpos] |= maskmask; mask[maskpos] |= maskmask;
} }
*dst = _colorMap[color]; *dst = _colorMap[color];