Logo Search packages:      
Sourcecode: scummvm version File versions

animation.cpp

/* ScummVM - Scumm Interpreter
 * Copyright (C) 2004 The ScummVM project
 *
 * The ReInherit Engine is (C)2000-2003 by Daniel Balsom.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.      See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/saga/animation.cpp,v 1.26 2004/12/03 19:15:44 eriktorbjorn Exp $
 *
 */

// Background animation management module
#include "saga/saga.h"
#include "saga/gfx.h"

#include "saga/console.h"
#include "saga/game_mod.h"
#include "saga/events.h"
#include "saga/render.h"

#include "saga/animation.h"

namespace Saga {

Anim::Anim(SagaEngine *vm) : _vm(vm) {
      int i;

      _anim_limit = MAX_ANIMATIONS;
      _anim_count = 0;

      for (i = 0; i < MAX_ANIMATIONS; i++)
            _anim_tbl[i] = NULL;

      _initialized = true;
}

Anim::~Anim(void) {
      uint16 i;

      for (i = 0; i < MAX_ANIMATIONS; i++)
            free(_anim_tbl[i]);

      _initialized = false;
}

int Anim::load(const byte *anim_resdata, size_t anim_resdata_len, uint16 *anim_id_p) {
 ANIMATION *new_anim;

      uint16 anim_id = 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;
                  break;
            }
      }

      if (i == MAX_ANIMATIONS) {
            warning("Anim::load could not find unused animation slot");
            return FAILURE;
      }

      new_anim = (ANIMATION *)malloc(sizeof *new_anim);
      if (new_anim == NULL) {
            warning("Anim::load Allocation failure");
            return MEM;
      }

      new_anim->resdata = anim_resdata;
      new_anim->resdata_len = anim_resdata_len;

      if (GAME_GetGameType() == GID_ITE) {
            if (getNumFrames(anim_resdata, anim_resdata_len, &new_anim->n_frames) != SUCCESS) {
                  warning("Anim::load Couldn't get animation frame count");
                  return FAILURE;
            }

            // Cache frame offsets
            new_anim->frame_offsets = (size_t *)malloc(new_anim->n_frames * sizeof *new_anim->frame_offsets);
            if (new_anim->frame_offsets == NULL) {
                  warning("Anim::load Allocation failure");
                  return MEM;
            }

            for (i = 0; i < new_anim->n_frames; i++) {
                  getFrameOffset(anim_resdata, anim_resdata_len, i + 1, &new_anim->frame_offsets[i]);
            }
      } else {
            new_anim->cur_frame_p = anim_resdata + SAGA_FRAME_HEADER_LEN;
            new_anim->cur_frame_len = anim_resdata_len - SAGA_FRAME_HEADER_LEN;
            getNumFrames(anim_resdata, anim_resdata_len, &new_anim->n_frames);
      }

      // Set animation data
      new_anim->current_frame = 1;
      new_anim->end_frame = new_anim->n_frames;
      new_anim->stop_frame = new_anim->end_frame;

      new_anim->frame_time = DEFAULT_FRAME_TIME;
      new_anim->flags = 0;
      new_anim->play_flag = 0;
      new_anim->link_flag = 0;
      new_anim->link_id = 0;

      _anim_tbl[anim_id] = new_anim;

      *anim_id_p = anim_id;

      _anim_count++;

      return SUCCESS;
}

int Anim::link(uint16 anim_id1, uint16 anim_id2) {
      ANIMATION *anim1;
      ANIMATION *anim2;

      if ((anim_id1 >= _anim_count) || (anim_id2 >= _anim_count)) {
            return FAILURE;
      }

      anim1 = _anim_tbl[anim_id1];
      anim2 = _anim_tbl[anim_id2];

      if ((anim1 == NULL) || (anim2 == NULL)) {
            return FAILURE;
      }

      anim1->link_id = anim_id2;
      anim1->link_flag = 1;

      anim2->frame_time = anim1->frame_time;

      return SUCCESS;
}

