aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gilbert2012-01-16 09:19:50 +1100
committerStrangerke2012-04-06 08:19:43 +0200
commit2416583449699ea6940acdfaac77d15bc1b012d9 (patch)
tree0b4834bace311845a7117a7e500f500ce1da0de2
parent833e46d18a963054949944571e5b07d3e74f2953 (diff)
downloadscummvm-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.cpp144
-rw-r--r--engines/mortevielle/graphics.h25
-rw-r--r--engines/mortevielle/level15.cpp12
-rw-r--r--engines/mortevielle/mortevielle.cpp57
-rw-r--r--engines/mortevielle/mortevielle.h13
-rw-r--r--engines/mortevielle/sprint.cpp2
-rw-r--r--engines/mortevielle/var_mor.cpp4
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) {