diff options
author | Paul Gilbert | 2012-01-14 11:35:08 +1100 |
---|---|---|
committer | Strangerke | 2012-04-06 08:19:37 +0200 |
commit | abc2f60edfc0f3dca8d5a871a70728998045a5e5 (patch) | |
tree | e0efaccf7fa154512c7400e6b68aa870dbe20db9 /engines | |
parent | e183f9f055c121d745a130d84dea0fa84a58fc66 (diff) | |
download | scummvm-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.cpp | 417 | ||||
-rw-r--r-- | engines/mortevielle/graphics.h | 16 | ||||
-rw-r--r-- | engines/mortevielle/mortevielle.h | 3 |
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 |