From d9a38f6f55262a945a9ae2a56f4eb0bed1b54551 Mon Sep 17 00:00:00 2001 From: Andrew Kurushin Date: Sat, 11 Jun 2005 17:24:06 +0000 Subject: rewritten animation loading removed animation warnings during game process svn-id: r18377 --- saga/animation.cpp | 502 ++++++++++++++++++++--------------------------------- saga/animation.h | 133 ++++++++------ saga/scene.cpp | 58 +++---- 3 files changed, 297 insertions(+), 396 deletions(-) (limited to 'saga') diff --git a/saga/animation.cpp b/saga/animation.cpp index 6bc97b5be7..8aa1dcecd0 100644 --- a/saga/animation.cpp +++ b/saga/animation.cpp @@ -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; - - new_anim->frame_time = DEFAULT_FRAME_TIME; - new_anim->flags = 0; - new_anim->link_id = -1; - new_anim->state = ANIM_PAUSE; + anim->currentFrame = 0; + anim->completed = 0; + anim->cycles = anim->maxFrame; - _anim_tbl[anim_id] = new_anim; + anim->frameTime = DEFAULT_FRAME_TIME; + anim->flags = 0; + anim->linkId = -1; + anim->state = ANIM_PAUSE; - *anim_id_p = anim_id; - - _anim_count++; - - return SUCCESS; + return animId; } -int Anim::link(int16 anim_id1, int16 anim_id2) { - ANIMATION *anim1; - ANIMATION *anim2; - - if ((anim_id1 >= _anim_count) || (anim_id2 >= _anim_count)) { - return FAILURE; - } - - anim1 = _anim_tbl[anim_id1]; +void Anim::link(int16 animId1, int16 animId2) { + AnimationData *anim1; + AnimationData *anim2; - anim1->link_id = anim_id2; + anim1 = getAnimation(animId1); - if (anim_id2 == -1) - return SUCCESS; + anim1->linkId = animId2; - anim2 = _anim_tbl[anim_id2]; - - if ((anim1 == NULL) || (anim2 == NULL)) { - return FAILURE; + if (animId2 == -1) { + return; } - anim2->frame_time = anim1->frame_time; - - return SUCCESS; + anim2 = getAnimation(animId2); + anim2->frameTime = anim1->frameTime; } -void Anim::setCycles(uint animId, int cycles) { - if (animId >= _anim_count) { - warning("Anim::setCycles(): wrong animation number (%d)", animId); - return; - } +void Anim::setCycles(uint16 animId, int cycles) { + AnimationData *anim; + + anim = getAnimation(animId); - _anim_tbl[animId]->cycles = cycles; + anim->cycles = cycles; } -int Anim::play(uint16 anim_id, int vector_time, bool playing) { +void Anim::play(uint16 animId, int vectorTime, bool playing) { EVENT event; - ANIMATION *anim; - ANIMATION *link_anim; - uint16 link_anim_id; - 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) + 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; - - if (anim_id > _anim_count) { - return FAILURE; - } - - anim = _anim_tbl[anim_id]; - if (anim == NULL) { - return FAILURE; - } +void Anim::setFrameTime(uint16 animId, int time) { + AnimationData *anim; - anim->frame_time = time; + anim = getAnimation(animId); - return SUCCESS; + anim->frameTime = time; } int16 Anim::getCurrentFrame(uint16 animId) { - if (animId >= _anim_count) { - warning("Anim::stop(): wrong animation number (%d)", animId); - return 0; - } - - return _anim_tbl[animId]->current_frame; -} + AnimationData *anim; -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(); + anim = getAnimation(animId); + + return anim->currentFrame; } -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); - - readAnimHeader(readS, ah); + MemoryReadStreamEndian readS(anim->resourceData, anim->resourceLength, IS_BIG_ENDIAN); - 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); } } diff --git a/saga/animation.h b/saga/animation.h index 2c8b0abc6d..ca6c027f73 100644 --- a/saga/animation.h +++ b/saga/animation.h @@ -48,58 +48,67 @@ 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; }; +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 ANIMATION { +struct AnimationData { + byte *resourceData; + size_t resourceLength; - const byte *resdata; - size_t resdata_len; + uint16 magic; + + uint16 screenWidth; + uint16 screenHeight; + + byte unknown06; + byte unknown07; + + uint16 maxFrame; + uint16 loopFrame; + + uint16 start; + + uint16 currentFrame; + size_t *frameOffsets; - 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; + int frameTime; + + AnimationState state; + int16 linkId; uint16 flags; -}; -enum ANIM_FLAGS { - ANIM_PLAYING = 0x01, - ANIM_PAUSE = 0x02, - ANIM_STOPPING = 0x04, - ANIM_ENDSCENE = 0x80 // When animation ends, dispatch scene end event + 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 { @@ -107,38 +116,56 @@ 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" */ diff --git a/saga/scene.cpp b/saga/scene.cpp index 777b399a79..b67510a128 100644 --- a/saga/scene.cpp +++ b/saga/scene.cpp @@ -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); } -- cgit v1.2.3