MADS: Properly implement drawing to a subset of the screen

This commit is contained in:
Paul Gilbert 2014-09-03 22:09:50 -04:00
parent 4be8aa8906
commit 82b2b2d65d
10 changed files with 83 additions and 53 deletions

View File

@ -546,8 +546,7 @@ void TextDisplayList::draw(MSurface *s) {
for (uint idx = 0; idx < size(); ++idx) {
TextDisplay &td = (*this)[idx];
if (td._active && (td._expire >= 0)) {
Common::Point destPos(td._bounds.left + _vm->_screen._offset.x,
td._bounds.top + _vm->_screen._offset.y);
Common::Point destPos(td._bounds.left, td._bounds.top);
td._font->setColors(0xFF, td._color1, td._color2, 0);
td._font->writeString(s, td._msg, destPos, td._spacing, td._bounds.width());
}

View File

@ -51,10 +51,9 @@ struct SpriteInfo {
* MADS graphics surface
*/
class MSurface : public Graphics::Surface {
private:
bool _freeFlag;
protected:
static MADSEngine *_vm;
bool _freeFlag;
public:
/**
* Sets the engine refrence used all surfaces

View File

@ -346,7 +346,6 @@ void DialogsNebular::showScummVMSaveDialog() {
}
scene->_spriteSlots.reset();
_vm->_screen._offset.y = 0;
scene->loadScene(scene->_currentSceneId, game._aaName, true);
scene->_userInterface.noInventoryAnim();
game._scene.drawElements(kTransitionFadeIn, false);
@ -560,7 +559,8 @@ FullScreenDialog::FullScreenDialog(MADSEngine *vm) : _vm(vm) {
}
FullScreenDialog::~FullScreenDialog() {
_vm->_screen._offset.y = 0;
_vm->_screen.resetClipBounds();
_vm->_game->_scene.restrictScene();
}
void FullScreenDialog::display() {
@ -577,7 +577,6 @@ void FullScreenDialog::display() {
scene._currentSceneId = currentSceneId;
scene._nextSceneId = nextSceneId;
_vm->_screen._offset.y = 22;
_vm->_events->initVars();
game._kernelMode = KERNEL_ROOM_INIT;
@ -590,11 +589,7 @@ void FullScreenDialog::display() {
_vm->_palette->fadeOut(pal, nullptr, 0, PALETTE_COUNT, 0, 1, 1, 16);
}
_vm->_screen.empty();
_vm->_screen.hLine(0, 20, MADS_SCREEN_WIDTH, 2);
_vm->_screen.hLine(0, 179, MADS_SCREEN_WIDTH, 2);
game._scene._spriteSlots.fullRefresh();
// Set Fx state and palette entries
game._fx = _vm->_screenFade == SCREEN_FADE_SMOOTH ? kTransitionFadeIn : kCenterVertTransition;
game._trigger = 0;
@ -604,6 +599,18 @@ void FullScreenDialog::display() {
_vm->_palette->setEntry(13, 45, 45, 0);
_vm->_palette->setEntry(14, 63, 63, 63);
_vm->_palette->setEntry(15, 45, 45, 45);
// Clear the screen and draw the upper and lower horizontal lines
_vm->_screen.empty();
_vm->_screen.hLine(0, 20, MADS_SCREEN_WIDTH, 2);
_vm->_screen.hLine(0, 179, MADS_SCREEN_WIDTH, 2);
_vm->_screen.copyRectToScreen(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT));
// Restrict the screen to the area between the two lines
_vm->_screen.setClipBounds(Common::Rect(0, DIALOG_TOP, MADS_SCREEN_WIDTH,
DIALOG_TOP + MADS_SCENE_HEIGHT));
_vm->_game->_scene.restrictScene();
}
/*------------------------------------------------------------------------*/
@ -667,7 +674,7 @@ void GameDialog::display() {
}
GameDialog::~GameDialog() {
_vm->_screen._offset.y = 0;
_vm->_screen.resetClipBounds();
}
void GameDialog::clearLines() {
@ -868,10 +875,11 @@ void GameDialog::handleEvents() {
_vm->_events->pollEvents();
// Scan for objects in the dialog
int objIndex = screenObjects.scan(events.currentPos() - _vm->_screen._offset, LAYER_GUI);
Common::Point mousePos = events.currentPos() - Common::Point(0, DIALOG_TOP);
int objIndex = screenObjects.scan(mousePos, LAYER_GUI);
if (_movedFlag) {
int yp = events.currentPos().y - _vm->_screen._offset.y;
int yp = mousePos.y;
if (yp < screenObjects[1]._bounds.top) {
if (!events._mouseReleased)
_lines[1]._state = DLGSTATE_SELECTED;

View File

@ -31,6 +31,8 @@ namespace MADS {
namespace Nebular {
#define DIALOG_TOP 22
enum CapitalizationMode { kUppercase = 0, kLowercase = 1, kUpperAndLower = 2 };
class DialogsNebular : public Dialogs {

View File

@ -35,7 +35,6 @@ namespace Nebular {
#define NEBULAR_MENUSCREEN 990
#define MADS_MENU_Y ((MADS_SCREEN_HEIGHT - MADS_SCENE_HEIGHT) / 2)
#define MADS_MENU_ANIM_DELAY 70
#define DIALOG_TOP 22
MenuView::MenuView(MADSEngine *vm) : FullScreenDialog(vm) {
_breakFlag = false;
@ -57,7 +56,6 @@ void MenuView::show() {
while (!_breakFlag && !_vm->shouldQuit()) {
if (_redrawFlag) {
_vm->_game->_scene.drawElements(_vm->_game->_fx, _vm->_game->_fx);
_vm->_screen.copyRectToScreen(Common::Rect(0, 0, 320, 200));
_redrawFlag = false;
}
@ -111,10 +109,10 @@ void MainMenu::display() {
// Register the menu item area in the screen objects
MSprite *frame0 = _menuItems[i]->getFrame(0);
Common::Point pt(frame0->_offset.x - (frame0->w / 2),
frame0->_offset.y - frame0->h + _vm->_screen._offset.y);
frame0->_offset.y - frame0->h);
screenObjects.add(
Common::Rect(pt.x, pt.y, pt.x + frame0->w, pt.y + frame0->h),
LAYER_GUI, CAT_COMMAND, i);
Common::Rect(pt.x, pt.y + DIALOG_TOP, pt.x + frame0->w,
pt.y + frame0->h + DIALOG_TOP), LAYER_GUI, CAT_COMMAND, i);
}
// Set the cursor for when it's shown

View File

@ -63,8 +63,7 @@ Scene::Scene(MADSEngine *vm)
_paletteUsageF.push_back(PaletteUsage::UsageEntry(0xF));
// Set up a scene surface that maps to our physical screen drawing surface
_sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH,
_vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8());
restrictScene();
// Set up the verb list
_verbList.push_back(VerbInit(VERB_LOOK, VERB_THAT, PREP_NONE));
@ -85,6 +84,11 @@ Scene::~Scene() {
delete _animationData;
}
void Scene::restrictScene() {
_sceneSurface.init(MADS_SCREEN_WIDTH, MADS_SCENE_HEIGHT, MADS_SCREEN_WIDTH,
_vm->_screen.getPixels(), Graphics::PixelFormat::createFormatCLUT8());
}
void Scene::clearVocab() {
_activeVocabs.clear();
}
@ -511,7 +515,7 @@ void Scene::drawElements(ScreenTransition transitionType, bool surfaceFlag) {
_vm->_sound->startQueuedCommands();
} else {
// Copy dirty areas to the screen
_dirtyAreas.copyToScreen(_vm->_screen._offset);
_dirtyAreas.copyToScreen();
}
_spriteSlots.cleanUp();

View File

@ -142,6 +142,8 @@ public:
*/
~Scene();
void restrictScene();
/**
* Clear the vocabulary list
*/

View File

@ -212,8 +212,7 @@ void DirtyAreas::copy(MSurface *srcSurface, MSurface *destSurface, const Common:
Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y,
srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y);
Common::Point destPos(bounds.left + _vm->_screen._offset.x,
bounds.top + _vm->_screen._offset.y);
Common::Point destPos(bounds.left, bounds.top);
if ((*this)[i]._active && bounds.isValidRect()) {
srcSurface->copyTo(destSurface, bounds, destPos);
@ -221,17 +220,14 @@ void DirtyAreas::copy(MSurface *srcSurface, MSurface *destSurface, const Common:
}
}
void DirtyAreas::copyToScreen(const Common::Point &posAdjust) {
void DirtyAreas::copyToScreen() {
for (uint i = 0; i < size(); ++i) {
const Common::Rect &srcBounds = (*this)[i]._bounds;
const Common::Rect &bounds = (*this)[i]._bounds;
// Check if this is a sane rectangle before attempting to create it
if (srcBounds.left >= srcBounds.right || srcBounds.top >= srcBounds.bottom)
if (bounds.left >= bounds.right || bounds.top >= bounds.bottom)
continue;
Common::Rect bounds(srcBounds.left + posAdjust.x, srcBounds.top + posAdjust.y,
srcBounds.right + posAdjust.x, srcBounds.bottom + posAdjust.y);
if ((*this)[i]._active && (*this)[i]._bounds.isValidRect()) {
_vm->_screen.copyRectToScreen(bounds);
}
@ -561,23 +557,32 @@ void ScreenObjects::synchronize(Common::Serializer &s) {
ScreenSurface::ScreenSurface() {
_shakeCountdown = -1;
_random = 0x4D2;
_surfacePixels = nullptr;
}
void ScreenSurface::init() {
setSize(g_system->getWidth(), g_system->getHeight());
// Set the size for the screen
setSize(MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT);
// Store a copy of the raw pixels pointer for the screen, since the surface
// itself may be later changed to only a subset of the screen
_surfacePixels = (byte *)getPixels();
_freeFlag = false;
}
void ScreenSurface::copyRectToScreen(const Common::Point &destPos,
const Common::Rect &bounds) {
const byte *buf = getBasePtr(destPos.x, destPos.y);
if (bounds.width() != 0 && bounds.height() != 0)
g_system->copyRectToScreen(buf, this->pitch, bounds.left, bounds.top,
bounds.width(), bounds.height());
ScreenSurface::~ScreenSurface() {
delete[] _surfacePixels;
}
void ScreenSurface::copyRectToScreen(const Common::Rect &bounds) {
copyRectToScreen(Common::Point(bounds.left, bounds.top), bounds);
const byte *buf = getBasePtr(bounds.left, bounds.top);
Common::Rect destBounds = bounds;
destBounds.translate(_clipBounds.left, _clipBounds.top);
if (bounds.width() != 0 && bounds.height() != 0)
g_system->copyRectToScreen(buf, this->pitch, destBounds.left, destBounds.top,
destBounds.width(), destBounds.height());
}
void ScreenSurface::updateScreen() {
@ -659,4 +664,15 @@ void ScreenSurface::transition(ScreenTransition transitionType, bool surfaceFlag
}
}
void ScreenSurface::setClipBounds(const Common::Rect &r) {
_clipBounds = r;
setPixels(_surfacePixels + pitch * r.top + r.left, r.width(), r.height());
this->pitch = MADS_SCREEN_WIDTH;
}
void ScreenSurface::resetClipBounds() {
setClipBounds(Common::Rect(0, 0, MADS_SCREEN_WIDTH, MADS_SCREEN_HEIGHT));
}
} // End of namespace MADS

View File

@ -117,8 +117,8 @@ public:
/**
* Use the lsit of dirty areas to copy areas of the screen surface to
* the physical screen
* @param posAdjust Position adjustment */
void copyToScreen(const Common::Point &posAdjust);
*/
void copyToScreen();
void reset();
};
@ -205,8 +205,9 @@ public:
class ScreenSurface : public MSurface {
private:
uint16 _random;
byte *_surfacePixels;
Common::Rect _clipBounds;
public:
Common::Point _offset;
int _shakeCountdown;
public:
/**
@ -214,19 +215,16 @@ public:
*/
ScreenSurface();
/**
* Destructor
*/
~ScreenSurface();
/**
* Initialize the surface
*/
void init();
/**
* Copys an area of the screen surface to a given destination position on
* the ScummVM physical screen buffer
* @param destPos Destination position
* @param bounds Area of screen surface to copy
*/
void copyRectToScreen(const Common::Point &destPos, const Common::Rect &bounds);
/**
* Copys an area of the screen surface to the ScmmVM physical screen buffer
* @param bounds Area of screen surface to copy
@ -239,6 +237,12 @@ public:
void updateScreen();
void transition(ScreenTransition transitionType, bool surfaceFlag);
void setClipBounds(const Common::Rect &r);
void resetClipBounds();
const Common::Rect &getClipBounds() { return _clipBounds; }
};
} // End of namespace MADS

View File

@ -331,8 +331,6 @@ void SpriteSlots::drawSprites(MSurface *s) {
xp = slot._position.x - (sprite->w / 2) - scene._posAdjust.x;
yp = slot._position.y - sprite->h - scene._posAdjust.y + 1;
}
xp += _vm->_screen._offset.x;
yp += _vm->_screen._offset.y;
if (slot._depth > 1) {
// Draw the frame with depth processing