DIRECTOR: Share Sprite parsing code between Frame and FilmLoopCastMember

This commit is contained in:
Scott Percival 2023-07-11 22:50:02 +08:00 committed by Eugene Sandulenko
parent f4bab7a34d
commit 889130a3fa
6 changed files with 231 additions and 333 deletions

View File

@ -29,6 +29,7 @@
#include "director/director.h"
#include "director/cast.h"
#include "director/channel.h"
#include "director/frame.h"
#include "director/movie.h"
#include "director/window.h"
#include "director/castmember/bitmap.h"
@ -111,25 +112,25 @@ Common::Array<Channel> *FilmLoopCastMember::getSubChannels(Common::Rect &bbox, C
return &_subchannels;
}
void FilmLoopCastMember::loadFilmLoopData(Common::SeekableReadStreamEndian &stream) {
void FilmLoopCastMember::loadFilmLoopDataD2(Common::SeekableReadStreamEndian &stream) {
_initialRect = Common::Rect();
_frames.clear();
uint32 size = stream.readUint32BE();
if (debugChannelSet(5, kDebugLoading)) {
debugC(5, kDebugLoading, "loadFilmLoopData: SCVW body:");
debugC(5, kDebugLoading, "loadFilmLoopDataD2: SCVW body:");
uint32 pos = stream.pos();
stream.seek(0);
stream.hexdump(size);
stream.seek(pos);
}
uint16 channelSize = 16;
uint16 channelSize = kSprChannelSizeD2;
FilmLoopFrame newFrame;
while (stream.pos() < size) {
uint16 frameSize = stream.readUint16BE() - 2;
if (debugChannelSet(5, kDebugLoading)) {
debugC(5, kDebugLoading, "loadFilmLoopData: Frame entry:");
debugC(5, kDebugLoading, "loadFilmLoopDataD2: Frame entry:");
stream.hexdump(frameSize);
}
@ -137,87 +138,49 @@ void FilmLoopCastMember::loadFilmLoopData(Common::SeekableReadStreamEndian &stre
int msgWidth = stream.readByte() * 2;
int order = stream.readByte() * 2 - 0x20;
frameSize -= 2;
debugC(8, kDebugLoading, "loadFilmLoopData: Message: msgWidth %d, order %d", msgWidth, order);
int channel = (order / channelSize) - 1;
int channelOffset = order % channelSize;
debugC(8, kDebugLoading, "loadFilmLoopDataD2: Message: msgWidth %d, channel %d, channelOffset %d", msgWidth, channel, channelOffset);
if (debugChannelSet(8, kDebugLoading)) {
stream.hexdump(msgWidth);
}
int fieldPosition = order;
int finishPosition = order + msgWidth;
while (fieldPosition < finishPosition) {
int channel = (fieldPosition / channelSize);
int channelOffset = fieldPosition % channelSize;
uint16 segSize = msgWidth;
uint16 nextStart = (channel + 1) * kSprChannelSizeD2;
while (segSize > 0) {
Sprite sprite(nullptr);
sprite._movie = g_director->getCurrentMovie();
if (newFrame.sprites.contains(channel)) {
sprite = newFrame.sprites.getVal(channel);
}
sprite._spriteType = kCastMemberSprite;
sprite._puppet = 1;
sprite._stretch = 1;
switch (channelOffset) {
case kSpritePositionUnk1:
stream.readByte();
fieldPosition++;
break;
case kSpritePositionEnabled:
sprite._enabled = stream.readByte() != 0;
fieldPosition++;
break;
case kSpritePositionUnk2:
stream.readUint16BE();
fieldPosition += 2;
break;
case kSpritePositionFlags:
sprite._thickness = stream.readByte();
sprite._inkData = stream.readByte();
sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
if (sprite._inkData & 0x40)
sprite._trails = 1;
else
sprite._trails = 0;
fieldPosition += 2;
break;
case kSpritePositionCastId:
sprite.setCast(CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB));
fieldPosition += 2;
break;
case kSpritePositionY:
sprite._startPoint.y = stream.readUint16();
fieldPosition += 2;
break;
case kSpritePositionX:
sprite._startPoint.x = stream.readUint16();
fieldPosition += 2;
break;
case kSpritePositionWidth:
sprite._width = stream.readUint16();
fieldPosition += 2;
break;
case kSpritePositionHeight:
sprite._height = stream.readUint16();
fieldPosition += 2;
break;
default:
stream.readUint16BE();
fieldPosition += 2;
break;
}
uint16 needSize = MIN((uint16)(nextStart - channelOffset), segSize);
int startPosition = stream.pos() - channelOffset;
int finishPosition = stream.pos() + needSize;
readSpriteDataD2(stream, sprite, startPosition, finishPosition);
newFrame.sprites.setVal(channel, sprite);
segSize -= needSize;
channel += 1;
channelOffset = 0;
nextStart += kSprChannelSizeD2;
}
frameSize -= msgWidth;
}
for (auto &s : newFrame.sprites) {
debugC(5, kDebugLoading, "loadFilmLoopData: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
debugC(5, kDebugLoading, "loadFilmLoopDataD2: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
s._value._castId.asString().c_str(), s._value._startPoint.x, s._value._startPoint.y,
s._value._width, s._value._height);
s._value.setCast(s._value._castId);
Common::Point topLeft = s._value._startPoint;
if (s._value._cast) {
topLeft -= s._value._cast->getRegistrationOffset(s._value._width, s._value._height);
@ -235,23 +198,23 @@ void FilmLoopCastMember::loadFilmLoopData(Common::SeekableReadStreamEndian &stre
_initialRect.extend(spriteBbox);
}
}
debugC(8, kDebugLoading, "loadFilmLoopData: New bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
debugC(8, kDebugLoading, "loadFilmLoopDataD2: New bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
}
_frames.push_back(newFrame);
}
debugC(5, kDebugLoading, "loadFilmLoopData: Full bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
debugC(5, kDebugLoading, "loadFilmLoopDataD2: Full bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
}
void FilmLoopCastMember::loadFilmLoopDataV4(Common::SeekableReadStreamEndian &stream) {
void FilmLoopCastMember::loadFilmLoopDataD4(Common::SeekableReadStreamEndian &stream) {
_initialRect = Common::Rect();
_frames.clear();
uint32 size = stream.readUint32BE();
if (debugChannelSet(5, kDebugLoading)) {
debugC(5, kDebugLoading, "loadFilmLoopDataV4: SCVW body:");
debugC(5, kDebugLoading, "loadFilmLoopDataD4: SCVW body:");
uint32 pos = stream.pos();
stream.seek(0);
stream.hexdump(size);
@ -259,11 +222,12 @@ void FilmLoopCastMember::loadFilmLoopDataV4(Common::SeekableReadStreamEndian &st
}
uint32 framesOffset = stream.readUint32BE();
if (debugChannelSet(5, kDebugLoading)) {
debugC(5, kDebugLoading, "loadFilmLoopDataV4: SCVW header:");
debugC(5, kDebugLoading, "loadFilmLoopDataD4: SCVW header:");
stream.hexdump(framesOffset - 8);
}
stream.skip(6);
uint16 channelSize = stream.readUint16BE(); // should be 20!
uint16 channelSize = kSprChannelSizeD4;
stream.readUint16BE(); // should be kSprChannelSizeD4 = 20!
stream.skip(framesOffset - 16);
FilmLoopFrame newFrame;
@ -271,7 +235,7 @@ void FilmLoopCastMember::loadFilmLoopDataV4(Common::SeekableReadStreamEndian &st
while (stream.pos() < size) {
uint16 frameSize = stream.readUint16BE() - 2;
if (debugChannelSet(5, kDebugLoading)) {
debugC(5, kDebugLoading, "loadFilmLoopDataV4: Frame entry:");
debugC(5, kDebugLoading, "loadFilmLoopDataD4: Frame entry:");
stream.hexdump(frameSize);
}
@ -283,93 +247,54 @@ void FilmLoopCastMember::loadFilmLoopDataV4(Common::SeekableReadStreamEndian &st
int channel = (order / channelSize) - 1;
int channelOffset = order % channelSize;
Sprite sprite(nullptr);
sprite._movie = g_director->getCurrentMovie();
if (newFrame.sprites.contains(channel)) {
sprite = newFrame.sprites.getVal(channel);
}
debugC(8, kDebugLoading, "loadFilmLoopDataV4: Message: msgWidth %d, channel %d, channelOffset %d", msgWidth, channel, channelOffset);
debugC(8, kDebugLoading, "loadFilmLoopDataD4: Message: msgWidth %d, channel %d, channelOffset %d", msgWidth, channel, channelOffset);
if (debugChannelSet(8, kDebugLoading)) {
stream.hexdump(msgWidth);
}
sprite._puppet = 1;
sprite._stretch = 1;
int fieldPosition = channelOffset;
int finishPosition = channelOffset + msgWidth;
while (fieldPosition < finishPosition) {
switch (fieldPosition) {
case kSpritePositionUnk1:
stream.readByte();
fieldPosition++;
break;
case kSpritePositionEnabled:
sprite._enabled = stream.readByte() != 0;
fieldPosition++;
break;
case kSpritePositionUnk2:
stream.readUint16BE();
fieldPosition += 2;
break;
case kSpritePositionFlags:
sprite._thickness = stream.readByte();
sprite._inkData = stream.readByte();
sprite._ink = static_cast<InkType>(sprite._inkData & 0x3f);
uint16 segSize = msgWidth;
uint16 nextStart = (channel + 1) * kSprChannelSizeD4;
if (sprite._inkData & 0x40)
sprite._trails = 1;
else
sprite._trails = 0;
fieldPosition += 2;
break;
case kSpritePositionCastId:
sprite.setCast(CastMemberID(stream.readUint16(), DEFAULT_CAST_LIB));
fieldPosition += 2;
break;
case kSpritePositionY:
sprite._startPoint.y = stream.readUint16();
fieldPosition += 2;
break;
case kSpritePositionX:
sprite._startPoint.x = stream.readUint16();
fieldPosition += 2;
break;
case kSpritePositionWidth:
sprite._width = stream.readUint16();
fieldPosition += 2;
break;
case kSpritePositionHeight:
sprite._height = stream.readUint16();
fieldPosition += 2;
break;
default:
stream.readUint16BE();
fieldPosition += 2;
break;
while (segSize > 0) {
Sprite sprite(nullptr);
sprite._movie = g_director->getCurrentMovie();
if (newFrame.sprites.contains(channel)) {
sprite = newFrame.sprites.getVal(channel);
}
sprite._puppet = 1;
sprite._stretch = 1;
uint16 needSize = MIN((uint16)(nextStart - channelOffset), segSize);
int startPosition = stream.pos() - channelOffset;
int finishPosition = stream.pos() + needSize;
readSpriteDataD4(stream, sprite, startPosition, finishPosition);
newFrame.sprites.setVal(channel, sprite);
segSize -= needSize;
channel += 1;
channelOffset = 0;
nextStart += kSprChannelSizeD2;
}
frameSize -= msgWidth;
newFrame.sprites.setVal(channel, sprite);
}
for (auto &s : newFrame.sprites) {
debugC(5, kDebugLoading, "loadFilmLoopDataV4: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
debugC(5, kDebugLoading, "loadFilmLoopDataD4: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
s._value._castId.asString().c_str(), s._value._startPoint.x, s._value._startPoint.y,
s._value._width, s._value._height);
if (s._key == -1) {
debugC(5, kDebugLoading, "loadFilmLoopDataV4: Skipping channel -1");
debugC(5, kDebugLoading, "loadFilmLoopDataD4: Skipping channel -1");
if (s._value._startPoint.x != 0 || s._value._startPoint.y != 0 || s._value._width != 0 ||
(s._value._height != -256 && s._value._height != 0))
warning("BUILDBOT: loadFilmLoopDataV4: Malformed VWSC resource: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
warning("BUILDBOT: loadFilmLoopDataD4: Malformed VWSC resource: Sprite: channel %d, castId %s, bbox %d %d %d %d", s._key,
s._value._castId.asString().c_str(), s._value._startPoint.x, s._value._startPoint.y,
s._value._width, s._value._height);
continue;
}
s._value.setCast(s._value._castId);
Common::Point topLeft = s._value._startPoint;
if (s._value._cast) {
topLeft -= s._value._cast->getRegistrationOffset(s._value._width, s._value._height);
@ -387,14 +312,14 @@ void FilmLoopCastMember::loadFilmLoopDataV4(Common::SeekableReadStreamEndian &st
_initialRect.extend(spriteBbox);
}
}
debugC(8, kDebugLoading, "loadFilmLoopDataV4: New bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
debugC(8, kDebugLoading, "loadFilmLoopDataD4: New bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
}
_frames.push_back(newFrame);
}
debugC(5, kDebugLoading, "loadFilmLoopDataV4: Full bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
debugC(5, kDebugLoading, "loadFilmLoopDataD4: Full bounding box: %d %d %d %d", _initialRect.left, _initialRect.top, _initialRect.width(), _initialRect.height());
}
@ -421,7 +346,7 @@ void FilmLoopCastMember::load() {
Common::SeekableReadStreamEndian *loop = _cast->getResource(tag, filmLoopId);
if (loop) {
debugC(2, kDebugLoading, "****** Loading '%s' id: %d, %d bytes", tag2str(tag), filmLoopId, (int)loop->size());
loadFilmLoopData(*loop);
loadFilmLoopDataD2(*loop);
delete loop;
} else {
warning("FilmLoopCastMember::load(): Film loop not found");
@ -433,7 +358,7 @@ void FilmLoopCastMember::load() {
Common::SeekableReadStreamEndian *loop = _cast->getResource(tag, filmLoopId);
if (loop) {
debugC(2, kDebugLoading, "****** Loading '%s' id: %d, %d bytes", tag2str(tag), filmLoopId, (int)loop->size());
loadFilmLoopDataV4(*loop);
loadFilmLoopDataD4(*loop);
delete loop;
} else {
warning("FilmLoopCastMember::load(): Film loop not found");

View File

@ -42,8 +42,10 @@ public:
Common::Array<Channel> *getSubChannels(Common::Rect &bbox, Channel *channel);
void loadFilmLoopData(Common::SeekableReadStreamEndian &stream);
void loadFilmLoopDataV4(Common::SeekableReadStreamEndian &stream);
void loadFilmLoopDataD2(Common::SeekableReadStreamEndian &stream);
void loadFilmLoopDataD4(Common::SeekableReadStreamEndian &stream);
void loadFilmLoopDataD5(Common::SeekableReadStreamEndian &stream);
void loadFilmLoopDataD6(Common::SeekableReadStreamEndian &stream);
Common::String formatInfo() override;

View File

@ -139,33 +139,34 @@ void Frame::readChannel(Common::MemoryReadStreamEndian &stream, uint16 offset, u
*
**************************/
enum {
kMainChannelSizeD2 = 32,
kSprChannelSizeD2 = 16
};
void Frame::readChannelD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
if (offset < kMainChannelSizeD2) {
uint16 needSize = MIN(size, (uint16)(kMainChannelSizeD2 - offset));
readMainChannelsD2(stream, offset, needSize);
size -= needSize;
offset += needSize;
}
if (offset >= kMainChannelSizeD2) {
if (size <= kSprChannelSizeD2)
readSpriteD2(stream, offset, size);
else {
// read > 1 sprites channel
while (size > kSprChannelSizeD2) {
byte spritePosition = (offset - kMainChannelSizeD2) / kSprChannelSizeD2;
uint16 nextStart = (spritePosition + 1) * kSprChannelSizeD2 + kMainChannelSizeD2;
uint16 needSize = nextStart - offset;
readSpriteD2(stream, offset, needSize);
offset += needSize;
size -= needSize;
}
readSpriteD2(stream, offset, size);
byte spritePosition = (offset - kMainChannelSizeD2) / kSprChannelSizeD2;
uint16 nextStart = (spritePosition + 1) * kSprChannelSizeD2 + kMainChannelSizeD2;
while (size > 0) {
uint16 needSize = MIN((uint16)(nextStart - offset), size);
readSpriteD2(stream, offset, needSize);
offset += needSize;
size -= needSize;
nextStart += kSprChannelSizeD2;
}
} else {
readMainChannelsD2(stream, offset, size);
}
}
void Frame::readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
if (debugChannelSet(8, kDebugLoading)) {
debugC(8, kDebugLoading, "Frame::readMainChannelsD2(): %d byte header", size);
stream.hexdump(size);
}
uint32 initPos = stream.pos();
uint32 finishPosition = initPos + size;
byte unk[6];
@ -260,8 +261,6 @@ void Frame::readMainChannelsD2(Common::MemoryReadStreamEndian &stream, uint16 of
debugC(8, kDebugLoading, "Frame::readMainChannelsD2(): STUB: unk1: %02x %02x %02x %02x %02x %02x", unk[0],
unk[1], unk[2], unk[3], unk[4], unk[5]);
break;
case 32:
break;
default:
// This means that a `case` label has to be split at this position
error("Frame::readMainChannelsD2(): Miscomputed field position: %ld", stream.pos() - initPos + offset);
@ -301,8 +300,22 @@ void Frame::readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset,
uint32 initPos = stream.pos();
uint32 finishPosition = initPos + size;
readSpriteDataD2(stream, sprite, initPos - fieldPosition, finishPosition);
if (stream.pos() > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
error("Frame::readSpriteD2(): Read %ld extra bytes", stream.pos() - finishPosition);
}
// Sometimes removed sprites leave garbage in the channel
// We set it to zero, so then could skip
if (sprite._width <= 0 || sprite._height <= 0)
sprite._width = sprite._height = 0;
}
void readSpriteDataD2(Common::SeekableReadStreamEndian &stream, Sprite &sprite, uint32 startPosition, uint32 finishPosition) {
while (stream.pos() < finishPosition) {
switch (stream.pos() - initPos + fieldPosition) {
switch (stream.pos() - startPosition) {
case 0:
sprite._scriptId = CastMemberID(stream.readByte(), DEFAULT_CAST_LIB);
break;
@ -313,11 +326,11 @@ void Frame::readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset,
break;
case 2:
// Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
sprite._foreColor = _vm->transformColor((128 + stream.readByte()) & 0xff);
sprite._foreColor = g_director->transformColor((128 + stream.readByte()) & 0xff);
break;
case 3:
// Normalize D2 and D3 colors from -128 ... 127 to 0 ... 255.
sprite._backColor = _vm->transformColor((128 + stream.readByte()) & 0xff);
sprite._backColor = g_director->transformColor((128 + stream.readByte()) & 0xff);
break;
case 4:
sprite._thickness = stream.readByte();
@ -351,26 +364,12 @@ void Frame::readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset,
case 14:
sprite._width = (int16)stream.readUint16();
break;
case 16:
// end of channel, go to next sprite channel
readSpriteD2(stream, spriteStart + kSprChannelSizeD2, finishPosition - stream.pos());
fieldPosition = finishPosition;
break;
default:
// This means that a `case` label has to be split at this position
error("Frame::readSpriteD2(): Miscomputed field position: %ld", stream.pos() - initPos + fieldPosition);
error("readSpriteDataD2(): Miscomputed field position: %ld", stream.pos() - startPosition);
}
}
if (stream.pos() > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
error("Frame::readSpriteD2(): Read %ld extra bytes", stream.pos() - finishPosition);
}
// Sometimes removed sprites leave garbage in the channel
// We set it to zero, so then could skip
if (sprite._width <= 0 || sprite._height <= 0)
sprite._width = sprite._height = 0;
}
@ -380,37 +379,33 @@ void Frame::readSpriteD2(Common::MemoryReadStreamEndian &stream, uint16 offset,
*
**************************/
enum {
kMainChannelSizeD4 = 40,
kSprChannelSizeD4 = 20
};
void Frame::readChannelD4(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
// 40 bytes header
if (offset < kMainChannelSizeD4) {
uint16 needSize = MIN(size, (uint16)(kMainChannelSizeD4 - offset));
readMainChannelsD4(stream, offset, needSize);
size -= needSize;
offset += needSize;
}
if (offset >= kMainChannelSizeD4) {
if (size <= kSprChannelSizeD4)
readSpriteD4(stream, offset, size);
else {
// read > 1 sprites channel
while (size > kSprChannelSizeD4) {
byte spritePosition = (offset - kMainChannelSizeD4) / kSprChannelSizeD4;
uint16 nextStart = (spritePosition + 1) * kSprChannelSizeD4 + kMainChannelSizeD4;
uint16 needSize = nextStart - offset;
readSpriteD4(stream, offset, needSize);
offset += needSize;
size -= needSize;
}
readSpriteD4(stream, offset, size);
byte spritePosition = (offset - kMainChannelSizeD4) / kSprChannelSizeD4;
uint16 nextStart = (spritePosition + 1) * kSprChannelSizeD4 + kMainChannelSizeD4;
while (size > 0) {
uint16 needSize = MIN((uint16)(nextStart - offset), size);
readSpriteD4(stream, offset, needSize);
offset += needSize;
size -= needSize;
nextStart += kSprChannelSizeD4;
}
} else {
readMainChannelsD4(stream, offset, size);
}
}
void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
if (debugChannelSet(8, kDebugLoading)) {
debugC(8, kDebugLoading, "Frame::readMainChannelsD4(): 40 byte header");
stream.hexdump(kMainChannelSizeD4);
debugC(8, kDebugLoading, "Frame::readMainChannelsD4(): %d byte header", size);
stream.hexdump(size);
}
uint32 initPos = stream.pos();
@ -541,8 +536,6 @@ void Frame::readMainChannelsD4(Common::MemoryReadStreamEndian &stream, uint16 of
if (unk1)
warning("Frame::readMainChannelsD4(): STUB: unk5: 0x%02x", unk1);
break;
case 40:
break;
default:
// This means that a `case` label has to be split at this position
error("Frame::readMainChannelsD4(): Miscomputed field position: %ld", stream.pos() - initPos + offset);
@ -582,8 +575,22 @@ void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset,
uint32 initPos = stream.pos();
uint32 finishPosition = initPos + size;
readSpriteDataD4(stream, sprite, initPos - fieldPosition, finishPosition);
if (stream.pos() > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
error("Frame::readSpriteD4(): Read %ld extra bytes", stream.pos() - finishPosition);
}
// Sometimes removed sprites leave garbage in the channel
// We set it to zero, so then could skip
if (sprite._width <= 0 || sprite._height <= 0)
sprite._width = sprite._height = 0;
}
void readSpriteDataD4(Common::SeekableReadStreamEndian &stream, Sprite &sprite, uint32 startPosition, uint32 finishPosition) {
while (stream.pos() < finishPosition) {
switch (stream.pos() - initPos + fieldPosition) {
switch (stream.pos() - startPosition) {
case 0:
sprite._scriptId = CastMemberID(stream.readByte(), DEFAULT_CAST_LIB);
break;
@ -593,10 +600,10 @@ void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset,
sprite._enabled = sprite._spriteType != kInactiveSprite;
break;
case 2:
sprite._foreColor = _vm->transformColor((uint8)stream.readByte());
sprite._foreColor = g_director->transformColor((uint8)stream.readByte());
break;
case 3:
sprite._backColor = _vm->transformColor((uint8)stream.readByte());
sprite._backColor = g_director->transformColor((uint8)stream.readByte());
break;
case 4:
sprite._thickness = stream.readByte();
@ -648,26 +655,11 @@ void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset,
case 19:
sprite._blendAmount = stream.readByte();
break;
case 20:
// end of channel, go to next sprite channel
readSpriteD4(stream, spriteStart + kSprChannelSizeD4, finishPosition - stream.pos());
fieldPosition = finishPosition;
break;
default:
// This means that a `case` label has to be split at this position
error("Frame::readSpriteD4(): Miscomputed field position: %ld", stream.pos() - initPos + fieldPosition);
error("readSpriteDataD4(): Miscomputed field position: %ld", stream.pos() - startPosition);
}
}
if (stream.pos() > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
error("Frame::readMainChannelsD4(): Read %ld extra bytes", stream.pos() - finishPosition);
}
// Sometimes removed sprites leave garbage in the channel
// We set it to zero, so then could skip
if (sprite._width <= 0 || sprite._height <= 0)
sprite._width = sprite._height = 0;
}
/**************************
@ -676,37 +668,33 @@ void Frame::readSpriteD4(Common::MemoryReadStreamEndian &stream, uint16 offset,
*
**************************/
enum {
kMainChannelSizeD5 = 48,
kSprChannelSizeD5 = 24
};
void Frame::readChannelD5(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
// 48 bytes header
if (offset < kMainChannelSizeD5) {
uint16 needSize = MIN(size, (uint16)(kMainChannelSizeD5 - offset));
readMainChannelsD5(stream, offset, needSize);
size -= needSize;
offset += needSize;
}
if (offset >= kMainChannelSizeD5) {
if (size <= kSprChannelSizeD5)
readSpriteD5(stream, offset, size);
else {
// read > 1 sprites channel
while (size > kSprChannelSizeD5) {
byte spritePosition = (offset - kMainChannelSizeD5) / kSprChannelSizeD5;
uint16 nextStart = (spritePosition + 1) * kSprChannelSizeD5 + kMainChannelSizeD5;
uint16 needSize = nextStart - offset;
readSpriteD5(stream, offset, needSize);
offset += needSize;
size -= needSize;
}
readSpriteD5(stream, offset, size);
byte spritePosition = (offset - kMainChannelSizeD5) / kSprChannelSizeD5;
uint16 nextStart = (spritePosition + 1) * kSprChannelSizeD5 + kMainChannelSizeD5;
while (size > 0) {
uint16 needSize = MIN((uint16)(nextStart - offset), size);
readSpriteD5(stream, offset, needSize);
offset += needSize;
size -= needSize;
nextStart += kSprChannelSizeD5;
}
} else {
readMainChannelsD5(stream, offset, size);
}
}
void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
if (debugChannelSet(8, kDebugLoading)) {
debugC(8, kDebugLoading, "Frame::readMainChannelsD5(): 40 byte header");
stream.hexdump(kMainChannelSizeD4);
debugC(8, kDebugLoading, "Frame::readMainChannelsD5(): %d byte header", size);
stream.hexdump(size);
}
uint32 initPos = stream.pos();
@ -806,8 +794,6 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
warning("Frame::readMainChannelsD5(): STUB: unk4: %s", s.c_str());
}
break;
case 48:
break;
default:
// This means that a `case` label has to be split at this position
error("Frame::readMainChannelsD5(): Miscomputed field position: %ld", stream.pos() - initPos + offset);
@ -817,7 +803,7 @@ void Frame::readMainChannelsD5(Common::MemoryReadStreamEndian &stream, uint16 of
if (stream.pos() > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
error("Frame::readMainChannelsD4(): Read %ld extra bytes", stream.pos() - finishPosition);
error("Frame::readMainChannelsD5(): Read %ld extra bytes", stream.pos() - finishPosition);
}
_transChunkSize = CLIP<byte>(_transChunkSize, 0, 128);
@ -847,8 +833,22 @@ void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset,
uint32 initPos = stream.pos();
uint32 finishPosition = initPos + size;
readSpriteDataD5(stream, sprite, initPos - fieldPosition, finishPosition);
if (fieldPosition > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
error("Frame::readSpriteD5(): Read %ld extra bytes", stream.pos() - finishPosition);
}
// Sometimes removed sprites leave garbage in the channel
// We set it to zero, so then could skip
if (sprite._width <= 0 || sprite._height <= 0)
sprite._width = sprite._height = 0;
}
void readSpriteDataD5(Common::SeekableReadStreamEndian &stream, Sprite &sprite, uint32 startPosition, uint32 finishPosition) {
while (stream.pos() < finishPosition) {
switch (stream.pos() - initPos + fieldPosition) {
switch (stream.pos() - startPosition) {
case 0:
sprite._spriteType = (SpriteType)stream.readByte();
break;
@ -885,10 +885,10 @@ void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset,
}
break;
case 10:
sprite._foreColor = _vm->transformColor((uint8)stream.readByte());
sprite._foreColor = g_director->transformColor((uint8)stream.readByte());
break;
case 11:
sprite._backColor = _vm->transformColor((uint8)stream.readByte());
sprite._backColor = g_director->transformColor((uint8)stream.readByte());
break;
case 12:
sprite._startPoint.y = (int16)stream.readUint16();
@ -923,26 +923,12 @@ void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset,
case 23:
(void)stream.readByte(); // unused
break;
case 24:
// end of channel, go to next sprite channel
readSpriteD5(stream, spriteStart + kSprChannelSizeD5, finishPosition - stream.pos());
fieldPosition = finishPosition;
break;
default:
// This means that a `case` label has to be split at this position
error("Frame::readSpriteD2(): Miscomputed field position: %ld", stream.pos() - initPos + fieldPosition);
error("readSpriteDataD5(): Miscomputed field position: %ld", stream.pos() - startPosition);
}
}
if (fieldPosition > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
error("Frame::readMainChannelsD4(): Read %ld extra bytes", stream.pos() - finishPosition);
}
// Sometimes removed sprites leave garbage in the channel
// We set it to zero, so then could skip
if (sprite._width <= 0 || sprite._height <= 0)
sprite._width = sprite._height = 0;
}
/**************************
@ -951,34 +937,34 @@ void Frame::readSpriteD5(Common::MemoryReadStreamEndian &stream, uint16 offset,
*
**************************/
enum {
kMainChannelSizeD6 = 48,
kSprChannelSizeD6 = 24
};
void Frame::readChannelD6(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
// 48 bytes header
if (offset < kMainChannelSizeD6) {
uint16 needSize = MIN(size, (uint16)(kMainChannelSizeD6 - offset));
readMainChannelsD6(stream, offset, needSize);
size -= needSize;
offset += needSize;
}
if (offset >= kMainChannelSizeD6) {
if (size <= kSprChannelSizeD6)
readSpriteD6(stream, offset, size);
else {
// read > 1 sprites channel
while (size > kSprChannelSizeD6) {
byte spritePosition = (offset - kMainChannelSizeD6) / kSprChannelSizeD6;
uint16 nextStart = (spritePosition + 1) * kSprChannelSizeD6 + kMainChannelSizeD6;
uint16 needSize = nextStart - offset;
readSpriteD6(stream, offset, needSize);
offset += needSize;
size -= needSize;
}
readSpriteD6(stream, offset, size);
byte spritePosition = (offset - kMainChannelSizeD6) / kSprChannelSizeD6;
uint16 nextStart = (spritePosition + 1) * kSprChannelSizeD6 + kMainChannelSizeD6;
while (size > 0) {
uint16 needSize = MIN((uint16)(nextStart - offset), size);
readSpriteD6(stream, offset, needSize);
offset += needSize;
size -= needSize;
nextStart += kSprChannelSizeD6;
}
} else {
readMainChannelsD6(stream, offset, size);
}
}
void Frame::readMainChannelsD6(Common::MemoryReadStreamEndian &stream, uint16 offset, uint16 size) {
if (debugChannelSet(8, kDebugLoading)) {
debugC(8, kDebugLoading, "Frame::readMainChannelsD6(): %d byte header", size);
stream.hexdump(size);
}
error("Frame::readMainChannelsD6(): Miscomputed field position: %d", offset);
}
@ -1005,8 +991,22 @@ void Frame::readSpriteD6(Common::MemoryReadStreamEndian &stream, uint16 offset,
uint32 initPos = stream.pos();
uint32 finishPosition = initPos + size;
readSpriteDataD6(stream, sprite, initPos - fieldPosition, finishPosition);
if (stream.pos() > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
error("Frame::readSpriteD6(): Read %ld extra bytes", stream.pos() - finishPosition);
}
// Sometimes removed sprites leave garbage in the channel
// We set it to zero, so then could skip
if (sprite._width <= 0 || sprite._height <= 0)
sprite._width = sprite._height = 0;
}
void readSpriteDataD6(Common::SeekableReadStreamEndian &stream, Sprite &sprite, uint32 startPosition, uint32 finishPosition) {
while (stream.pos() < finishPosition) {
switch (stream.pos() - initPos + fieldPosition) {
switch (stream.pos() - startPosition) {
case 0:
sprite._spriteType = (SpriteType)stream.readByte();
break;
@ -1021,10 +1021,10 @@ void Frame::readSpriteD6(Common::MemoryReadStreamEndian &stream, uint16 offset,
break;
case 2:
sprite._foreColor = _vm->transformColor((uint8)stream.readByte());
sprite._foreColor = g_director->transformColor((uint8)stream.readByte());
break;
case 3:
sprite._backColor = _vm->transformColor((uint8)stream.readByte());
sprite._backColor = g_director->transformColor((uint8)stream.readByte());
break;
case 4: {
uint16 castLib = stream.readUint16();
@ -1071,26 +1071,11 @@ void Frame::readSpriteD6(Common::MemoryReadStreamEndian &stream, uint16 offset,
case 23:
(void)stream.readByte(); // unused
break;
case 24:
// end of channel, go to next sprite channel
readSpriteD6(stream, spriteStart + kSprChannelSizeD6, finishPosition - stream.pos());
fieldPosition = finishPosition;
break;
default:
// This means that a `case` label has to be split at this position
error("Frame::readSpriteD2(): Miscomputed field position: %ld", stream.pos() - initPos + fieldPosition);
error("readSpriteDataD6(): Miscomputed field position: %ld", stream.pos() - startPosition);
}
}
if (stream.pos() > finishPosition) {
// This means that the relevant `case` label reads too many bytes and must be split
error("Frame::readMainChannelsD4(): Read %ld extra bytes", stream.pos() - finishPosition);
}
// Sometimes removed sprites leave garbage in the channel
// We set it to zero, so then could skip
if (sprite._width <= 0 || sprite._height <= 0)
sprite._width = sprite._height = 0;
}
Common::String Frame::formatChannelInfo() {

View File

@ -43,7 +43,15 @@ class Sprite;
class TextCastMember;
enum {
kChannelDataSize = (25 * 50)
kChannelDataSize = (25 * 50),
kMainChannelSizeD2 = 32,
kSprChannelSizeD2 = 16,
kMainChannelSizeD4 = 40,
kSprChannelSizeD4 = 20,
kMainChannelSizeD5 = 48,
kSprChannelSizeD5 = 24,
kMainChannelSizeD6 = 48,
kSprChannelSizeD6 = 24
};
struct PaletteInfo {
@ -154,6 +162,11 @@ public:
DirectorEngine *_vm;
};
void readSpriteDataD2(Common::SeekableReadStreamEndian &stream, Sprite &sprite, uint32 startPosition, uint32 finishPosition);
void readSpriteDataD4(Common::SeekableReadStreamEndian &stream, Sprite &sprite, uint32 startPosition, uint32 finishPosition);
void readSpriteDataD5(Common::SeekableReadStreamEndian &stream, Sprite &sprite, uint32 startPosition, uint32 finishPosition);
void readSpriteDataD6(Common::SeekableReadStreamEndian &stream, Sprite &sprite, uint32 startPosition, uint32 finishPosition);
} // End of namespace Director
#endif

View File

@ -1398,8 +1398,8 @@ void Score::loadFrames(Common::SeekableReadStreamEndian &stream, uint16 version)
_framesStream->readUint16(); // Skip
}
warning("STUB: Score::loadFrames. frame1Offset: %x numFrames: %x version: %x spriteRecordSize: %x numChannels: %x numChannelsDisplayed: %x",
frame1Offset, _numFrames, _framesVersion, spriteRecordSize, _numChannels, _numChannelsDisplayed);
warning("STUB: Score::loadFrames(): frame1Offset: %x, version: %x, spriteRecordSize: %x, numChannels: %x, numChannelsDisplayed: %x",
frame1Offset, _framesVersion, spriteRecordSize, _numChannels, _numChannelsDisplayed);
// Unknown, some bytes - constant (refer to contuinity).
}

View File

@ -29,33 +29,6 @@ class BitmapCastMember;
class ShapeCastMember;
class TextCastMember;
enum SpritePosition {
kSpritePositionUnk1 = 0,
kSpritePositionEnabled = 1,
kSpritePositionUnk2 = 2,
kSpritePositionFlags = 4,
kSpritePositionCastId = 6,
kSpritePositionY = 8,
kSpritePositionX = 10,
kSpritePositionHeight = 12,
kSpritePositionWidth = 14
};
enum MainChannelsPosition {
kScriptIdPosition = 0,
kSoundType1Position,
kTransFlagsPosition,
kTransChunkSizePosition,
kTempoPosition,
kTransTypePosition,
kSound1Position,
kSkipFrameFlagsPosition = 8,
kBlendPosition,
kSound2Position,
kSound2TypePosition = 11,
kPalettePosition = 15
};
class Sprite {
public:
Sprite(Frame *frame = nullptr);