aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorPaul Gilbert2012-01-14 11:35:08 +1100
committerStrangerke2012-04-06 08:19:37 +0200
commitabc2f60edfc0f3dca8d5a871a70728998045a5e5 (patch)
treee0efaccf7fa154512c7400e6b68aa870dbe20db9 /engines
parente183f9f055c121d745a130d84dea0fa84a58fc66 (diff)
downloadscummvm-rg350-abc2f60edfc0f3dca8d5a871a70728998045a5e5.tar.gz
scummvm-rg350-abc2f60edfc0f3dca8d5a871a70728998045a5e5.tar.bz2
scummvm-rg350-abc2f60edfc0f3dca8d5a871a70728998045a5e5.zip
MORTEVIELLE: Implemented more of the image decompression code
Diffstat (limited to 'engines')
-rw-r--r--engines/mortevielle/graphics.cpp417
-rw-r--r--engines/mortevielle/graphics.h16
-rw-r--r--engines/mortevielle/mortevielle.h3
3 files changed, 372 insertions, 64 deletions
diff --git a/engines/mortevielle/graphics.cpp b/engines/mortevielle/graphics.cpp
index 3df9001c3b..9b06972232 100644
--- a/engines/mortevielle/graphics.cpp
+++ b/engines/mortevielle/graphics.cpp
@@ -25,11 +25,13 @@
namespace Mortevielle {
#define INCR_TAIX { if (_xSize & 1) ++_xSize; }
+#define DEFAULT_WIDTH 320
+#define BUFFER_SIZE 8192
void GfxSurface::decode(const byte *pSrc) {
_width = _height = 0;
_var1 = *pSrc++;
- _entryCount = *pSrc++;
+ int entryCount = *pSrc++;
pSrc += 2;
if (!_var1)
@@ -37,11 +39,12 @@ void GfxSurface::decode(const byte *pSrc) {
// First run through the data to calculate starting offsets
const byte *p = pSrc;
- int xOffset = 0xffff, yOffset = 0xffff;
+ _xOffset = _yOffset = 0xffff;
- for (int idx = 0; idx < _entryCount; ++idx) {
+ assert(entryCount > 0);
+ for (int idx = 0; idx < entryCount; ++idx) {
_xp = READ_BE_UINT16(p + 4);
- if (_xp < xOffset)
+ if (_xp < _xOffset)
_xOffset = _xp;
_yp = READ_BE_UINT16(p + 6);
@@ -60,131 +63,146 @@ void GfxSurface::decode(const byte *pSrc) {
byte outputBuffer[65536];
byte *pDest = &outputBuffer[0];
const byte *pSrcStart = pSrc;
+ const byte *pLookup = NULL;
- byte table4140[256];
- byte table7110[256];
+ byte lookupTable[BUFFER_SIZE];
+ byte srcBuffer[BUFFER_SIZE];
// Main processing loop
do {
- _var4 = READ_BE_UINT16(pSrc);
- _var6 = READ_BE_UINT16(pSrc + 2);
+ int lookupBytes = READ_BE_UINT16(pSrc);
+ int srcSize = READ_BE_UINT16(pSrc + 2);
_xp = READ_BE_UINT16(pSrc + 4) - _xOffset;
_yp = READ_BE_UINT16(pSrc + 6) - _yOffset;
pSrc += 8;
- _varC = READ_BE_UINT16(pSrc);
+ int decomCode = READ_BE_UINT16(pSrc);
_xSize = READ_BE_UINT16(pSrc + 2) + 1;
_ySize = READ_BE_UINT16(pSrc + 4) + 1;
majTtxTty();
+
+ pSrc += 6;
+ pDest = &outputBuffer[0];
- _var15 = _var18 = 0;
+ _var18 = 0;
+ _nibbleFlag = false;
int decomIndex = 0;
- if (_varC >> 8) {
+ if (decomCode >> 8) {
// Build up reference table
int tableOffset = 0;
- if (_varC & 1) {
+ if (decomCode & 1) {
+ // Handle decompression of the pattern lookup table
do {
_var12 = desanalyse(pSrc);
_var14 = desanalyse(pSrc);
- int savedVar15 = _var15;
+ bool savedVar15 = _nibbleFlag;
int savedVar18 = _var18;
do {
const byte *pTemp = pSrc;
- _var15 = savedVar15;
+ _nibbleFlag = savedVar15;
_var18 = savedVar18;
assert(_var14 < 256);
for (int idx = 0; idx < _var14; ++idx, ++tableOffset)
- table4140[tableOffset] = suiv(pTemp);
+ assert(tableOffset < BUFFER_SIZE);
+ lookupTable[tableOffset] = suiv(pTemp);
} while (--_var12 > 0);
- } while (_var18 < (_var4 - 1));
+ } while (_var18 < (lookupBytes - 1));
} else {
- assert(_var4 < 256);
- for (int idx = 0; idx < _var4; ++idx)
- table4140[idx] = suiv(pSrc);
+ assert(lookupBytes < BUFFER_SIZE);
+ for (int idx = 0; idx < (lookupBytes * 2); ++idx)
+ lookupTable[idx] = suiv(pSrc);
}
- if (_var15) {
+ if (_nibbleFlag) {
++pSrc;
- _var15 = 0;
+ _nibbleFlag = false;
}
- if ((_var4 + _var6) & 1)
+ if ((lookupBytes + srcSize) & 1)
++pSrc;
tableOffset = 0;
_var18 = 0;
- if (_varC & 2) {
+ if (decomCode & 2) {
+ // Handle decompression of the temporary source buffer
do {
_var12 = desanalyse(pSrc);
- _var18 = _var14 = desanalyse(pSrc);
- if (_var15 & 1) {
+ _var14 = desanalyse(pSrc);
+ _var18 += _var14;
+
+ if (_nibbleFlag) {
++pSrc;
++_var18;
- _var15 = 0;
+ _nibbleFlag = false;
}
const byte *pStart = pSrc;
do {
pSrc = pStart;
for (int idx = 0; idx < _var14; ++idx) {
- table7110[tableOffset++] = *pSrc++;
+ assert(tableOffset < BUFFER_SIZE);
+ srcBuffer[tableOffset++] = *pSrc++;
}
} while (--_var12 > 0);
- } while (_var18 < (_var6 - 1));
+ } while (_var18 < (srcSize - 1));
} else {
- assert(_var6 < 256);
- for (int idx = 0; idx < _var4; ++idx)
- table7110[idx] = *pSrc++;
+ assert(srcSize < BUFFER_SIZE);
+ for (int idx = 0; idx < srcSize; ++idx)
+ srcBuffer[idx] = *pSrc++;
}
- if (_var15)
+ if (_nibbleFlag)
++pSrc;
+ // Switch over to using the decompressed source and lookup buffers
pSrcStart = pSrc;
- pDest = &outputBuffer[_yp * SCREEN_WIDTH + _xp];
- pSrc = &table7110[0];
- _var1A = _var18 = _var15 = 0;
- decomIndex = _varC;
+ pDest = &outputBuffer[_yp * DEFAULT_WIDTH + _xp];
+ pSrc = &srcBuffer[0];
+ pLookup = &lookupTable[0] - 1;
+
+ _lookupValue = _var18 = 0;
+ _nibbleFlag = false;
+ decomIndex = decomCode >> 8;
}
// Main decompression switch
switch (decomIndex) {
case 0:
// Draw rect at pos
- pDest = &outputBuffer[_yp * SCREEN_WIDTH + _xp];
+ pDest = &outputBuffer[_yp * DEFAULT_WIDTH + _xp];
pSrcStart = pSrc;
INCR_TAIX;
- for (int yCtr = 0; yCtr < _ySize; ++yCtr, pDest += SCREEN_WIDTH) {
+ for (int yCtr = 0; yCtr < _ySize; ++yCtr, pDest += DEFAULT_WIDTH) {
byte *pDestLine = pDest;
for (int xCtr = 0; xCtr < _xSize; ++xCtr) {
*pDestLine++ = suiv(pSrc);
}
}
- pSrc = pSrcStart + _var4 + ((_var4 & 1) ? 1 : 0);
+ pSrc = pSrcStart + lookupBytes + ((lookupBytes & 1) ? 1 : 0);
break;
case 1:
// Draw rect alternating left to right, right to left
INCR_TAIX;
for (int yCtr = 0; yCtr < _ySize; ++yCtr) {
- if (yCtr % 2) {
+ if ((yCtr % 2) == 0) {
for (int xCtr = 0; xCtr < _xSize; ++xCtr) {
- *pDest++ = suiv(pSrc);
+ *pDest++ = csuiv(pSrc, pLookup);
}
} else {
for (int xCtr = 0; xCtr < _xSize; ++xCtr) {
- *--pDest = suiv(pSrc);
+ *--pDest = csuiv(pSrc, pLookup);
}
}
- pDest += SCREEN_WIDTH;
+ pDest += DEFAULT_WIDTH;
}
break;
@@ -193,12 +211,12 @@ void GfxSurface::decode(const byte *pSrc) {
INCR_TAIX;
for (int xCtr = 0; xCtr < _xSize; ++xCtr) {
if (xCtr % 2) {
- for (int yCtr = 0; yCtr < _ySize; ++yCtr, pDest += SCREEN_WIDTH) {
- *pDest = suiv(pSrc);
+ for (int yCtr = 0; yCtr < _ySize; ++yCtr, pDest += DEFAULT_WIDTH) {
+ *pDest = csuiv(pSrc, pLookup);
}
} else {
- for (int yCtr = 0; yCtr < _ySize; ++yCtr, pDest -= SCREEN_WIDTH) {
- *pDest = suiv(pSrc);
+ for (int yCtr = 0; yCtr < _ySize; ++yCtr, pDest -= DEFAULT_WIDTH) {
+ *pDest = csuiv(pSrc, pLookup);
}
}
++pDest;
@@ -206,14 +224,141 @@ void GfxSurface::decode(const byte *pSrc) {
break;
case 3:
- // Draw horizontal line?
- _var1C = 2;
- horizontal(pSrc, pDest);
+ // Draw horizontal area?
+ _thickness = 2;
+ horizontal(pSrc, pDest, pLookup);
+ break;
+
+ case 4:
+ // Draw vertical area?
+ _thickness = 2;
+ vertical(pSrc, pDest, pLookup);
+ break;
+
+ case 5:
+ _thickness = 3;
+ horizontal(pSrc, pDest, pLookup);
+ break;
+
+ case 6:
+ _thickness = 4;
+ vertical(pSrc, pDest, pLookup);
+ break;
+
+ case 7:
+ // Draw box
+ INCR_TAIX;
+ for (int yCtr = 0; yCtr < _ySize; ++yCtr, pDest += DEFAULT_WIDTH) {
+ byte *pDestLine = pDest;
+ for (int xCtr = 0; xCtr < _xSize; ++xCtr, ++pDestLine)
+ *pDestLine++ = csuiv(pSrc, pLookup);
+ }
+ break;
+
+ case 8:
+ // Draw box
+ for (int xCtr = 0; xCtr < _xSize; ++xCtr, ++pDest) {
+ byte *pDestLine = pDest;
+ for (int yCtr = 0; yCtr < _ySize; ++yCtr, pDestLine += DEFAULT_WIDTH)
+ *pDestLine = csuiv(pSrc, pLookup);
+ }
+ break;
+
+ case 9:
+ _thickness = 4;
+ horizontal(pSrc, pDest, pLookup);
+ break;
+
+ case 10:
+ _thickness = 6;
+ horizontal(pSrc, pDest, pLookup);
+ break;
+
+ case 11:
+ warning("TODO: Switch 11");
+ break;
+
+ case 12:
+ INCR_TAIX;
+ _thickness = _var22 = 1;
+ _var1E = 320;
+ _var20 = _ySize;
+ _var24 = _xSize;
+ diag();
+ break;
+
+ case 13:
+ INCR_TAIX;
+ _thickness = _xSize;
+ _var1E = 1;
+ _var20 = _xSize;
+ _var22 = 320;
+ _var24 = _ySize;
+ diag();
+ break;
+
+ case 14:
+ _thickness = _var1E = 1;
+ _var20 = _xSize;
+ _var22 = 320;
+ _var24 = _ySize;
+ diag();
+ break;
+
+ case 15:
+ INCR_TAIX;
+ _thickness = 2;
+ _var1E = 320;
+ _var20 = _ySize;
+ _var22 = 1;
+ _var24 = _xSize;
+ diag();
+ break;
+
+ case 16:
+ _thickness = 3;
+ _var1E = 1;
+ _var20 = _xSize;
+ _var22 = 320;
+ _var24 = _ySize;
+ diag();
+ break;
+
+ case 17:
+ INCR_TAIX;
+ _thickness = 3;
+ _var1E = 320;
+ _var20 = _ySize;
+ _var22 = 1;
+ _var24 = _xSize;
+ diag();
+ break;
+
+ case 18:
+ INCR_TAIX;
+ _thickness = 5;
+ _var1E = 320;
+ _var20 = _ySize;
+ _var22 = 1;
+ _var24 = _xSize;
+ diag();
break;
}
pSrc = pSrcStart;
- } while (--_entryCount > 0);
+ } while (--entryCount > 0);
+
+ // At this point, the outputBuffer has the data for the image. The pitch is
+ // 320 pixels, the _xOffset and _yOffset represent the top left of the image data,
+ // and the _xSize and _ySize fields indicate the image size
+ create(_xOffset + _xSize, _yOffset + _ySize, Graphics::PixelFormat::createFormatCLUT8());
+
+ for (int yCtr = 0; yCtr < _ySize; ++yCtr) {
+ const byte *copySrc = &outputBuffer[yCtr * DEFAULT_WIDTH];
+ byte *copyDest = (byte *)getBasePtr(_xOffset, yCtr + _yOffset);
+
+ Common::copy(copySrc, copySrc + _xSize, copyDest);
+ }
}
void GfxSurface::majTtxTty() {
@@ -226,24 +371,41 @@ void GfxSurface::majTtxTty() {
byte GfxSurface::suiv(const byte *&pSrc) {
int v = *pSrc;
- if (_var15) {
+ if (_nibbleFlag) {
++pSrc;
++_var18;
- _var15 = 0;
+ _nibbleFlag = false;
return v & 0xf;
} else {
- _var15 = ~(v >> 8);
+ _nibbleFlag = !_nibbleFlag;
return v >> 4;
}
}
+byte GfxSurface::csuiv(const byte *&pSrc, const byte *&pLookup) {
+ assert(pLookup);
+
+ while (!_lookupValue) {
+ int v;
+ do {
+ v = suiv(pSrc) & 0xff;
+ _lookupValue += v;
+ } while (v == 0xf);
+ ++pLookup;
+ }
+
+ --_lookupValue;
+ return *pLookup;
+}
+
int GfxSurface::desanalyse(const byte *&pSrc) {
int total = 0;
int v = suiv(pSrc);
- if (!v) {
+ if (v == 15) {
int v2;
do {
v2 = suiv(pSrc);
+ total += v2;
} while (v2 == 15);
total *= 15;
@@ -254,8 +416,151 @@ int GfxSurface::desanalyse(const byte *&pSrc) {
return total;
}
-void GfxSurface::horizontal(const byte *&pSrc, byte *&pDest) {
+void GfxSurface::horizontal(const byte *&pSrc, byte *&pDest, const byte *&pLookup) {
+ INCR_TAIX;
+ byte *pDestEnd = pDest + (_ySize - 1) * DEFAULT_WIDTH + _xSize;
+
+ for (;;) {
+ // If position is past end point, then skip this line
+ if (((_thickness - 1) * DEFAULT_WIDTH) + pDest >= pDestEnd) {
+ if (--_thickness == 0) break;
+ continue;
+ }
+
+ bool continueFlag = false;
+ do {
+ for (int xIndex = 0; xIndex < _xSize; ++xIndex, ++pDest) {
+ if ((xIndex % 2) == 0) {
+ // Write out vertical slice top to bottom
+ for (int yIndex = 0; yIndex < _thickness; ++yIndex, pDest += DEFAULT_WIDTH)
+ *pDest = csuiv(pSrc, pLookup);
+ } else {
+ // Write out vertical slice bottom to top
+ for (int yIndex = 0; yIndex < _thickness; ++yIndex, pDest -= DEFAULT_WIDTH)
+ *pDest = csuiv(pSrc, pLookup);
+ }
+ }
+
+ if ((_xSize % 2) == 0) {
+ int blockSize = _thickness * DEFAULT_WIDTH;
+ pDest += blockSize;
+ blockSize -= DEFAULT_WIDTH;
+
+ if (pDestEnd < (pDest + blockSize)) {
+ do {
+ if (--_thickness == 0)
+ return;
+ } while ((pDest + (_thickness - 1) * DEFAULT_WIDTH) >= pDestEnd);
+ }
+ } else {
+ while ((pDest + (_thickness - 1) * DEFAULT_WIDTH) >= pDestEnd) {
+ if (--_thickness == 0)
+ return;
+ }
+ }
+
+ for (int xIndex = 0; xIndex < _xSize; ++xIndex, --pDest) {
+ if ((xIndex % 2) == 0) {
+ // Write out vertical slice top to bottom
+ for (int yIndex = 0; yIndex < _thickness; ++yIndex, pDest += DEFAULT_WIDTH)
+ *pDest = csuiv(pSrc, pLookup);
+ } else {
+ // Write out vertical slice top to bottom
+ for (int yIndex = 0; yIndex < _thickness; ++yIndex, pDest -= DEFAULT_WIDTH)
+ *pDest = csuiv(pSrc, pLookup);
+ }
+ }
+
+ if ((_xSize % 2) == 1) {
+ ++pDest;
+
+ if ((pDest + (_thickness - 1) * DEFAULT_WIDTH) < pDestEnd) {
+ continueFlag = true;
+ break;
+ }
+ } else {
+ pDest += _thickness * DEFAULT_WIDTH + 1;
+ continueFlag = true;
+ break;
+ }
+
+ ++pDest;
+ } while (((_thickness - 1) * DEFAULT_WIDTH + pDest) < pDestEnd);
+
+ if (continueFlag)
+ continue;
+
+ // Move to next line
+ if (--_thickness == 0)
+ break;
+ }
+}
+
+void GfxSurface::vertical(const byte *&pSrc, byte *&pDest, const byte *&pLookup) {
+// byte *pDestEnd = pDest + (_ySize - 1) * DEFAULT_WIDTH + _xSize;
+ int var28 = 0;
+
+ for (;;) {
+ // Reduce thickness as necessary
+ while ((var28 + _thickness) >= _xSize) {
+ if (--_thickness == 0)
+ return;
+ }
+
+ // Loop
+ for (int idx = 0; idx < _thickness; ++idx) {
+ if ((idx % 2) == 0) {
+ if (idx > 0)
+ pDest -= DEFAULT_WIDTH;
+
+ // Write out horizontal slice left to right
+ var28 += _thickness;
+ for (int xIndex = 0; xIndex < _thickness; ++xIndex)
+ *pDest++ = suiv(pSrc);
+ } else {
+ // Write out horizontal slice right to left
+ pDest += DEFAULT_WIDTH;
+ var28 -= _thickness;
+ for (int xIndex = 0; xIndex < _thickness; ++xIndex)
+ *pDest-- = csuiv(pSrc, pLookup);
+ }
+ }
+ if ((_thickness % 2) == 0) {
+ pDest += _thickness;
+ var28 += _thickness;
+ }
+
+ // Reduce thickness as necessary
+ while ((var28 + _thickness) < _xSize) {
+ if (--_thickness == 0)
+ return;
+ }
+
+ for (int yIndex = 0; yIndex < _ySize; ++yIndex) {
+ if ((yIndex % 2) == 0) {
+ if (yIndex > 0)
+ pDest -= DEFAULT_WIDTH;
+
+ // Draw horizontal slice
+ var28 += _thickness;
+
+ for (int xIndex = 0; xIndex < _thickness; ++xIndex)
+ *pDest++ = suiv(pSrc);
+ } else {
+ pDest -= DEFAULT_WIDTH;
+ var28 -= _thickness;
+
+ for (int xIndex = 0; xIndex < _thickness; ++xIndex)
+ *pDest-- = csuiv(pSrc, pLookup);
+ }
+ }
+ }
+}
+void GfxSurface::diag() {
+ // The diag method in the original source doesn't seem to have any exit point,
+ // which if the case, means the routine may not be used by the game
+ error("Non-exitable method diag() called");
}
} // End of namespace Mortevielle
diff --git a/engines/mortevielle/graphics.h b/engines/mortevielle/graphics.h
index d3f64a01fe..4e7db305ca 100644
--- a/engines/mortevielle/graphics.h
+++ b/engines/mortevielle/graphics.h
@@ -31,20 +31,22 @@ namespace Mortevielle {
class GfxSurface: public Graphics::Surface {
private:
int _var1;
- int _entryCount;
- int _var4, _var6;
int _xp, _yp;
- int _varC, _xSize, _ySize, _var12;
- int _var14, _var15, _var18, _var1A;
- int _var1C, _var1E, _var20, _var22;
- int _var24, _var26, _var28;
+ int _xSize, _ySize, _var12;
+ int _var14, _var18, _lookupValue;
+ bool _nibbleFlag;
+ int _thickness, _var1E, _var20, _var22;
+ int _var24, _var26;
int _width, _height;
int _xOffset, _yOffset;
void majTtxTty();
byte suiv(const byte *&pSrc);
+ byte csuiv(const byte *&pSrc, const byte *&pLookup);
int desanalyse(const byte *&pSrc);
- void horizontal(const byte *&pSrc, byte *&pDest);
+ void horizontal(const byte *&pSrc, byte *&pDest, const byte *&pLookup);
+ void vertical(const byte *&pSrc, byte *&pDest, const byte *&pLookup);
+ void diag();
public:
void decode(const byte *pSrc);
};
diff --git a/engines/mortevielle/mortevielle.h b/engines/mortevielle/mortevielle.h
index b9d8265385..0e72090ec3 100644
--- a/engines/mortevielle/mortevielle.h
+++ b/engines/mortevielle/mortevielle.h
@@ -33,7 +33,8 @@
namespace Mortevielle {
enum {
- kMortevielleCore = 1 << 0
+ kMortevielleCore = 1 << 0,
+ kMortevielleGraphics = 1 << 1
};
#define SCREEN_WIDTH 640