int Anim::play(uint16 anim_id, int vector_time) {
      EVENT event;
      ANIMATION *anim;
      ANIMATION *link_anim;
      uint16 link_anim_id;

      BUFFER_INFO buf_info;

      byte *display_buf;

      const byte *nextf_p;
      size_t nextf_len;

      uint16 frame;
      int result;

      GAME_DISPLAYINFO disp_info;

      if (anim_id >= _anim_count) {
            return FAILURE;
      }

      GAME_GetDisplayInfo(&disp_info);

      _vm->_render->getBufferInfo(&buf_info);
      display_buf = buf_info.bg_buf;

      anim = _anim_tbl[anim_id];
      if (anim == NULL) {
            return FAILURE;
      }

      if (anim->flags & ANIM_PAUSE)
            return SUCCESS;

      if (anim->play_flag) {
            frame = anim->current_frame;
            if (GAME_GetGameType() == GID_ITE) {
                  result = ITE_DecodeFrame(anim->resdata, anim->resdata_len, anim->frame_offsets[frame - 1], display_buf,
                                                      disp_info.logical_w * disp_info.logical_h);
                  if (result != SUCCESS) {
                        warning("ANIM::play: Error decoding frame %u", anim->current_frame);
                        anim->play_flag = 0;
                        return FAILURE;
                  }
            } else {
                  if (anim->cur_frame_p == NULL) {
                        warning("ANIM::play: Frames exhausted");
                        return FAILURE;
                  }

                  result = IHNM_DecodeFrame(display_buf,  disp_info.logical_w * disp_info.logical_h,
                                                      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);
                        anim->play_flag = 0;
                        return FAILURE;
                  }

                  anim->cur_frame_p = nextf_p;
                  anim->cur_frame_len = nextf_len;
            }
            anim->current_frame++;
      }

      anim->play_flag = 1;

      if (anim->current_frame > anim->n_frames) {
            // Animation done playing
            if (anim->link_flag) {
                  // If this animation has a link, follow it
                  anim->play_flag = 0;
                  anim->current_frame = 1;

                  link_anim_id = anim->link_id;
                  link_anim = _anim_tbl[link_anim_id];

                  if (link_anim != NULL) {
                        link_anim->current_frame = 1;
                        link_anim->play_flag = 1;
                  }

                  anim_id = link_anim_id;
            } else if (anim->flags & ANIM_LOOP) {
                  // Loop animation
                  anim->current_frame = 1;
                  anim->cur_frame_p = anim->resdata + SAGA_FRAME_HEADER_LEN;
                  anim->cur_frame_len = anim->resdata_len - SAGA_FRAME_HEADER_LEN;
            } else {
                  // No link, stop playing
                  anim->current_frame = anim->n_frames;
                  anim->play_flag = 0;

                  if (anim->flags & ANIM_ENDSCENE) {
                        // This animation ends the scene
                        event.type = ONESHOT_EVENT;
                        event.code = SCENE_EVENT;
                        event.op = EVENT_END;
                        event.time = anim->frame_time + vector_time;
                        _vm->_events->queue(&event);
                  }
                  return SUCCESS;
            }
      }

      event.type = ONESHOT_EVENT;
      event.code = ANIM_EVENT;
      event.op = EVENT_FRAME;
      event.param = anim_id;
      event.time = anim->frame_time + vector_time;

      _vm->_events->queue(&event);

      return SUCCESS;
}

int Anim::reset() {
      uint16 i;

      for (i = 0; i < MAX_ANIMATIONS; i++) {

            freeId(i);
      }

      _anim_count = 0;

      return SUCCESS;
}

int Anim::setFlag(uint16 anim_id, uint16 flag) {
      ANIMATION *anim;

      if (anim_id > _anim_count) {
            return FAILURE;
      }

      anim = _anim_tbl[anim_id];
      if (anim == NULL) {
            return FAILURE;
      }

      anim->flags |= flag;

      return SUCCESS;
}

int Anim::clearFlag(uint16 anim_id, uint16 flag) {
      ANIMATION *anim;

      if (anim_id > _anim_count) {
            return FAILURE;
      }

      anim = _anim_tbl[anim_id];
      if (anim == NULL) {
            return FAILURE;
      }

      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;
      }

      anim->frame_time = time;

      return SUCCESS;
}

