diff options
author | Gregory Montoir | 2005-08-19 22:12:09 +0000 |
---|---|---|
committer | Gregory Montoir | 2005-08-19 22:12:09 +0000 |
commit | 24265fd3dd1681835f63e3c901158adef1ec5bc5 (patch) | |
tree | 36a28654b271ca5d8f12006f95f4990deaf371f8 /kyra/wsamovie.cpp | |
parent | ed2a18569a68d5be78d5a893d66979eef9fe06cd (diff) | |
download | scummvm-rg350-24265fd3dd1681835f63e3c901158adef1ec5bc5.tar.gz scummvm-rg350-24265fd3dd1681835f63e3c901158adef1ec5bc5.tar.bz2 scummvm-rg350-24265fd3dd1681835f63e3c901158adef1ec5bc5.zip |
some WIP code to start introduction (with glitches) in Kyrandia 1 :
- the decoders have been rewritten due to crashes I encountered with the previous ones in Compression::
- the wsa code loader for v1 have been rewritten too, to handle the same flags as the original
- some cleanup
- this has only been tested with the floppy version
svn-id: r18704
Diffstat (limited to 'kyra/wsamovie.cpp')
-rw-r--r-- | kyra/wsamovie.cpp | 533 |
1 files changed, 149 insertions, 384 deletions
diff --git a/kyra/wsamovie.cpp b/kyra/wsamovie.cpp index 7c8a57abb1..e2ab2242e3 100644 --- a/kyra/wsamovie.cpp +++ b/kyra/wsamovie.cpp @@ -20,421 +20,186 @@ */ #include "common/stdafx.h" +#include "kyra/kyra.h" +#include "kyra/screen.h" #include "kyra/wsamovie.h" -#include "kyra/codecs.h" -#include "common/stream.h" - -#ifdef DUMP_FILES -#include <stdio.h> -#endif namespace Kyra { -WSAMovieV1::WSAMovieV1(uint8* data, uint32 size, uint8 gameid) { - if (!data) { - error("resource created without data"); - } - - _background = 0; - _currentFrame = 0; - _ownPalette = 0; - _offsetTable = 0; - _prefetchedFrame = 0xFFFE; - _buffer = data; - - // I like these Streams .... =) - Common::MemoryReadStream datastream(data, size); - - _wsaHeader._numFrames = datastream.readUint16LE(); - _wsaHeader._width = datastream.readUint16LE(); - _wsaHeader._height = datastream.readUint16LE(); - _wsaHeader._xPos = datastream.readByte(); - _wsaHeader._yPos = datastream.readByte(); - _wsaHeader._delta = datastream.readUint16LE(); - _wsaHeader._type = datastream.readUint16LE(); - -#ifdef DUMP_FILES - // TODO: make Linux/BSD conform - FILE* wsaheader = fopen("dumps/wsaheader.txt", "w+"); - - if (wsaheader) { - for (uint32 pos = 0; pos < sizeof(_wsaHeader); ++pos) - fprintf(wsaheader, "%d pos. byte: %d\n", pos + 1, ((uint8*)&_wsaHeader)[pos]); - fprintf(wsaheader, "\n"); - for (uint32 pos = 0; pos < sizeof(_wsaHeader) / 2; ++pos) - fprintf(wsaheader, "%d pos. word: %d\n", pos + 1, ((uint16*)&_wsaHeader)[pos]); - fprintf(wsaheader, "\n"); - for (uint32 pos = 0; pos < sizeof(_wsaHeader) / 4; ++pos) - fprintf(wsaheader, "%d pos. dword: %d\n", pos + 1, ((uint32*)&_wsaHeader)[pos]); - } - fclose(wsaheader); -#endif - - if (gameid == KYRA1CD) { - uint16 tmp = _wsaHeader._delta; - _wsaHeader._delta = _wsaHeader._type; - _wsaHeader._type = tmp; - - // skip 2 bytes - datastream.readUint16LE(); - } - - debug("_wsaHeader._numFrames = %d", _wsaHeader._numFrames); - debug("_wsaHeader._width = %d", _wsaHeader._width); - debug("_wsaHeader._height = %d", _wsaHeader._height); - debug("_wsaHeader._xPos = %d", _wsaHeader._xPos); - debug("_wsaHeader._yPos = %d", _wsaHeader._yPos); - debug("_wsaHeader._delta = %d", _wsaHeader._delta); - debug("_wsaHeader._type = %d", _wsaHeader._type); - - // check for version - if (_wsaHeader._type) { - error("loading a WSA version 2 with the WSA version 1 loader"); - } - - uint16 offsetAdd = 0; - // checks now for own palette - if (_wsaHeader._type % 2) { - // don't now if this will work right, because a few lines before we use - // _wsaHeader._type for detect the version of the WSA movie, - // but this code was from FreeKyra Tools so I think it will work - - // if this is a packed palette we have a problem :) - offsetAdd = 768 /* 0x300 */; - } - - // last frame seems every time to be a empty one - _frameCount = _wsaHeader._numFrames - 1; - _offsetTable = new uint32[_wsaHeader._numFrames + 2]; - assert(_offsetTable); - - // loads the offset table - for (uint32 tmp = 0; tmp < (uint32)_wsaHeader._numFrames + 2; ++tmp) { - _offsetTable[tmp] = datastream.readUint32LE() + offsetAdd; +WSAMovieV1 *KyraEngine::wsa_open(const char *filename, int offscreenDecode, uint8 *palBuf) { + debug(9, "KyraEngine::wsa_open('%s', %d, 0x%X)", filename, offscreenDecode, palBuf); + uint32 flags = 0; + uint32 fileSize; + uint8 *p = _res->fileData(filename, &fileSize); + + WSAMovieV1 *wsa = new WSAMovieV1; + const uint8 *wsaData = p; + wsa->numFrames = READ_LE_UINT16(wsaData); wsaData += 2; + wsa->width = READ_LE_UINT16(wsaData); wsaData += 2; + wsa->height = READ_LE_UINT16(wsaData); wsaData += 2; + wsa->deltaBufferSize = READ_LE_UINT16(wsaData); wsaData += 2; + wsa->flags = 0; + if (_game == KYRA1CD) { + flags = READ_LE_UINT16(wsaData); wsaData += 2; + } + + uint32 offsPal = 0; + if (flags & 1) { + offsPal = 0x300; + wsa->flags |= WF_HAS_PALETTE; + if (palBuf) { + memcpy(palBuf, wsaData + (wsa->numFrames + 2) * 4, 0x300); + } } + + if (offscreenDecode) { + wsa->flags |= WF_OFFSCREEN_DECODE; + const int offscreenBufferSize = wsa->width * wsa->height; + wsa->offscreenBuffer = (uint8 *)malloc(offscreenBufferSize); + memset(wsa->offscreenBuffer, 0, offscreenBufferSize); + } + + if (wsa->numFrames & 0x8000) { + warning("Unhandled wsa flags 0x80"); + wsa->flags |= 0x80; + wsa->numFrames &= 0x7FFF; + } + wsa->currentFrame = wsa->numFrames; + + wsa->deltaBuffer = (uint8 *)malloc(wsa->deltaBufferSize); + memset(wsa->deltaBuffer, 0, wsa->deltaBufferSize); + + // read frame offsets + wsa->frameOffsTable = (uint32 *)malloc((wsa->numFrames + 2) * 4); + wsa->frameOffsTable[0] = 0; + uint32 frameDataOffs = READ_LE_UINT32(wsaData); wsaData += 4; + bool firstFrame = true; + if (frameDataOffs == 0) { + firstFrame = false; + frameDataOffs = READ_LE_UINT32(wsaData); + wsa->flags |= WF_NO_FIRST_FRAME; + } + for (int i = 1; i < wsa->numFrames + 2; ++i) { + wsa->frameOffsTable[i] = READ_LE_UINT32(wsaData) - frameDataOffs; + wsaData += 4; + } + + // skip palette + wsaData += offsPal; + + // read frame data + const int frameDataSize = p + fileSize - wsaData; + wsa->frameData = (uint8 *)malloc(frameDataSize); + memcpy(wsa->frameData, wsaData, frameDataSize); + + // decode first frame + if (firstFrame) { + Screen::decodeFrame4(wsa->frameData, wsa->deltaBuffer, wsa->deltaBufferSize); + } + + delete[] p; + return wsa; +} - if (offsetAdd) { - uint8* palbuffer = new uint8[offsetAdd]; - assert(palbuffer); - - datastream.read(palbuffer, offsetAdd); - - _ownPalette = new Palette(palbuffer, offsetAdd); - assert(_ownPalette); +void KyraEngine::wsa_close(WSAMovieV1 *wsa) { + debug(9, "KyraEngine::wsa_close(0x%X)", wsa); + if (wsa) { + free(wsa->deltaBuffer); + free(wsa->offscreenBuffer); + free(wsa->frameOffsTable); + delete wsa; } - - // FIXME: Confirm the default value here? - // LordHoto: What is the 'default' value? 0? - _transparency = -1; } -WSAMovieV1::~WSAMovieV1() { - delete [] _buffer; - delete [] _offsetTable; - delete [] _currentFrame; - delete _ownPalette; +uint16 KyraEngine::wsa_getNumFrames(WSAMovieV1 *wsa) const { + debug(9, "KyraEngine::wsa_getNumFrames(0x%X)", wsa); + uint16 n = 0; + if (wsa) { + n = wsa->numFrames; + } + return n; } -const uint8* WSAMovieV1::loadFrame(uint16 frame, uint16* width, uint16* height) { - if (width) *width = _wsaHeader._width; - if (height) *height = _wsaHeader._height; +void KyraEngine::wsa_play(WSAMovieV1 *wsa, int frameNum, int x, int y, int pageNum) { + debug(9, "KyraEngine::wsa_play(0x%X, %d, %d, %d, %d)", wsa, frameNum, x, y, pageNum); + assert(frameNum <= wsa->numFrames); - if (frame == _prefetchedFrame) { - return _currentFrame; + uint8 *dst; + if (wsa->flags & WF_OFFSCREEN_DECODE) { + dst = wsa->offscreenBuffer; } else { - if (!_currentFrame) { - _currentFrame = new uint8[_wsaHeader._width * _wsaHeader._height]; - assert(_currentFrame); - memset(_currentFrame, 0, sizeof(uint8) * _wsaHeader._width * _wsaHeader._height); - } - - if (frame >= _wsaHeader._numFrames) - return 0; - - uint8* frameData = 0; - static uint8 image40[64000]; // I think this will crash on Plam OS :) - memset(image40, 0, ARRAYSIZE(image40)); - - if (frame == _prefetchedFrame + 1) { - frameData = _buffer + _offsetTable[frame]; - Compression::decode80(frameData, image40); - Compression::decode40(image40, _currentFrame); - } else { - if (_background) { - setImageBackground(_background, _backWidth, _backHeight); + dst = _screen->getPagePtr(pageNum) + y * Screen::SCREEN_W + x; + } + + if (wsa->currentFrame == wsa->numFrames) { + if (!(wsa->flags & WF_NO_FIRST_FRAME)) { + if (wsa->flags & WF_OFFSCREEN_DECODE) { + Screen::decodeFrameDelta(dst, wsa->deltaBuffer); } else { - memset(_currentFrame, 0, sizeof(uint8) * _wsaHeader._width * _wsaHeader._height); - } - - for (uint32 i = 0; i <= frame; ++i) - { - frameData = _buffer + _offsetTable[i]; - Compression::decode80(frameData, image40); - Compression::decode40(image40, _currentFrame); + Screen::decodeFrameDeltaPage(dst, wsa->deltaBuffer, wsa->width); } } - - _prefetchedFrame = frame; - return _currentFrame; + wsa->currentFrame = 0; } - return 0; -} - -void WSAMovieV1::renderFrame(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 frame) { - if (!loadFrame(frame, 0, 0)) - return; - - uint8* src = _currentFrame; - uint8* dst = &plane[_wsaHeader._yPos * planepitch + _wsaHeader._xPos]; - uint32 copysize = planepitch - _wsaHeader._xPos; - - if (copysize > _wsaHeader._width) - copysize = _wsaHeader._width; - - if (_transparency == -1) { - for (uint16 y_ = 0; y_ < _wsaHeader._height && _wsaHeader._yPos + y_ < planeheight; ++y_) { - memcpy(dst, src, copysize * sizeof(uint8)); - dst += planepitch; - src += _wsaHeader._width; + // try to reduce the number of needed frame operations + int diffCount = ABS(wsa->currentFrame - frameNum); + int frameStep = 1; + int frameCount; + if (wsa->currentFrame < frameNum) { + frameCount = wsa->numFrames - frameNum + wsa->currentFrame; + if (diffCount > frameCount) { + frameStep = -1; + } else { + frameCount = diffCount; } } else { - for (uint16 yadd = 0; yadd < _wsaHeader._height; ++yadd) { - for (uint16 xadd = 0; xadd < copysize; ++xadd) { - if (*src == _transparency) { - ++dst; - ++src; - } else { - *dst++ = *src++; - } - } - - src += _wsaHeader._width - copysize; - dst += planepitch - copysize; + frameCount = wsa->numFrames - wsa->currentFrame + frameNum; + if (frameCount >= diffCount) { + frameStep = -1; + frameCount = diffCount; } } -} - -void WSAMovieV1::setImageBackground(uint8* plane, uint16 planepitch, uint16 height) { - assert(plane); - - _background = plane; - _backWidth = planepitch; _backHeight = height; - - if (!_currentFrame) { - _currentFrame = new uint8[_wsaHeader._width * _wsaHeader._height]; - assert(_currentFrame); - } - - memset(_currentFrame, 0, sizeof(uint8) * _wsaHeader._width * _wsaHeader._height); - - uint8* src = &plane[_wsaHeader._yPos * planepitch + _wsaHeader._xPos]; - uint8* dst = _currentFrame; - uint32 copysize = planepitch - _wsaHeader._xPos; - - if (copysize > _wsaHeader._width) - copysize = _wsaHeader._width; - - // now copy the rect of the plane - for (uint16 y_ = 0; y_ < _wsaHeader._height && _wsaHeader._yPos + y_ < height; ++y_) { - memcpy(dst, src, copysize * sizeof(uint8)); - dst += _wsaHeader._width; - src += planepitch; - } - - for (uint16 y_ = 0; y_ < _wsaHeader._height && _wsaHeader._yPos + y_ < height; ++y_) { - for (uint16 x = 0; x < _wsaHeader._width; ++x) { - _currentFrame[y_ * _wsaHeader._width + x] ^= 0; - } - } - - _prefetchedFrame = 0xFFFE; -} - -// Kyrandia 2+ Movies -WSAMovieV2::WSAMovieV2(uint8* data, uint32 size) { - if (!data) { - error("resource created without data"); - } - - _background = 0; - _currentFrame = 0; - _ownPalette = 0; - _offsetTable = 0; - _prefetchedFrame = 0xFFFE; - _looping = false; - _buffer = data; - - // I like these Streams .... =) - Common::MemoryReadStream datastream(data, size); - - datastream.read(&_wsaHeader, sizeof(_wsaHeader)); - - // check for version - if (!_wsaHeader._type) { - error("loading a WSA version 1 with the WSA version 2 loader"); - } - - uint16 offsetAdd = 0; - - // checks now for own palette - if (_wsaHeader._type % 2) { - // don't now if this will work right, because a few lines before we use - // _wsaHeader._type for detect the version of the WSA movie, - // but this code was from FreeKyra Tools so I think it will work - - // if this is a packed palette we have a problem :) - offsetAdd = 768 /* 0x300 */; - } - - _offsetTable = new uint32[_wsaHeader._numFrames + 2]; - assert(_offsetTable); - - // loads the offset table - for (uint32 tmp = 0; tmp < (uint32)_wsaHeader._numFrames + 2; ++tmp) { - _offsetTable[tmp] = datastream.readUint32LE() + offsetAdd; - } - - if (offsetAdd) { - uint8* palbuffer = new uint8[offsetAdd]; - assert(palbuffer); - - datastream.read(palbuffer, offsetAdd); - - _ownPalette = new Palette(palbuffer, offsetAdd); - assert(_ownPalette); - } - - if (_offsetTable[_wsaHeader._numFrames + 1] - offsetAdd) { - ++_wsaHeader._numFrames; - _looping = true; - } - - _frameCount = _wsaHeader._numFrames; -} - -WSAMovieV2::~WSAMovieV2() { - delete [] _buffer; - delete [] _offsetTable; - delete [] _currentFrame; - delete _ownPalette; -} - -const uint8* WSAMovieV2::loadFrame(uint16 frame, uint16* width, uint16* height) { - if (width) *width = _wsaHeader._width; - if (height) *height = _wsaHeader._height; - - if (frame == _prefetchedFrame) { - return _currentFrame; - } else { - if (!_currentFrame) { - _currentFrame = new uint8[_wsaHeader._width * _wsaHeader._height]; - assert(_currentFrame); - memset(_currentFrame, 0, sizeof(uint8) * _wsaHeader._width * _wsaHeader._height); - } - - if (frame >= _wsaHeader._numFrames) - return 0; - - uint8* frameData = 0; - static uint8 image40[64000]; // I think this will crash on Plam OS :) - memset(image40, 0, ARRAYSIZE(image40)); - - if (frame == _prefetchedFrame + 1) { - frameData = _buffer + _offsetTable[frame]; - Compression::decode80(frameData, image40); - Compression::decode40(image40, _currentFrame); - } else { - if (_background) { - setImageBackground(_background, _backWidth, _backHeight); - } else { - memset(_currentFrame, 0, sizeof(uint8) * _wsaHeader._width * _wsaHeader._height); - } - - for (uint32 i = 0; i <= frame; ++i) - { - frameData = _buffer + _offsetTable[i]; - Compression::decode80(frameData, image40); - Compression::decode40(image40, _currentFrame); + + // process + if (frameStep > 0) { + uint16 cf = wsa->currentFrame; + while (frameCount--) { + cf += frameStep; + wsa_processFrame(wsa, cf, dst); + if (cf == wsa->numFrames) { + cf = 0; } } - - _prefetchedFrame = frame; - return _currentFrame; - } - - return 0; -} - -void WSAMovieV2::renderFrame(uint8* plane, uint16 planepitch, uint16 planeheight, uint16 frame) { - if (!loadFrame(frame, 0, 0)) - return; - - uint8* src = _currentFrame; - uint8* dst = &plane[_wsaHeader._yPos * planepitch + _wsaHeader._xPos]; - uint32 copysize = planepitch - _wsaHeader._xPos; - - if (copysize > _wsaHeader._width) - copysize = _wsaHeader._width; - - if (_transparency == -1) { - for (uint16 y_ = 0; y_ < _wsaHeader._height && _wsaHeader._yPos + y_ < planeheight; ++y_) { - memcpy(dst, src, copysize * sizeof(uint8)); - dst += planepitch; - src += _wsaHeader._width; - } } else { - for (uint16 yadd = 0; yadd < _wsaHeader._height; ++yadd) { - for (uint16 xadd = 0; xadd < copysize; ++xadd) { - if (*src == _transparency) { - ++dst; - ++src; - } else { - *dst++ = *src++; - } + uint16 cf = wsa->currentFrame; + while (frameCount--) { + if (cf == 0) { + cf = wsa->numFrames; } - - src += _wsaHeader._width - copysize; - dst += planepitch - copysize; + wsa_processFrame(wsa, cf, dst); + cf += frameStep; } } -} - -void WSAMovieV2::setImageBackground(uint8* plane, uint16 planepitch, uint16 height) { - assert(plane); - - _background = plane; - _backWidth = planepitch; _backHeight = height; - - if (!_currentFrame) { - _currentFrame = new uint8[_wsaHeader._width * _wsaHeader._height]; - assert(_currentFrame); - } - - memset(_currentFrame, 0, sizeof(uint8) * _wsaHeader._width * _wsaHeader._height); - - uint8* src = &plane[_wsaHeader._yPos * planepitch + _wsaHeader._xPos]; - uint8* dst = _currentFrame; - uint32 copysize = planepitch - _wsaHeader._xPos; - - if (copysize > _wsaHeader._width) - copysize = _wsaHeader._width; - - // now copy the rect of the plane - for (uint16 y_ = 0; y_ < _wsaHeader._height && _wsaHeader._yPos + y_ < height; ++y_) { - memcpy(dst, src, copysize * sizeof(uint8)); - dst += _wsaHeader._width; - src += planepitch; + + // display + wsa->currentFrame = frameNum; + if (wsa->flags & WF_OFFSCREEN_DECODE) { + _screen->copyBlockToPage(pageNum, x, y, wsa->width, wsa->height, wsa->offscreenBuffer); } +} - for (uint16 y_ = 0; y_ < _wsaHeader._height && _wsaHeader._yPos + y_ < height; ++y_) { - for (uint16 x = 0; x < _wsaHeader._width; ++x) { - _currentFrame[y_ * _wsaHeader._width + x] ^= 0; - } +void KyraEngine::wsa_processFrame(WSAMovieV1 *wsa, int frameNum, uint8 *dst) { + debug(9, "KyraEngine::wsa_processFrame(0x%X, %d, 0x%X)", wsa, frameNum, dst); + assert(frameNum <= wsa->numFrames); + const uint8 *src = wsa->frameData + wsa->frameOffsTable[frameNum]; + Screen::decodeFrame4(src, wsa->deltaBuffer, wsa->deltaBufferSize); + if (wsa->flags & WF_OFFSCREEN_DECODE) { + Screen::decodeFrameDelta(dst, wsa->deltaBuffer); + } else { + Screen::decodeFrameDeltaPage(dst, wsa->deltaBuffer, wsa->width); } - - _prefetchedFrame = 0xFFFE; } + } // end of namespace Kyra - |