2007-05-30 21:56:52 +00:00
|
|
|
/* ScummVM - Graphic Adventure Engine
|
2004-04-12 21:40:49 +00:00
|
|
|
*
|
2007-05-30 21:56:52 +00:00
|
|
|
* ScummVM is the legal property of its developers, whose names
|
|
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
|
|
* file distributed with this source distribution.
|
2004-04-12 21:40:49 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2005-10-18 01:30:26 +00:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2004-04-12 21:40:49 +00:00
|
|
|
*
|
2006-02-11 12:44:16 +00:00
|
|
|
* $URL$
|
|
|
|
* $Id$
|
2004-04-12 21:40:49 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2004-05-01 06:16:57 +00:00
|
|
|
// Background animation management module
|
2007-07-31 18:08:40 +00:00
|
|
|
|
2004-08-02 16:20:35 +00:00
|
|
|
#include "saga/saga.h"
|
|
|
|
#include "saga/gfx.h"
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-08-10 18:31:33 +00:00
|
|
|
#include "saga/console.h"
|
2004-08-10 19:00:30 +00:00
|
|
|
#include "saga/events.h"
|
2005-09-24 10:13:17 +00:00
|
|
|
#include "saga/interface.h"
|
2004-08-02 16:20:35 +00:00
|
|
|
#include "saga/render.h"
|
2005-09-24 10:13:17 +00:00
|
|
|
#include "saga/rscfile.h"
|
|
|
|
#include "saga/scene.h"
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-08-02 16:20:35 +00:00
|
|
|
#include "saga/animation.h"
|
2004-04-12 21:40:49 +00:00
|
|
|
|
|
|
|
namespace Saga {
|
|
|
|
|
2004-08-01 13:34:20 +00:00
|
|
|
Anim::Anim(SagaEngine *vm) : _vm(vm) {
|
2005-06-11 17:24:06 +00:00
|
|
|
uint16 i;
|
2004-08-01 07:23:36 +00:00
|
|
|
|
2005-09-23 14:29:26 +00:00
|
|
|
_cutawayList = NULL;
|
|
|
|
_cutawayListLength = 0;
|
2005-09-24 19:29:55 +00:00
|
|
|
_cutawayActive = false;
|
2005-09-23 14:29:26 +00:00
|
|
|
|
2004-10-27 21:32:28 +00:00
|
|
|
for (i = 0; i < MAX_ANIMATIONS; i++)
|
2005-06-11 17:24:06 +00:00
|
|
|
_animations[i] = NULL;
|
2005-09-27 06:16:16 +00:00
|
|
|
|
|
|
|
for (i = 0; i < ARRAYSIZE(_cutawayAnimations); i++)
|
|
|
|
_cutawayAnimations[i] = NULL;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-07-31 13:34:43 +00:00
|
|
|
Anim::~Anim(void) {
|
2005-06-11 17:24:06 +00:00
|
|
|
reset();
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2005-09-23 14:29:26 +00:00
|
|
|
void Anim::loadCutawayList(const byte *resourcePointer, size_t resourceLength) {
|
|
|
|
free(_cutawayList);
|
|
|
|
_cutawayListLength = resourceLength / 8;
|
|
|
|
_cutawayList = (Cutaway *)malloc(_cutawayListLength * sizeof(Cutaway));
|
|
|
|
|
|
|
|
MemoryReadStream cutawayS(resourcePointer, resourceLength);
|
|
|
|
|
|
|
|
for (int i = 0; i < _cutawayListLength; i++) {
|
2005-09-24 10:13:17 +00:00
|
|
|
_cutawayList[i].backgroundResourceId = cutawayS.readUint16LE();
|
|
|
|
_cutawayList[i].animResourceId = cutawayS.readUint16LE();
|
2005-09-25 14:41:52 +00:00
|
|
|
_cutawayList[i].cycles = cutawayS.readSint16LE();
|
|
|
|
_cutawayList[i].frameRate = cutawayS.readSint16LE();
|
2005-09-23 14:29:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Anim::freeCutawayList(void) {
|
|
|
|
free(_cutawayList);
|
|
|
|
_cutawayList = NULL;
|
|
|
|
_cutawayListLength = 0;
|
|
|
|
}
|
|
|
|
|
2005-09-24 10:13:17 +00:00
|
|
|
void Anim::playCutaway(int cut, bool fade) {
|
|
|
|
debug(0, "playCutaway(%d, %d)", cut, fade);
|
|
|
|
|
2007-06-16 01:59:04 +00:00
|
|
|
bool startImmediately = false;
|
|
|
|
|
2007-06-07 12:11:33 +00:00
|
|
|
_cutAwayFade = fade;
|
|
|
|
|
2007-08-24 11:35:59 +00:00
|
|
|
_vm->_gfx->savePalette();
|
2007-06-11 02:30:04 +00:00
|
|
|
|
2007-06-16 08:53:46 +00:00
|
|
|
if (fade) {
|
|
|
|
_vm->_gfx->getCurrentPal(saved_pal);
|
|
|
|
// TODO
|
|
|
|
/*
|
2007-06-06 18:02:33 +00:00
|
|
|
Event event;
|
|
|
|
static PalEntry cur_pal[PAL_ENTRIES];
|
|
|
|
|
|
|
|
_vm->_gfx->getCurrentPal(cur_pal);
|
|
|
|
|
|
|
|
event.type = kEvTImmediate;
|
|
|
|
event.code = kPalEvent;
|
|
|
|
event.op = kEventPalToBlack;
|
|
|
|
event.time = 0;
|
|
|
|
event.duration = kNormalFadeDuration;
|
|
|
|
event.data = cur_pal;
|
|
|
|
|
|
|
|
_vm->_events->queue(&event);
|
2007-06-16 08:53:46 +00:00
|
|
|
*/
|
|
|
|
}
|
2005-09-24 10:13:17 +00:00
|
|
|
|
2007-06-16 02:38:17 +00:00
|
|
|
// Prepare cutaway
|
2007-08-25 16:00:50 +00:00
|
|
|
if (!_cutawayActive) {
|
|
|
|
_vm->_gfx->showCursor(false);
|
|
|
|
_vm->_interface->setStatusText("");
|
|
|
|
_vm->_interface->setSaveReminderState(0);
|
|
|
|
_vm->_interface->rememberMode();
|
|
|
|
_cutawayActive = true;
|
|
|
|
} else {
|
|
|
|
// If another cutaway is up, start the next cutaway immediately
|
|
|
|
startImmediately = true;
|
|
|
|
}
|
2005-09-24 10:13:17 +00:00
|
|
|
|
2007-08-25 19:59:07 +00:00
|
|
|
if (_cutAwayMode == kPanelVideo)
|
|
|
|
_vm->_interface->setMode(kPanelVideo);
|
|
|
|
else
|
|
|
|
_vm->_interface->setMode(kPanelCutaway);
|
|
|
|
|
2005-09-24 10:13:17 +00:00
|
|
|
// Set the initial background and palette for the cutaway
|
|
|
|
ResourceContext *context = _vm->_resource->getContext(GAME_RESOURCEFILE);
|
|
|
|
|
|
|
|
byte *resourceData;
|
|
|
|
size_t resourceDataLength;
|
|
|
|
|
|
|
|
_vm->_resource->loadResource(context, _cutawayList[cut].backgroundResourceId, resourceData, resourceDataLength);
|
|
|
|
|
|
|
|
byte *buf;
|
|
|
|
size_t buflen;
|
|
|
|
int width;
|
|
|
|
int height;
|
|
|
|
|
|
|
|
_vm->decodeBGImage(resourceData, resourceDataLength, &buf, &buflen, &width, &height);
|
|
|
|
|
2005-09-27 17:00:32 +00:00
|
|
|
const PalEntry *palette = (const PalEntry *)_vm->getImagePal(resourceData, resourceDataLength);
|
2005-09-24 10:13:17 +00:00
|
|
|
|
|
|
|
Surface *bgSurface = _vm->_render->getBackGroundSurface();
|
|
|
|
const Rect rect(width, height);
|
|
|
|
|
|
|
|
bgSurface->blit(rect, buf);
|
2007-06-15 03:16:06 +00:00
|
|
|
_vm->_frameCount++;
|
|
|
|
|
2005-10-05 01:40:55 +00:00
|
|
|
_vm->_gfx->setPalette(palette);
|
2005-09-24 10:13:17 +00:00
|
|
|
|
|
|
|
free(buf);
|
|
|
|
free(resourceData);
|
|
|
|
|
2005-09-28 06:33:13 +00:00
|
|
|
// Play the animation
|
|
|
|
|
2005-09-27 06:16:16 +00:00
|
|
|
int cutawaySlot = -1;
|
|
|
|
|
|
|
|
for (int i = 0; i < ARRAYSIZE(_cutawayAnimations); i++) {
|
|
|
|
if (!_cutawayAnimations[i]) {
|
|
|
|
cutawaySlot = i;
|
|
|
|
} else if (_cutawayAnimations[i]->state == ANIM_PAUSE) {
|
|
|
|
delete _cutawayAnimations[i];
|
|
|
|
_cutawayAnimations[i] = NULL;
|
|
|
|
cutawaySlot = i;
|
|
|
|
} else if (_cutawayAnimations[i]->state == ANIM_PLAYING) {
|
|
|
|
_cutawayAnimations[i]->state = ANIM_PAUSE;
|
|
|
|
}
|
|
|
|
}
|
2005-09-24 19:29:55 +00:00
|
|
|
|
2005-09-27 06:16:16 +00:00
|
|
|
if (cutawaySlot == -1) {
|
|
|
|
warning("Could not allocate cutaway animation slot");
|
|
|
|
return;
|
|
|
|
}
|
2007-06-14 23:28:30 +00:00
|
|
|
|
2007-06-15 02:29:08 +00:00
|
|
|
// Some cutaways in IHNM have animResourceId equal to 0, which means that they only have
|
|
|
|
// a background frame and no animation. Those animations are actually game scripts.
|
|
|
|
// An example is the "nightfall" animation in Ben's chapter (fadein-fadeout), the animation
|
|
|
|
// for the second from the left monitor in Ellen's chapter etc
|
|
|
|
// Therefore, skip the animation bit if animResourceId is 0 and only show the background
|
2007-08-24 13:40:03 +00:00
|
|
|
if (_cutawayList[cut].animResourceId != 0) {
|
|
|
|
_vm->_resource->loadResource(context, _cutawayList[cut].animResourceId, resourceData, resourceDataLength);
|
|
|
|
load(MAX_ANIMATIONS + cutawaySlot, resourceData, resourceDataLength);
|
|
|
|
free(resourceData);
|
2005-09-24 19:29:55 +00:00
|
|
|
|
2007-08-24 13:40:03 +00:00
|
|
|
setCycles(MAX_ANIMATIONS + cutawaySlot, _cutawayList[cut].cycles);
|
|
|
|
setFrameTime(MAX_ANIMATIONS + cutawaySlot, 1000 / _cutawayList[cut].frameRate);
|
|
|
|
}
|
2007-06-16 01:59:04 +00:00
|
|
|
|
|
|
|
if (_cutAwayMode != kPanelVideo || startImmediately)
|
2007-06-07 15:49:12 +00:00
|
|
|
play(MAX_ANIMATIONS + cutawaySlot, 0);
|
|
|
|
else {
|
|
|
|
Event event;
|
|
|
|
event.type = kEvTOneshot;
|
|
|
|
event.code = kAnimEvent;
|
|
|
|
event.op = kEventPlay;
|
|
|
|
event.param = MAX_ANIMATIONS + cutawaySlot;
|
|
|
|
event.time = (40 / 3) * 1000 / _cutawayList[cut].frameRate;
|
|
|
|
|
|
|
|
_vm->_events->queue(&event);
|
|
|
|
}
|
2005-09-24 19:29:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Anim::endCutaway(void) {
|
2007-08-21 12:46:21 +00:00
|
|
|
// This is called by scripts after a cutaway is finished. At this time,
|
|
|
|
// nothing needs to be done here.
|
2005-09-24 19:29:55 +00:00
|
|
|
|
|
|
|
debug(0, "endCutaway()");
|
|
|
|
}
|
|
|
|
|
|
|
|
void Anim::returnFromCutaway(void) {
|
2007-08-21 12:46:21 +00:00
|
|
|
// This is called by scripts after a cutaway is finished, to return back
|
|
|
|
// to the scene that the cutaway was called from. It's not called by the
|
|
|
|
// IHNM intro, as there is no old scene to return to.
|
2005-09-24 19:29:55 +00:00
|
|
|
|
|
|
|
debug(0, "returnFromCutaway()");
|
|
|
|
|
2007-06-16 08:53:46 +00:00
|
|
|
|
2005-09-24 19:29:55 +00:00
|
|
|
if (_cutawayActive) {
|
2007-06-16 08:53:46 +00:00
|
|
|
Event event;
|
|
|
|
Event *q_event = NULL;
|
|
|
|
|
|
|
|
if (_cutAwayFade) {
|
|
|
|
static PalEntry cur_pal[PAL_ENTRIES];
|
|
|
|
|
|
|
|
_vm->_gfx->getCurrentPal(cur_pal);
|
|
|
|
|
|
|
|
event.type = kEvTImmediate;
|
|
|
|
event.code = kPalEvent;
|
|
|
|
event.op = kEventPalToBlack;
|
|
|
|
event.time = 0;
|
2007-06-17 01:50:49 +00:00
|
|
|
event.duration = kNormalFadeDuration;
|
2007-06-16 08:53:46 +00:00
|
|
|
event.data = cur_pal;
|
|
|
|
|
|
|
|
q_event = _vm->_events->queue(&event);
|
|
|
|
}
|
|
|
|
|
2007-06-17 01:50:49 +00:00
|
|
|
// Clear the cutaway. Note that this sets _cutawayActive to false
|
2007-06-16 08:53:46 +00:00
|
|
|
event.type = kEvTImmediate;
|
|
|
|
event.code = kCutawayEvent;
|
2007-06-17 16:21:05 +00:00
|
|
|
event.op = kEventClear;
|
2007-06-16 08:53:46 +00:00
|
|
|
event.time = 0;
|
|
|
|
event.duration = 0;
|
|
|
|
|
|
|
|
if (_cutAwayFade)
|
|
|
|
q_event = _vm->_events->chain(q_event, &event); // chain with the other events
|
|
|
|
else
|
|
|
|
q_event = _vm->_events->queue(&event);
|
|
|
|
|
2007-06-17 01:00:06 +00:00
|
|
|
_vm->_scene->restoreScene();
|
2007-06-16 14:06:17 +00:00
|
|
|
|
|
|
|
// Restore the animations
|
|
|
|
event.type = kEvTImmediate;
|
|
|
|
event.code = kAnimEvent;
|
|
|
|
event.op = kEventResumeAll;
|
|
|
|
event.time = 0;
|
|
|
|
event.duration = 0;
|
|
|
|
|
|
|
|
q_event = _vm->_events->chain(q_event, &event); // chain with the other events
|
2005-09-27 06:16:16 +00:00
|
|
|
|
2007-06-17 01:50:49 +00:00
|
|
|
// Draw the scene
|
|
|
|
event.type = kEvTImmediate;
|
|
|
|
event.code = kSceneEvent;
|
2007-06-17 16:21:05 +00:00
|
|
|
event.op = kEventDraw;
|
2007-06-17 01:50:49 +00:00
|
|
|
event.time = 0;
|
|
|
|
event.duration = 0;
|
|
|
|
|
|
|
|
q_event = _vm->_events->chain(q_event, &event); // chain with the other events
|
|
|
|
|
2007-06-06 19:46:10 +00:00
|
|
|
// Handle fade up, if we previously faded down
|
2007-06-16 08:53:46 +00:00
|
|
|
if (_cutAwayFade) {
|
2007-06-07 12:11:33 +00:00
|
|
|
event.type = kEvTImmediate;
|
|
|
|
event.code = kPalEvent;
|
|
|
|
event.op = kEventBlackToPal;
|
|
|
|
event.time = 0;
|
2007-06-17 01:50:49 +00:00
|
|
|
event.duration = kNormalFadeDuration;
|
2007-06-07 12:11:33 +00:00
|
|
|
event.data = saved_pal;
|
|
|
|
|
2007-06-16 08:53:46 +00:00
|
|
|
q_event = _vm->_events->chain(q_event, &event);
|
2007-06-17 01:00:06 +00:00
|
|
|
|
2007-06-16 08:53:46 +00:00
|
|
|
}
|
2007-06-17 01:00:06 +00:00
|
|
|
|
|
|
|
event.type = kEvTOneshot;
|
|
|
|
event.code = kScriptEvent;
|
|
|
|
event.op = kEventThreadWake;
|
|
|
|
event.param = kWaitTypeWakeUp;
|
|
|
|
|
|
|
|
q_event = _vm->_events->chain(q_event, &event);
|
2005-10-03 10:01:09 +00:00
|
|
|
}
|
|
|
|
}
|
2005-09-24 19:29:55 +00:00
|
|
|
|
2005-10-03 10:01:09 +00:00
|
|
|
void Anim::clearCutaway(void) {
|
2007-08-24 11:35:59 +00:00
|
|
|
PalEntry *pal;
|
|
|
|
|
2007-06-17 01:00:06 +00:00
|
|
|
debug(1, "clearCutaway()");
|
2007-08-24 11:35:59 +00:00
|
|
|
|
2005-10-03 10:01:09 +00:00
|
|
|
if (_cutawayActive) {
|
|
|
|
_cutawayActive = false;
|
2005-09-24 19:29:55 +00:00
|
|
|
|
2005-10-03 10:01:09 +00:00
|
|
|
for (int i = 0; i < ARRAYSIZE(_cutawayAnimations); i++) {
|
|
|
|
delete _cutawayAnimations[i];
|
|
|
|
_cutawayAnimations[i] = NULL;
|
|
|
|
}
|
2005-09-24 19:29:55 +00:00
|
|
|
|
2005-10-06 15:56:06 +00:00
|
|
|
_vm->_interface->restoreMode();
|
2007-07-30 23:37:18 +00:00
|
|
|
|
|
|
|
if (_vm->getGameId() != GID_IHNM_DEMO) {
|
2007-08-24 12:05:05 +00:00
|
|
|
_vm->_gfx->showCursor(true);
|
|
|
|
} else {
|
|
|
|
if (_vm->_scene->isNonInteractiveIHNMDemoPart()) {
|
2007-07-30 23:37:18 +00:00
|
|
|
// Don't show the mouse cursor in the non-interactive part of the IHNM demo
|
|
|
|
} else {
|
|
|
|
_vm->_gfx->showCursor(true);
|
|
|
|
}
|
|
|
|
// Enable the save reminder state after each cutaway for the IHNM demo
|
|
|
|
_vm->_interface->setSaveReminderState(true);
|
|
|
|
}
|
2007-08-24 11:35:59 +00:00
|
|
|
|
|
|
|
// Set the scene's palette
|
|
|
|
_vm->_scene->getBGPal(pal);
|
|
|
|
_vm->_gfx->setPalette(pal);
|
2005-09-24 19:29:55 +00:00
|
|
|
}
|
2005-09-24 10:13:17 +00:00
|
|
|
}
|
|
|
|
|
2007-06-06 19:46:10 +00:00
|
|
|
void Anim::startVideo(int vid, bool fade) {
|
|
|
|
debug(0, "startVideo(%d, %d)", vid, fade);
|
|
|
|
|
2007-06-07 12:11:33 +00:00
|
|
|
_vm->_interface->setStatusText("");
|
2007-06-07 15:49:12 +00:00
|
|
|
_vm->_frameCount = 0;
|
2007-06-06 19:46:10 +00:00
|
|
|
|
2007-06-07 12:11:33 +00:00
|
|
|
playCutaway(vid, fade);
|
2007-06-06 19:46:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Anim::endVideo(void) {
|
|
|
|
debug(0, "endVideo()");
|
|
|
|
|
2007-06-07 12:11:33 +00:00
|
|
|
clearCutaway();
|
2007-06-06 19:46:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Anim::returnFromVideo(void) {
|
|
|
|
debug(0, "returnFromVideo()");
|
|
|
|
|
2007-06-07 12:11:33 +00:00
|
|
|
returnFromCutaway();
|
2007-06-06 19:46:10 +00:00
|
|
|
}
|
|
|
|
|
2005-06-20 11:46:34 +00:00
|
|
|
void Anim::load(uint16 animId, const byte *animResourceData, size_t animResourceLength) {
|
2005-06-11 17:24:06 +00:00
|
|
|
AnimationData *anim;
|
2005-07-19 19:05:52 +00:00
|
|
|
uint16 temp;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-20 11:46:34 +00:00
|
|
|
if (animId >= MAX_ANIMATIONS) {
|
2005-09-27 06:16:16 +00:00
|
|
|
if (animId >= MAX_ANIMATIONS + ARRAYSIZE(_cutawayAnimations))
|
|
|
|
error("Anim::load could not find unused animation slot");
|
|
|
|
anim = _cutawayAnimations[animId - MAX_ANIMATIONS] = new AnimationData(animResourceData, animResourceLength);
|
|
|
|
} else
|
|
|
|
anim = _animations[animId] = new AnimationData(animResourceData, animResourceLength);
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-07-19 19:05:52 +00:00
|
|
|
MemoryReadStreamEndian headerReadS(anim->resourceData, anim->resourceLength, _vm->isBigEndian());
|
2005-06-11 17:24:06 +00:00
|
|
|
anim->magic = headerReadS.readUint16LE(); // cause ALWAYS LE
|
|
|
|
anim->screenWidth = headerReadS.readUint16();
|
|
|
|
anim->screenHeight = headerReadS.readUint16();
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
anim->unknown06 = headerReadS.readByte();
|
|
|
|
anim->unknown07 = headerReadS.readByte();
|
|
|
|
anim->maxFrame = headerReadS.readByte() - 1;
|
|
|
|
anim->loopFrame = headerReadS.readByte() - 1;
|
2005-07-19 19:05:52 +00:00
|
|
|
temp = headerReadS.readUint16BE();
|
|
|
|
anim->start = headerReadS.pos();
|
|
|
|
if (temp == (uint16)(-1)) {
|
|
|
|
temp = 0;
|
|
|
|
}
|
|
|
|
anim->start += temp;
|
2004-12-28 03:44:07 +00:00
|
|
|
|
2005-07-25 16:22:32 +00:00
|
|
|
// Cache frame offsets
|
|
|
|
anim->frameOffsets = (size_t *)malloc((anim->maxFrame + 1) * sizeof(*anim->frameOffsets));
|
|
|
|
if (anim->frameOffsets == NULL) {
|
|
|
|
memoryError("Anim::load");
|
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-07-25 16:22:32 +00:00
|
|
|
fillFrameOffsets(anim);
|
2005-07-19 19:05:52 +00:00
|
|
|
|
2004-05-01 06:16:57 +00:00
|
|
|
// Set animation data
|
2005-06-11 17:24:06 +00:00
|
|
|
anim->currentFrame = 0;
|
|
|
|
anim->completed = 0;
|
|
|
|
anim->cycles = anim->maxFrame;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
anim->frameTime = DEFAULT_FRAME_TIME;
|
2005-10-01 11:09:49 +00:00
|
|
|
anim->flags = ANIM_FLAG_NONE;
|
2005-06-11 17:24:06 +00:00
|
|
|
anim->linkId = -1;
|
2005-07-29 17:58:00 +00:00
|
|
|
anim->state = ANIM_PAUSE;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
void Anim::link(int16 animId1, int16 animId2) {
|
|
|
|
AnimationData *anim1;
|
|
|
|
AnimationData *anim2;
|
2004-12-28 03:44:07 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
anim1 = getAnimation(animId1);
|
2004-12-28 03:44:07 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
anim1->linkId = animId2;
|
2004-12-28 03:44:07 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
if (animId2 == -1) {
|
|
|
|
return;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
anim2 = getAnimation(animId2);
|
|
|
|
anim2->frameTime = anim1->frameTime;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
void Anim::setCycles(uint16 animId, int cycles) {
|
|
|
|
AnimationData *anim;
|
|
|
|
|
|
|
|
anim = getAnimation(animId);
|
2005-07-29 17:58:00 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
anim->cycles = cycles;
|
2004-12-28 03:44:07 +00:00
|
|
|
}
|
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
void Anim::play(uint16 animId, int vectorTime, bool playing) {
|
2005-08-10 14:11:22 +00:00
|
|
|
Event event;
|
2005-07-09 16:23:45 +00:00
|
|
|
Surface *backGroundSurface;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
byte *displayBuffer;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-04-30 23:02:23 +00:00
|
|
|
uint16 frame;
|
2005-06-11 17:24:06 +00:00
|
|
|
int frameTime;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
AnimationData *anim;
|
|
|
|
AnimationData *linkAnim;
|
|
|
|
|
2005-09-27 06:16:16 +00:00
|
|
|
if (animId > MAX_ANIMATIONS && !_cutawayActive)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (animId < MAX_ANIMATIONS && _cutawayActive)
|
|
|
|
return;
|
|
|
|
|
2007-08-24 13:40:03 +00:00
|
|
|
if (animId >= MAX_ANIMATIONS && _cutawayAnimations[animId - MAX_ANIMATIONS] == NULL) {
|
|
|
|
// In IHNM, cutaways without an animation bit are not rendered, but the framecount
|
|
|
|
// needs to be updated
|
|
|
|
_vm->_frameCount++;
|
|
|
|
|
|
|
|
event.type = kEvTOneshot;
|
|
|
|
event.code = kAnimEvent;
|
|
|
|
event.op = kEventFrame;
|
|
|
|
event.param = animId;
|
|
|
|
event.time = 10;
|
|
|
|
|
|
|
|
_vm->_events->queue(&event);
|
|
|
|
|
|
|
|
// Nothing to render here (apart from the background, which is already rendered),
|
|
|
|
// so return
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
anim = getAnimation(animId);
|
|
|
|
|
2005-07-09 16:23:45 +00:00
|
|
|
backGroundSurface = _vm->_render->getBackGroundSurface();
|
|
|
|
displayBuffer = (byte*)backGroundSurface->pixels;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
if (playing) {
|
2004-12-28 04:09:10 +00:00
|
|
|
anim->state = ANIM_PLAYING;
|
2005-06-11 17:24:06 +00:00
|
|
|
}
|
2004-12-28 03:44:07 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
if (anim->state == ANIM_PAUSE) {
|
|
|
|
return;
|
|
|
|
}
|
2004-08-10 23:04:52 +00:00
|
|
|
|
2004-12-28 03:44:07 +00:00
|
|
|
if (anim->completed < anim->cycles) {
|
2007-08-13 08:51:40 +00:00
|
|
|
if (anim->currentFrame < 0)
|
|
|
|
anim->currentFrame = 0;
|
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
frame = anim->currentFrame;
|
2007-07-05 21:19:47 +00:00
|
|
|
|
|
|
|
// WORKAROUND for a buggy animation in IHNM. Animation 0 in scene 67 (the mob of angry prisoners) should
|
|
|
|
// start from frame 0, not frame 1. Frame 0 is the background of the animation (the mob of prisoners), whereas
|
|
|
|
// the rest of the frames are their animated arms. Therefore, in order for the prisoners to appear correctly,
|
|
|
|
// frame 0 should be displayed as the first frame, but anim->currentframe is set to 1, which means that the
|
|
|
|
// prisoners will never be shown. In the original, the prisoners (first frame in the animation) are shown a
|
|
|
|
// bit after the animation is started (which is wrong again, but not that apparent), whereas in ScummVM the
|
|
|
|
// first frame is never shown. Therefore, make sure that for this animation, frame 0 is shown first
|
|
|
|
if (_vm->getGameType() == GType_IHNM && _vm->_scene->currentChapterNumber() == 4 &&
|
|
|
|
_vm->_scene->currentSceneNumber() == 67 && animId == 0 && anim->completed == 1)
|
|
|
|
frame = 0;
|
|
|
|
|
2005-07-25 16:22:32 +00:00
|
|
|
// FIXME: if start > 0, then this works incorrectly
|
|
|
|
decodeFrame(anim, anim->frameOffsets[frame], displayBuffer, _vm->getDisplayWidth() * _vm->getDisplayHeight());
|
2007-06-07 12:11:33 +00:00
|
|
|
_vm->_frameCount++;
|
2005-06-11 17:24:06 +00:00
|
|
|
anim->currentFrame++;
|
2005-06-25 15:55:43 +00:00
|
|
|
if (anim->completed != 65535) {
|
|
|
|
anim->completed++;
|
|
|
|
}
|
2004-12-28 03:44:07 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
if (anim->currentFrame > anim->maxFrame) {
|
2007-06-11 12:14:06 +00:00
|
|
|
|
2007-06-14 23:28:30 +00:00
|
|
|
anim->currentFrame = anim->loopFrame;
|
|
|
|
_vm->_frameCount++;
|
2005-07-29 17:58:00 +00:00
|
|
|
|
2005-10-01 11:09:49 +00:00
|
|
|
if (anim->state == ANIM_STOPPING || anim->currentFrame == -1) {
|
2004-12-28 04:09:10 +00:00
|
|
|
anim->state = ANIM_PAUSE;
|
2005-06-11 17:24:06 +00:00
|
|
|
}
|
2004-12-28 03:44:07 +00:00
|
|
|
}
|
|
|
|
} else {
|
2007-06-11 12:39:44 +00:00
|
|
|
_vm->_frameCount += 100; // make sure the waiting thread stops waiting
|
2004-05-01 06:16:57 +00:00
|
|
|
// Animation done playing
|
2005-08-13 16:27:47 +00:00
|
|
|
anim->state = ANIM_PAUSE;
|
|
|
|
if (anim->linkId == -1) {
|
2005-10-01 11:09:49 +00:00
|
|
|
if (anim->flags & ANIM_FLAG_ENDSCENE) {
|
2004-05-01 06:16:57 +00:00
|
|
|
// This animation ends the scene
|
2005-08-10 15:31:15 +00:00
|
|
|
event.type = kEvTOneshot;
|
|
|
|
event.code = kSceneEvent;
|
|
|
|
event.op = kEventEnd;
|
2005-06-11 17:24:06 +00:00
|
|
|
event.time = anim->frameTime + vectorTime;
|
2004-08-10 19:00:30 +00:00
|
|
|
_vm->_events->queue(&event);
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
2005-06-11 17:24:06 +00:00
|
|
|
return;
|
2005-10-12 17:56:07 +00:00
|
|
|
} else {
|
|
|
|
anim->currentFrame = 0;
|
|
|
|
anim->completed = 0;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
if (anim->state == ANIM_PAUSE && anim->linkId != -1) {
|
2004-12-28 03:44:07 +00:00
|
|
|
// If this animation has a link, follow it
|
2005-06-11 17:24:06 +00:00
|
|
|
linkAnim = getAnimation(anim->linkId);
|
2004-12-28 03:44:07 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
debug(5, "Animation ended going to %d", anim->linkId);
|
|
|
|
linkAnim->state = ANIM_PLAYING;
|
|
|
|
animId = anim->linkId;
|
|
|
|
frameTime = 0;
|
2005-01-12 11:07:56 +00:00
|
|
|
} else {
|
2005-06-11 17:24:06 +00:00
|
|
|
frameTime = anim->frameTime + vectorTime;
|
2004-12-28 03:44:07 +00:00
|
|
|
}
|
|
|
|
|
2005-08-10 15:31:15 +00:00
|
|
|
event.type = kEvTOneshot;
|
|
|
|
event.code = kAnimEvent;
|
|
|
|
event.op = kEventFrame;
|
2005-06-11 17:24:06 +00:00
|
|
|
event.param = animId;
|
|
|
|
event.time = frameTime;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-08-10 19:00:30 +00:00
|
|
|
_vm->_events->queue(&event);
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-12-28 03:44:07 +00:00
|
|
|
void Anim::stop(uint16 animId) {
|
2005-06-11 17:24:06 +00:00
|
|
|
AnimationData *anim;
|
|
|
|
|
|
|
|
anim = getAnimation(animId);
|
|
|
|
|
|
|
|
anim->state = ANIM_PAUSE;
|
2004-12-28 04:09:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Anim::finish(uint16 animId) {
|
2005-06-11 17:24:06 +00:00
|
|
|
AnimationData *anim;
|
|
|
|
|
|
|
|
anim = getAnimation(animId);
|
|
|
|
|
|
|
|
anim->state = ANIM_STOPPING;
|
2004-12-28 04:09:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Anim::resume(uint16 animId, int cycles) {
|
2005-06-11 17:24:06 +00:00
|
|
|
AnimationData *anim;
|
|
|
|
|
|
|
|
anim = getAnimation(animId);
|
2005-07-29 17:58:00 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
anim->cycles += cycles;
|
2004-12-28 04:09:10 +00:00
|
|
|
play(animId, 0, true);
|
2004-12-28 03:44:07 +00:00
|
|
|
}
|
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
void Anim::reset() {
|
2004-04-30 23:02:23 +00:00
|
|
|
uint16 i;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-10-27 21:32:28 +00:00
|
|
|
for (i = 0; i < MAX_ANIMATIONS; i++) {
|
2005-06-11 17:24:06 +00:00
|
|
|
if (_animations[i] != NULL) {
|
|
|
|
delete _animations[i];
|
|
|
|
_animations[i] = NULL;
|
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
2005-09-27 06:16:16 +00:00
|
|
|
|
|
|
|
for (i = 0; i < ARRAYSIZE(_cutawayAnimations); i++) {
|
|
|
|
if (_cutawayAnimations[i] != NULL) {
|
|
|
|
delete _cutawayAnimations[i];
|
|
|
|
_cutawayAnimations[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
void Anim::setFlag(uint16 animId, uint16 flag) {
|
|
|
|
AnimationData *anim;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
anim = getAnimation(animId);
|
2004-04-12 21:40:49 +00:00
|
|
|
|
|
|
|
anim->flags |= flag;
|
|
|
|
}
|
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
void Anim::clearFlag(uint16 animId, uint16 flag) {
|
|
|
|
AnimationData *anim;
|
2004-08-10 23:04:52 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
anim = getAnimation(animId);
|
2004-08-10 23:04:52 +00:00
|
|
|
|
|
|
|
anim->flags &= ~flag;
|
|
|
|
}
|
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
void Anim::setFrameTime(uint16 animId, int time) {
|
|
|
|
AnimationData *anim;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
anim = getAnimation(animId);
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
anim->frameTime = time;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2005-04-16 20:59:24 +00:00
|
|
|
int16 Anim::getCurrentFrame(uint16 animId) {
|
2005-06-11 17:24:06 +00:00
|
|
|
AnimationData *anim;
|
2005-04-16 20:59:24 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
anim = getAnimation(animId);
|
2005-07-29 17:58:00 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
return anim->currentFrame;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2005-07-25 16:22:32 +00:00
|
|
|
void Anim::decodeFrame(AnimationData *anim, size_t frameOffset, byte *buf, size_t bufLength) {
|
|
|
|
byte *writePointer = NULL;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-07-25 16:22:32 +00:00
|
|
|
uint16 xStart = 0;
|
|
|
|
uint16 yStart = 0;
|
2005-06-11 17:24:06 +00:00
|
|
|
uint32 screenWidth;
|
|
|
|
uint32 screenHeight;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-07-25 16:22:32 +00:00
|
|
|
int markByte;
|
|
|
|
byte dataByte;
|
|
|
|
int newRow;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-07-25 16:22:32 +00:00
|
|
|
uint16 controlChar;
|
|
|
|
uint16 paramChar;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-04-30 23:02:23 +00:00
|
|
|
uint16 runcount;
|
2005-07-25 16:22:32 +00:00
|
|
|
int xVector;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-04-30 23:02:23 +00:00
|
|
|
uint16 i;
|
2005-07-25 16:22:32 +00:00
|
|
|
bool longData = isLongData();
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
screenWidth = anim->screenWidth;
|
|
|
|
screenHeight = anim->screenHeight;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
if ((screenWidth * screenHeight) > bufLength) {
|
2004-05-01 06:16:57 +00:00
|
|
|
// Buffer argument is too small to hold decoded frame, abort.
|
2005-07-25 16:22:32 +00:00
|
|
|
error("decodeFrame() Buffer size inadequate");
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
MemoryReadStream readS(anim->resourceData + frameOffset, anim->resourceLength - frameOffset);
|
2004-04-12 21:40:49 +00:00
|
|
|
|
|
|
|
|
2004-12-15 00:24:12 +00:00
|
|
|
#if 1
|
|
|
|
#define VALIDATE_WRITE_POINTER \
|
2005-07-25 16:22:32 +00:00
|
|
|
if ((writePointer < buf) || (writePointer >= (buf + screenWidth * screenHeight))) { \
|
2006-03-08 11:37:25 +00:00
|
|
|
error("VALIDATE_WRITE_POINTER: writePointer=%p buf=%p", (void *)writePointer, (void *)buf); \
|
2004-12-15 00:24:12 +00:00
|
|
|
}
|
|
|
|
#else
|
2005-07-29 17:58:00 +00:00
|
|
|
#define VALIDATE_WRITE_POINTER
|
2004-12-15 00:24:12 +00:00
|
|
|
#endif
|
|
|
|
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2004-05-01 06:16:57 +00:00
|
|
|
// Begin RLE decompression to output buffer
|
2007-06-07 12:11:33 +00:00
|
|
|
do {
|
2005-07-25 16:22:32 +00:00
|
|
|
markByte = readS.readByte();
|
|
|
|
switch (markByte) {
|
|
|
|
case SAGA_FRAME_START:
|
|
|
|
xStart = readS.readUint16BE();
|
|
|
|
if (longData)
|
|
|
|
yStart = readS.readUint16BE();
|
|
|
|
else
|
|
|
|
yStart = readS.readByte();
|
2007-07-31 18:08:40 +00:00
|
|
|
readS.readByte(); // Skip pad byte
|
2005-07-25 16:22:32 +00:00
|
|
|
/*xPos = */readS.readUint16BE();
|
|
|
|
/*yPos = */readS.readUint16BE();
|
|
|
|
/*width = */readS.readUint16BE();
|
|
|
|
/*height = */readS.readUint16BE();
|
|
|
|
|
|
|
|
// Setup write pointer to the draw origin
|
|
|
|
writePointer = (buf + (yStart * screenWidth) + xStart);
|
|
|
|
VALIDATE_WRITE_POINTER;
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
case SAGA_FRAME_NOOP: // Does nothing
|
|
|
|
readS.readByte();
|
|
|
|
readS.readByte();
|
2005-07-29 17:58:00 +00:00
|
|
|
readS.readByte();
|
2005-07-25 16:22:32 +00:00
|
|
|
continue;
|
|
|
|
break;
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_LONG_UNCOMPRESSED_RUN: // Long Unencoded Run
|
2004-08-01 10:02:41 +00:00
|
|
|
runcount = readS.readSint16BE();
|
2004-04-12 21:40:49 +00:00
|
|
|
for (i = 0; i < runcount; i++) {
|
2005-07-25 16:22:32 +00:00
|
|
|
dataByte = readS.readByte();
|
|
|
|
if (dataByte != 0) {
|
|
|
|
*writePointer = dataByte;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
2005-07-25 16:22:32 +00:00
|
|
|
writePointer++;
|
2004-12-15 00:24:12 +00:00
|
|
|
VALIDATE_WRITE_POINTER;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
break;
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_LONG_COMPRESSED_RUN: // Long encoded run
|
2004-08-01 10:02:41 +00:00
|
|
|
runcount = readS.readSint16BE();
|
2005-07-25 16:22:32 +00:00
|
|
|
dataByte = readS.readByte();
|
2004-04-12 21:40:49 +00:00
|
|
|
for (i = 0; i < runcount; i++) {
|
2005-07-25 16:22:32 +00:00
|
|
|
*writePointer++ = dataByte;
|
2004-12-15 00:24:12 +00:00
|
|
|
VALIDATE_WRITE_POINTER;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
break;
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_ROW_END: // End of row
|
2005-07-25 16:22:32 +00:00
|
|
|
xVector = readS.readSint16BE();
|
2005-07-29 17:58:00 +00:00
|
|
|
|
2005-07-25 16:22:32 +00:00
|
|
|
if (longData)
|
|
|
|
newRow = readS.readSint16BE();
|
2004-12-15 00:24:12 +00:00
|
|
|
else
|
2005-07-25 16:22:32 +00:00
|
|
|
newRow = readS.readByte();
|
2004-12-15 00:24:12 +00:00
|
|
|
|
2004-05-01 06:16:57 +00:00
|
|
|
// Set write pointer to the new draw origin
|
2005-07-25 16:22:32 +00:00
|
|
|
writePointer = buf + ((yStart + newRow) * screenWidth) + xStart + xVector;
|
2004-12-15 00:24:12 +00:00
|
|
|
VALIDATE_WRITE_POINTER;
|
2004-04-12 21:40:49 +00:00
|
|
|
continue;
|
|
|
|
break;
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_REPOSITION: // Reposition command
|
2005-07-25 16:22:32 +00:00
|
|
|
xVector = readS.readSint16BE();
|
|
|
|
writePointer += xVector;
|
2004-12-15 00:24:12 +00:00
|
|
|
VALIDATE_WRITE_POINTER;
|
2004-04-12 21:40:49 +00:00
|
|
|
continue;
|
|
|
|
break;
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_END: // End of frame marker
|
2005-06-11 17:24:06 +00:00
|
|
|
return;
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2004-05-01 06:16:57 +00:00
|
|
|
// Mask all but two high order control bits
|
2005-07-25 16:22:32 +00:00
|
|
|
controlChar = markByte & 0xC0U;
|
|
|
|
paramChar = markByte & 0x3FU;
|
|
|
|
switch (controlChar) {
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_EMPTY_RUN: // 1100 0000
|
2004-05-01 06:16:57 +00:00
|
|
|
// Run of empty pixels
|
2005-07-25 16:22:32 +00:00
|
|
|
runcount = paramChar + 1;
|
|
|
|
writePointer += runcount;
|
2004-12-15 00:24:12 +00:00
|
|
|
VALIDATE_WRITE_POINTER;
|
2004-04-12 21:40:49 +00:00
|
|
|
continue;
|
|
|
|
break;
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_COMPRESSED_RUN: // 1000 0000
|
2004-05-01 06:16:57 +00:00
|
|
|
// Run of compressed data
|
2005-07-25 16:22:32 +00:00
|
|
|
runcount = paramChar + 1;
|
|
|
|
dataByte = readS.readByte();
|
2004-04-12 21:40:49 +00:00
|
|
|
for (i = 0; i < runcount; i++) {
|
2005-07-25 16:22:32 +00:00
|
|
|
*writePointer++ = dataByte;
|
2004-12-15 00:24:12 +00:00
|
|
|
VALIDATE_WRITE_POINTER;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
break;
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_UNCOMPRESSED_RUN: // 0100 0000
|
2004-05-01 06:16:57 +00:00
|
|
|
// Uncompressed run
|
2005-07-25 16:22:32 +00:00
|
|
|
runcount = paramChar + 1;
|
2004-04-12 21:40:49 +00:00
|
|
|
for (i = 0; i < runcount; i++) {
|
2005-07-25 16:22:32 +00:00
|
|
|
dataByte = readS.readByte();
|
|
|
|
if (dataByte != 0) {
|
|
|
|
*writePointer = dataByte;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
2005-07-25 16:22:32 +00:00
|
|
|
writePointer++;
|
2004-12-15 00:24:12 +00:00
|
|
|
VALIDATE_WRITE_POINTER;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
default:
|
2004-05-01 06:16:57 +00:00
|
|
|
// Unknown marker found - abort
|
2005-07-25 16:22:32 +00:00
|
|
|
error("decodeFrame() Invalid RLE marker encountered");
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-07-25 16:22:32 +00:00
|
|
|
} while (1);
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
void Anim::fillFrameOffsets(AnimationData *anim) {
|
|
|
|
uint16 currentFrame;
|
2005-07-25 16:22:32 +00:00
|
|
|
byte markByte;
|
2004-04-30 23:02:23 +00:00
|
|
|
uint16 control;
|
|
|
|
uint16 runcount;
|
2004-05-04 03:33:03 +00:00
|
|
|
int i;
|
2005-07-25 16:22:32 +00:00
|
|
|
bool longData = isLongData();
|
2004-05-04 03:33:03 +00:00
|
|
|
|
2005-07-29 17:58:00 +00:00
|
|
|
MemoryReadStreamEndian readS(anim->resourceData, anim->resourceLength, _vm->isBigEndian());
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-07-25 16:22:32 +00:00
|
|
|
readS.seek(12);
|
2005-07-29 17:58:00 +00:00
|
|
|
|
2005-07-19 19:05:52 +00:00
|
|
|
readS._bigEndian = !_vm->isBigEndian(); // RLE has inversion BE<>LE
|
2004-12-15 00:24:12 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
for (currentFrame = 0; currentFrame <= anim->maxFrame; currentFrame++) {
|
|
|
|
anim->frameOffsets[currentFrame] = readS.pos();
|
2004-12-15 00:24:12 +00:00
|
|
|
|
2004-05-01 06:16:57 +00:00
|
|
|
// For some strange reason, the animation header is in little
|
2005-07-29 17:58:00 +00:00
|
|
|
// endian format, but the actual RLE encoded frame data,
|
2007-08-21 12:46:21 +00:00
|
|
|
// including the frame header, is in big endian format
|
2004-04-12 21:40:49 +00:00
|
|
|
do {
|
2005-07-25 16:22:32 +00:00
|
|
|
markByte = readS.readByte();
|
|
|
|
// debug(7, "_pos=%x currentFrame=%i markByte=%x", readS.pos(), currentFrame, markByte);
|
|
|
|
|
|
|
|
switch (markByte) {
|
|
|
|
case SAGA_FRAME_START: // Start of frame
|
|
|
|
// skip header
|
|
|
|
if (longData) {
|
|
|
|
readS.seek(13, SEEK_CUR);
|
|
|
|
} else {
|
|
|
|
readS.seek(12, SEEK_CUR);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
break;
|
2004-12-15 00:24:12 +00:00
|
|
|
|
|
|
|
case SAGA_FRAME_END: // End of frame marker
|
2004-04-12 21:40:49 +00:00
|
|
|
continue;
|
|
|
|
break;
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_REPOSITION: // Reposition command
|
|
|
|
readS.readSint16BE();
|
2004-04-12 21:40:49 +00:00
|
|
|
continue;
|
|
|
|
break;
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_ROW_END: // End of row marker
|
|
|
|
readS.readSint16BE();
|
2005-07-25 16:22:32 +00:00
|
|
|
if (longData)
|
2004-12-15 00:24:12 +00:00
|
|
|
readS.readSint16BE();
|
|
|
|
else
|
|
|
|
readS.readByte();
|
2004-04-12 21:40:49 +00:00
|
|
|
continue;
|
|
|
|
break;
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_LONG_COMPRESSED_RUN: // Long compressed run marker
|
|
|
|
readS.readSint16BE();
|
2004-08-01 10:02:41 +00:00
|
|
|
readS.readByte();
|
2004-04-12 21:40:49 +00:00
|
|
|
continue;
|
|
|
|
break;
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_LONG_UNCOMPRESSED_RUN: // (16) 0001 0000
|
2004-05-01 06:16:57 +00:00
|
|
|
// Long Uncompressed Run
|
2004-08-01 10:02:41 +00:00
|
|
|
runcount = readS.readSint16BE();
|
2004-05-04 03:33:03 +00:00
|
|
|
for (i = 0; i < runcount; i++)
|
2004-08-01 10:02:41 +00:00
|
|
|
readS.readByte();
|
2004-04-12 21:40:49 +00:00
|
|
|
continue;
|
|
|
|
break;
|
2005-07-25 02:38:43 +00:00
|
|
|
case SAGA_FRAME_NOOP: // Does nothing
|
|
|
|
readS.readByte();
|
|
|
|
readS.readByte();
|
|
|
|
readS.readByte();
|
|
|
|
continue;
|
|
|
|
break;
|
2004-04-12 21:40:49 +00:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2004-05-01 06:16:57 +00:00
|
|
|
// Mask all but two high order (control) bits
|
2005-07-25 16:22:32 +00:00
|
|
|
control = markByte & 0xC0;
|
2004-04-12 21:40:49 +00:00
|
|
|
switch (control) {
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_EMPTY_RUN:
|
2004-05-01 06:16:57 +00:00
|
|
|
// Run of empty pixels
|
2004-04-12 21:40:49 +00:00
|
|
|
continue;
|
|
|
|
break;
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_COMPRESSED_RUN:
|
2004-05-01 06:16:57 +00:00
|
|
|
// Run of compressed data
|
2004-08-01 10:02:41 +00:00
|
|
|
readS.readByte(); // Skip data byte
|
2004-04-12 21:40:49 +00:00
|
|
|
continue;
|
|
|
|
break;
|
2004-12-15 00:24:12 +00:00
|
|
|
case SAGA_FRAME_UNCOMPRESSED_RUN:
|
2004-05-01 06:16:57 +00:00
|
|
|
// Uncompressed run
|
2005-07-25 16:22:32 +00:00
|
|
|
runcount = (markByte & 0x3f) + 1;
|
2004-05-04 03:33:03 +00:00
|
|
|
for (i = 0; i < runcount; i++)
|
2004-08-01 10:02:41 +00:00
|
|
|
readS.readByte();
|
2004-04-12 21:40:49 +00:00
|
|
|
continue;
|
|
|
|
break;
|
|
|
|
default:
|
2005-07-25 16:22:32 +00:00
|
|
|
error("Encountered unknown RLE marker %i", markByte);
|
2004-04-12 21:40:49 +00:00
|
|
|
break;
|
2004-05-01 06:16:57 +00:00
|
|
|
}
|
2005-07-25 16:22:32 +00:00
|
|
|
} while (markByte != SAGA_FRAME_END);
|
2004-05-01 06:16:57 +00:00
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2004-12-03 19:15:44 +00:00
|
|
|
void Anim::animInfo() {
|
2005-06-11 17:24:06 +00:00
|
|
|
uint16 animCount;
|
2004-04-30 23:02:23 +00:00
|
|
|
uint16 i;
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
animCount = getAnimationCount();
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
_vm->_console->DebugPrintf("There are %d animations loaded:\n", animCount);
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
for (i = 0; i < MAX_ANIMATIONS; i++) {
|
|
|
|
if (_animations[i] == NULL) {
|
2005-06-20 11:46:34 +00:00
|
|
|
continue;
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
|
|
|
|
2005-06-11 17:24:06 +00:00
|
|
|
_vm->_console->DebugPrintf("%02d: Frames: %u Flags: %u\n", i, _animations[i]->maxFrame, _animations[i]->flags);
|
2004-04-12 21:40:49 +00:00
|
|
|
}
|
2004-07-31 23:33:14 +00:00
|
|
|
}
|
2004-04-12 21:40:49 +00:00
|
|
|
|
2007-06-14 23:28:30 +00:00
|
|
|
void Anim::cutawayInfo() {
|
|
|
|
uint16 i;
|
|
|
|
|
|
|
|
_vm->_console->DebugPrintf("There are %d cutaways loaded:\n", _cutawayListLength);
|
|
|
|
|
|
|
|
for (i = 0; i < _cutawayListLength; i++) {
|
|
|
|
_vm->_console->DebugPrintf("%02d: Bg res: %u Anim res: %u Cycles: %u Framerate: %u\n", i,
|
|
|
|
_cutawayList[i].backgroundResourceId, _cutawayList[i].animResourceId,
|
|
|
|
_cutawayList[i].cycles, _cutawayList[i].frameRate);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-16 14:06:17 +00:00
|
|
|
void Anim::resumeAll() {
|
|
|
|
// Restore the animations
|
|
|
|
for (int i = 0; i < MAX_ANIMATIONS; i++) {
|
|
|
|
if (_animations[i] && _animations[i]->state == ANIM_PLAYING) {
|
|
|
|
resume(i, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-04-12 21:40:49 +00:00
|
|
|
} // End of namespace Saga
|