diff options
author | Paul Gilbert | 2012-01-16 09:19:50 +1100 |
---|---|---|
committer | Strangerke | 2012-04-06 08:19:43 +0200 |
commit | 2416583449699ea6940acdfaac77d15bc1b012d9 (patch) | |
tree | 0b4834bace311845a7117a7e500f500ce1da0de2 | |
parent | 833e46d18a963054949944571e5b07d3e74f2953 (diff) | |
download | scummvm-rg350-2416583449699ea6940acdfaac77d15bc1b012d9.tar.gz scummvm-rg350-2416583449699ea6940acdfaac77d15bc1b012d9.tar.bz2 scummvm-rg350-2416583449699ea6940acdfaac77d15bc1b012d9.zip |
MORTEVIELLE: Implemented a screen surface class to hold all the graphics functionality.
This includes moving the already created pixel and character functions into it, as well as a new method for drawing decoded graphic images.
-rw-r--r-- | engines/mortevielle/graphics.cpp | 144 | ||||
-rw-r--r-- | engines/mortevielle/graphics.h | 25 | ||||
-rw-r--r-- | engines/mortevielle/level15.cpp | 12 | ||||
-rw-r--r-- | engines/mortevielle/mortevielle.cpp | 57 | ||||
-rw-r--r-- | engines/mortevielle/mortevielle.h | 13 | ||||
-rw-r--r-- | engines/mortevielle/sprint.cpp | 2 | ||||
-rw-r--r-- | engines/mortevielle/var_mor.cpp | 4 |
7 files changed, 177 insertions, 80 deletions
diff --git a/engines/mortevielle/graphics.cpp b/engines/mortevielle/graphics.cpp index 2d09b6b7fc..5099504536 100644 --- a/engines/mortevielle/graphics.cpp +++ b/engines/mortevielle/graphics.cpp @@ -20,10 +20,21 @@ * */ +#include "common/endian.h" +#include "common/system.h" #include "mortevielle/graphics.h" +#include "mortevielle/mortevielle.h" namespace Mortevielle { +/*-------------------------------------------------------------------------* + * Image decoding + * + * The code in this section is responsible for decoding image resources. + * Images are broken down into rectangular sections, which can use one + * of 18 different encoding methods. + *-------------------------------------------------------------------------*/ + #define INCR_TAIX { if (_xSize & 1) ++_xSize; } #define DEFAULT_WIDTH (SCREEN_WIDTH / 2) #define BUFFER_SIZE 8192 @@ -774,4 +785,137 @@ void GfxSurface::TF2(const byte *&pSrc, byte *&pDest, const byte *&pLookup, int } } +/*-------------------------------------------------------------------------*/ + +GfxSurface::~GfxSurface() { + free(); +} + +/*-------------------------------------------------------------------------* + * Screen surface + *-------------------------------------------------------------------------*/ + +/** + * Called to populate the font data from the passed file + */ +void ScreenSurface::readFontData(Common::File &f, int dataSize) { + assert(dataSize == (FONT_NUM_CHARS * FONT_HEIGHT)); + f.read(_fontData, FONT_NUM_CHARS * FONT_HEIGHT); +} + +/** + * Returns a graphics surface representing a subset of the screen. The affected area + * is also marked as dirty + */ +Graphics::Surface ScreenSurface::lockArea(const Common::Rect &bounds) { + _dirtyRects.push_back(bounds); + + Graphics::Surface s; + s.pixels = getBasePtr(bounds.left, bounds.top); + s.pitch = pitch; + s.w = bounds.width(); + s.h = bounds.height(); + + return s; +} + +/** + * Updates the affected areas of the surface to the underlying physical screen + */ +void ScreenSurface::updateScreen() { + // Iterate through copying dirty areas to the screen + for (Common::List<Common::Rect>::iterator i = _dirtyRects.begin(); i != _dirtyRects.end(); ++i) { + Common::Rect r = *i; + g_system->copyRectToScreen((const byte *)getBasePtr(r.left, r.top), pitch, + r.left, r.top, r.width(), r.height()); + } + _dirtyRects.clear(); + + // Update the screen + g_system->updateScreen(); +} + +/** + * Draws a decoded picture on the screen + * @remarks Because the ScummVM surface is using a double height 640x200 surface to + * simulate the original 640x200 surface, all Y values have to be doubled. + * Also, image resources are stored at 320x200, so when drawn onto the screen every + * other column is interpolated. + */ +void ScreenSurface::drawPicture(GfxSurface &surface, int x, int y) { + // Lock the affected area of the surface to write to + Graphics::Surface destSurface = lockArea(Common::Rect(x, y, + x + surface.w * 2, y + surface.h * 2)); + + // Loop through writing + for (int yp = 0; yp < surface.h; ++yp) { + if (((y + yp) < 0) || ((y + yp) >= 200)) + continue; + + const byte *pSrc = (const byte *)surface.getBasePtr(0, yp); + byte *pDest = (byte *)destSurface.getBasePtr(0, yp * 2); + + for (int xp = 0; xp < surface.w; ++xp, ++pSrc) { + // Draw pixel from source image + *pDest = *pSrc; + *(pDest + SCREEN_WIDTH) = *pSrc; + ++pDest; + + // TODO: I'm not sure what algorithm the original uses to calculate + // which pixel to use on the alternate columns, so for now I'm doing + // a simple output of null values. This should be revisited once we've + // got the palette loading so we can compare palettes. In fact, the + // original had the alternate columns very noticablely striped. With + // the larger 256 colour palette, it may be worthwhile to offer a + // better blended graphics mode as an option. + *pDest = 0; + *(pDest + SCREEN_WIDTH) = 0; + ++pDest; + } + } + + // TODO: Remove this once we have a proper game loop + updateScreen(); +} + +/** + * Draws a character at the specified co-ordinates + * @remarks Because the ScummVM surface is using a double height 640x200 surface to + * simulate the original 640x200 surface, all Y values have to be doubled + */ +void ScreenSurface::writeCharacter(const Common::Point &pt, unsigned char ch, int palIndex) { + Graphics::Surface destSurface = lockArea(Common::Rect(pt.x, pt.y * 2, + pt.x + FONT_WIDTH, (pt.y + FONT_HEIGHT) * 2)); + + // Get the start of the character to use + assert((ch >= ' ') && (ch <= (unsigned char)(32 + FONT_NUM_CHARS))); + const byte *charData = &_fontData[((int)ch - 32) * FONT_HEIGHT]; + + // Loop through decoding each character's data + for (int yp = 0; yp < FONT_HEIGHT; ++yp) { + byte *lineP = (byte *)destSurface.getBasePtr(0, yp * 2); + byte byteVal = *charData++; + + for (int xp = 0; xp < FONT_WIDTH; ++xp, ++lineP, byteVal <<= 1) { + if (byteVal & 0x80) { + *lineP = palIndex; + *(lineP + SCREEN_WIDTH) = palIndex; + } + } + } +} + +/** + * Sets a single pixel at the specified co-ordinates + * @remarks Because the ScummVM surface is using a double height 640x200 surface to + * simulate the original 640x200 surface, all Y values have to be doubled + */ +void ScreenSurface::setPixel(const Common::Point &pt, int palIndex) { + Graphics::Surface destSurface = lockArea(Common::Rect(pt.x, pt.y * 2, pt.x + 1, (pt.y + 1) * 2)); + + byte *destP = (byte *)destSurface.pixels; + *destP = palIndex; + *(destP + SCREEN_WIDTH) = palIndex; +} + } // End of namespace Mortevielle diff --git a/engines/mortevielle/graphics.h b/engines/mortevielle/graphics.h index ce11fd8245..c733cbc501 100644 --- a/engines/mortevielle/graphics.h +++ b/engines/mortevielle/graphics.h @@ -23,11 +23,17 @@ #ifndef MORTEVIELLE_GRAPHICS_H #define MORTEVIELLE_GRAPHICS_H +#include "common/file.h" +#include "common/list.h" +#include "common/rect.h" #include "graphics/surface.h" -#include "mortevielle/mortevielle.h" namespace Mortevielle { +#define FONT_WIDTH 8 +#define FONT_HEIGHT 6 +#define FONT_NUM_CHARS 121 + class GfxSurface: public Graphics::Surface { private: int _var1; @@ -55,9 +61,26 @@ private: void TF1(byte *&pDest, int &v); void TF2(const byte *&pSrc, byte *&pDest, const byte *&pLookup, int &v); public: + ~GfxSurface(); + void decode(const byte *pSrc); }; +class ScreenSurface: public Graphics::Surface { +private: + Common::List<Common::Rect> _dirtyRects; + byte _fontData[FONT_NUM_CHARS * FONT_HEIGHT]; +public: + void readFontData(Common::File &f, int dataSize); + Graphics::Surface lockArea(const Common::Rect &bounds); + void updateScreen(); + void drawPicture(GfxSurface &surface, int x, int y); + void writeCharacter(const Common::Point &pt, unsigned char ch, int palIndex); + + // TODO: Refactor code to remove this method, for increased performance + void setPixel(const Common::Point &pt, int palIndex); +}; + } // End of namespace Mortevielle #endif diff --git a/engines/mortevielle/level15.cpp b/engines/mortevielle/level15.cpp index 7e1f47d668..8b8dbcf02f 100644 --- a/engines/mortevielle/level15.cpp +++ b/engines/mortevielle/level15.cpp @@ -29,6 +29,7 @@ #include "common/file.h" #include "mortevielle/graphics.h" #include "mortevielle/level15.h" +#include "mortevielle/mortevielle.h" #include "mortevielle/mouse.h" #include "mortevielle/var_mor.h" @@ -99,15 +100,8 @@ void writepal(int n) { void pictout(int seg, int dep, int x, int y) { -#ifdef DEBUG GfxSurface surface; - surface.decode(&mem[0x7000 * 16]); - - g_system->copyRectToScreen((const byte *)surface.pixels, surface.pitch, 0, 0, - surface.w, surface.h); - g_system->updateScreen(); - -#endif + surface.decode(&mem[seg * 16 + dep]); decomp(seg, dep); if (gd == her) { @@ -116,7 +110,7 @@ void pictout(int seg, int dep, int x, int y) { } if ((caff != 51) && (READ_LE_UINT16(&mem[0x7000 * 16 + 0x4138]) > 0x100)) WRITE_LE_UINT16(&mem[0x7000 * 16 + 0x4138], 0x100); - afff(gd, seg, dep, x, y); + g_vm->_screenSurface.drawPicture(surface, x, y); } void putxy(int x, int y) { diff --git a/engines/mortevielle/mortevielle.cpp b/engines/mortevielle/mortevielle.cpp index bba22f1ba5..cdeb412625 100644 --- a/engines/mortevielle/mortevielle.cpp +++ b/engines/mortevielle/mortevielle.cpp @@ -97,8 +97,7 @@ Common::ErrorCode MortevielleEngine::loadMortDat() { if (!strncmp(dataType, "FONT", 4)) { // Font resource - assert(dataSize == (FONT_NUM_CHARS * FONT_HEIGHT)); - f.read(_fontData, FONT_NUM_CHARS * FONT_HEIGHT); + _screenSurface.readFontData(f, dataSize); } else { // Unknown section f.skip(dataSize); @@ -111,60 +110,6 @@ Common::ErrorCode MortevielleEngine::loadMortDat() { /*-------------------------------------------------------------------------*/ -/** - * Update the physical screen - */ -void MortevielleEngine::updateScreen() { - g_system->copyRectToScreen((const byte *)_screenSurface.getBasePtr(0, 0), - SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); - g_system->updateScreen(); -} -/** - * Draws a character at the specified co-ordinates - * @remarks Because the ScummVM surface is using a double height 640x200 surface to - * simulate the original 640x200 surface, all Y values have to be doubled - */ -void MortevielleEngine::writeCharacter(const Common::Point &pt, unsigned char ch, - int palIndex, Graphics::Surface *surface) { - if (surface == NULL) - surface = &_screenSurface; - - // Get the start of the character to use - assert((ch >= ' ') && (ch <= (unsigned char)(32 + FONT_NUM_CHARS))); - const byte *charData = &_fontData[((int)ch - 32) * FONT_HEIGHT]; - - // Loop through decoding each character's data - for (int yp = 0; yp < FONT_HEIGHT; ++yp) { - byte *lineP = (byte *)surface->getBasePtr(pt.x, (pt.y + yp) * 2); - byte byteVal = *charData++; - - for (int xp = 0; xp < 8; ++xp, ++lineP, byteVal <<= 1) { - if (byteVal & 0x80) { - *lineP = palIndex; - *(lineP + SCREEN_WIDTH) = palIndex; - } - } - } -} - -/** - * Sets a single pixel at the specified co-ordinates - * @remarks Because the ScummVM surface is using a double height 640x200 surface to - * simulate the original 640x200 surface, all Y values have to be doubled - */ -void MortevielleEngine::setPixel(const Common::Point &pt, int palIndex, - Graphics::Surface *surface) { - if (surface == NULL) - surface = &_screenSurface; - - byte *destP = (byte *)surface->getBasePtr(pt.x, pt.y * 2); - *destP = palIndex; - *(destP + SCREEN_WIDTH) = palIndex; -} - - -/*-------------------------------------------------------------------------*/ - Common::Error MortevielleEngine::run() { // Initialise the game Common::ErrorCode err = initialise(); diff --git a/engines/mortevielle/mortevielle.h b/engines/mortevielle/mortevielle.h index 0e72090ec3..bcd6f666d0 100644 --- a/engines/mortevielle/mortevielle.h +++ b/engines/mortevielle/mortevielle.h @@ -29,6 +29,7 @@ #include "engines/engine.h" #include "common/error.h" #include "graphics/surface.h" +#include "mortevielle/graphics.h" namespace Mortevielle { @@ -42,10 +43,6 @@ enum { #define MORT_DAT_REQUIRED_VERSION 1 #define MORT_DAT "mort.dat" -#define FONT_WIDTH 8 -#define FONT_HEIGHT 6 -#define FONT_NUM_CHARS 121 - class MortevielleEngine : public Engine { private: const ADGameDescription *_gameDescription; @@ -54,19 +51,13 @@ private: Common::ErrorCode loadMortDat(); void loadFont(Common::File &f); public: - Graphics::Surface _screenSurface; - byte _fontData[FONT_NUM_CHARS * FONT_HEIGHT]; + ScreenSurface _screenSurface; public: MortevielleEngine(OSystem *system, const ADGameDescription *gameDesc); ~MortevielleEngine(); virtual bool hasFeature(EngineFeature f) const; virtual Common::Error run(); uint32 getGameFlags() const; - - void updateScreen(); - void writeCharacter(const Common::Point &pt, - unsigned char ch, int palIndex, Graphics::Surface *surface = NULL); - void setPixel(const Common::Point &pt, int palIndex, Graphics::Surface *surface = NULL); }; extern MortevielleEngine *g_vm; diff --git a/engines/mortevielle/sprint.cpp b/engines/mortevielle/sprint.cpp index 67bd3ab119..027d74791a 100644 --- a/engines/mortevielle/sprint.cpp +++ b/engines/mortevielle/sprint.cpp @@ -88,7 +88,7 @@ void writeg(Common::String l, int c) show_mouse(); // TODO: Move screen updates to main loop once constructed - g_vm->updateScreen(); + g_vm->_screenSurface.updateScreen(); } } // End of namespace Mortevielle diff --git a/engines/mortevielle/var_mor.cpp b/engines/mortevielle/var_mor.cpp index 5166f201c4..5cca06f011 100644 --- a/engines/mortevielle/var_mor.cpp +++ b/engines/mortevielle/var_mor.cpp @@ -312,9 +312,9 @@ void hirs() { */ void affput(const Common::Point &pt, int palIndex, int ch) { if (ch == 0) - g_vm->setPixel(pt, palIndex); + g_vm->_screenSurface.setPixel(pt, palIndex); else - g_vm->writeCharacter(pt, ch, palIndex); + g_vm->_screenSurface.writeCharacter(pt, ch, palIndex); } void affcar(int gd, int x, int y, int coul, int chr) { |