mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-27 05:32:45 +00:00
1dfdcc7252
Reorganize all files in sub directories. The file placement isn't as intuitive as it might be for other engines, which is probably the reason why this hasn't been done before.
464 lines
12 KiB
C++
464 lines
12 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "kyra/graphics/wsamovie.h"
|
|
#include "kyra/resource/resource.h"
|
|
|
|
#include "common/endian.h"
|
|
|
|
namespace Kyra {
|
|
|
|
WSAMovie_v1::WSAMovie_v1(KyraEngine_v1 *vm)
|
|
: Movie(vm), _frameData(0), _frameOffsTable(0), _offscreenBuffer(0), _deltaBuffer(0) {
|
|
}
|
|
|
|
WSAMovie_v1::~WSAMovie_v1() {
|
|
close();
|
|
}
|
|
|
|
int WSAMovie_v1::open(const char *filename, int offscreenDecode, Palette *palBuf) {
|
|
close();
|
|
|
|
uint32 flags = 0;
|
|
uint32 fileSize;
|
|
uint8 *p = _vm->resource()->fileData(filename, &fileSize);
|
|
if (!p)
|
|
return 0;
|
|
|
|
const uint8 *wsaData = p;
|
|
_numFrames = READ_LE_UINT16(wsaData); wsaData += 2;
|
|
_width = READ_LE_UINT16(wsaData); wsaData += 2;
|
|
_height = READ_LE_UINT16(wsaData); wsaData += 2;
|
|
_deltaBufferSize = READ_LE_UINT16(wsaData); wsaData += 2;
|
|
_offscreenBuffer = NULL;
|
|
_flags = 0;
|
|
if (_vm->gameFlags().useAltShapeHeader) {
|
|
flags = READ_LE_UINT16(wsaData);
|
|
wsaData += 2;
|
|
}
|
|
|
|
uint32 offsPal = 0;
|
|
if (flags & 1) {
|
|
offsPal = 0x300;
|
|
_flags |= WF_HAS_PALETTE;
|
|
if (palBuf)
|
|
_screen->loadPalette(wsaData + 8 + ((_numFrames << 2) & 0xFFFF), *palBuf, 0x300);
|
|
}
|
|
|
|
if (offscreenDecode) {
|
|
_flags |= WF_OFFSCREEN_DECODE;
|
|
const int offscreenBufferSize = _width * _height;
|
|
_offscreenBuffer = new uint8[offscreenBufferSize];
|
|
memset(_offscreenBuffer, 0, offscreenBufferSize);
|
|
}
|
|
|
|
if (_numFrames & 0x8000) {
|
|
// This is used in the Amiga version.
|
|
if (_vm->gameFlags().platform != Common::kPlatformAmiga)
|
|
warning("Unhandled wsa flags 0x8000");
|
|
_flags |= WF_FLIPPED;
|
|
_numFrames &= 0x7FFF;
|
|
}
|
|
_currentFrame = _numFrames;
|
|
|
|
_deltaBuffer = new uint8[_deltaBufferSize];
|
|
memset(_deltaBuffer, 0, _deltaBufferSize);
|
|
|
|
// read frame offsets
|
|
_frameOffsTable = new uint32[_numFrames + 2];
|
|
_frameOffsTable[0] = 0;
|
|
uint32 frameDataOffs = READ_LE_UINT32(wsaData); wsaData += 4;
|
|
bool firstFrame = true;
|
|
|
|
if (frameDataOffs == 0) {
|
|
firstFrame = false;
|
|
frameDataOffs = READ_LE_UINT32(wsaData);
|
|
_flags |= WF_NO_FIRST_FRAME;
|
|
}
|
|
|
|
for (int i = 1; i < _numFrames + 2; ++i) {
|
|
_frameOffsTable[i] = READ_LE_UINT32(wsaData);
|
|
if (_frameOffsTable[i])
|
|
_frameOffsTable[i] -= frameDataOffs;
|
|
wsaData += 4;
|
|
}
|
|
|
|
if (!_frameOffsTable[_numFrames + 1])
|
|
_flags |= WF_NO_LAST_FRAME;
|
|
|
|
// skip palette
|
|
wsaData += offsPal;
|
|
|
|
// read frame data
|
|
const int frameDataSize = p + fileSize - wsaData;
|
|
_frameData = new uint8[frameDataSize];
|
|
memcpy(_frameData, wsaData, frameDataSize);
|
|
|
|
// decode first frame
|
|
if (firstFrame)
|
|
Screen::decodeFrame4(_frameData, _deltaBuffer, _deltaBufferSize);
|
|
|
|
delete[] p;
|
|
_opened = true;
|
|
|
|
return _numFrames;
|
|
}
|
|
|
|
void WSAMovie_v1::close() {
|
|
if (_opened) {
|
|
delete[] _deltaBuffer;
|
|
delete[] _offscreenBuffer;
|
|
delete[] _frameOffsTable;
|
|
delete[] _frameData;
|
|
_opened = false;
|
|
}
|
|
}
|
|
|
|
void WSAMovie_v1::displayFrame(int frameNum, int pageNum, int x, int y, uint16 flags, const uint8 *table1, const uint8 *table2) {
|
|
if (frameNum >= _numFrames || frameNum < 0 || !_opened)
|
|
return;
|
|
|
|
_x = x;
|
|
_y = y;
|
|
_drawPage = pageNum;
|
|
|
|
uint8 *dst = 0;
|
|
if (_flags & WF_OFFSCREEN_DECODE)
|
|
dst = _offscreenBuffer;
|
|
else
|
|
dst = _screen->getPageRect(_drawPage, _x, _y, _width, _height);
|
|
|
|
if (_currentFrame == _numFrames) {
|
|
if (!(_flags & WF_NO_FIRST_FRAME)) {
|
|
if (_flags & WF_OFFSCREEN_DECODE)
|
|
Screen::decodeFrameDelta(dst, _deltaBuffer);
|
|
else
|
|
Screen::decodeFrameDeltaPage(dst, _deltaBuffer, _width, (_flags & WF_XOR) == 0);
|
|
}
|
|
_currentFrame = 0;
|
|
}
|
|
|
|
// try to reduce the number of needed frame operations
|
|
int diffCount = ABS(_currentFrame - frameNum);
|
|
int frameStep = 1;
|
|
int frameCount;
|
|
if (_currentFrame < frameNum) {
|
|
frameCount = _numFrames - frameNum + _currentFrame;
|
|
if (diffCount > frameCount && !(_flags & WF_NO_LAST_FRAME))
|
|
frameStep = -1;
|
|
else
|
|
frameCount = diffCount;
|
|
} else {
|
|
frameCount = _numFrames - _currentFrame + frameNum;
|
|
if (frameCount >= diffCount || (_flags & WF_NO_LAST_FRAME)) {
|
|
frameStep = -1;
|
|
frameCount = diffCount;
|
|
}
|
|
}
|
|
|
|
// process
|
|
if (frameStep > 0) {
|
|
uint16 cf = _currentFrame;
|
|
while (frameCount--) {
|
|
cf += frameStep;
|
|
processFrame(cf, dst);
|
|
if (cf == _numFrames)
|
|
cf = 0;
|
|
}
|
|
} else {
|
|
uint16 cf = _currentFrame;
|
|
while (frameCount--) {
|
|
if (cf == 0)
|
|
cf = _numFrames;
|
|
processFrame(cf, dst);
|
|
cf += frameStep;
|
|
}
|
|
}
|
|
|
|
// display
|
|
_currentFrame = frameNum;
|
|
if (_flags & WF_OFFSCREEN_DECODE) {
|
|
int pageBackUp = _screen->setCurPage(_drawPage);
|
|
|
|
int plotFunc = (flags & 0xFF00) >> 12;
|
|
int unk1 = flags & 0xFF;
|
|
|
|
_screen->copyWsaRect(_x, _y, _width, _height, 0, plotFunc, _offscreenBuffer, unk1, table1, table2);
|
|
|
|
_screen->_curPage = pageBackUp;
|
|
}
|
|
}
|
|
|
|
void WSAMovie_v1::processFrame(int frameNum, uint8 *dst) {
|
|
if (!_opened)
|
|
return;
|
|
assert(frameNum <= _numFrames);
|
|
const uint8 *src = _frameData + _frameOffsTable[frameNum];
|
|
Screen::decodeFrame4(src, _deltaBuffer, _deltaBufferSize);
|
|
if (_flags & WF_OFFSCREEN_DECODE)
|
|
Screen::decodeFrameDelta(dst, _deltaBuffer);
|
|
else
|
|
Screen::decodeFrameDeltaPage(dst, _deltaBuffer, _width, false);
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
WSAMovieAmiga::WSAMovieAmiga(KyraEngine_v1 *vm) : WSAMovie_v1(vm), _buffer(0) {}
|
|
|
|
int WSAMovieAmiga::open(const char *filename, int offscreenDecode, Palette *palBuf) {
|
|
int res = WSAMovie_v1::open(filename, offscreenDecode, palBuf);
|
|
|
|
if (!res)
|
|
return 0;
|
|
|
|
_buffer = new uint8[_width * _height];
|
|
assert(_buffer);
|
|
return res;
|
|
}
|
|
|
|
void WSAMovieAmiga::close() {
|
|
if (_opened) {
|
|
delete[] _buffer;
|
|
_buffer = 0;
|
|
}
|
|
WSAMovie_v1::close();
|
|
}
|
|
|
|
void WSAMovieAmiga::displayFrame(int frameNum, int pageNum, int x, int y, uint16 flags, const uint8 *table1, const uint8 *table2) {
|
|
if (frameNum >= _numFrames || frameNum < 0 || !_opened)
|
|
return;
|
|
|
|
_x = x;
|
|
_y = y;
|
|
_drawPage = pageNum;
|
|
|
|
uint8 *dst;
|
|
dst = _buffer;
|
|
memset(_buffer, 0, _width * _height);
|
|
|
|
if (_currentFrame == _numFrames) {
|
|
if (!(_flags & WF_NO_FIRST_FRAME)) {
|
|
Screen::decodeFrameDelta(dst, _deltaBuffer, true);
|
|
Screen::convertAmigaGfx(dst, _width, _height, 5, (_flags & WF_FLIPPED) != 0);
|
|
|
|
if (_flags & WF_OFFSCREEN_DECODE) {
|
|
dst = _offscreenBuffer;
|
|
const uint8 *src = _buffer;
|
|
int size = _width * _height;
|
|
|
|
for (int i = 0; i < size; ++i)
|
|
*dst++ ^= *src++;
|
|
|
|
dst = _buffer;
|
|
} else {
|
|
_screen->copyBlockToPage(_drawPage, _x, _y, _width, _height, _buffer);
|
|
}
|
|
}
|
|
_currentFrame = 0;
|
|
}
|
|
|
|
// try to reduce the number of needed frame operations
|
|
int diffCount = ABS(_currentFrame - frameNum);
|
|
int frameStep = 1;
|
|
int frameCount;
|
|
if (_currentFrame < frameNum) {
|
|
frameCount = _numFrames - frameNum + _currentFrame;
|
|
if (diffCount > frameCount && !(_flags & WF_NO_LAST_FRAME))
|
|
frameStep = -1;
|
|
else
|
|
frameCount = diffCount;
|
|
} else {
|
|
frameCount = _numFrames - _currentFrame + frameNum;
|
|
if (frameCount >= diffCount || (_flags & WF_NO_LAST_FRAME)) {
|
|
frameStep = -1;
|
|
frameCount = diffCount;
|
|
}
|
|
}
|
|
|
|
// process
|
|
if (frameStep > 0) {
|
|
uint16 cf = _currentFrame;
|
|
while (frameCount--) {
|
|
cf += frameStep;
|
|
processFrame(cf, dst);
|
|
if (cf == _numFrames)
|
|
cf = 0;
|
|
}
|
|
} else {
|
|
uint16 cf = _currentFrame;
|
|
while (frameCount--) {
|
|
if (cf == 0)
|
|
cf = _numFrames;
|
|
processFrame(cf, dst);
|
|
cf += frameStep;
|
|
}
|
|
}
|
|
|
|
// display
|
|
_currentFrame = frameNum;
|
|
if (_flags & WF_OFFSCREEN_DECODE) {
|
|
int pageBackUp = _screen->setCurPage(_drawPage);
|
|
|
|
int plotFunc = (flags & 0xFF00) >> 12;
|
|
int unk1 = flags & 0xFF;
|
|
|
|
_screen->copyWsaRect(_x, _y, _width, _height, 0, plotFunc, _offscreenBuffer, unk1, table1, table2);
|
|
|
|
_screen->_curPage = pageBackUp;
|
|
}
|
|
}
|
|
|
|
void WSAMovieAmiga::processFrame(int frameNum, uint8 *dst) {
|
|
if (!_opened)
|
|
return;
|
|
assert(frameNum <= _numFrames);
|
|
|
|
memset(dst, 0, _width * _height);
|
|
|
|
const uint8 *src = _frameData + _frameOffsTable[frameNum];
|
|
Screen::decodeFrame4(src, _deltaBuffer, _deltaBufferSize);
|
|
Screen::decodeFrameDelta(dst, _deltaBuffer, true);
|
|
Screen::convertAmigaGfx(dst, _width, _height, 5, (_flags & WF_FLIPPED) != 0);
|
|
|
|
src = dst;
|
|
dst = 0;
|
|
int dstPitch = 0;
|
|
if (_flags & WF_OFFSCREEN_DECODE) {
|
|
dst = _offscreenBuffer;
|
|
dstPitch = _width;
|
|
} else {
|
|
dst = _screen->getPageRect(_drawPage, _x, _y, _width, _height);
|
|
dstPitch = Screen::SCREEN_W;
|
|
}
|
|
|
|
for (int y = 0; y < _height; ++y) {
|
|
for (int x = 0; x < _width; ++x)
|
|
*dst++ ^= *src++;
|
|
dst += dstPitch - _width;
|
|
}
|
|
}
|
|
|
|
#pragma mark -
|
|
|
|
WSAMovie_v2::WSAMovie_v2(KyraEngine_v1 *vm) : WSAMovie_v1(vm), _xAdd(0), _yAdd(0) {}
|
|
|
|
int WSAMovie_v2::open(const char *filename, int unk1, Palette *palBuf) {
|
|
close();
|
|
|
|
uint32 flags = 0;
|
|
uint32 fileSize;
|
|
uint8 *p = _vm->resource()->fileData(filename, &fileSize);
|
|
if (!p) {
|
|
warning("couldn't load wsa file: '%s'", filename);
|
|
return 0;
|
|
}
|
|
|
|
const uint8 *wsaData = p;
|
|
_numFrames = READ_LE_UINT16(wsaData); wsaData += 2;
|
|
_xAdd = (int16)(READ_LE_UINT16(wsaData)); wsaData += 2;
|
|
_yAdd = (int16)(READ_LE_UINT16(wsaData)); wsaData += 2;
|
|
_width = READ_LE_UINT16(wsaData); wsaData += 2;
|
|
_height = READ_LE_UINT16(wsaData); wsaData += 2;
|
|
_deltaBufferSize = READ_LE_UINT16(wsaData); wsaData += 2;
|
|
_offscreenBuffer = NULL;
|
|
_flags = 0;
|
|
flags = READ_LE_UINT16(wsaData); wsaData += 2;
|
|
|
|
uint32 offsPal = 0;
|
|
if (flags & 1) {
|
|
offsPal = 0x300;
|
|
_flags |= WF_HAS_PALETTE;
|
|
if (palBuf)
|
|
_screen->loadPalette(wsaData + 8 + ((_numFrames << 2) & 0xFFFF), *palBuf, 0x300);
|
|
}
|
|
|
|
if (flags & 2) {
|
|
if (_vm->gameFlags().use16ColorMode) {
|
|
offsPal = 0x30;
|
|
_flags |= WF_HAS_PALETTE;
|
|
if (palBuf)
|
|
_screen->loadPalette(wsaData + 8 + ((_numFrames << 2) & 0xFFFF), *palBuf, 0x30);
|
|
}
|
|
|
|
_flags |= WF_XOR;
|
|
}
|
|
|
|
|
|
if (!(unk1 & 2)) {
|
|
_flags |= WF_OFFSCREEN_DECODE;
|
|
const int offscreenBufferSize = _width * _height;
|
|
_offscreenBuffer = new uint8[offscreenBufferSize];
|
|
memset(_offscreenBuffer, 0, offscreenBufferSize);
|
|
}
|
|
|
|
if (_numFrames & 0x8000) {
|
|
warning("Unhandled wsa flags 0x80");
|
|
_flags |= 0x80;
|
|
_numFrames &= 0x7FFF;
|
|
}
|
|
_currentFrame = _numFrames;
|
|
|
|
_deltaBuffer = new uint8[_deltaBufferSize];
|
|
memset(_deltaBuffer, 0, _deltaBufferSize);
|
|
|
|
// read frame offsets
|
|
_frameOffsTable = new uint32[_numFrames + 2];
|
|
_frameOffsTable[0] = 0;
|
|
uint32 frameDataOffs = READ_LE_UINT32(wsaData); wsaData += 4;
|
|
bool firstFrame = true;
|
|
if (frameDataOffs == 0) {
|
|
firstFrame = false;
|
|
frameDataOffs = READ_LE_UINT32(wsaData);
|
|
_flags |= WF_NO_FIRST_FRAME;
|
|
}
|
|
|
|
for (int i = 1; i < _numFrames + 2; ++i) {
|
|
_frameOffsTable[i] = READ_LE_UINT32(wsaData);
|
|
if (_frameOffsTable[i])
|
|
_frameOffsTable[i] -= frameDataOffs;
|
|
wsaData += 4;
|
|
}
|
|
|
|
if (!_frameOffsTable[_numFrames + 1])
|
|
_flags |= WF_NO_LAST_FRAME;
|
|
|
|
// skip palette
|
|
wsaData += offsPal;
|
|
|
|
// read frame data
|
|
const int frameDataSize = p + fileSize - wsaData;
|
|
|
|
_frameData = new uint8[frameDataSize];
|
|
memcpy(_frameData, wsaData, frameDataSize);
|
|
|
|
// decode first frame
|
|
if (firstFrame)
|
|
Screen::decodeFrame4(_frameData, _deltaBuffer, _deltaBufferSize);
|
|
|
|
delete[] p;
|
|
_opened = true;
|
|
|
|
return _numFrames;
|
|
}
|
|
|
|
} // End of namespace Kyra
|