mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-14 16:07:39 +00:00
Changed the KQ6 floppy SEQ decoder to use the common VideoPlayer interface. Some cleanup
svn-id: r45124
This commit is contained in:
parent
6d95f8ca61
commit
da7652deb3
@ -1059,52 +1059,23 @@ static reg_t kShowMovie_Windows(EngineState *s, int argc, reg_t *argv) {
|
||||
static reg_t kShowMovie_DOS(EngineState *s, int argc, reg_t *argv) {
|
||||
Common::String filename = s->_segMan->getString(argv[0]);
|
||||
int delay = argv[1].toUint16(); // Time between frames in ticks
|
||||
SeqDecoder seq;
|
||||
|
||||
if (!seq.loadFile(filename, s->resMan) &&
|
||||
!seq.loadFile(Common::String("SEQ/") + filename, s->resMan)) {
|
||||
Common::Event stopEvent;
|
||||
Common::List<Common::Event> stopEvents;
|
||||
stopEvents.clear();
|
||||
stopEvent.type = Common::EVENT_KEYDOWN;
|
||||
stopEvent.kbd = Common::KEYCODE_ESCAPE;
|
||||
stopEvents.push_back(stopEvent);
|
||||
|
||||
Graphics::SeqDecoder *seqDecoder = new Graphics::SeqDecoder();
|
||||
Graphics::VideoPlayer *player = new Graphics::VideoPlayer(seqDecoder);
|
||||
if (seqDecoder->loadFile(filename.c_str(), delay))
|
||||
player->playVideo(stopEvents);
|
||||
else
|
||||
warning("Failed to open movie file %s", filename.c_str());
|
||||
return s->r_acc;
|
||||
}
|
||||
|
||||
bool play = true;
|
||||
while (play) {
|
||||
uint32 startTime = g_system->getMillis();
|
||||
SeqFrame *frame = seq.getFrame(play);
|
||||
Common::Rect frameRect = frame->frameRect;
|
||||
|
||||
byte *scr = (byte *)g_system->lockScreen()->pixels;
|
||||
int cur = 0;
|
||||
for (int y = frameRect.top; y < frameRect.bottom; y++) {
|
||||
for (int x = frameRect.left; x < frameRect.right; x++) {
|
||||
if (frame->data[cur] != frame->colorKey)
|
||||
scr[y * 320 + x] = frame->data[cur];
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
g_system->unlockScreen();
|
||||
g_system->updateScreen();
|
||||
|
||||
delete frame->data;
|
||||
delete frame;
|
||||
|
||||
// Wait before showing the next frame
|
||||
while (play && (g_system->getMillis() < startTime + (delay * 1000 / 60))) {
|
||||
// FIXME: we should probably make a function that handles quitting in these kinds of situations
|
||||
Common::Event curEvent;
|
||||
Common::EventManager *eventMan = g_system->getEventManager();
|
||||
|
||||
// Process quit events
|
||||
while (eventMan->pollEvent(curEvent)) {
|
||||
if (curEvent.type == Common::EVENT_QUIT) {
|
||||
play = false;
|
||||
quit_vm();
|
||||
}
|
||||
}
|
||||
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
}
|
||||
seqDecoder->closeFile();
|
||||
delete player;
|
||||
delete seqDecoder;
|
||||
|
||||
return s->r_acc;
|
||||
}
|
||||
|
@ -23,40 +23,77 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/endian.h"
|
||||
#include "common/archive.h"
|
||||
#include "sci/gfx/seq_decoder.h"
|
||||
#include "sci/resource.h"
|
||||
#include "sci/gui/gui_screen.h"
|
||||
#include "sci/gui/gui_palette.h"
|
||||
#include "common/system.h"
|
||||
#include "common/util.h"
|
||||
|
||||
namespace Sci {
|
||||
#include "graphics/surface.h"
|
||||
|
||||
#include "sci/gfx/seq_decoder.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
enum seqPalTypes {
|
||||
kSeqPalVariable = 0,
|
||||
kSeqPalConstant = 1
|
||||
};
|
||||
|
||||
enum seqFrameTypes {
|
||||
kSeqFrameFull = 0,
|
||||
kSeqFrameDiff = 1
|
||||
};
|
||||
|
||||
SeqDecoder::~SeqDecoder() {
|
||||
closeFile();
|
||||
}
|
||||
|
||||
bool SeqDecoder::loadFile(Common::String fileName, ResourceManager *resMan) {
|
||||
bool SeqDecoder::loadFile(const char *fileName, int frameDelay) {
|
||||
closeFile();
|
||||
|
||||
_fileStream = SearchMan.createReadStreamForMember(fileName);
|
||||
if (!_fileStream)
|
||||
return false;
|
||||
|
||||
_frameCount = _fileStream->readUint16LE();
|
||||
// Seek to the first frame
|
||||
_videoInfo.currentFrame = 0;
|
||||
|
||||
_videoInfo.width = 320;
|
||||
_videoInfo.height = 200;
|
||||
_videoInfo.frameCount = _fileStream->readUint16LE();
|
||||
// Our frameDelay is calculated in 1/100 ms, so we convert it here
|
||||
_videoInfo.frameDelay = 100 * frameDelay * 1000 / 60;
|
||||
_videoFrameBuffer = new byte[_videoInfo.width * _videoInfo.height];
|
||||
|
||||
// Set palette
|
||||
int paletteSize = _fileStream->readUint32LE();
|
||||
|
||||
byte *paletteData = new byte[paletteSize];
|
||||
_fileStream->read(paletteData, paletteSize);
|
||||
GuiPalette seqPalette;
|
||||
SciGuiScreen *videoScreen = new SciGuiScreen(320, 200, 1);
|
||||
SciGuiPalette *pal = new SciGuiPalette(resMan, videoScreen, false);
|
||||
pal->createFromData(paletteData, &seqPalette);
|
||||
pal->set(&seqPalette, 2);
|
||||
delete pal;
|
||||
delete[] paletteData;
|
||||
delete videoScreen;
|
||||
|
||||
_currentFrame = 0;
|
||||
// SCI1.1 palette
|
||||
byte palFormat = paletteData[32];
|
||||
uint16 palColorStart = READ_LE_UINT16(paletteData + 25);
|
||||
uint16 palColorCount = READ_LE_UINT16(paletteData + 29);
|
||||
|
||||
byte palette[256 * 4];
|
||||
int palOffset = 37;
|
||||
|
||||
for (uint16 colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) {
|
||||
if (palFormat == kSeqPalVariable)
|
||||
palOffset++;
|
||||
palette[colorNo * 4 + 0] = paletteData[palOffset++];
|
||||
palette[colorNo * 4 + 1] = paletteData[palOffset++];
|
||||
palette[colorNo * 4 + 2] = paletteData[palOffset++];
|
||||
palette[colorNo * 4 + 3] = 0;
|
||||
}
|
||||
|
||||
g_system->setPalette(palette, 0, 256);
|
||||
|
||||
delete paletteData;
|
||||
|
||||
_videoInfo.firstframeOffset = _fileStream->pos();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -67,26 +104,60 @@ void SeqDecoder::closeFile() {
|
||||
|
||||
delete _fileStream;
|
||||
_fileStream = 0;
|
||||
|
||||
delete[] _videoFrameBuffer;
|
||||
_videoFrameBuffer = 0;
|
||||
}
|
||||
|
||||
bool SeqDecoder::decodeNextFrame() {
|
||||
int16 frameWidth = _fileStream->readUint16LE();
|
||||
int16 frameHeight = _fileStream->readUint16LE();
|
||||
int16 frameLeft = _fileStream->readUint16LE();
|
||||
int16 frameTop = _fileStream->readUint16LE();
|
||||
byte colorKey = _fileStream->readByte();
|
||||
byte frameType = _fileStream->readByte();
|
||||
_fileStream->skip(2);
|
||||
uint16 frameSize = _fileStream->readUint16LE();
|
||||
_fileStream->skip(2);
|
||||
uint16 rleSize = _fileStream->readUint16LE();
|
||||
_fileStream->skip(6);
|
||||
uint32 offset = _fileStream->readUint32LE();
|
||||
|
||||
_fileStream->seek(offset);
|
||||
|
||||
if (_videoInfo.currentFrame == 0)
|
||||
_videoInfo.startTime = g_system->getMillis();
|
||||
|
||||
if (frameType == kSeqFrameFull) {
|
||||
assert (frameLeft == 0);
|
||||
assert (frameWidth == 320);
|
||||
_fileStream->read(_videoFrameBuffer + 320 * frameTop, frameSize);
|
||||
} else {
|
||||
byte *buf = new byte[frameSize];
|
||||
_fileStream->read(buf, frameSize);
|
||||
decodeFrame(buf, rleSize, buf + rleSize, frameSize - rleSize, _videoFrameBuffer + 320 * frameTop, frameLeft, frameWidth, frameHeight, colorKey);
|
||||
delete buf;
|
||||
}
|
||||
|
||||
return ++_videoInfo.currentFrame < _videoInfo.frameCount;
|
||||
}
|
||||
|
||||
#define WRITE_TO_BUFFER(n) \
|
||||
if (writeRow * width + writeCol + (n) > width * height) { \
|
||||
if (writeRow * 320 + writeCol + (n) > 320 * height) { \
|
||||
warning("SEQ player: writing out of bounds, aborting"); \
|
||||
return false; \
|
||||
} \
|
||||
if (litPos + (n) > litSize) { \
|
||||
warning("SEQ player: reading out of bounds, aborting"); \
|
||||
} \
|
||||
memcpy(dest + writeRow * width + writeCol, litData + litPos, n);
|
||||
memcpy(dest + writeRow * 320 + writeCol, litData + litPos, n);
|
||||
|
||||
bool SeqDecoder::decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int width, int height, int colorKey) {
|
||||
bool SeqDecoder::decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey) {
|
||||
int writeRow = 0;
|
||||
int writeCol = 0;
|
||||
int writeCol = left;
|
||||
int litPos = 0;
|
||||
int rlePos = 0;
|
||||
|
||||
memset(dest, colorKey, width * height);
|
||||
|
||||
while (rlePos < rleSize) {
|
||||
int op = rleData[rlePos++];
|
||||
|
||||
@ -95,7 +166,7 @@ bool SeqDecoder::decodeFrame(byte *rleData, int rleSize, byte *litData, int litS
|
||||
if (op == 0) {
|
||||
// Go to next line in target buffer
|
||||
writeRow++;
|
||||
writeCol = 0;
|
||||
writeCol = left;
|
||||
} else {
|
||||
// Skip bytes on current line
|
||||
writeCol += op;
|
||||
@ -104,11 +175,11 @@ bool SeqDecoder::decodeFrame(byte *rleData, int rleSize, byte *litData, int litS
|
||||
op &= 0x3f;
|
||||
if (op == 0) {
|
||||
// Copy remainder of current line
|
||||
int rem = width - writeCol;
|
||||
int rem = width - (writeCol - left);
|
||||
|
||||
WRITE_TO_BUFFER(rem);
|
||||
writeRow++;
|
||||
writeCol = 0;
|
||||
writeCol = left;
|
||||
litPos += rem;
|
||||
} else {
|
||||
// Copy bytes
|
||||
@ -159,37 +230,4 @@ bool SeqDecoder::decodeFrame(byte *rleData, int rleSize, byte *litData, int litS
|
||||
return true;
|
||||
}
|
||||
|
||||
SeqFrame *SeqDecoder::getFrame(bool &hasNext) {
|
||||
int16 frameWidth = _fileStream->readUint16LE();
|
||||
int16 frameHeight = _fileStream->readUint16LE();
|
||||
int16 frameLeft = _fileStream->readUint16LE();
|
||||
int16 frameTop = _fileStream->readUint16LE();
|
||||
byte colorKey = _fileStream->readByte();
|
||||
byte type = _fileStream->readByte();
|
||||
_fileStream->skip(2);
|
||||
uint16 bytes = _fileStream->readUint16LE();
|
||||
_fileStream->skip(2);
|
||||
uint16 rle_bytes = _fileStream->readUint16LE();
|
||||
_fileStream->skip(6);
|
||||
uint32 offset = _fileStream->readUint32LE();
|
||||
|
||||
_fileStream->seek(offset);
|
||||
SeqFrame *frame = new SeqFrame();
|
||||
frame->frameRect = Common::Rect(frameLeft, frameTop, frameLeft + frameWidth, frameTop + frameHeight);
|
||||
frame->data = new byte[frameWidth * frameHeight];
|
||||
frame->colorKey = colorKey;
|
||||
|
||||
if (type == 0)
|
||||
_fileStream->read(frame->data, bytes);
|
||||
else {
|
||||
byte *buf = new byte[bytes];
|
||||
_fileStream->read(buf, bytes);
|
||||
decodeFrame(buf, rle_bytes, buf + rle_bytes, bytes - rle_bytes, frame->data, frameWidth, frameHeight, colorKey);
|
||||
}
|
||||
|
||||
hasNext = ++_currentFrame < _frameCount;
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
} // End of namespace Sci
|
||||
} // End of namespace Graphics
|
||||
|
@ -23,39 +23,46 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/file.h"
|
||||
#include "common/rect.h"
|
||||
#ifndef SEQ_DECODER_H
|
||||
#define SEQ_DECODER_H
|
||||
|
||||
namespace Sci {
|
||||
#include "graphics/video/video_player.h"
|
||||
|
||||
struct SeqFrame {
|
||||
Common::Rect frameRect;
|
||||
byte colorKey;
|
||||
byte *data;
|
||||
};
|
||||
|
||||
class ResourceManager;
|
||||
class SciGuiScreen;
|
||||
namespace Graphics {
|
||||
|
||||
/**
|
||||
* Decoder for image sequences
|
||||
* Implementation of the KQ6 floppy SEQ decoder
|
||||
*/
|
||||
class SeqDecoder {
|
||||
class SeqDecoder : public VideoDecoder {
|
||||
public:
|
||||
SeqDecoder() : _fileStream(0) { }
|
||||
~SeqDecoder();
|
||||
bool loadFile(Common::String fileName, ResourceManager *resMan);
|
||||
SeqDecoder() {}
|
||||
virtual ~SeqDecoder();
|
||||
|
||||
/**
|
||||
* Load a SEQ encoded video file
|
||||
* @param filename the filename to load
|
||||
* @param frameDelay the delay between frames, in ms
|
||||
*/
|
||||
bool loadFile(const char *fileName) { return loadFile(fileName, 10); }
|
||||
|
||||
/**
|
||||
* Load a SEQ encoded video file
|
||||
* @param filename the filename to load
|
||||
* @param frameDelay the delay between frames, in ms
|
||||
*/
|
||||
bool loadFile(const char *fileName, int frameDelay);
|
||||
|
||||
/**
|
||||
* Close a SEQ encoded video file
|
||||
*/
|
||||
void closeFile();
|
||||
SeqFrame *getFrame(bool &hasNext);
|
||||
|
||||
bool decodeNextFrame();
|
||||
|
||||
private:
|
||||
bool decodeFrame(byte *runlength_data, int runlength_size,
|
||||
byte *literal_data, int literal_size, byte *dest, int xl, int yl,
|
||||
int color_key);
|
||||
|
||||
Common::SeekableReadStream *_fileStream;
|
||||
int _frameCount;
|
||||
int _currentFrame;
|
||||
bool decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey);
|
||||
};
|
||||
|
||||
} // End of namespace Sci
|
||||
} // End of namespace Graphics
|
||||
|
||||
#endif
|
||||
|
@ -51,14 +51,6 @@ class GfxDriver;
|
||||
|
||||
SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc)
|
||||
: Engine(syst), _gameDescription(desc), _system(syst) {
|
||||
// Put your engine in a sane state, but do nothing big yet;
|
||||
// in particular, do not load data from files; rather, if you
|
||||
// need to do such things, do them from init().
|
||||
|
||||
// However this is the place to specify all default directories
|
||||
//File::addDefaultDirectory(_gameDataPath + "sound/");
|
||||
//printf("%s\n", _gameDataPath.c_str());
|
||||
|
||||
_console = NULL;
|
||||
|
||||
// Set up the engine specific debug levels
|
||||
@ -86,6 +78,8 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc)
|
||||
Common::addDebugChannel(kDebugLevelSci0Pic, "Sci0Pic", "SCI0 pic drawing debugging");
|
||||
|
||||
_gamestate = 0;
|
||||
|
||||
SearchMan.addSubDirectoryMatching(_gameDataDir, "seq"); // KQ6 SEQ directory
|
||||
}
|
||||
|
||||
SciEngine::~SciEngine() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user