diff options
author | Matthew Stewart | 2018-02-25 02:01:02 -0500 |
---|---|---|
committer | Eugene Sandulenko | 2018-08-09 08:37:30 +0200 |
commit | a69f025818224c9bfeb52be11f31a2b6387bb76f (patch) | |
tree | d398acfc0660500df8f03fb8e836b87b58d40fee | |
parent | 7c62092367d00418d930411ff4a080f6ad2d0417 (diff) | |
download | scummvm-rg350-a69f025818224c9bfeb52be11f31a2b6387bb76f.tar.gz scummvm-rg350-a69f025818224c9bfeb52be11f31a2b6387bb76f.tar.bz2 scummvm-rg350-a69f025818224c9bfeb52be11f31a2b6387bb76f.zip |
STARTREK: Implement drawAllSprites properly.
Still need to do the part which calculates sprite priorities.
-rw-r--r-- | engines/startrek/common.cpp | 35 | ||||
-rw-r--r-- | engines/startrek/common.h | 39 | ||||
-rwxr-xr-x | engines/startrek/graphics.cpp | 138 | ||||
-rwxr-xr-x | engines/startrek/graphics.h | 1 | ||||
-rwxr-xr-x | engines/startrek/module.mk | 1 | ||||
-rw-r--r-- | engines/startrek/sprite.h | 22 | ||||
-rwxr-xr-x | engines/startrek/startrek.cpp | 13 | ||||
-rw-r--r-- | engines/startrek/text.cpp | 10 |
8 files changed, 215 insertions, 44 deletions
diff --git a/engines/startrek/common.cpp b/engines/startrek/common.cpp new file mode 100644 index 0000000000..cef01c5fae --- /dev/null +++ b/engines/startrek/common.cpp @@ -0,0 +1,35 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "startrek/common.h" + +namespace StarTrek { + +Common::Rect getRectEncompassing(Common::Rect r1, Common::Rect r2) { + uint16 l = min(r1.left, r2.left); + uint16 t = min(r1.top, r2.top); + uint16 r = max(r1.right, r2.right); + uint16 b = max(r1.bottom, r2.bottom); + + return Common::Rect(l,t,r,b); +} + +} diff --git a/engines/startrek/common.h b/engines/startrek/common.h new file mode 100644 index 0000000000..4598085a27 --- /dev/null +++ b/engines/startrek/common.h @@ -0,0 +1,39 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef STARTREK_COMMON_H +#define STARTREK_COMMON_H + +#include "common/rect.h" + +namespace StarTrek { + +template<class T> +T min(T a, T b) { return a < b ? a : b; } + +template<class T> +T max(T a, T b) { return a > b ? a : b; } + +Common::Rect getRectEncompassing(Common::Rect r1, Common::Rect r2); + +} + +#endif diff --git a/engines/startrek/graphics.cpp b/engines/startrek/graphics.cpp index cf63faa889..467d1f5605 100755 --- a/engines/startrek/graphics.cpp +++ b/engines/startrek/graphics.cpp @@ -19,11 +19,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "startrek/common.h" #include "startrek/graphics.h" #include "common/config-manager.h" #include "common/rendermode.h" #include "graphics/palette.h" +#include "graphics/surface.h" namespace StarTrek { @@ -34,7 +36,7 @@ Graphics::Graphics(StarTrekEngine *vm) : _vm(vm), _egaMode(false) { _priData = nullptr; _lutData = nullptr; - _screenRect = Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT); + _screenRect = Common::Rect(SCREEN_WIDTH-1, SCREEN_HEIGHT-1); if (ConfMan.hasKey("render_mode")) _egaMode = (Common::parseRenderMode(ConfMan.get("render_mode").c_str()) == Common::kRenderEGA) && (_vm->getGameType() != GType_STJR) && !(_vm->getFeatures() & GF_DEMO); @@ -43,7 +45,6 @@ Graphics::Graphics(StarTrekEngine *vm) : _vm(vm), _egaMode(false) { _font = new Font(_vm); _backgroundImage = new Bitmap(_vm->openFile("DEMON0.BMP").get()); - _canvas = new Bitmap(SCREEN_WIDTH, SCREEN_HEIGHT); _numSprites = 0; } @@ -55,7 +56,6 @@ Graphics::~Graphics() { delete _font; delete _backgroundImage; - delete _canvas; } @@ -137,12 +137,8 @@ SharedPtr<Bitmap> Graphics::loadBitmap(Common::String basename) { } void Graphics::redrawScreen() { - // TODO: get rid of _canvas for efficiency - memcpy(_canvas->pixels, _backgroundImage->pixels, SCREEN_WIDTH*SCREEN_HEIGHT); - + _vm->_system->copyRectToScreen(_backgroundImage->pixels, SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); drawAllSprites(); - - drawBitmapToScreen(_canvas); } void Graphics::drawSprite(const Sprite &sprite) { @@ -158,7 +154,9 @@ void Graphics::drawSprite(const Sprite &sprite, const Common::Rect &rect) { assert(_screenRect.contains(rect)); assert(spriteRect.contains(rect)); - byte *dest = _canvas->pixels + rect.top*SCREEN_WIDTH + rect.left; + ::Graphics::Surface *surface = _vm->_system->lockScreen(); + + byte *dest = (byte*)surface->getPixels() + rect.top*SCREEN_WIDTH + rect.left; switch(sprite.drawMode) { case 0: { // Normal sprite @@ -233,7 +231,7 @@ void Graphics::drawSprite(const Sprite &sprite, const Common::Rect &rect) { int drawWidth = rectangle1.width() + 1; int drawHeight = rectangle1.height() + 1; - dest =_canvas->pixels + sprite.drawY*SCREEN_WIDTH + sprite.drawX + dest = (byte*)surface->getPixels() + sprite.drawY*SCREEN_WIDTH + sprite.drawX + rectangle1.top*8*SCREEN_WIDTH + rectangle1.left*8; byte *src = sprite.bitmap->pixels + rectangle1.top*sprite.bitmap->width/8 + rectangle1.left; @@ -283,16 +281,120 @@ void Graphics::drawSprite(const Sprite &sprite, const Common::Rect &rect) { error("drawSprite: draw mode %d invalid", sprite.drawMode); break; } + + _vm->_system->unlockScreen(); } void Graphics::drawAllSprites() { - // TODO: implement properly + if (_numSprites == 0) + return; + + // TODO: calculateSpriteDrawPriority() + + // Update sprite rectangles for (int i=0; i<_numSprites; i++) { Sprite *spr = _sprites[i]; - spr->drawX = spr->pos.x; - spr->drawY = spr->pos.y; - drawSprite(*spr); + spr->bitmapChanged = true; // FIXME (delete this later) + Common::Rect rect; + + rect.left = spr->pos.x - spr->bitmap->xoffset; + rect.top = spr->pos.y - spr->bitmap->yoffset; + rect.right = rect.left + spr->bitmap->width - 1; + rect.bottom = rect.top + spr->bitmap->height - 1; + + spr->drawX = rect.left; + spr->drawY = rect.top; + + spr->drawRect = rect.findIntersectingRect(_screenRect); + + if (!spr->drawRect.isEmpty()) { // At least partly on-screen + if (spr->lastDrawRect.left <= spr->lastDrawRect.right) { + // If the sprite's position is close to where it was last time it was + // drawn, combine the two rectangles and redraw that whole section. + // Otherwise, redraw the old position and current position separately. + rect = spr->drawRect.findIntersectingRect(spr->lastDrawRect); + + if (rect.isEmpty()) + spr->rect2Valid = 0; + else { + spr->rectangle2 = getRectEncompassing(spr->drawRect, spr->lastDrawRect); + spr->rect2Valid = 1; + } + } + else { + spr->rectangle2 = spr->drawRect; + spr->rect2Valid = 1; + } + + spr->isOnScreen = 1; + } + else { // Off-screen + spr->rect2Valid = 0; + spr->isOnScreen = 0; + } } + + // Determine what portions of the screen need to be updated + Common::Rect dirtyRects[MAX_SPRITES*2]; + int numDirtyRects = 0; + + for (int i=0; i<_numSprites; i++) { + Sprite *spr = _sprites[i]; + + if (spr->bitmapChanged) { + if (spr->isOnScreen) { + if (spr->rect2Valid) { + dirtyRects[numDirtyRects++] = spr->rectangle2; + } + else { + dirtyRects[numDirtyRects++] = spr->drawRect; + dirtyRects[numDirtyRects++] = spr->lastDrawRect; + } + } + else { + dirtyRects[numDirtyRects++] = spr->lastDrawRect; + } + } + } + + // Redraw the background on every dirty rectangle + for (int i=0; i<numDirtyRects; i++) { + Common::Rect &r = dirtyRects[i]; + + int offset = r.top*SCREEN_WIDTH + r.left; + _vm->_system->copyRectToScreen(_backgroundImage->pixels+offset, SCREEN_WIDTH, r.left, r.top, r.width(), r.height()); + } + + // For each sprite, merge the rectangles that overlap with it and redraw the sprite. + for (int i=0; i<_numSprites; i++) { + Sprite *spr = _sprites[i]; + + if (spr->field16 == 0 && spr->isOnScreen) { + bool mustRedrawSprite = false; + Common::Rect rect2; + + for (int j=0; j<numDirtyRects; j++) { + Common::Rect rect1 = spr->drawRect.findIntersectingRect(dirtyRects[j]); + + if (!rect1.isEmpty()) { + if (mustRedrawSprite) + rect2 = getRectEncompassing(rect1, rect2); + else + rect2 = rect1; + mustRedrawSprite = true; + } + } + + if (mustRedrawSprite) + drawSprite(*spr, rect2); + } + + spr->field16 = 0; + spr->bitmapChanged = 0; + spr->lastDrawRect = spr->drawRect; + } + + _vm->_system->updateScreen(); } void Graphics::addSprite(Sprite *sprite) { @@ -304,10 +406,10 @@ void Graphics::addSprite(Sprite *sprite) { sprite->field8 = 0; sprite->field16 = 0; - sprite->rectangle1.top = -1; - sprite->rectangle1.left = -1; - sprite->rectangle1.bottom = -2; - sprite->rectangle1.right = -2; + sprite->lastDrawRect.top = -1; + sprite->lastDrawRect.left = -1; + sprite->lastDrawRect.bottom = -2; + sprite->lastDrawRect.right = -2; _sprites[_numSprites++] = sprite; } diff --git a/engines/startrek/graphics.h b/engines/startrek/graphics.h index 88e68cbea7..fa9f90b3fc 100755 --- a/engines/startrek/graphics.h +++ b/engines/startrek/graphics.h @@ -105,7 +105,6 @@ private: Common::Rect _screenRect; Bitmap *_backgroundImage; - Bitmap *_canvas; Sprite *_sprites[MAX_SPRITES]; int _numSprites; diff --git a/engines/startrek/module.mk b/engines/startrek/module.mk index e2670b443a..23af200fb2 100755 --- a/engines/startrek/module.mk +++ b/engines/startrek/module.mk @@ -2,6 +2,7 @@ MODULE := engines/startrek MODULE_OBJS = \ bitmap.o \ + common.o \ detection.o \ filestream.o \ font.o \ diff --git a/engines/startrek/sprite.h b/engines/startrek/sprite.h index 93fd2dc53f..5fdc0f511f 100644 --- a/engines/startrek/sprite.h +++ b/engines/startrek/sprite.h @@ -37,6 +37,12 @@ using Common::SharedPtr; namespace StarTrek { +// Note: Rects in Star Trek are probably considered to have their bottom-right pixel +// contained in the rectangle, but ScummVM is the opposite... (Trek might be inconsistent) +// Be careful when using some of Rect's functions, including: +// * The width/height constructor +// * width/height methods +// * "contains" method for points (it should work for other rects) struct Sprite { Common::Point pos; uint16 drawPriority; @@ -45,16 +51,16 @@ struct Sprite { SharedPtr<Bitmap> bitmap; uint16 drawMode; uint16 textColor; - uint16 bitmapChanged; - uint16 redrawCondition2; - uint16 redrawCondition3; - uint16 field16; - Common::Rect rectangle1; - Common::Rect clickRectangle; + bool bitmapChanged; + bool rect2Valid; + bool isOnScreen; + uint16 field16; // When set, sprite isn't drawn next refresh? (Gets reset to 0 after) + Common::Rect lastDrawRect; // Rect encompassing the sprite last time it was drawn + Common::Rect drawRect; // Rect encompassing the sprite currently Common::Rect rectangle2; - uint16 drawX,drawY; - + int16 drawX,drawY; + Sprite() { memset(this, 0, sizeof(Sprite)); } void setBitmap(SharedPtr<Bitmap> b); }; diff --git a/engines/startrek/startrek.cpp b/engines/startrek/startrek.cpp index 8dd4f9010e..726fc3fe6e 100755 --- a/engines/startrek/startrek.cpp +++ b/engines/startrek/startrek.cpp @@ -101,7 +101,6 @@ Common::Error StarTrekEngine::run() { _gfx->drawBackgroundImage("BRIDGE.BGD"); } - // Sprite tests // Draw mode 0 @@ -110,7 +109,7 @@ Common::Error StarTrekEngine::run() { spr->bitmap = _gfx->loadBitmap("MWALKE00"); spr->drawPriority = 1; spr->pos.x = 150; - spr->pos.y = 30; + spr->pos.y = 100; spr->drawMode = 0; // Draw mode 2 (translucent background) @@ -119,9 +118,10 @@ Common::Error StarTrekEngine::run() { spr->bitmap = _gfx->loadBitmap("KWALKS00"); spr->drawPriority = 1; spr->pos.x = 200; - spr->pos.y = 40; + spr->pos.y = 140; spr->drawMode = 2; + /* // Draw mode 3 (text) spr = new Sprite; _gfx->addSprite(spr); @@ -134,15 +134,14 @@ Common::Error StarTrekEngine::run() { spr->drawMode = 3; // initTextSprite function - /* spr = new Sprite; int x=0,y=0; _gfx->initTextSprite(&x, &y, 0xb3, 3, false, spr); spr->pos.y = 150; + */ - _gfx->showText(&Graphics::tmpFunction, 0, 50, 50, 0xb3, 0, 10, 0); - */ + _gfx->showText(&Graphics::tmpFunction, 0, 150, 50, 0xb3, 0, 10, 0); while (!shouldQuit()) { pollEvents(); @@ -164,7 +163,7 @@ void StarTrekEngine::pollEvents() { break; } } - _gfx->redrawScreen(); + _gfx->drawAllSprites(); _system->delayMillis(1000/60); } diff --git a/engines/startrek/text.cpp b/engines/startrek/text.cpp index dcc4b88d91..18a283bde3 100644 --- a/engines/startrek/text.cpp +++ b/engines/startrek/text.cpp @@ -64,8 +64,6 @@ int Graphics::showText(TextGetterFunc textGetter, int var, int xoffset, int yoff Sprite textboxSprite; SharedPtr<TextBitmap> textBitmap = initTextSprite(&xoffset, &yoffset, textColor, numTextboxLines, numChoicesWithNames, &textboxSprite); - debug("X: %d, Y: %d\n", xoffset, yoffset); - int choiceIndex = 0; int var28 = 0; if (tmpTextboxVar1 != 0 && tmpTextboxVar1 != 1 && numChoices == 1 @@ -178,25 +176,17 @@ SharedPtr<TextBitmap> Graphics::initTextSprite(int *xoffsetPtr, int *yoffsetPtr, if (varC < 0) xoffset += varC; - debug("xoffset A: %d", xoffset); - varC = xoffset - (bitmap->width+0x1d)/2; if (varC < 1) xoffset += varC-1; - debug("xoffset B: %d", xoffset); - varC = yoffset - (bitmap->height+0x11) - 20; if (varC < 0) yoffset -= varC; - debug("Mid xoffset: %d", xoffset); - xoffset -= (bitmap->width+0x1d)/2; yoffset -= bitmap->height; - debug("Final xoffset: %d", xoffset); - bitmap->pixels[0] = 0x10; memset(&bitmap->pixels[1], 0x11, TEXTBOX_WIDTH-2); bitmap->pixels[TEXTBOX_WIDTH-1] = 0x12; |