mirror of
https://github.com/libretro/scummvm.git
synced 2025-03-03 00:35:54 +00:00
added FLIC player from KoM engine module.
changes : - changed methods name to match the ones from DXAPlayer - added file read streaming - added possibiltiy to reset playback svn-id: r35068
This commit is contained in:
parent
e5d0462af6
commit
48363b80fb
264
graphics/flic_player.cpp
Normal file
264
graphics/flic_player.cpp
Normal file
@ -0,0 +1,264 @@
|
||||
/* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "flic_player.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
FlicPlayer::FlicPlayer(const char *fileName)
|
||||
: _paletteDirty(false), _offscreen(0), _currFrame(0) {
|
||||
|
||||
memset(&_flicInfo, 0, sizeof(_flicInfo));
|
||||
_fileStream.open(fileName);
|
||||
|
||||
_flicInfo.size = _fileStream.readUint32LE();
|
||||
_flicInfo.type = _fileStream.readUint16LE();
|
||||
_flicInfo.numFrames = _fileStream.readUint16LE();
|
||||
_flicInfo.width = _fileStream.readUint16LE();
|
||||
_flicInfo.height = _fileStream.readUint16LE();
|
||||
_fileStream.skip(4);
|
||||
_flicInfo.speed = _fileStream.readUint32LE();
|
||||
|
||||
_fileStream.seek(80);
|
||||
_flicInfo.offsetFrame1 = _fileStream.readUint32LE();
|
||||
_flicInfo.offsetFrame2 = _fileStream.readUint32LE();
|
||||
|
||||
// Check FLC magic number
|
||||
if (_flicInfo.type != 0xAF12) {
|
||||
error("FlicPlayer::FlicPlayer(): attempted to load non-FLC data (type = 0x%04X)", _flicInfo.type);
|
||||
}
|
||||
|
||||
_offscreen = new uint8[_flicInfo.width * _flicInfo.height];
|
||||
memset(_palette, 0, sizeof(_palette));
|
||||
|
||||
// Seek to the first frame
|
||||
_fileStream.seek(_flicInfo.offsetFrame1);
|
||||
}
|
||||
|
||||
FlicPlayer::~FlicPlayer() {
|
||||
delete[] _offscreen;
|
||||
}
|
||||
|
||||
void FlicPlayer::redraw() {
|
||||
_dirtyRects.clear();
|
||||
_dirtyRects.push_back(Common::Rect(0, 0, _flicInfo.width, _flicInfo.height));
|
||||
}
|
||||
|
||||
ChunkHeader FlicPlayer::readChunkHeader() {
|
||||
ChunkHeader head;
|
||||
head.size = _fileStream.readUint32LE();
|
||||
head.type = _fileStream.readUint16LE();
|
||||
|
||||
/* XXX: You'll want to read the rest of the chunk here as well! */
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
FrameTypeChunkHeader FlicPlayer::readFrameTypeChunkHeader(ChunkHeader chunkHead) {
|
||||
FrameTypeChunkHeader head;
|
||||
|
||||
head.header = chunkHead;
|
||||
head.numChunks = _fileStream.readUint16LE();
|
||||
head.delay = _fileStream.readUint16LE();
|
||||
head.reserved = _fileStream.readUint16LE();
|
||||
head.widthOverride = _fileStream.readUint16LE();
|
||||
head.heightOverride = _fileStream.readUint16LE();
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
void FlicPlayer::decodeByteRun(uint8 *data) {
|
||||
uint8 *ptr = (uint8 *)_offscreen;
|
||||
while((ptr - _offscreen) < (_flicInfo.width * _flicInfo.height)) {
|
||||
uint8 chunks = *data++;
|
||||
while (chunks--) {
|
||||
int8 count = *data++;
|
||||
if (count > 0) {
|
||||
memset(ptr, *data++, count);
|
||||
ptr += count;
|
||||
} else {
|
||||
uint8 copyBytes = -count;
|
||||
memcpy(ptr, data, copyBytes);
|
||||
ptr += copyBytes;
|
||||
data += copyBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
redraw();
|
||||
}
|
||||
|
||||
#define OP_PACKETCOUNT 0
|
||||
#define OP_UNDEFINED 1
|
||||
#define OP_LASTPIXEL 2
|
||||
#define OP_LINESKIPCOUNT 3
|
||||
|
||||
void FlicPlayer::decodeDeltaFLC(uint8 *data) {
|
||||
uint16 linesInChunk = READ_LE_UINT16(data); data += 2;
|
||||
uint16 currentLine = 0;
|
||||
uint16 packetCount = 0;
|
||||
|
||||
while (linesInChunk--) {
|
||||
uint16 opcode;
|
||||
|
||||
// First process all the opcodes.
|
||||
do {
|
||||
opcode = READ_LE_UINT16(data); data += 2;
|
||||
|
||||
switch ((opcode >> 14) & 3) {
|
||||
case OP_PACKETCOUNT:
|
||||
packetCount = opcode;
|
||||
break;
|
||||
case OP_UNDEFINED:
|
||||
break;
|
||||
case OP_LASTPIXEL:
|
||||
*(uint8 *)(_offscreen + (currentLine * _flicInfo.width) + (_flicInfo.width - 1)) = (opcode & 0xFF);
|
||||
_dirtyRects.push_back(Common::Rect(_flicInfo.width - 1, currentLine, _flicInfo.width, currentLine + 1));
|
||||
break;
|
||||
case OP_LINESKIPCOUNT:
|
||||
currentLine += -(int16)opcode;
|
||||
break;
|
||||
}
|
||||
} while (((opcode >> 14) & 3) != OP_PACKETCOUNT);
|
||||
|
||||
uint16 column = 0;
|
||||
|
||||
// Now interpret the RLE data
|
||||
while (packetCount--) {
|
||||
column += *data++;
|
||||
int8 rleCount = (int8)*data++;
|
||||
if (rleCount > 0) {
|
||||
memcpy((void *)(_offscreen + (currentLine * _flicInfo.width) + column), data, rleCount * 2);
|
||||
_dirtyRects.push_back(Common::Rect(column, currentLine, column + (rleCount * 2), currentLine + 1));
|
||||
data += rleCount * 2;
|
||||
column += rleCount * 2;
|
||||
} else if (rleCount < 0) {
|
||||
uint16 dataWord = *(uint16 *)data; data += 2;
|
||||
for (int i = 0; i < -(int16)rleCount; ++i) {
|
||||
WRITE_LE_UINT16(_offscreen + (currentLine * _flicInfo.width) + column + (i * 2), dataWord);
|
||||
}
|
||||
_dirtyRects.push_back(Common::Rect(column, currentLine, column + (-(int16)rleCount * 2), currentLine + 1));
|
||||
|
||||
column += (-(int16)rleCount) * 2;
|
||||
} else { // End of cutscene ?
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
currentLine++;
|
||||
}
|
||||
}
|
||||
|
||||
#define COLOR_256 4
|
||||
#define FLI_SS2 7
|
||||
#define FLI_BRUN 15
|
||||
#define PSTAMP 18
|
||||
#define FRAME_TYPE 0xF1FA
|
||||
|
||||
void FlicPlayer::decodeFrame() {
|
||||
FrameTypeChunkHeader frameHeader;
|
||||
|
||||
// Read chunk
|
||||
ChunkHeader cHeader = readChunkHeader();
|
||||
switch (cHeader.type) {
|
||||
case FRAME_TYPE:
|
||||
frameHeader = readFrameTypeChunkHeader(cHeader);
|
||||
_currFrame++;
|
||||
break;
|
||||
default:
|
||||
error("FlicPlayer::decodeFrame(): unknown main chunk type (type = 0x%02X)", cHeader.type);
|
||||
break;
|
||||
}
|
||||
|
||||
// Read subchunks
|
||||
if (cHeader.type == FRAME_TYPE) {
|
||||
for (int i = 0; i < frameHeader.numChunks; ++i) {
|
||||
cHeader = readChunkHeader();
|
||||
uint8 *data = new uint8[cHeader.size - 6];
|
||||
_fileStream.read(data, cHeader.size - 6);
|
||||
switch (cHeader.type) {
|
||||
case COLOR_256:
|
||||
setPalette(data);
|
||||
_paletteDirty = true;
|
||||
break;
|
||||
case FLI_SS2:
|
||||
decodeDeltaFLC(data);
|
||||
break;
|
||||
case FLI_BRUN:
|
||||
decodeByteRun(data);
|
||||
break;
|
||||
case PSTAMP:
|
||||
/* PSTAMP - skip for now */
|
||||
break;
|
||||
default:
|
||||
error("FlicPlayer::decodeFrame(): unknown subchunk type (type = 0x%02X)", cHeader.type);
|
||||
break;
|
||||
}
|
||||
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
|
||||
// If we just processed the ring frame, set the next frame
|
||||
if (_currFrame == _flicInfo.numFrames + 1) {
|
||||
_currFrame = 1;
|
||||
_fileStream.seek(_flicInfo.offsetFrame2);
|
||||
}
|
||||
}
|
||||
|
||||
void FlicPlayer::reset() {
|
||||
_fileStream.seek(_flicInfo.offsetFrame1);
|
||||
}
|
||||
|
||||
void FlicPlayer::setPalette(uint8 *mem) {
|
||||
uint16 numPackets = READ_LE_UINT16(mem); mem += 2;
|
||||
|
||||
if (0 == READ_LE_UINT16(mem)) { //special case
|
||||
mem += 2;
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
for (int j = 0; j < 3; ++j)
|
||||
_palette[i * 4 + j] = (mem[i * 3 + j]);
|
||||
_palette[i * 4 + 3] = 0;
|
||||
}
|
||||
} else {
|
||||
uint8 palPos = 0;
|
||||
|
||||
while (numPackets--) {
|
||||
palPos += *mem++;
|
||||
uint8 change = *mem++;
|
||||
|
||||
for (int i = 0; i < change; ++i) {
|
||||
for (int j = 0; j < 3; ++j)
|
||||
_palette[(palPos + i) * 4 + j] = (mem[i * 3 + j]);
|
||||
_palette[(palPos + i) * 4 + 3] = 0;
|
||||
}
|
||||
|
||||
palPos += change;
|
||||
mem += (change * 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Graphics
|
100
graphics/flic_player.h
Normal file
100
graphics/flic_player.h
Normal file
@ -0,0 +1,100 @@
|
||||
/* 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.
|
||||
*
|
||||
* $URL$
|
||||
* $Id$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef GRAPHICS_FLICPLAYER_H
|
||||
#define GRAPHICS_FLICPLAYER_H
|
||||
|
||||
#include "common/endian.h"
|
||||
#include "common/list.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/file.h"
|
||||
|
||||
namespace Graphics {
|
||||
|
||||
struct FlicHeader {
|
||||
uint32 size;
|
||||
uint16 type;
|
||||
uint16 numFrames;
|
||||
uint16 width;
|
||||
uint16 height;
|
||||
uint32 speed;
|
||||
uint16 offsetFrame1;
|
||||
uint16 offsetFrame2;
|
||||
};
|
||||
|
||||
struct ChunkHeader {
|
||||
uint32 size;
|
||||
uint16 type;
|
||||
};
|
||||
|
||||
struct FrameTypeChunkHeader {
|
||||
ChunkHeader header;
|
||||
uint16 numChunks;
|
||||
uint16 delay;
|
||||
uint16 reserved; // always zero
|
||||
uint16 widthOverride;
|
||||
uint16 heightOverride;
|
||||
};
|
||||
|
||||
class FlicPlayer {
|
||||
public:
|
||||
FlicPlayer(const char *fileName);
|
||||
~FlicPlayer();
|
||||
|
||||
void decodeFrame();
|
||||
int getWidth() const { return _flicInfo.width; }
|
||||
int getHeight() const { return _flicInfo.height; }
|
||||
bool hasFrames() const { return _flicInfo.numFrames > 0; }
|
||||
int getCurFrame() const { return _currFrame; }
|
||||
int getFrameCount() const { return _flicInfo.numFrames; }
|
||||
uint32 getSpeed() const { return _flicInfo.speed; }
|
||||
bool isPaletteDirty() const { return _paletteDirty; }
|
||||
const uint8 *getPalette() { _paletteDirty = false; return _palette; }
|
||||
const uint8 *getOffscreen() const { return _offscreen; }
|
||||
const Common::List<Common::Rect> *getDirtyRects() const { return &_dirtyRects; }
|
||||
void clearDirtyRects() { _dirtyRects.clear(); }
|
||||
void redraw();
|
||||
void reset();
|
||||
|
||||
protected:
|
||||
ChunkHeader readChunkHeader();
|
||||
FrameTypeChunkHeader readFrameTypeChunkHeader(ChunkHeader chunkHead);
|
||||
void decodeByteRun(uint8 *data);
|
||||
void decodeDeltaFLC(uint8 *data);
|
||||
void setPalette(uint8 *mem);
|
||||
|
||||
Common::File _fileStream;
|
||||
bool _paletteDirty;
|
||||
uint8 *_offscreen;
|
||||
uint8 _palette[256 * 4];
|
||||
FlicHeader _flicInfo;
|
||||
uint16 _currFrame;
|
||||
uint32 _lastFrameTime;
|
||||
Common::List<Common::Rect> _dirtyRects;
|
||||
};
|
||||
|
||||
} // End of namespace Graphics
|
||||
|
||||
#endif
|
@ -3,6 +3,7 @@ MODULE := graphics
|
||||
MODULE_OBJS := \
|
||||
cursorman.o \
|
||||
dxa_player.o \
|
||||
flic_player.o \
|
||||
font.o \
|
||||
fontman.o \
|
||||
fonts/consolefont.o \
|
||||
|
Loading…
x
Reference in New Issue
Block a user