int Anim::freeId(uint16 anim_id) {
      ANIMATION *anim;

      if (anim_id > _anim_count) {
            return FAILURE;
      }

      anim = _anim_tbl[anim_id];
      if (anim == NULL) {
            return FAILURE;
      }

      if (GAME_GetGameType() == GID_ITE) {
            free(anim->frame_offsets);
            anim->frame_offsets = NULL;
      }

      free(anim);
      _anim_tbl[anim_id] = NULL;
      _anim_count--;

      return SUCCESS;
}

// The actual number of frames present in an animation resource is 
// sometimes less than number present in the .nframes member of the
// animation header. For this reason, the function attempts to find
// the last valid frame number, which it returns via 'n_frames'
int Anim::getNumFrames(const byte *anim_resource, size_t anim_resource_len, uint16 *n_frames) {
      ANIMATION_HEADER ah;

      size_t offset;
      int magic;

      int x;

      if (!_initialized) {
            return FAILURE;
      }

      MemoryReadStream readS(anim_resource, anim_resource_len);

      ah.magic = readS.readUint16LE();
      ah.screen_w = readS.readUint16LE();
      ah.screen_h = readS.readUint16LE();

      ah.unknown06 = readS.readByte();
      ah.unknown07 = readS.readByte();
      ah.nframes = readS.readByte();

      if (GAME_GetGameType() == GID_IHNM) {
            *n_frames = ah.nframes;
      }

      if (ah.magic == 68) {
            for (x = ah.nframes; x > 0; x--) {
                  if (getFrameOffset(anim_resource, anim_resource_len, x, &offset) != SUCCESS) {
                        return FAILURE;
                  }

                  magic = *(anim_resource + offset);
                  if (magic == SAGA_FRAME_HEADER_MAGIC) {
                        *n_frames = x;
                        return SUCCESS;
                  }
            }

            return FAILURE;
      }

      return FAILURE;
}

