VIDEO: Implement decoder for PACo files
The code decodes PACo video frames. Other features, such as audio and palette changes are detected but not handled. Format documentation: https://wiki.multimedia.cx/index.php?title=PACo Thanks to Kostya for reverse engineering the format and the original C code.
This commit is contained in:
parent
c20dc805c5
commit
24b7267b8b
3 changed files with 609 additions and 0 deletions
|
@ -9,6 +9,7 @@ MODULE_OBJS := \
|
|||
hnm_decoder.o \
|
||||
mpegps_decoder.o \
|
||||
mve_decoder.o \
|
||||
paco_decoder.o \
|
||||
psx_decoder.o \
|
||||
qt_decoder.o \
|
||||
smk_decoder.o \
|
||||
|
|
505
video/paco_decoder.cpp
Normal file
505
video/paco_decoder.cpp
Normal file
|
@ -0,0 +1,505 @@
|
|||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/system.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "video/qt_data.h"
|
||||
#include "video/paco_decoder.h"
|
||||
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/decoders/raw.h"
|
||||
|
||||
namespace Video {
|
||||
|
||||
PacoDecoder::PacoDecoder() {
|
||||
}
|
||||
|
||||
PacoDecoder::~PacoDecoder() {
|
||||
close();
|
||||
}
|
||||
|
||||
bool PacoDecoder::loadStream(Common::SeekableReadStream *stream) {
|
||||
close();
|
||||
|
||||
stream->readUint16BE(); // 1
|
||||
stream->readUint16BE(); // 0x26
|
||||
|
||||
uint16 width = stream->readUint16BE();
|
||||
uint16 height = stream->readUint16BE();
|
||||
int16 frameRate = stream->readUint16BE();
|
||||
frameRate = ABS(frameRate); // Negative framerate is indicative of audio, but not always
|
||||
uint16 flags = stream->readUint16BE();
|
||||
bool hasAudio = (flags & 0x100) == 0x100;
|
||||
|
||||
stream->readUint32BE(); // maxChunksize
|
||||
stream->readUint32BE(); // always 0
|
||||
stream->readUint32BE(); // audio related flags
|
||||
uint16 frameCount = stream->readUint16BE();
|
||||
stream->readUint16BE(); // copy of frameCount
|
||||
stream->readUint16BE(); // always 8?
|
||||
stream->readUint16BE(); // always 0x600?
|
||||
stream->readUint32BE(); // flags
|
||||
stream->readUint16BE(); // 0
|
||||
|
||||
addTrack(new PacoVideoTrack(stream, frameRate, frameCount, hasAudio, width, height));
|
||||
return true;
|
||||
}
|
||||
|
||||
const Common::List<Common::Rect> *PacoDecoder::getDirtyRects() const {
|
||||
const Track *track = getTrack(0);
|
||||
|
||||
if (track)
|
||||
return ((const PacoVideoTrack *)track)->getDirtyRects();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void PacoDecoder::clearDirtyRects() {
|
||||
Track *track = getTrack(0);
|
||||
|
||||
if (track)
|
||||
((PacoVideoTrack *)track)->clearDirtyRects();
|
||||
}
|
||||
|
||||
void PacoDecoder::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) {
|
||||
Track *track = getTrack(0);
|
||||
|
||||
if (track)
|
||||
((PacoVideoTrack *)track)->copyDirtyRectsToBuffer(dst, pitch);
|
||||
}
|
||||
|
||||
PacoDecoder::PacoVideoTrack::PacoVideoTrack(
|
||||
Common::SeekableReadStream *stream, uint16 frameRate, uint16 frameCount, bool hasAudio, uint16 width, uint16 height) {
|
||||
|
||||
_fileStream = stream;
|
||||
_frameDelay = 1000 / frameRate; // frameRate is in fps, ms per frame
|
||||
_frameCount = frameCount;
|
||||
|
||||
_surface = new Graphics::Surface();
|
||||
_surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
|
||||
_palette = new byte[3 * 256]();
|
||||
memcpy(_palette, quickTimeDefaultPalette256, 256 * 3);
|
||||
_dirtyPalette = false;
|
||||
|
||||
_curFrame = 0;
|
||||
_nextFrameStartTime = 0;
|
||||
|
||||
for (uint i = 0; i < _frameCount; i++) {
|
||||
_frameSizes[i] = stream->readUint32BE();
|
||||
}
|
||||
}
|
||||
|
||||
PacoDecoder::PacoVideoTrack::~PacoVideoTrack() {
|
||||
delete _fileStream;
|
||||
delete[] _palette;
|
||||
|
||||
_surface->free();
|
||||
delete _surface;
|
||||
}
|
||||
|
||||
bool PacoDecoder::PacoVideoTrack::endOfTrack() const {
|
||||
return getCurFrame() >= getFrameCount();
|
||||
}
|
||||
|
||||
uint16 PacoDecoder::PacoVideoTrack::getWidth() const {
|
||||
return _surface->w;
|
||||
}
|
||||
|
||||
uint16 PacoDecoder::PacoVideoTrack::getHeight() const {
|
||||
return _surface->h;
|
||||
}
|
||||
|
||||
Graphics::PixelFormat PacoDecoder::PacoVideoTrack::getPixelFormat() const {
|
||||
return _surface->format;
|
||||
}
|
||||
|
||||
|
||||
enum frameTypes {
|
||||
NOP = 0, // nop
|
||||
// 1 - old initialisation data?
|
||||
PALLETE = 2, // - new initialisation data (usually 0x30 0x00 0x00 ... meaning 8-bit with default QuickTime palette)
|
||||
DELAY = 3, // - delay information
|
||||
AUDIO = 4, // - audio data (8-bit unsigned PCM)
|
||||
// 5 - should not be present
|
||||
// 6 - should not be present
|
||||
// 7 - unknown
|
||||
VIDEO = 8, // - video frame
|
||||
// 9 - unknown
|
||||
// 10 - dummy?
|
||||
EOC = 11 // - end of chunk marker
|
||||
};
|
||||
|
||||
const Graphics::Surface *PacoDecoder::PacoVideoTrack::decodeNextFrame() {
|
||||
uint32 nextFrame = _fileStream->pos() + _frameSizes[_curFrame];
|
||||
|
||||
debug(" frame %3d size %d @ %lX", _curFrame, _frameSizes[_curFrame], _fileStream->pos());
|
||||
|
||||
while (_fileStream->pos() < nextFrame) {
|
||||
int64 currentPos = _fileStream->pos();
|
||||
int frameType = _fileStream->readByte();
|
||||
int v = _fileStream->readByte();
|
||||
uint32 chunkSize = (v << 16 ) | _fileStream->readUint16BE();
|
||||
debug(" slot type %d size %d @ %lX", frameType, chunkSize, _fileStream->pos() - 4);
|
||||
|
||||
switch (frameType) {
|
||||
case AUDIO:
|
||||
warning("PacoDecode::decodeFrame(): Audio not implemented");
|
||||
break;
|
||||
case VIDEO:
|
||||
handleFrame(chunkSize - 4);
|
||||
break;
|
||||
case PALLETE:
|
||||
warning("PacoDecode::decodeFrame(): Palette not implemented");
|
||||
break;
|
||||
case EOC:
|
||||
break;
|
||||
default:
|
||||
error("PacoDecoder::decodeFrame(): unknown main chunk type (type = 0x%02X)", frameType);
|
||||
break;
|
||||
}
|
||||
_fileStream->seek(currentPos + chunkSize);
|
||||
}
|
||||
|
||||
_curFrame++;
|
||||
_nextFrameStartTime += _frameDelay;
|
||||
|
||||
return _surface;
|
||||
}
|
||||
|
||||
enum {
|
||||
COPY = 0, // raw copy pixels
|
||||
RLE, // RLE
|
||||
PRLE, // pair RLE (read a pair of pixels and repeat it the specified number of times)
|
||||
QRLE, // quad RLE (read four pixels and repeat it the specified number of times)
|
||||
SKIP, // skip
|
||||
ENDCURRENTLINE, // end current line and skip additional len lines
|
||||
EOFRAME = 15 // not real opcode but 00 F0 00 00 is often seen at the end of frame and can serve as an end marker
|
||||
};
|
||||
|
||||
#define ADJUST_LINE \
|
||||
if (compr == 1) \
|
||||
ypos2 = ypos; \
|
||||
else { \
|
||||
ypos2 = ypos * 2 - y; \
|
||||
if (ypos2 >= y + bh) { \
|
||||
ypos2 -= bh; \
|
||||
if (!(bh & 1)) \
|
||||
ypos2++; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define PUTPIX(pix) \
|
||||
do { \
|
||||
*dst++ = pix; \
|
||||
xpos++; \
|
||||
} while(0);
|
||||
|
||||
#define SKIP() \
|
||||
do { \
|
||||
dst++; \
|
||||
xpos++; \
|
||||
} while(0);
|
||||
|
||||
|
||||
void PacoDecoder::PacoVideoTrack::handleFrame(uint32 chunkSize) {
|
||||
uint16 w = getWidth();
|
||||
|
||||
uint16 x = _fileStream->readUint16BE(); // x offset of the updated area
|
||||
uint16 y = _fileStream->readUint16BE(); // y offset of the updated area
|
||||
uint16 bw = _fileStream->readUint16BE(); // updated area width
|
||||
uint16 bh = _fileStream->readUint16BE(); // updated area height
|
||||
uint compr = _fileStream->readByte(); // compression method and flags
|
||||
_fileStream->readByte(); // padding
|
||||
|
||||
debug(" +%d,%d - %dx%d compr %X", x, y, bw, bh, compr);
|
||||
|
||||
compr = compr & 0xF;
|
||||
|
||||
uint8 *fdata = new uint8[1048576]; // 0x100000 copied from original pacodec
|
||||
_fileStream->read(fdata, chunkSize - 10); // remove header length
|
||||
debug("pos: %ld", _fileStream->pos());
|
||||
int16 xpos = x, ypos = y, ypos2 = y;
|
||||
byte *dst = (byte *)_surface->getPixels() + x + y * w;
|
||||
|
||||
const uint8 *src = fdata;
|
||||
int16 i, c, c1, c2, c3, c4;
|
||||
uint8 clrs[16];
|
||||
|
||||
|
||||
while (ypos < y + bh) {
|
||||
c = *src++;
|
||||
debug("debug info: ypos %d y %d bh %d src: %d", ypos, y, bh, c);
|
||||
|
||||
if (c == 0 ){ // long operation
|
||||
int16 op = src[0] >> 4;
|
||||
int16 len = ((src[0] & 0xF) << 8) | src[1];
|
||||
src += 2;
|
||||
debug(" long operation: opcode: %d", op);
|
||||
switch (op) {
|
||||
case COPY:
|
||||
while (len--)
|
||||
PUTPIX(*src++);
|
||||
break;
|
||||
case RLE:
|
||||
c1 = *src++;
|
||||
while (len--)
|
||||
PUTPIX(c1);
|
||||
break;
|
||||
case PRLE:
|
||||
c1 = *src++;
|
||||
c2 = *src++;
|
||||
while (len--){
|
||||
PUTPIX(c1);
|
||||
PUTPIX(c2);
|
||||
}
|
||||
break;
|
||||
case QRLE:
|
||||
c1 = *src++;
|
||||
c2 = *src++;
|
||||
c3 = *src++;
|
||||
c4 = *src++;
|
||||
while (len--) {
|
||||
PUTPIX(c1);
|
||||
PUTPIX(c2);
|
||||
PUTPIX(c3);
|
||||
PUTPIX(c4);
|
||||
}
|
||||
break;
|
||||
case SKIP:
|
||||
while (len--)
|
||||
SKIP();
|
||||
break;
|
||||
case ENDCURRENTLINE:
|
||||
xpos = x;
|
||||
ypos += len + 1;
|
||||
ADJUST_LINE;
|
||||
dst = (byte *)_surface->getPixels() + xpos + ypos2 * w;
|
||||
break;
|
||||
case EOFRAME:
|
||||
xpos = x;
|
||||
ypos = y + bh;
|
||||
break;
|
||||
default:
|
||||
PUTPIX(0xFF);
|
||||
debug("PacoDecoder::PacoVideoTrack::handleFrame: Long op: 0x0 op %d", op);
|
||||
}
|
||||
|
||||
} else if (c < 128) { // copy the same amount of pixels
|
||||
debug(" copy pixels: %d", c);
|
||||
while (c--)
|
||||
PUTPIX(*src++);
|
||||
} else if (c < 254) { // repeat the following value 256 - op times
|
||||
debug(" copy pixels -op: %d", 256 - c);
|
||||
c1 = *src++;
|
||||
c = 256 - c;
|
||||
while (c--)
|
||||
PUTPIX(c1);
|
||||
} else if (c < 255) {
|
||||
// next byte is either the number of pixels to skip (if non-zero) or
|
||||
// a signal of compact RLE mode
|
||||
c = *src++;
|
||||
|
||||
if (!c) { // compact RLE mode
|
||||
unsigned mask = (src[0] << 8) | src[1];
|
||||
src += 2;
|
||||
debug("debug info compact RLE: c: %d mask: %d", c, mask);
|
||||
|
||||
for (i = 0; i < 16; i++, mask >>= 1) {
|
||||
if (mask & 1)
|
||||
clrs[i] = *src++;
|
||||
}
|
||||
while (xpos < x + bw) {
|
||||
int16 op = *src++;
|
||||
int16 len = op & 0xF;
|
||||
op >>= 4;
|
||||
if (op == 0) { // low nibble....
|
||||
op = len;
|
||||
len = *src++;
|
||||
debug("debug info compact: op: %d", op);
|
||||
switch (op) {
|
||||
case COPY:
|
||||
debug("debug info COPY: %d", len);
|
||||
while (len--) {
|
||||
c = *src++;
|
||||
PUTPIX(clrs[c >> 4]);
|
||||
if (!len)
|
||||
break;
|
||||
len--;
|
||||
PUTPIX(clrs[c & 0xF]);
|
||||
}
|
||||
break;
|
||||
case RLE:
|
||||
debug("debug info RLE: %d", len);
|
||||
c = *src++;
|
||||
while (len--)
|
||||
PUTPIX(clrs[c & 0xF]);
|
||||
break;
|
||||
case PRLE:
|
||||
debug("debug info PRLE: %d", len);
|
||||
c = *src++;
|
||||
c1 = clrs[c >> 4];
|
||||
c2 = clrs[c & 0xF];
|
||||
while (len--) {
|
||||
PUTPIX(c1);
|
||||
PUTPIX(c2);
|
||||
}
|
||||
break;
|
||||
case QRLE:
|
||||
debug("debug info QRLE: %d", len);
|
||||
c = *src++;
|
||||
c1 = clrs[c >> 4];
|
||||
c2 = clrs[c & 0xF];
|
||||
c = *src++;
|
||||
c3 = clrs[c >> 4];
|
||||
c4 = clrs[c & 0xF];
|
||||
while (len--) {
|
||||
PUTPIX(c1);
|
||||
PUTPIX(c2);
|
||||
PUTPIX(c3);
|
||||
PUTPIX(c4);
|
||||
}
|
||||
break;
|
||||
case SKIP:
|
||||
debug("debug info SKIP: %d", len);
|
||||
while (len--)
|
||||
SKIP();
|
||||
break;
|
||||
case ENDCURRENTLINE:
|
||||
debug("debug info ENDCURRENTLINE: %d", len);
|
||||
xpos = x + bw;
|
||||
break;
|
||||
default:
|
||||
warning("PacoDecoder::PacoVideoTrack::handleFrame: Compact RLE mode: 0x0 op %d", op);
|
||||
}
|
||||
} else if (op < 8) { // copy 1-7 colors
|
||||
debug("debug info copy 1-7 colors: %d", len);
|
||||
PUTPIX(clrs[len]);
|
||||
op--;
|
||||
while (op--) {
|
||||
c = *src++;
|
||||
PUTPIX(clrs[c >> 4]);
|
||||
if (!op)
|
||||
break;
|
||||
op--;
|
||||
PUTPIX(clrs[c & 0xF]);
|
||||
}
|
||||
} else if (op < 14) { // repeat color
|
||||
debug("debug info Repeat color: %d", len);
|
||||
op = 16 - op;
|
||||
while (op--)
|
||||
PUTPIX(clrs[len]);
|
||||
} else if (op < 15) { // skip number of pixels in low nibbel
|
||||
debug("debug info Skip number of pixels: %d", len);
|
||||
while (len--)
|
||||
SKIP();
|
||||
} else {
|
||||
if (len < 8) { // Pair run
|
||||
debug("debug info pair run: %d", len);
|
||||
c = *src++;
|
||||
c1 = clrs[c >> 4];
|
||||
c2 = clrs[c & 0xF];
|
||||
while (len--) {
|
||||
PUTPIX(c1);
|
||||
PUTPIX(c2);
|
||||
}
|
||||
} else { // Quad run
|
||||
debug("debug info quad run: %d", len);
|
||||
len = 16 - len;
|
||||
c = *src++;
|
||||
c1 = clrs[c >> 4];
|
||||
c2 = clrs[c & 0xF];
|
||||
c = *src++;
|
||||
c3 = clrs[c >> 4];
|
||||
c4 = clrs[c & 0xF];
|
||||
while (len--) {
|
||||
PUTPIX(c1);
|
||||
PUTPIX(c2);
|
||||
PUTPIX(c3);
|
||||
PUTPIX(c4);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug("debug info SKIP: %d", c);
|
||||
while (c--)
|
||||
SKIP();
|
||||
}
|
||||
} else {
|
||||
// pair or quad run. Read the next byte and if it is below 128 then read and
|
||||
// repeat a pair of pixels len times, otherwise read and repeat four pixels
|
||||
// (but 256 - len times)
|
||||
c = *src++;
|
||||
if (c < 128) { // pair run
|
||||
debug("debug info PAIR RUN: %d", c);
|
||||
|
||||
c1 = *src++;
|
||||
c2 = *src++;
|
||||
while (c--) {
|
||||
PUTPIX(c1);
|
||||
PUTPIX(c2);
|
||||
}
|
||||
} else { // quad run
|
||||
debug("debug info QUAD RUN: %d", c);
|
||||
c = 256 - c;
|
||||
c1 = *src++;
|
||||
c2 = *src++;
|
||||
c3 = *src++;
|
||||
c4 = *src++;
|
||||
while (c--) {
|
||||
PUTPIX(c1);
|
||||
PUTPIX(c2);
|
||||
PUTPIX(c3);
|
||||
PUTPIX(c4);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (xpos > x + bw) debug("!!!");
|
||||
if (xpos >= x + bw) {
|
||||
debug("debug info ADJUST LINE");
|
||||
xpos = x;
|
||||
ypos++;
|
||||
ADJUST_LINE;
|
||||
dst = (byte *)_surface->getPixels() + x + ypos2 * w;
|
||||
}
|
||||
}
|
||||
|
||||
_dirtyRects.clear();
|
||||
_dirtyRects.push_back(Common::Rect(x, y, bw, bh));
|
||||
|
||||
}
|
||||
|
||||
void PacoDecoder::PacoVideoTrack::copyDirtyRectsToBuffer(uint8 *dst, uint pitch) {
|
||||
for (Common::List<Common::Rect>::const_iterator it = _dirtyRects.begin(); it != _dirtyRects.end(); ++it) {
|
||||
for (int y = (*it).top; y < (*it).bottom; ++y) {
|
||||
const int x = (*it).left;
|
||||
memcpy(dst + y * pitch + x, (byte *)_surface->getBasePtr(x, y), (*it).right - x);
|
||||
}
|
||||
}
|
||||
clearDirtyRects();
|
||||
}
|
||||
|
||||
} // End of namespace Video
|
103
video/paco_decoder.h
Normal file
103
video/paco_decoder.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VIDEO_PACODECODER_H
|
||||
#define VIDEO_PACODECODER_H
|
||||
|
||||
#include "video/video_decoder.h"
|
||||
#include "common/list.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace Graphics {
|
||||
struct PixelFormat;
|
||||
struct Surface;
|
||||
}
|
||||
|
||||
namespace Video {
|
||||
|
||||
/**
|
||||
* Decoder for PACo videos.
|
||||
*
|
||||
* Video decoder used in engines:
|
||||
* - director
|
||||
*/
|
||||
class PacoDecoder : public VideoDecoder {
|
||||
public:
|
||||
PacoDecoder();
|
||||
virtual ~PacoDecoder();
|
||||
|
||||
virtual bool loadStream(Common::SeekableReadStream *stream);
|
||||
|
||||
const Common::List<Common::Rect> *getDirtyRects() const;
|
||||
void clearDirtyRects();
|
||||
void copyDirtyRectsToBuffer(uint8 *dst, uint pitch);
|
||||
|
||||
protected:
|
||||
class PacoVideoTrack : public VideoTrack {
|
||||
public:
|
||||
PacoVideoTrack(
|
||||
Common::SeekableReadStream *stream, uint16 frameRate, uint16 frameCount,
|
||||
bool hasAudio, uint16 width, uint16 height);
|
||||
~PacoVideoTrack();
|
||||
|
||||
bool endOfTrack() const;
|
||||
virtual bool isRewindable() const { return false; }
|
||||
|
||||
uint16 getWidth() const;
|
||||
uint16 getHeight() const;
|
||||
Graphics::PixelFormat getPixelFormat() const;
|
||||
int getCurFrame() const { return _curFrame; }
|
||||
int getFrameCount() const { return _frameCount; }
|
||||
uint32 getNextFrameStartTime() const { return _nextFrameStartTime; }
|
||||
virtual const Graphics::Surface *decodeNextFrame();
|
||||
virtual void handleFrame(uint32 chunkSize);
|
||||
const byte *getPalette() const { return _palette; }
|
||||
bool hasDirtyPalette() const { return false; }
|
||||
|
||||
const Common::List<Common::Rect> *getDirtyRects() const { return &_dirtyRects; }
|
||||
void clearDirtyRects() { _dirtyRects.clear(); }
|
||||
void copyDirtyRectsToBuffer(uint8 *dst, uint pitch);
|
||||
|
||||
protected:
|
||||
Common::SeekableReadStream *_fileStream;
|
||||
Graphics::Surface *_surface;
|
||||
|
||||
int _curFrame;
|
||||
|
||||
byte *_palette;
|
||||
int _frameSizes[65536]; // can be done differently?
|
||||
mutable bool _dirtyPalette;
|
||||
|
||||
uint32 _frameCount;
|
||||
uint32 _frameDelay;
|
||||
uint32 _nextFrameStartTime;
|
||||
|
||||
Common::List<Common::Rect> _dirtyRects;
|
||||
};
|
||||
};
|
||||
|
||||
} // End of namespace Video
|
||||
|
||||
#endif
|
Loading…
Add table
Add a link
Reference in a new issue