diff --git a/scumm/camera.cpp b/scumm/camera.cpp index 0357392ce9d..c35a93a5ca6 100644 --- a/scumm/camera.cpp +++ b/scumm/camera.cpp @@ -29,7 +29,7 @@ namespace Scumm { void ScummEngine::setCameraAtEx(int at) { if (!(_features & GF_NEW_CAMERA)) { - camera._mode = CM_NORMAL; + camera._mode = kNormalCameraMode; camera._cur.x = at; setCameraAt(at, 0); camera._movingToActor = false; @@ -37,7 +37,7 @@ void ScummEngine::setCameraAtEx(int at) { } void ScummEngine::setCameraAt(int pos_x, int pos_y) { - if (camera._mode != CM_FOLLOW_ACTOR || abs(pos_x - camera._cur.x) > (_screenWidth / 2)) { + if (camera._mode != kFollowActorCameraMode || abs(pos_x - camera._cur.x) > (_screenWidth / 2)) { camera._cur.x = pos_x; } camera._dest.x = pos_x; @@ -89,12 +89,12 @@ void ScummEngine::setCameraFollows(Actor *a) { int t, i; - camera._mode = CM_FOLLOW_ACTOR; + camera._mode = kFollowActorCameraMode; camera._follows = a->number; if (!a->isInCurrentRoom()) { startScene(a->getRoom(), 0, 0); - camera._mode = CM_FOLLOW_ACTOR; + camera._mode = kFollowActorCameraMode; camera._cur.x = a->_pos.x; setCameraAt(camera._cur.x, 0); } @@ -174,7 +174,7 @@ void ScummEngine::moveCamera() { return; } - if (camera._mode == CM_FOLLOW_ACTOR) { + if (camera._mode == kFollowActorCameraMode) { a = derefActor(camera._follows, "moveCamera"); actorx = a->_pos.x; @@ -353,7 +353,7 @@ void ScummEngine::cameraMoved() { void ScummEngine::panCameraTo(int x, int y) { camera._dest.x = x; - camera._mode = CM_PANNING; + camera._mode = kPanningCameraMode; camera._movingToActor = false; } @@ -373,7 +373,7 @@ void ScummEngine::actorFollowCamera(int act) { /* // MI1 compatibilty if (act == 0) { - camera._mode = CM_NORMAL; + camera._mode = kNormalCameraMode; camera._follows = 0; camera._movingToActor = false; return; diff --git a/scumm/gfx.cpp b/scumm/gfx.cpp index 8a124e245bc..583e52698a2 100644 --- a/scumm/gfx.cpp +++ b/scumm/gfx.cpp @@ -250,9 +250,9 @@ void ScummEngine::initScreens(int a, int b, int w, int h) { initVirtScreen(3, 0, 80, _screenWidth, 13, false, false); } } - initVirtScreen(0, 0, b, _screenWidth, h - b, true, true); - initVirtScreen(1, 0, 0, _screenWidth, b, false, false); - initVirtScreen(2, 0, h, _screenWidth, _screenHeight - h, false, false); + initVirtScreen(kMainVirtScreen, 0, b, _screenWidth, h - b, true, true); + initVirtScreen(kTextVirtScreen, 0, 0, _screenWidth, b, false, false); + initVirtScreen(kVerbVirtScreen, 0, h, _screenWidth, _screenHeight - h, false, false); _screenB = b; _screenH = h; @@ -371,32 +371,34 @@ void ScummEngine::updateDirtyRect(int virt, int left, int right, int top, int bo } } +/** + * Update all dirty screen areas. This method blits all of the internal engine + * graphics to the actual display, as needed. In addition, the 'shaking' + * code in the backend is controlled from here. + */ void ScummEngine::drawDirtyScreenParts() { - int i; - VirtScreen *vs; - byte *src; - - updateDirtyScreen(2); + // Update verbs + updateDirtyScreen(kVerbVirtScreen); + + // In V1-V3, update the conversation area (at the top of the screen) if (_version <= 3) - updateDirtyScreen(1); + updateDirtyScreen(kTextVirtScreen); - if (camera._last.x == camera._cur.x && (camera._last.y == camera._cur.y || !(_features & GF_NEW_CAMERA))) { - updateDirtyScreen(0); + // Update game area ("stage") + if (camera._last.x != camera._cur.x || (_features & GF_NEW_CAMERA && (camera._cur.y != camera._last.y))) { + // Camera moved: redraw everything + // Small side note: most of our GFX code relies on this identity: + // gdi._numStrips * 8 == _screenWidth == vs->width + VirtScreen *vs = &virtscr[kMainVirtScreen]; + gdi.drawStripToScreen(vs, 0, vs->width, 0, vs->height); + vs->setDirtyRange(vs->height, 0); } else { - vs = &virtscr[0]; - - src = vs->screenPtr + vs->xstart + _screenTop * _screenWidth; - _system->copy_rect(src, _screenWidth, 0, vs->topline, _screenWidth, vs->height - _screenTop); - - for (i = 0; i < gdi._numStrips; i++) { - vs->tdirty[i] = vs->height; - vs->bdirty[i] = 0; - } + updateDirtyScreen(kMainVirtScreen); } - /* Handle shaking */ + // Handle shaking if (_shakeEnabled) { - _shakeFrame = (_shakeFrame + 1) & (NUM_SHAKE_POSITIONS - 1); + _shakeFrame = (_shakeFrame + 1) % NUM_SHAKE_POSITIONS; _system->set_shake_pos(shake_positions[_shakeFrame]); } else if (!_shakeEnabled &&_shakeFrame != 0) { _shakeFrame = 0; @@ -409,44 +411,38 @@ void ScummEngine::updateDirtyScreen(int slot) { } /** - * Blit the data from the given VirtScreen to the display. If the camera moved, + * Blit the dirty 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) { + // Do nothing for unused virtual screens if (vs->height == 0) return; - if (_vm->_features & GF_NEW_CAMERA && (_vm->camera._cur.y != _vm->camera._last.y)) { - drawStripToScreen(vs, 0, _numStrips * 8, 0, vs->height); - } else { - int i; - int start, w, top, bottom; + int i; + int w = 8; + int start = 0; - w = 8; - start = 0; - - for (i = 0; i < _numStrips; i++) { - bottom = vs->bdirty[i]; - - if (bottom) { - top = vs->tdirty[i]; - vs->tdirty[i] = vs->height; - vs->bdirty[i] = 0; - if (i != (_numStrips - 1) && vs->bdirty[i + 1] == bottom && vs->tdirty[i + 1] == top) { - // Simple optimizations: if two or more neighbouring strips form one bigger rectangle, - // blit them all at once. - w += 8; - continue; - } - // handle vertically scrolling rooms - if (_vm->_features & GF_NEW_CAMERA) - drawStripToScreen(vs, start * 8, w, 0, vs->height); - else - drawStripToScreen(vs, start * 8, w, top, bottom); - w = 8; + for (i = 0; i < _numStrips; i++) { + if (vs->bdirty[i]) { + const int bottom = vs->bdirty[i]; + const int top = vs->tdirty[i]; + vs->tdirty[i] = vs->height; + vs->bdirty[i] = 0; + if (i != (_numStrips - 1) && vs->bdirty[i + 1] == bottom && vs->tdirty[i + 1] == top) { + // Simple optimizations: if two or more neighbouring strips form one bigger rectangle, + // blit them all at once. + w += 8; + continue; } - start = i + 1; + // handle vertically scrolling rooms + if (_vm->_features & GF_NEW_CAMERA) + drawStripToScreen(vs, start * 8, w, 0, vs->height); + else + drawStripToScreen(vs, start * 8, w, top, bottom); + w = 8; } + start = i + 1; } } @@ -2257,7 +2253,7 @@ void ScummEngine::fadeOut(int effect) { case 129: // Just blit screen 0 to the display (i.e. display will be black) vs->setDirtyRange(0, vs->height); - updateDirtyScreen(0); + updateDirtyScreen(kMainVirtScreen); break; case 134: dissolveEffect(1, 1); @@ -2341,7 +2337,7 @@ void ScummEngine::transitionEffect(int a) { else virtscr[0].bdirty[l] = (b + 1) * 8; } - updateDirtyScreen(0); + updateDirtyScreen(kMainVirtScreen); } for (i = 0; i < 16; i++) diff --git a/scumm/gfx.h b/scumm/gfx.h index 5dc17a97f07..367f92b4fed 100644 --- a/scumm/gfx.h +++ b/scumm/gfx.h @@ -29,13 +29,15 @@ namespace Scumm { class ScummEngine; -enum { /** Camera modes */ - CM_NORMAL = 1, - CM_FOLLOW_ACTOR = 2, - CM_PANNING = 3 +/** Camera modes */ +enum { + kNormalCameraMode = 1, + kFollowActorCameraMode = 2, + kPanningCameraMode = 3 }; -struct CameraData { /** Camera state data */ +/** Camera state data */ +struct CameraData { Common::Point _cur; Common::Point _dest; Common::Point _accel; @@ -45,7 +47,15 @@ struct CameraData { /** Camera state data */ bool _movingToActor; }; -struct VirtScreen { /** Virtual screen areas */ +/** Virtual screen identifiers */ +enum { + kMainVirtScreen = 0, // The 'stage' + kTextVirtScreen = 1, // In V1-V3 games: the area where text is printed + kVerbVirtScreen = 2 // The verb area +}; + +/** Virtual screen areas */ +struct VirtScreen { int number; uint16 topline; uint16 width, height; @@ -66,7 +76,8 @@ struct VirtScreen { /** Virtual screen areas */ } }; -struct ColorCycle { /** Palette cycles */ +/** Palette cycles */ +struct ColorCycle { uint16 delay; uint16 counter; uint16 flags; @@ -74,7 +85,8 @@ struct ColorCycle { /** Palette cycles */ byte end; }; -struct BlastObject { /** BlastObjects to draw */ +/** BlastObjects to draw */ +struct BlastObject { uint16 number; int16 posX, posY; uint16 width, height; @@ -190,14 +202,14 @@ public: // 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. +// Doing this correctly will be 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 +// alternative (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 diff --git a/scumm/script_v2.cpp b/scumm/script_v2.cpp index 19a2b558f48..d21c8449431 100644 --- a/scumm/script_v2.cpp +++ b/scumm/script_v2.cpp @@ -1411,7 +1411,7 @@ void ScummEngine_v2::o2_endCutscene() { if (_gameId == GID_MANIAC) { camera._mode = (byte) vm.cutSceneData[3]; - if (camera._mode == CM_FOLLOW_ACTOR) { + if (camera._mode == kFollowActorCameraMode) { actorFollowCamera(VAR(VAR_EGO)); } else if (vm.cutSceneData[2] != _currentRoom) { startScene(vm.cutSceneData[2], 0, 0); diff --git a/scumm/scummvm.cpp b/scumm/scummvm.cpp index 1072356ad32..ffb7b749425 100644 --- a/scumm/scummvm.cpp +++ b/scumm/scummvm.cpp @@ -2083,7 +2083,7 @@ void ScummEngine::startScene(int room, Actor *a, int objectNr) { VAR(VAR_CAMERA_MAX_Y) = _roomHeight - (_screenHeight / 2); setCameraAt(_screenWidth / 2, _screenHeight / 2); } else { - camera._mode = CM_NORMAL; + camera._mode = kNormalCameraMode; if (_version > 2) camera._cur.x = camera._dest.x = _screenWidth / 2; camera._cur.y = camera._dest.y = _screenHeight / 2;