int Anim::ITE_DecodeFrame(const byte *resdata, size_t resdata_len, size_t frame_offset, byte *buf, size_t buf_len) {
      ANIMATION_HEADER ah;
      FRAME_HEADER fh;

      byte *write_p;

      uint16 magic;

      uint16 x_start;
      uint16 y_start;
      uint32 screen_w;
      uint32 screen_h;

      int mark_byte;
      byte data_byte;
      int new_row;

      uint16 control_ch;
      uint16 param_ch;

      uint16 runcount;
      int x_vector;

      uint16 i;

      if (!_initialized) {
            return FAILURE;
      }

      MemoryReadStream headerReadS(resdata, resdata_len);
      // Read animation header
      ah.magic = headerReadS.readUint16LE();
      ah.screen_w = headerReadS.readUint16LE();
      ah.screen_h = headerReadS.readUint16LE();
      ah.unknown06 = headerReadS.readByte();
      ah.unknown07 = headerReadS.readByte();
      ah.nframes = headerReadS.readByte();
      ah.flags = headerReadS.readByte();
      ah.unknown10 = headerReadS.readByte();
      ah.unknown11 = headerReadS.readByte();

      screen_w = ah.screen_w;
      screen_h = ah.screen_h;

      if ((screen_w * screen_h) > buf_len) {
            // Buffer argument is too small to hold decoded frame, abort.
            warning("ITE_DecodeFrame: Buffer size inadequate");
            return FAILURE;
      }

      // Read frame header
      MemoryReadStream readS(resdata + frame_offset, resdata_len - frame_offset);

      // Check for frame magic byte
      magic = readS.readByte();
      if (magic != SAGA_FRAME_HEADER_MAGIC) {
            warning("ITE_DecodeFrame: Invalid frame offset");
            return FAILURE;
      }

      // For some strange reason, the animation header is in little 
      // endian format, but the actual RLE encoded frame data, 
      // including the frame header, is in big endian format.

      fh.x_start = readS.readUint16BE();
      fh.y_start = readS.readByte();
      readS.readByte();       /* Skip pad byte */
      fh.x_pos = readS.readUint16BE();
      fh.y_pos = readS.readUint16BE();
      fh.width = readS.readUint16BE();
      fh.height = readS.readUint16BE();

      x_start = fh.x_start;
      y_start = fh.y_start;

      // Setup write pointer to the draw origin
      write_p = (buf + (y_start * screen_w) + x_start);

      // Begin RLE decompression to output buffer
      do {
            mark_byte = readS.readByte();
            switch (mark_byte) {
            case 0x10: // Long Unencoded Run
                  runcount = readS.readSint16BE();
                  for (i = 0; i < runcount; i++) {
                        data_byte = readS.readByte();
                        if (data_byte != 0) {
                              *write_p = data_byte;
                        }
                        write_p++;
                  }
                  continue;
                  break;
            case 0x20: // Long encoded run
                  runcount = readS.readSint16BE();
                  data_byte = readS.readByte();
                  for (i = 0; i < runcount; i++) {
                        *write_p++ = data_byte;
                  }
                  continue;
                  break;
            case 0x2F: // End of row
                  x_vector = readS.readSint16BE();
                  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;
                  continue;
                  break;
            case 0x30: // Reposition command
                  x_vector = readS.readSint16BE();
                  write_p += x_vector;
                  continue;
                  break;
            case 0x3F: // End of frame marker
                  return SUCCESS;
                  break;
            default:
                  break;
            }

            // Mask all but two high order control bits
            control_ch = mark_byte & 0xC0U;
            param_ch = mark_byte & 0x3FU;
            switch (control_ch) {
            case 0xC0: // 1100 0000
                  // Run of empty pixels
                  runcount = param_ch + 1;
                  write_p += runcount;
                  continue;
                  break;
            case 0x80: // 1000 0000
                  // Run of compressed data
                  runcount = param_ch + 1;
                  data_byte = readS.readByte();
                  for (i = 0; i < runcount; i++) {
                        *write_p++ = data_byte;
                  }
                  continue;
                  break;
            case 0x40: // 0100 0000
                  // Uncompressed run
                  runcount = param_ch + 1;
                  for (i = 0; i < runcount; i++) {
                        data_byte = readS.readByte();
                        if (data_byte != 0) {
                              *write_p = data_byte;
                        }
                        write_p++;
                  }
                  continue;
                  break;
            default:
                  // Unknown marker found - abort
                  warning("ITE_DecodeFrame: Invalid RLE marker encountered");
                  return FAILURE;
                  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,
                              size_t thisf_len, const byte **nextf_p, size_t *nextf_len) {
      int in_ch;
      int decoded_data = 0;
      int cont_flag = 1;
      int control_ch;
      int param_ch;
      byte data_pixel;
      int x_origin = 0;
      int y_origin = 0;
      int x_vector;
      int new_row;

      uint16 runcount;
      uint16 c;

      size_t in_ch_offset;

      MemoryReadStream readS(thisf_p, thisf_len);

      byte *outbuf_p = decode_buf;
      byte *outbuf_endp = (decode_buf + decode_buf_len) - 1;
      size_t outbuf_remain = decode_buf_len;

      GAME_DISPLAYINFO di;

      GAME_GetDisplayInfo(&di);

      *nextf_p = NULL;

      for (; cont_flag; decoded_data = 1) {
            in_ch_offset = readS.pos();
            in_ch = readS.readByte();
            switch (in_ch) {
            case 0x0F: // 15: Frame header
                  {
                        int param1;
                        int param2;
                        int param3;
                        int param4;
                        int param5;
                        int param6;

                        if (thisf_len - readS.pos() < 13) {
                              warning("0x%02X: Input buffer underrun", in_ch);
                              return FAILURE;
                        }

                        param1 = readS.readUint16BE();
                        param2 = readS.readUint16BE();
                        readS.readByte(); // skip 1?
                        param3 = readS.readUint16BE();
                        param4 = readS.readUint16BE();
                        param5 = readS.readUint16BE();
                        param6 = readS.readUint16BE();

                        x_origin = param1;
                        y_origin = param2;

                        outbuf_p = decode_buf + x_origin + (y_origin * di.logical_w);

                        if (outbuf_p > outbuf_endp) {
                              warning("0x%02X: (0x%X) Invalid output position. (x: %d, y: %d)",
                                          in_ch, in_ch_offset, x_origin, y_origin);
                              return FAILURE;
                        }

                        outbuf_remain = (outbuf_endp - outbuf_p) + 1;
                        continue;
                  }
                  break;
            case 0x10: // Long Unencoded Run
                  runcount = readS.readSint16BE();
                  if (thisf_len - readS.pos() < runcount) {
                        warning("0x%02X: Input buffer underrun", in_ch);
                        return FAILURE;
                  }
                  if (outbuf_remain < runcount) {
                        warning("0x%02X: Output buffer overrun", in_ch);
                        return FAILURE;
                  }

                  for (c = 0; c < runcount; c++) {
                        data_pixel = readS.readByte();
                        if (data_pixel != 0) {
                              *outbuf_p = data_pixel;
                        }
                        outbuf_p++;
                  }

                  outbuf_remain -= runcount;
                  continue;
                  break;
            case 0x1F: // 31: Unusued?
                  if (thisf_len - readS.pos() < 3) {
                        warning("0x%02X: Input buffer underrun", in_ch);
                        return FAILURE;
                  }

                  readS.readByte();
                  readS.readByte();
                  readS.readByte();
                  continue;
                  break;
            case 0x20: // Long compressed run
                  if (thisf_len - readS.pos() <= 3) {
                        warning("0x%02X: Input buffer underrun", in_ch);
                        return FAILURE;
                  }

                  runcount = readS.readSint16BE();
                  data_pixel = readS.readByte();

                  for (c = 0; c < runcount; c++) {
                        *outbuf_p++ = data_pixel;
                  }

                  outbuf_remain -= runcount;
                  continue;
                  break;

            case 0x2F: // End of row
                  if (thisf_len - readS.pos() <= 4) {
                        return FAILURE;
                  }

                  x_vector = readS.readSint16BE();
                  new_row = readS.readSint16BE();

                  outbuf_p = decode_buf + ((y_origin + new_row) * di.logical_w) + x_origin + x_vector;
                  outbuf_remain = (outbuf_endp - outbuf_p) + 1;
                  continue;
                  break;
            case 0x30: // Reposition command
                  if (thisf_len - readS.pos() < 2) {
                        return FAILURE;
                  }

                  x_vector = readS.readSint16BE();

                  if (((x_vector > 0) && ((size_t) x_vector > outbuf_remain)) || (-x_vector > outbuf_p - decode_buf)) {
                        warning("0x30: Invalid x_vector");
                        return FAILURE;
                  }

                  outbuf_p += x_vector;
                  outbuf_remain -= x_vector;
                  continue;
                  break;

            case 0x3F:  // 68: Frame end marker
                  debug(1, "0x3F: Frame end marker");
                  if (decoded_data && (thisf_len - readS.pos() > 0)) {
                        *nextf_p = thisf_p + readS.pos();
                        *nextf_len = thisf_len - readS.pos();
                  } else {
                        *nextf_p = NULL;
                        *nextf_len = 0;
                  }

                  cont_flag = 0;
                  continue;
                  break;

            default:
                  break;
            }

            control_ch = in_ch & 0xC0;
            param_ch = in_ch & 0x3f;
            switch (control_ch) {

            case 0xC0: // Run of empty pixels
                  runcount = param_ch + 1;
                  if (outbuf_remain < runcount) {
                        return FAILURE;
                  }

                  outbuf_p += runcount;
                  outbuf_remain -= runcount;
                  continue;
                  break;
            case 0x80: // Run of compressed data
                  runcount = param_ch + 1;
                  if ((outbuf_remain < runcount) || (thisf_len - readS.pos() <= 1)) {
                        return FAILURE;
                  }

                  data_pixel = readS.readByte();

                  for (c = 0; c < runcount; c++) {
                        *outbuf_p++ = data_pixel;
                  }

                  outbuf_remain -= runcount;
                  continue;
                  break;
            case 0x40: // Uncompressed run
                  runcount = param_ch + 1;
                  if ((outbuf_remain < runcount) || (thisf_len - readS.pos() < runcount)) {
                        return FAILURE;
                  }

                  for (c = 0; c < runcount; c++) {
                        data_pixel = readS.readByte();
                        if (data_pixel != 0) {
                              *outbuf_p = data_pixel;
                        }
                        outbuf_p++;
                  }

                  outbuf_remain -= runcount;

                  continue;
                  break;

            default:
                  break;
            }
      }

      return SUCCESS;
}

int Anim::getFrameOffset(const byte *resdata, size_t resdata_len, uint16 find_frame, size_t *frame_offset_p) {
      ANIMATION_HEADER ah;

      uint16 num_frames;
      uint16 current_frame;

      byte mark_byte;
      uint16 control;
      uint16 runcount;
      uint16 magic;

      int i;

      if (!_initialized) {
            return FAILURE;
      }

      MemoryReadStream readS(resdata, resdata_len);

      // Read animation header
      ah.magic = readS.readUint16LE();
      ah.screen_w = readS.readUint16LE();
      ah.screen_h = readS.readUint16LE();
      ah.unknown06 = readS.readByte();
      ah.unknown07 = readS.readByte();
      ah.nframes = readS.readByte();
      ah.flags = readS.readByte();
      ah.unknown10 = readS.readByte();
      ah.unknown11 = readS.readByte();

      num_frames = ah.nframes;

      if ((find_frame < 1) || (find_frame > num_frames)) {
            return FAILURE;
      }

      for (current_frame = 1; current_frame < find_frame; current_frame++) {
            magic = readS.readByte();
            if (magic != SAGA_FRAME_HEADER_MAGIC) {
                  // Frame sync failure. Magic Number not found
                  return FAILURE;
            }

            // skip header
            for (i = 0; i < SAGA_FRAME_HEADER_LEN; i++)
                  readS.readByte();

            // For some strange reason, the animation header is in little
            // endian format, but the actual RLE encoded frame data, 
            // including the frame header, is in big endian format. */
            do {
                  mark_byte = readS.readByte();
                  switch (mark_byte) {
                  case 0x3F: // End of frame marker
                        continue;
                        break;
                  case 0x30: // Reposition command
                        readS.readByte();
                        readS.readByte();
                        continue;
                        break;
                  case 0x2F: // End of row marker
                        readS.readByte();
                        readS.readByte();
                        readS.readByte();
                        continue;
                        break;
                  case 0x20: // Long compressed run marker
                        readS.readByte();
                        readS.readByte();
                        readS.readByte();
                        continue;
                        break;
                  case 0x10: // (16) 0001 0000
                        // Long Uncompressed Run
                        runcount = readS.readSint16BE();
                        for (i = 0; i < runcount; i++)
                              readS.readByte();
                        continue;
                        break;
                  default:
                        break;
                  }

                  // Mask all but two high order (control) bits
                  control = mark_byte & 0xC0;
                  switch (control) {
                  case 0xC0:
                        // Run of empty pixels
                        continue;
                        break;
                  case 0x80:
                        // Run of compressed data
                        readS.readByte(); // Skip data byte
                        continue;
                        break;
                  case 0x40:
                        // Uncompressed run
                        runcount = (mark_byte & 0x3f) + 1;
                        for (i = 0; i < runcount; i++)
                              readS.readByte();
                        continue;
                        break;
                  default:
                        // Encountered unknown RLE marker, abort
                        return FAILURE;
                        break;
                  }
            } while (mark_byte != 63);
      }

      *frame_offset_p = readS.pos();
      return SUCCESS;
}

void Anim::animInfo() {
      uint16 anim_ct;
      uint16 i;
      uint16 idx;

      anim_ct = _anim_count;

      _vm->_console->DebugPrintf("There are %d animations loaded:\n", anim_ct);

      for (idx = 0, i = 0; i < anim_ct; idx++, i++) {
            while (_anim_tbl[idx] == NULL) {
                  idx++;
            }

            _vm->_console->DebugPrintf("%02d: Frames: %u Flags: %u\n", i, _anim_tbl[idx]->n_frames, _anim_tbl[idx]->flags);
      }
}

} // End of namespace Saga

Generated by  Doxygen 1.6.0   Back to index