mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-15 14:18:37 +00:00
rewritten animation loading
removed animation warnings during game process svn-id: r18377
This commit is contained in:
parent
cf80e36831
commit
d9a38f6f55
@ -34,232 +34,189 @@
|
||||
namespace Saga {
|
||||
|
||||
Anim::Anim(SagaEngine *vm) : _vm(vm) {
|
||||
int i;
|
||||
|
||||
_anim_limit = MAX_ANIMATIONS;
|
||||
_anim_count = 0;
|
||||
uint16 i;
|
||||
|
||||
for (i = 0; i < MAX_ANIMATIONS; i++)
|
||||
_anim_tbl[i] = NULL;
|
||||
|
||||
_initialized = true;
|
||||
_animations[i] = NULL;
|
||||
}
|
||||
|
||||
Anim::~Anim(void) {
|
||||
uint16 i;
|
||||
|
||||
for (i = 0; i < MAX_ANIMATIONS; i++)
|
||||
free(_anim_tbl[i]);
|
||||
|
||||
_initialized = false;
|
||||
reset();
|
||||
}
|
||||
|
||||
int Anim::load(const byte *anim_resdata, size_t anim_resdata_len, uint16 *anim_id_p) {
|
||||
ANIMATION *new_anim;
|
||||
ANIMATION_HEADER ah;
|
||||
|
||||
uint16 anim_id = 0;
|
||||
uint16 Anim::load(const byte *animResourceData, size_t animResourceLength) {
|
||||
AnimationData *anim;
|
||||
uint16 animId = 0;
|
||||
uint16 i;
|
||||
|
||||
if (!_initialized) {
|
||||
warning("Anim::load not initialised");
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
// Find an unused animation slot
|
||||
for (i = 0; i < MAX_ANIMATIONS; i++) {
|
||||
if (_anim_tbl[i] == NULL) {
|
||||
anim_id = i;
|
||||
if (_animations[i] == NULL) {
|
||||
animId = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == MAX_ANIMATIONS) {
|
||||
warning("Anim::load could not find unused animation slot");
|
||||
return FAILURE;
|
||||
if (animId == MAX_ANIMATIONS) {
|
||||
error("Anim::load could not find unused animation slot");
|
||||
}
|
||||
|
||||
new_anim = (ANIMATION *)malloc(sizeof(*new_anim));
|
||||
if (new_anim == NULL) {
|
||||
warning("Anim::load Allocation failure");
|
||||
return MEM;
|
||||
}
|
||||
anim = _animations[animId] = new AnimationData(animResourceData, animResourceLength);
|
||||
|
||||
new_anim->resdata = anim_resdata;
|
||||
new_anim->resdata_len = anim_resdata_len;
|
||||
MemoryReadStreamEndian headerReadS(anim->resourceData, anim->resourceLength, IS_BIG_ENDIAN);
|
||||
anim->magic = headerReadS.readUint16LE(); // cause ALWAYS LE
|
||||
anim->screenWidth = headerReadS.readUint16();
|
||||
anim->screenHeight = headerReadS.readUint16();
|
||||
|
||||
MemoryReadStreamEndian headerReadS(anim_resdata, anim_resdata_len, IS_BIG_ENDIAN);
|
||||
anim->unknown06 = headerReadS.readByte();
|
||||
anim->unknown07 = headerReadS.readByte();
|
||||
anim->maxFrame = headerReadS.readByte() - 1;
|
||||
anim->loopFrame = headerReadS.readByte() - 1;
|
||||
anim->start = headerReadS.readUint16BE();
|
||||
|
||||
if (anim->start != 65535 && anim->start != 0)
|
||||
warning("Anim::load: found different start: %d. Fix Anim::play()", anim->start);
|
||||
anim->start += headerReadS.pos();
|
||||
|
||||
readAnimHeader(headerReadS, ah);
|
||||
new_anim->maxframe = ah.maxframe;
|
||||
new_anim->loopframe = ah.loopframe;
|
||||
|
||||
if (_vm->getGameType() == GType_ITE) {
|
||||
// Cache frame offsets
|
||||
new_anim->frame_offsets = (size_t *)malloc((new_anim->maxframe + 1) * sizeof(*new_anim->frame_offsets));
|
||||
if (new_anim->frame_offsets == NULL) {
|
||||
warning("Anim::load Allocation failure");
|
||||
return MEM;
|
||||
anim->frameOffsets = (size_t *)malloc((anim->maxFrame + 1) * sizeof(*anim->frameOffsets));
|
||||
if (anim->frameOffsets == NULL) {
|
||||
memoryError("Anim::load");
|
||||
}
|
||||
|
||||
for (i = 0; i <= new_anim->maxframe; i++) {
|
||||
getFrameOffset(anim_resdata, anim_resdata_len, i, &new_anim->frame_offsets[i]);
|
||||
}
|
||||
fillFrameOffsets(anim);
|
||||
} else {
|
||||
new_anim->cur_frame_p = anim_resdata + SAGA_FRAME_HEADER_LEN; // ? len - may vary
|
||||
new_anim->cur_frame_len = anim_resdata_len - SAGA_FRAME_HEADER_LEN;
|
||||
anim->cur_frame_p = anim->resourceData + SAGA_FRAME_HEADER_LEN; // ? len - may vary
|
||||
anim->cur_frame_len = anim->resourceLength - SAGA_FRAME_HEADER_LEN;
|
||||
}
|
||||
|
||||
// Set animation data
|
||||
new_anim->current_frame = 0;
|
||||
new_anim->completed = 0;
|
||||
new_anim->cycles = new_anim->maxframe;
|
||||
anim->currentFrame = 0;
|
||||
anim->completed = 0;
|
||||
anim->cycles = anim->maxFrame;
|
||||
|
||||
new_anim->frame_time = DEFAULT_FRAME_TIME;
|
||||
new_anim->flags = 0;
|
||||
new_anim->link_id = -1;
|
||||
new_anim->state = ANIM_PAUSE;
|
||||
anim->frameTime = DEFAULT_FRAME_TIME;
|
||||
anim->flags = 0;
|
||||
anim->linkId = -1;
|
||||
anim->state = ANIM_PAUSE;
|
||||
|
||||
_anim_tbl[anim_id] = new_anim;
|
||||
|
||||
*anim_id_p = anim_id;
|
||||
|
||||
_anim_count++;
|
||||
|
||||
return SUCCESS;
|
||||
return animId;
|
||||
}
|
||||
|
||||
int Anim::link(int16 anim_id1, int16 anim_id2) {
|
||||
ANIMATION *anim1;
|
||||
ANIMATION *anim2;
|
||||
void Anim::link(int16 animId1, int16 animId2) {
|
||||
AnimationData *anim1;
|
||||
AnimationData *anim2;
|
||||
|
||||
if ((anim_id1 >= _anim_count) || (anim_id2 >= _anim_count)) {
|
||||
return FAILURE;
|
||||
}
|
||||
anim1 = getAnimation(animId1);
|
||||
|
||||
anim1 = _anim_tbl[anim_id1];
|
||||
anim1->linkId = animId2;
|
||||
|
||||
anim1->link_id = anim_id2;
|
||||
|
||||
if (anim_id2 == -1)
|
||||
return SUCCESS;
|
||||
|
||||
anim2 = _anim_tbl[anim_id2];
|
||||
|
||||
if ((anim1 == NULL) || (anim2 == NULL)) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
anim2->frame_time = anim1->frame_time;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void Anim::setCycles(uint animId, int cycles) {
|
||||
if (animId >= _anim_count) {
|
||||
warning("Anim::setCycles(): wrong animation number (%d)", animId);
|
||||
if (animId2 == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
_anim_tbl[animId]->cycles = cycles;
|
||||
|
||||
anim2 = getAnimation(animId2);
|
||||
anim2->frameTime = anim1->frameTime;
|
||||
}
|
||||
|
||||
int Anim::play(uint16 anim_id, int vector_time, bool playing) {
|
||||
EVENT event;
|
||||
ANIMATION *anim;
|
||||
ANIMATION *link_anim;
|
||||
uint16 link_anim_id;
|
||||
void Anim::setCycles(uint16 animId, int cycles) {
|
||||
AnimationData *anim;
|
||||
|
||||
anim = getAnimation(animId);
|
||||
|
||||
anim->cycles = cycles;
|
||||
}
|
||||
|
||||
void Anim::play(uint16 animId, int vectorTime, bool playing) {
|
||||
EVENT event;
|
||||
BUFFER_INFO buf_info;
|
||||
|
||||
byte *display_buf;
|
||||
byte *displayBuffer;
|
||||
|
||||
const byte *nextf_p;
|
||||
size_t nextf_len;
|
||||
|
||||
uint16 frame;
|
||||
int frame_time;
|
||||
int frameTime;
|
||||
int result;
|
||||
|
||||
if (anim_id >= _anim_count) {
|
||||
return FAILURE;
|
||||
}
|
||||
AnimationData *anim;
|
||||
AnimationData *linkAnim;
|
||||
|
||||
anim = getAnimation(animId);
|
||||
|
||||
|
||||
_vm->_render->getBufferInfo(&buf_info);
|
||||
display_buf = buf_info.bg_buf;
|
||||
displayBuffer = buf_info.bg_buf;
|
||||
|
||||
anim = _anim_tbl[anim_id];
|
||||
if (anim == NULL) {
|
||||
return FAILURE;
|
||||
|
||||
if (playing) {
|
||||
anim->state = ANIM_PLAYING;
|
||||
}
|
||||
|
||||
if (playing)
|
||||
anim->state = ANIM_PLAYING;
|
||||
|
||||
if (anim->state == ANIM_PAUSE)
|
||||
return SUCCESS;
|
||||
if (anim->state == ANIM_PAUSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (anim->completed < anim->cycles) {
|
||||
frame = anim->current_frame;
|
||||
frame = anim->currentFrame;
|
||||
if (_vm->getGameType() == GType_ITE) {
|
||||
// FIXME: if start > 0, then this works incorrectly
|
||||
result = ITE_DecodeFrame(anim->resdata, anim->resdata_len, anim->frame_offsets[frame], display_buf,
|
||||
_vm->getDisplayWidth() * _vm->getDisplayHeight());
|
||||
if (result != SUCCESS) {
|
||||
warning("Anim::play: Error decoding frame %u", anim->current_frame);
|
||||
anim->state = ANIM_PAUSE;
|
||||
return FAILURE;
|
||||
}
|
||||
ITE_DecodeFrame(anim, anim->frameOffsets[frame], displayBuffer,
|
||||
_vm->getDisplayWidth() * _vm->getDisplayHeight());
|
||||
} else {
|
||||
if (anim->cur_frame_p == NULL) {
|
||||
warning("Anim::play: Frames exhausted");
|
||||
return FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
result = IHNM_DecodeFrame(display_buf, _vm->getDisplayWidth() * _vm->getDisplayHeight(),
|
||||
result = IHNM_DecodeFrame(displayBuffer, _vm->getDisplayWidth() * _vm->getDisplayHeight(),
|
||||
anim->cur_frame_p, anim->cur_frame_len, &nextf_p, &nextf_len);
|
||||
if (result != SUCCESS) {
|
||||
warning("Anim::play: Error decoding frame %u", anim->current_frame);
|
||||
warning("Anim::play: Error decoding frame %u", anim->currentFrame);
|
||||
anim->state = ANIM_PAUSE;
|
||||
return FAILURE;
|
||||
return;
|
||||
}
|
||||
|
||||
anim->cur_frame_p = nextf_p;
|
||||
anim->cur_frame_len = nextf_len;
|
||||
}
|
||||
anim->current_frame++;
|
||||
|
||||
anim->currentFrame++;
|
||||
anim->completed++;
|
||||
|
||||
if (anim->current_frame > anim->maxframe) {
|
||||
anim->current_frame = anim->loopframe;
|
||||
if (anim->currentFrame > anim->maxFrame) {
|
||||
anim->currentFrame = anim->loopFrame;
|
||||
|
||||
// FIXME: HACK. probably needs more testing for IHNM
|
||||
anim->cur_frame_p = anim->resdata + SAGA_FRAME_HEADER_LEN;
|
||||
anim->cur_frame_len = anim->resdata_len - SAGA_FRAME_HEADER_LEN;
|
||||
|
||||
if (anim->flags & ANIM_STOPPING || anim->current_frame == -1)
|
||||
if (_vm->getGameType() == GType_IHNM) {
|
||||
// FIXME: HACK. probably needs more testing for IHNM
|
||||
anim->cur_frame_p = anim->resourceData + SAGA_FRAME_HEADER_LEN;
|
||||
anim->cur_frame_len = anim->resourceLength - SAGA_FRAME_HEADER_LEN;
|
||||
}
|
||||
|
||||
if (anim->flags & ANIM_STOPPING || anim->currentFrame == (uint16)-1) {
|
||||
anim->state = ANIM_PAUSE;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Animation done playing
|
||||
if (anim->link_id != -1) {
|
||||
if (anim->linkId != -1) {
|
||||
// If this animation has a link, follow it
|
||||
anim->current_frame = 0;
|
||||
anim->currentFrame = 0;
|
||||
anim->state = ANIM_PAUSE;
|
||||
|
||||
link_anim_id = anim->link_id;
|
||||
link_anim = _anim_tbl[link_anim_id];
|
||||
/* linkAnim = getAnimation(anim->linkId);
|
||||
|
||||
if (link_anim != NULL) {
|
||||
link_anim->current_frame = 0;
|
||||
link_anim->state = ANIM_PLAYING;
|
||||
}
|
||||
linkAnim->currentFrame = 0;
|
||||
linkAnim->state = ANIM_PLAYING;
|
||||
|
||||
anim_id = link_anim_id;
|
||||
animId = anim->linkId;*/
|
||||
} else {
|
||||
// No link, stop playing
|
||||
anim->current_frame = anim->maxframe;
|
||||
anim->currentFrame = anim->maxFrame;
|
||||
anim->state = ANIM_PAUSE;
|
||||
|
||||
if (anim->flags & ANIM_ENDSCENE) {
|
||||
@ -267,183 +224,115 @@ int Anim::play(uint16 anim_id, int vector_time, bool playing) {
|
||||
event.type = ONESHOT_EVENT;
|
||||
event.code = SCENE_EVENT;
|
||||
event.op = EVENT_END;
|
||||
event.time = anim->frame_time + vector_time;
|
||||
event.time = anim->frameTime + vectorTime;
|
||||
_vm->_events->queue(&event);
|
||||
}
|
||||
return SUCCESS;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (anim->state == ANIM_PAUSE && anim->link_id != -1) {
|
||||
if (anim->state == ANIM_PAUSE && anim->linkId != -1) {
|
||||
// If this animation has a link, follow it
|
||||
link_anim_id = anim->link_id;
|
||||
link_anim = _anim_tbl[link_anim_id];
|
||||
linkAnim = getAnimation(anim->linkId);
|
||||
|
||||
if (link_anim != NULL) {
|
||||
debug(5, "Animation ended going to %d", link_anim_id);
|
||||
link_anim->current_frame = 0;
|
||||
link_anim->state = ANIM_PLAYING;
|
||||
}
|
||||
anim_id = link_anim_id;
|
||||
frame_time = 0;
|
||||
debug(5, "Animation ended going to %d", anim->linkId);
|
||||
linkAnim->currentFrame = 0;
|
||||
linkAnim->state = ANIM_PLAYING;
|
||||
animId = anim->linkId;
|
||||
frameTime = 0;
|
||||
} else {
|
||||
frame_time = anim->frame_time + vector_time;
|
||||
frameTime = anim->frameTime + vectorTime;
|
||||
}
|
||||
|
||||
event.type = ONESHOT_EVENT;
|
||||
event.code = ANIM_EVENT;
|
||||
event.op = EVENT_FRAME;
|
||||
event.param = anim_id;
|
||||
event.time = frame_time;
|
||||
event.param = animId;
|
||||
event.time = frameTime;
|
||||
|
||||
_vm->_events->queue(&event);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void Anim::stop(uint16 animId) {
|
||||
if (animId >= _anim_count) {
|
||||
warning("Anim::stop(): wrong animation number (%d)", animId);
|
||||
return;
|
||||
}
|
||||
|
||||
_anim_tbl[animId]->state = ANIM_PAUSE;
|
||||
AnimationData *anim;
|
||||
|
||||
anim = getAnimation(animId);
|
||||
|
||||
anim->state = ANIM_PAUSE;
|
||||
}
|
||||
|
||||
void Anim::finish(uint16 animId) {
|
||||
if (animId >= _anim_count) {
|
||||
warning("Anim::finish(): wrong animation number (%d)", animId);
|
||||
return;
|
||||
}
|
||||
|
||||
_anim_tbl[animId]->state = ANIM_STOPPING;
|
||||
AnimationData *anim;
|
||||
|
||||
anim = getAnimation(animId);
|
||||
|
||||
anim->state = ANIM_STOPPING;
|
||||
}
|
||||
|
||||
void Anim::resume(uint16 animId, int cycles) {
|
||||
if (animId >= _anim_count) {
|
||||
warning("Anim::resume(): wrong animation number (%d)", animId);
|
||||
return;
|
||||
}
|
||||
AnimationData *anim;
|
||||
|
||||
anim = getAnimation(animId);
|
||||
|
||||
_anim_tbl[animId]->cycles += cycles;
|
||||
anim->cycles += cycles;
|
||||
play(animId, 0, true);
|
||||
}
|
||||
|
||||
int Anim::reset() {
|
||||
void Anim::reset() {
|
||||
uint16 i;
|
||||
|
||||
for (i = 0; i < MAX_ANIMATIONS; i++) {
|
||||
freeId(i);
|
||||
if (_animations[i] != NULL) {
|
||||
delete _animations[i];
|
||||
_animations[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int Anim::setFlag(uint16 anim_id, uint16 flag) {
|
||||
ANIMATION *anim;
|
||||
void Anim::setFlag(uint16 animId, uint16 flag) {
|
||||
AnimationData *anim;
|
||||
|
||||
if (anim_id > _anim_count) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
anim = _anim_tbl[anim_id];
|
||||
if (anim == NULL) {
|
||||
return FAILURE;
|
||||
}
|
||||
anim = getAnimation(animId);
|
||||
|
||||
anim->flags |= flag;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int Anim::clearFlag(uint16 anim_id, uint16 flag) {
|
||||
ANIMATION *anim;
|
||||
void Anim::clearFlag(uint16 animId, uint16 flag) {
|
||||
AnimationData *anim;
|
||||
|
||||
if (anim_id > _anim_count) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
anim = _anim_tbl[anim_id];
|
||||
if (anim == NULL) {
|
||||
return FAILURE;
|
||||
}
|
||||
anim = getAnimation(animId);
|
||||
|
||||
anim->flags &= ~flag;
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int Anim::setFrameTime(uint16 anim_id, int time) {
|
||||
ANIMATION *anim;
|
||||
void Anim::setFrameTime(uint16 animId, int time) {
|
||||
AnimationData *anim;
|
||||
|
||||
if (anim_id > _anim_count) {
|
||||
return FAILURE;
|
||||
}
|
||||
anim = getAnimation(animId);
|
||||
|
||||
anim = _anim_tbl[anim_id];
|
||||
if (anim == NULL) {
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
anim->frame_time = time;
|
||||
|
||||
return SUCCESS;
|
||||
anim->frameTime = time;
|
||||
}
|
||||
|
||||
int16 Anim::getCurrentFrame(uint16 animId) {
|
||||
if (animId >= _anim_count) {
|
||||
warning("Anim::stop(): wrong animation number (%d)", animId);
|
||||
return 0;
|
||||
}
|
||||
AnimationData *anim;
|
||||
|
||||
anim = getAnimation(animId);
|
||||
|
||||
return _anim_tbl[animId]->current_frame;
|
||||
return anim->currentFrame;
|
||||
}
|
||||
|
||||
void Anim::freeId(uint16 animId) {
|
||||
ANIMATION *anim;
|
||||
|
||||
anim = _anim_tbl[animId];
|
||||
if (anim == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_vm->getGameType() == GType_ITE) {
|
||||
free(anim->frame_offsets);
|
||||
}
|
||||
|
||||
free(anim);
|
||||
_anim_tbl[animId] = NULL;
|
||||
_anim_count--;
|
||||
}
|
||||
|
||||
void Anim::readAnimHeader(MemoryReadStreamEndian &readS, ANIMATION_HEADER &ah) {
|
||||
ah.magic = readS.readUint16LE(); // cause ALWAYS LE
|
||||
ah.screen_w = readS.readUint16();
|
||||
ah.screen_h = readS.readUint16();
|
||||
|
||||
ah.unknown06 = readS.readByte();
|
||||
ah.unknown07 = readS.readByte();
|
||||
ah.maxframe = readS.readByte() - 1;
|
||||
ah.loopframe = readS.readByte() - 1;
|
||||
ah.start = readS.readUint16BE();
|
||||
|
||||
if (ah.start != 65535 && ah.start != 0)
|
||||
warning("Anim::readAnimHeader(): found different start: %d. Fix Anim::play()", ah.start);
|
||||
ah.start += readS.pos();
|
||||
}
|
||||
|
||||
int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_offset, byte *buf, size_t buf_len) {
|
||||
ANIMATION_HEADER ah;
|
||||
void Anim::ITE_DecodeFrame(AnimationData *anim, size_t frameOffset, byte *buf, size_t bufLength) {
|
||||
FRAME_HEADER fh;
|
||||
|
||||
byte *write_p;
|
||||
|
||||
uint16 magic;
|
||||
|
||||
uint16 x_start;
|
||||
uint16 y_start;
|
||||
uint32 screen_w;
|
||||
uint32 screen_h;
|
||||
uint16 xStart;
|
||||
uint16 yStart;
|
||||
uint32 screenWidth;
|
||||
uint32 screenHeight;
|
||||
|
||||
int mark_byte;
|
||||
byte data_byte;
|
||||
@ -457,59 +346,52 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_
|
||||
|
||||
uint16 i;
|
||||
|
||||
if (!_initialized) {
|
||||
return FAILURE;
|
||||
}
|
||||
screenWidth = anim->screenWidth;
|
||||
screenHeight = anim->screenHeight;
|
||||
|
||||
MemoryReadStreamEndian headerReadS(resdata, resdata_len, IS_BIG_ENDIAN);
|
||||
|
||||
readAnimHeader(headerReadS, ah);
|
||||
|
||||
screen_w = ah.screen_w;
|
||||
screen_h = ah.screen_h;
|
||||
|
||||
if ((screen_w * screen_h) > buf_len) {
|
||||
if ((screenWidth * screenHeight) > bufLength) {
|
||||
// Buffer argument is too small to hold decoded frame, abort.
|
||||
warning("ITE_DecodeFrame: Buffer size inadequate");
|
||||
return FAILURE;
|
||||
error("ITE_DecodeFrame: Buffer size inadequate");
|
||||
}
|
||||
|
||||
MemoryReadStream readS(resdata + frame_offset, resdata_len - frame_offset);
|
||||
MemoryReadStream readS(anim->resourceData + frameOffset, anim->resourceLength - frameOffset);
|
||||
|
||||
// Check for frame magic byte
|
||||
magic = readS.readByte();
|
||||
if (magic == SAGA_FRAME_END) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (magic != SAGA_FRAME_START) {
|
||||
warning("ITE_DecodeFrame: Invalid frame offset %x", frame_offset);
|
||||
return FAILURE;
|
||||
error("ITE_DecodeFrame: Invalid frame offset %x", frameOffset);
|
||||
}
|
||||
|
||||
|
||||
fh.x_start = readS.readUint16BE();
|
||||
fh.xStart = readS.readUint16BE();
|
||||
if (_vm->getFeatures() & GF_BIG_ENDIAN_DATA)
|
||||
fh.y_start = readS.readUint16BE();
|
||||
fh.yStart = readS.readUint16BE();
|
||||
else
|
||||
fh.y_start = readS.readByte();
|
||||
fh.yStart = readS.readByte();
|
||||
readS.readByte(); /* Skip pad byte */
|
||||
fh.x_pos = readS.readUint16BE();
|
||||
fh.y_pos = readS.readUint16BE();
|
||||
fh.xPos = readS.readUint16BE();
|
||||
fh.yPos = readS.readUint16BE();
|
||||
fh.width = readS.readUint16BE();
|
||||
fh.height = readS.readUint16BE();
|
||||
|
||||
x_start = fh.x_start;
|
||||
y_start = fh.y_start;
|
||||
xStart = fh.xStart;
|
||||
yStart = fh.yStart;
|
||||
|
||||
#if 1
|
||||
#define VALIDATE_WRITE_POINTER \
|
||||
if ((write_p < buf) || (write_p >= (buf + screen_w * screen_h))) { \
|
||||
warning("VALIDATE_WRITE_POINTER: write_p=%x buf=%x", write_p, buf); \
|
||||
return FAILURE; \
|
||||
if ((write_p < buf) || (write_p >= (buf + screenWidth * screenHeight))) { \
|
||||
error("VALIDATE_WRITE_POINTER: write_p=%x buf=%x", write_p, buf); \
|
||||
}
|
||||
#else
|
||||
#define VALIDATE_WRITE_POINTER
|
||||
#endif
|
||||
|
||||
// Setup write pointer to the draw origin
|
||||
write_p = (buf + (y_start * screen_w) + x_start);
|
||||
write_p = (buf + (yStart * screenWidth) + xStart);
|
||||
VALIDATE_WRITE_POINTER;
|
||||
|
||||
// Begin RLE decompression to output buffer
|
||||
@ -546,7 +428,7 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_
|
||||
new_row = readS.readByte();
|
||||
|
||||
// Set write pointer to the new draw origin
|
||||
write_p = buf + ((y_start + new_row) * screen_w) + x_start + x_vector;
|
||||
write_p = buf + ((yStart + new_row) * screenWidth) + xStart + x_vector;
|
||||
VALIDATE_WRITE_POINTER;
|
||||
continue;
|
||||
break;
|
||||
@ -557,7 +439,7 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_
|
||||
continue;
|
||||
break;
|
||||
case SAGA_FRAME_END: // End of frame marker
|
||||
return SUCCESS;
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -599,13 +481,11 @@ int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_
|
||||
break;
|
||||
default:
|
||||
// Unknown marker found - abort
|
||||
warning("ITE_DecodeFrame: Invalid RLE marker encountered");
|
||||
return FAILURE;
|
||||
error("ITE_DecodeFrame: Invalid RLE marker encountered");
|
||||
break;
|
||||
}
|
||||
} while (mark_byte != 63); // end of frame marker
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *thisf_p,
|
||||
@ -829,10 +709,8 @@ int Anim::IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
int Anim::getFrameOffset(const byte *resdata, size_t resdata_len, uint16 find_frame, size_t *frame_offset_p) {
|
||||
ANIMATION_HEADER ah;
|
||||
|
||||
uint16 current_frame;
|
||||
void Anim::fillFrameOffsets(AnimationData *anim) {
|
||||
uint16 currentFrame;
|
||||
|
||||
byte mark_byte;
|
||||
uint16 control;
|
||||
@ -841,27 +719,28 @@ int Anim::getFrameOffset(const byte *resdata, size_t resdata_len, uint16 find_fr
|
||||
|
||||
int i;
|
||||
|
||||
MemoryReadStreamEndian readS(resdata, resdata_len, IS_BIG_ENDIAN);
|
||||
MemoryReadStreamEndian readS(anim->resourceData, anim->resourceLength, IS_BIG_ENDIAN);
|
||||
|
||||
readAnimHeader(readS, ah);
|
||||
|
||||
if (find_frame > ah.maxframe) {
|
||||
return FAILURE;
|
||||
}
|
||||
readS.seek(12);
|
||||
|
||||
|
||||
readS._bigEndian = !IS_BIG_ENDIAN; // RLE has inversion BE<>LE
|
||||
|
||||
for (current_frame = 0; current_frame < find_frame; current_frame++) {
|
||||
for (currentFrame = 0; currentFrame <= anim->maxFrame; currentFrame++) {
|
||||
anim->frameOffsets[currentFrame] = readS.pos();
|
||||
magic = readS.readByte();
|
||||
if (magic == SAGA_FRAME_END) {
|
||||
if (currentFrame != anim->maxFrame) {
|
||||
error("currentFrame != anim->maxFrame");
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (magic != SAGA_FRAME_START) {
|
||||
// Frame sync failure. Magic Number not found
|
||||
return FAILURE;
|
||||
error("Frame sync failure. Magic Number not found");
|
||||
}
|
||||
|
||||
// skip header
|
||||
for (i = 0; i < SAGA_FRAME_HEADER_LEN; i++)
|
||||
readS.readByte();
|
||||
|
||||
readS.seek(SAGA_FRAME_HEADER_LEN, SEEK_CUR);
|
||||
|
||||
// For some strange reason, the animation header is in little
|
||||
// endian format, but the actual RLE encoded frame data,
|
||||
@ -922,32 +801,27 @@ int Anim::getFrameOffset(const byte *resdata, size_t resdata_len, uint16 find_fr
|
||||
continue;
|
||||
break;
|
||||
default:
|
||||
// Encountered unknown RLE marker, abort
|
||||
return FAILURE;
|
||||
error("Encountered unknown RLE marker");
|
||||
break;
|
||||
}
|
||||
} while (mark_byte != SAGA_FRAME_END);
|
||||
}
|
||||
|
||||
*frame_offset_p = readS.pos();
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void Anim::animInfo() {
|
||||
uint16 anim_ct;
|
||||
uint16 animCount;
|
||||
uint16 i;
|
||||
uint16 idx;
|
||||
|
||||
anim_ct = _anim_count;
|
||||
animCount = getAnimationCount();
|
||||
|
||||
_vm->_console->DebugPrintf("There are %d animations loaded:\n", anim_ct);
|
||||
_vm->_console->DebugPrintf("There are %d animations loaded:\n", animCount);
|
||||
|
||||
for (idx = 0, i = 0; i < anim_ct; idx++, i++) {
|
||||
while (_anim_tbl[idx] == NULL) {
|
||||
idx++;
|
||||
for (i = 0; i < MAX_ANIMATIONS; i++) {
|
||||
if (_animations[i] == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
_vm->_console->DebugPrintf("%02d: Frames: %u Flags: %u\n", i, _anim_tbl[idx]->maxframe, _anim_tbl[idx]->flags);
|
||||
_vm->_console->DebugPrintf("%02d: Frames: %u Flags: %u\n", i, _animations[i]->maxFrame, _animations[i]->flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
145
saga/animation.h
145
saga/animation.h
@ -48,97 +48,124 @@ namespace Saga {
|
||||
// All animation resources begin with an ANIMATION_HEADER
|
||||
// at 0x00, followed by a RLE code stream
|
||||
|
||||
struct ANIMATION_HEADER {
|
||||
uint16 magic;
|
||||
|
||||
uint16 screen_w;
|
||||
uint16 screen_h;
|
||||
|
||||
byte unknown06;
|
||||
byte unknown07;
|
||||
|
||||
byte maxframe;
|
||||
byte loopframe;
|
||||
|
||||
uint16 start;
|
||||
};
|
||||
|
||||
struct FRAME_HEADER {
|
||||
int x_start;
|
||||
int y_start;
|
||||
int xStart;
|
||||
int yStart;
|
||||
|
||||
int x_pos;
|
||||
int y_pos;
|
||||
int xPos;
|
||||
int yPos;
|
||||
|
||||
int width;
|
||||
int height;
|
||||
};
|
||||
|
||||
// Animation info array member
|
||||
struct ANIMATION {
|
||||
|
||||
const byte *resdata;
|
||||
size_t resdata_len;
|
||||
|
||||
uint16 maxframe;
|
||||
size_t *frame_offsets;
|
||||
int16 current_frame;
|
||||
uint16 completed;
|
||||
uint16 cycles;
|
||||
int16 loopframe;
|
||||
const byte *cur_frame_p;
|
||||
size_t cur_frame_len;
|
||||
int frame_time;
|
||||
|
||||
int state;
|
||||
int16 link_id;
|
||||
uint16 flags;
|
||||
};
|
||||
|
||||
enum ANIM_FLAGS {
|
||||
enum AnimationState {
|
||||
ANIM_PLAYING = 0x01,
|
||||
ANIM_PAUSE = 0x02,
|
||||
ANIM_STOPPING = 0x04,
|
||||
ANIM_ENDSCENE = 0x80 // When animation ends, dispatch scene end event
|
||||
};
|
||||
|
||||
// Animation info array member
|
||||
struct AnimationData {
|
||||
byte *resourceData;
|
||||
size_t resourceLength;
|
||||
|
||||
uint16 magic;
|
||||
|
||||
uint16 screenWidth;
|
||||
uint16 screenHeight;
|
||||
|
||||
byte unknown06;
|
||||
byte unknown07;
|
||||
|
||||
uint16 maxFrame;
|
||||
uint16 loopFrame;
|
||||
|
||||
uint16 start;
|
||||
|
||||
uint16 currentFrame;
|
||||
size_t *frameOffsets;
|
||||
|
||||
uint16 completed;
|
||||
uint16 cycles;
|
||||
|
||||
const byte *cur_frame_p;
|
||||
size_t cur_frame_len;
|
||||
|
||||
int frameTime;
|
||||
|
||||
AnimationState state;
|
||||
int16 linkId;
|
||||
uint16 flags;
|
||||
|
||||
AnimationData(const byte *animResourceData, size_t animResourceLength) {
|
||||
memset(this, 0, sizeof(*this));
|
||||
resourceLength = animResourceLength;
|
||||
resourceData = (byte*)malloc(animResourceLength);
|
||||
memcpy(resourceData, animResourceData, animResourceLength);
|
||||
}
|
||||
~AnimationData() {
|
||||
free(frameOffsets);
|
||||
free(resourceData);
|
||||
}
|
||||
};
|
||||
|
||||
class Anim {
|
||||
public:
|
||||
Anim(SagaEngine *vm);
|
||||
~Anim(void);
|
||||
|
||||
int load(const byte *anim_resdata, size_t anim_resdata_len, uint16 *anim_id_p);
|
||||
uint16 load(const byte *animResourceData, size_t animResourceLength);
|
||||
void freeId(uint16 animId);
|
||||
int play(uint16 anim_id, int vector_time, bool playing = true);
|
||||
int link(int16 anim_id1, int16 anim_id2);
|
||||
int setFlag(uint16 anim_id, uint16 flag);
|
||||
int clearFlag(uint16 anim_id, uint16 flag);
|
||||
int setFrameTime(uint16 anim_id, int time);
|
||||
int reset(void);
|
||||
void play(uint16 animId, int vectorTime, bool playing = true);
|
||||
void link(int16 animId1, int16 animId2);
|
||||
void setFlag(uint16 animId, uint16 flag);
|
||||
void clearFlag(uint16 animId, uint16 flag);
|
||||
void setFrameTime(uint16 animId, int time);
|
||||
void reset(void);
|
||||
void animInfo(void);
|
||||
void setCycles(uint animId, int cycles);
|
||||
void setCycles(uint16 animId, int cycles);
|
||||
void stop(uint16 animId);
|
||||
void finish(uint16 animId);
|
||||
void resume(uint16 animId, int cycles);
|
||||
int16 getCurrentFrame(uint16 anim_id);
|
||||
int16 getCurrentFrame(uint16 animId);
|
||||
|
||||
private:
|
||||
int ITE_DecodeFrame(const byte *anim_resource, size_t anim_resource_len, size_t frame_offset, byte *buf, size_t buf_len);
|
||||
void ITE_DecodeFrame(AnimationData *anim, size_t frameOffset, byte *buf, size_t bufLength);
|
||||
int IHNM_DecodeFrame(byte *decode_buf, size_t decode_buf_len, const byte *thisf_p,
|
||||
size_t thisf_len, const byte **nextf_p, size_t *nextf_len);
|
||||
int getFrameOffset(const byte *anim_resource, size_t anim_resource_len, uint16 find_frame, size_t *frame_offset);
|
||||
void readAnimHeader(MemoryReadStreamEndian &readS, ANIMATION_HEADER &ah);
|
||||
void fillFrameOffsets(AnimationData *anim);
|
||||
|
||||
void validateAnimationId(uint16 animId) {
|
||||
if (animId >= MAX_ANIMATIONS) {
|
||||
error("validateAnimationId: animId out of range");
|
||||
}
|
||||
if (_animations[animId] == NULL) {
|
||||
error("validateAnimationId: animId=%i unassigned", animId);
|
||||
}
|
||||
}
|
||||
|
||||
AnimationData* getAnimation(uint16 animId) {
|
||||
validateAnimationId(animId);
|
||||
return _animations[animId];
|
||||
}
|
||||
|
||||
uint16 getAnimationCount() const {
|
||||
uint16 i = 0;
|
||||
for (; i < MAX_ANIMATIONS; i++) {
|
||||
if (_animations[i] == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
SagaEngine *_vm;
|
||||
bool _initialized;
|
||||
|
||||
uint16 _anim_count;
|
||||
uint16 _anim_limit;
|
||||
ANIMATION *_anim_tbl[MAX_ANIMATIONS];
|
||||
AnimationData *_animations[MAX_ANIMATIONS];
|
||||
|
||||
};
|
||||
|
||||
} // End of namespace Saga
|
||||
|
||||
#endif /* ANIMATION_H_ */
|
||||
/* end "r_animation.h" */
|
||||
|
@ -718,25 +718,24 @@ int Scene::loadSceneResourceList(uint32 reslist_rn) {
|
||||
}
|
||||
|
||||
int Scene::processSceneResources() {
|
||||
const byte *res_data;
|
||||
size_t res_data_len;
|
||||
byte *resourceData;
|
||||
size_t resourceDataLength;
|
||||
const byte *pal_p;
|
||||
int i;
|
||||
|
||||
// Process the scene resource list
|
||||
for (i = 0; i < _resListEntries; i++) {
|
||||
res_data = _resList[i].res_data;
|
||||
res_data_len = _resList[i].res_data_len;
|
||||
resourceData = _resList[i].res_data;
|
||||
resourceDataLength = _resList[i].res_data_len;
|
||||
switch (_resList[i].res_type) {
|
||||
case SAGA_BG_IMAGE: // Scene background resource
|
||||
if (_bg.loaded) {
|
||||
warning("Scene::processSceneResources(): Multiple background resources encountered");
|
||||
return FAILURE;
|
||||
error("Scene::processSceneResources(): Multiple background resources encountered");
|
||||
}
|
||||
|
||||
debug(0, "Loading background resource.");
|
||||
_bg.res_buf = _resList[i].res_data;
|
||||
_bg.res_len = _resList[i].res_data_len;
|
||||
_bg.res_buf = resourceData;
|
||||
_bg.res_len = resourceDataLength;
|
||||
_bg.loaded = 1;
|
||||
|
||||
if (_vm->decodeBGImage(_bg.res_buf,
|
||||
@ -754,11 +753,11 @@ int Scene::processSceneResources() {
|
||||
break;
|
||||
case SAGA_BG_MASK: // Scene background mask resource
|
||||
if (_bgMask.loaded) {
|
||||
warning("Scene::ProcessSceneResources(): Duplicate background mask resource encountered");
|
||||
error("Scene::ProcessSceneResources(): Duplicate background mask resource encountered");
|
||||
}
|
||||
debug(0, "Loading BACKGROUND MASK resource.");
|
||||
_bgMask.res_buf = _resList[i].res_data;
|
||||
_bgMask.res_len = _resList[i].res_data_len;
|
||||
_bgMask.res_buf = resourceData;
|
||||
_bgMask.res_len = resourceDataLength;
|
||||
_bgMask.loaded = 1;
|
||||
_vm->decodeBGImage(_bgMask.res_buf, _bgMask.res_len, &_bgMask.buf,
|
||||
&_bgMask.buf_len, &_bgMask.w, &_bgMask.h);
|
||||
@ -766,15 +765,15 @@ int Scene::processSceneResources() {
|
||||
break;
|
||||
case SAGA_STRINGS:
|
||||
debug(0, "Loading scene strings resource...");
|
||||
_vm->loadStrings(_sceneStrings, _resList[i].res_data, _resList[i].res_data_len);
|
||||
_vm->loadStrings(_sceneStrings, resourceData, resourceDataLength);
|
||||
break;
|
||||
case SAGA_OBJECT_MAP:
|
||||
debug(0, "Loading object map resource...");
|
||||
_objectMap->load(res_data, res_data_len);
|
||||
_objectMap->load(resourceData, resourceDataLength);
|
||||
break;
|
||||
case SAGA_ACTION_MAP:
|
||||
debug(0, "Loading action map resource...");
|
||||
_actionMap->load(res_data, res_data_len);
|
||||
_actionMap->load(resourceData, resourceDataLength);
|
||||
break;
|
||||
case SAGA_ISO_IMAGES:
|
||||
if (!(_sceneDescription.flags & kSceneFlagISO)) {
|
||||
@ -783,7 +782,7 @@ int Scene::processSceneResources() {
|
||||
|
||||
debug(0, "Loading isometric images resource.");
|
||||
|
||||
_vm->_isoMap->loadImages(res_data, res_data_len);
|
||||
_vm->_isoMap->loadImages(resourceData, resourceDataLength);
|
||||
break;
|
||||
case SAGA_ISO_MAP:
|
||||
if (!(_sceneDescription.flags & kSceneFlagISO)) {
|
||||
@ -792,7 +791,7 @@ int Scene::processSceneResources() {
|
||||
|
||||
debug(0, "Loading isometric map resource.");
|
||||
|
||||
_vm->_isoMap->loadMap(res_data, res_data_len);
|
||||
_vm->_isoMap->loadMap(resourceData, resourceDataLength);
|
||||
break;
|
||||
case SAGA_ISO_PLATFORMS:
|
||||
if (!(_sceneDescription.flags & kSceneFlagISO)) {
|
||||
@ -801,7 +800,7 @@ int Scene::processSceneResources() {
|
||||
|
||||
debug(0, "Loading isometric platforms resource.");
|
||||
|
||||
_vm->_isoMap->loadPlatforms(res_data, res_data_len);
|
||||
_vm->_isoMap->loadPlatforms(resourceData, resourceDataLength);
|
||||
break;
|
||||
case SAGA_ISO_METATILES:
|
||||
if (!(_sceneDescription.flags & kSceneFlagISO)) {
|
||||
@ -810,7 +809,7 @@ int Scene::processSceneResources() {
|
||||
|
||||
debug(0, "Loading isometric metatiles resource.");
|
||||
|
||||
_vm->_isoMap->loadMetaTiles(res_data, res_data_len);
|
||||
_vm->_isoMap->loadMetaTiles(resourceData, resourceDataLength);
|
||||
break;
|
||||
case SAGA_ANIM_1:
|
||||
case SAGA_ANIM_2:
|
||||
@ -820,21 +819,17 @@ int Scene::processSceneResources() {
|
||||
case SAGA_ANIM_6:
|
||||
case SAGA_ANIM_7:
|
||||
{
|
||||
uint16 new_anim_id;
|
||||
uint16 animId;
|
||||
|
||||
debug(0, "Loading animation resource...");
|
||||
|
||||
if (_vm->_anim->load(_resList[i].res_data,
|
||||
_resList[i].res_data_len, &new_anim_id) != SUCCESS) {
|
||||
warning("Scene::ProcessSceneResources(): Error loading animation resource");
|
||||
return FAILURE;
|
||||
}
|
||||
animId = _vm->_anim->load(resourceData, resourceDataLength);
|
||||
|
||||
SCENE_ANIMINFO *new_animinfo;
|
||||
|
||||
new_animinfo = _animList.pushBack().operator->();
|
||||
|
||||
new_animinfo->anim_handle = new_anim_id;
|
||||
new_animinfo->anim_handle = animId;
|
||||
new_animinfo->anim_res_number = _resList[i].res_number;
|
||||
_animEntries++;
|
||||
}
|
||||
@ -846,15 +841,15 @@ int Scene::processSceneResources() {
|
||||
|
||||
debug(0, "Loading isometric multi resource.");
|
||||
|
||||
_vm->_isoMap->loadMulti(res_data, res_data_len);
|
||||
_vm->_isoMap->loadMulti(resourceData, resourceDataLength);
|
||||
break;
|
||||
case SAGA_PAL_ANIM:
|
||||
debug(0, "Loading palette animation resource.");
|
||||
_vm->_palanim->loadPalAnim(_resList[i].res_data, _resList[i].res_data_len);
|
||||
_vm->_palanim->loadPalAnim(resourceData, resourceDataLength);
|
||||
break;
|
||||
case SAGA_ENTRY:
|
||||
debug(0, "Loading entry list resource...");
|
||||
loadSceneEntryList(res_data, res_data_len);
|
||||
loadSceneEntryList(resourceData, resourceDataLength);
|
||||
break;
|
||||
case SAGA_FACES:
|
||||
_vm->_interface->loadScenePortraits(_resList[i].res_number);
|
||||
@ -889,6 +884,8 @@ void Scene::draw() {
|
||||
}
|
||||
|
||||
void Scene::endScene() {
|
||||
int i;
|
||||
|
||||
if (!_sceneLoaded)
|
||||
return;
|
||||
|
||||
@ -921,8 +918,11 @@ void Scene::endScene() {
|
||||
}
|
||||
|
||||
// Free scene resource list
|
||||
if (_loadDescription) {
|
||||
for (i = 0; i < _resListEntries; i++) {
|
||||
RSC_FreeResource(_resList[i].res_data);
|
||||
}
|
||||
|
||||
if (_loadDescription) {
|
||||
free(_resList);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user