Logo Search packages:      
Sourcecode: scummvm version File versions

credits.cpp

/* ScummVM - Scumm Interpreter
 * Copyright (C) 2003-2004 The ScummVM project
 *
 * 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/sword1/credits.cpp,v 1.5.2.1 2004/12/20 18:33:54 chrilith Exp $
 *
 */

#include "stdafx.h"
#include "sword1/credits.h"
#include "sword1/screen.h"
#include "common/file.h"
#include "sound/mixer.h"
#include "common/util.h"
#include "sound/audiostream.h"

#include "sword1.h"

#define CREDITS_X 480
#define CREDITS_Y 300
#define BUFSIZE_Y 640

#define START_X ((640 - CREDITS_X) / 2)
#define START_Y ((480 - CREDITS_Y) / 2)

#define SCROLL_TIMING (2000 / 59) // 29.5 frames per second

#define LOGO_FADEUP_TIME (133 * 1000)
#define LOGO_FADEDOWN_TIME (163 * 1000)

namespace Sword1 {

enum {
      FONT_PAL = 0,
      FONT,
      TEXT,
      REVO_PAL,
      REVO_LOGO,
      F_EOF
};

enum {
      FNT_LFT = 0,   // left column
      FNT_RGT,       // right column
      FNT_CEN,       // centered
      FNT_BIG = 64,  // big font
      FNT_EOL = 128, // linebreak
      FNT_EOB = 255  // end of textblock
};


CreditsPlayer::CreditsPlayer(OSystem *pSystem, SoundMixer *pMixer) {
      _system = pSystem;
      _mixer = pMixer;
      _smlFont = _bigFont = NULL;
}

bool spaceInBuf(uint16 blitSta, uint16 blitEnd, uint16 renderDest) {
      if (blitEnd > blitSta) {
            if ((renderDest > blitEnd) || (renderDest + 15 < blitSta))
                  return true;
      } else {
            if ((renderDest > blitEnd) && (renderDest + 15 < blitSta))
                  return true;
      }
      return false;
}

void CreditsPlayer::play(void) {
      AudioStream *bgSoundStream = AudioStream::openStreamFile("credits");
      if (bgSoundStream == NULL) {
            warning("\"credits.ogg\" not found, skipping credits sequence");
            return;
      }
      ArcFile credFile;
      if (!credFile.open("credits.dat")) {
            warning("\"credits.dat\" not found, skipping credits sequence");
            return;
      }

      uint8 *palSrc = credFile.fetchFile(FONT_PAL, &_palLen);
      for (uint32 cnt = 0; cnt < _palLen; cnt++)
            _palette[(cnt / 3) * 4 + cnt % 3] = palSrc[cnt];
      _palLen /= 3;     
    
      generateFonts(&credFile);

      uint8 *textData = credFile.fetchFile(TEXT);
      textData += READ_LE_UINT32(textData + SwordEngine::_systemVars.language * 4);

      uint8 *screenBuf = (uint8*)malloc(CREDITS_X * BUFSIZE_Y);
      memset(screenBuf, 0, CREDITS_X * BUFSIZE_Y);
      _system->copyRectToScreen(screenBuf, 640, 0, 0, 640, 480);
      _system->setPalette(_palette, 0, _palLen);
      _system->updateScreen();

      // everything's initialized, time to render and show the credits.
      PlayingSoundHandle bgSound;
      _mixer->playInputStream(&bgSound, bgSoundStream, true, 0);

      int relDelay = 0;
      uint16 scrollY = 0;
      uint16 renderY = BUFSIZE_Y / 2;
      uint16 clearY = 0xFFFF;
      bool clearLine = false;
      while (((*textData != FNT_EOB) || (scrollY != renderY)) && !SwordEngine::_systemVars.engineQuit) {
            if ((int32)_mixer->getSoundElapsedTime(bgSound) - relDelay < (SCROLL_TIMING * 2)) { // sync to audio
                  if (scrollY < BUFSIZE_Y - CREDITS_Y)
                        _system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, CREDITS_Y);
                  else {
                        _system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, BUFSIZE_Y - scrollY);
                        _system->copyRectToScreen(screenBuf, CREDITS_X, START_X, START_Y + BUFSIZE_Y - scrollY, CREDITS_X, CREDITS_Y - (BUFSIZE_Y - scrollY));
                  }
                  _system->updateScreen();
            } else
                  warning("frame skipped");

            while (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY) && (*textData != FNT_EOB)) {
                  if (*textData & FNT_EOL) {
                        renderY = (renderY + 16) % BUFSIZE_Y; // linebreak
                        clearLine = true;
                        *textData &= ~FNT_EOL;
                  }
                  if (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY)) {
                        if (clearLine)
                              memset(screenBuf + renderY * CREDITS_X, 0, 16 * CREDITS_X);
                        clearLine = false;
                        renderLine(screenBuf, textData + 1, renderY, *textData);
                        if (*textData & FNT_BIG)
                              renderY += 16;
                        while (*++textData != 0) // search for the start of next string
                              ;
                        textData++;
                  }
                  if (*textData == FNT_EOB)
                        clearY = renderY;
            }
            if ((*textData == FNT_EOB) && spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, clearY)) {
                  memset(screenBuf + clearY * CREDITS_X, 0, 16 * CREDITS_X);
                  clearY = (clearY + 16) % BUFSIZE_Y;
            }

            relDelay += SCROLL_TIMING;
            delay(relDelay - (int32)_mixer->getSoundElapsedTime(bgSound));
            scrollY = (scrollY + 1) % BUFSIZE_Y;
      }
      free(_smlFont);
      free(_bigFont);
      _smlFont = _bigFont = NULL;
      free(screenBuf);
      
      // credits done, now show the revolution logo
      uint8 *revoBuf = credFile.decompressFile(REVO_LOGO);
      uint8 *revoPal = credFile.fetchFile(REVO_PAL, &_palLen);
      _palLen /= 3;
      while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEUP_TIME) && !SwordEngine::_systemVars.engineQuit) {
            _system->updateScreen();
            delay(100);
      }
      memset(_palette, 0, 256 * 4);
      _system->setPalette(_palette, 0, 256);
      _system->copyRectToScreen(revoBuf, 480, START_X, START_Y, CREDITS_X, CREDITS_Y);
      _system->updateScreen();

      fadePalette(revoPal, true, _palLen);
      while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEDOWN_TIME) && !SwordEngine::_systemVars.engineQuit) {
            _system->updateScreen();
            delay(100);
      }
      fadePalette(revoPal, false, _palLen);
      delay(3000);

      if (SwordEngine::_systemVars.engineQuit)
            _mixer->stopAll();
      free(revoBuf);
}

void CreditsPlayer::fadePalette(uint8 *srcPal, bool fadeup, uint16 len) {
      int8 fadeDir = fadeup ? 1 : -1;
      int fadeStart = fadeup ? 0 : 12;

      int relDelay = _system->getMillis();
      for (int fadeStep = fadeStart; (fadeStep >= 0) && (fadeStep <= 12) && !SwordEngine::_systemVars.engineQuit; fadeStep += fadeDir) {
            for (uint16 cnt = 0; cnt < len * 3; cnt++)
                  _palette[(cnt / 3) * 4 + (cnt % 3)] = (srcPal[cnt] * fadeStep) / 12;
            _system->setPalette(_palette, 0, 256);
            _system->updateScreen();
            relDelay += 1000 / 12;
            delay(relDelay - _system->getMillis());
      }
}

void CreditsPlayer::renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags) {
      uint8 *font;
      uint16 fntSize = 16;
      if (flags & FNT_BIG) {
            font = _bigFont;
            fntSize = 32;
            flags &= ~FNT_BIG;
      } else 
            font = _smlFont;

      uint16 width = getWidth(font, line);
      uint16 xBufPos = (flags == FNT_CEN) ? (CREDITS_X - width) / 2 : ((flags == FNT_LFT) ? (234 - width) : 255);
      uint8 *bufDest = screenBuf + yBufPos * CREDITS_X + xBufPos;
      while (*line) {
            uint8 *chrSrc = font + _numChars + (*line - 1) * fntSize * fntSize;
            for (uint16 cnty = 0; cnty < fntSize; cnty++) {
                  for (uint16 cntx = 0; cntx < fntSize; cntx++)
                        bufDest[cnty * CREDITS_X + cntx] = chrSrc[cntx];
                  chrSrc += fntSize;
            }
            bufDest += font[*line++ - 1];
      }
}

uint16 CreditsPlayer::getWidth(uint8 *font, uint8 *line) {
      uint16 width = 0;
      while (*line)
            width += font[*line++ - 1];
      return width;
}

void CreditsPlayer::generateFonts(ArcFile *arcFile) {
      _bigFont = arcFile->decompressFile(FONT);
      _numChars = *_bigFont;
      memmove(_bigFont, _bigFont + 1, _numChars * (32 * 32 + 1));
      _smlFont = (uint8*)malloc(_numChars * (32 * 32 + 1));
      uint8 *src = _bigFont + _numChars;
      uint8 *dst = _smlFont + _numChars;
      for (uint16 cnt = 0; cnt < _numChars; cnt++) {
            _smlFont[cnt] = (_bigFont[cnt]++ + 1) / 2; // width table
            for (uint16 cnty = 0; cnty < 16; cnty++) {
                  for (uint16 cntx = 0; cntx < 16; cntx++) {
                        uint8 resR = (uint8)((_palette[src[0] * 4 + 0] + _palette[src[1] * 4 + 0] + _palette[src[32] * 4 + 0] + _palette[src[33] * 4 + 0]) >> 2);
                        uint8 resG = (uint8)((_palette[src[0] * 4 + 1] + _palette[src[1] * 4 + 1] + _palette[src[32] * 4 + 1] + _palette[src[33] * 4 + 1]) >> 2);
                        uint8 resB = (uint8)((_palette[src[0] * 4 + 2] + _palette[src[1] * 4 + 2] + _palette[src[32] * 4 + 2] + _palette[src[33] * 4 + 2]) >> 2);
                        *dst++ = getPalIdx(resR, resG, resB);
                        src += 2;
                  }
                  src += 32;
            }
      }
}

uint8 CreditsPlayer::getPalIdx(uint8 r, uint8 g, uint8 b) {
      for (uint16 cnt = 0; cnt < _palLen; cnt++)
            if ((_palette[cnt * 4 + 0] == r) && (_palette[cnt * 4 + 1] == g) && (_palette[cnt * 4 + 2] == b))
                  return (uint8)cnt;
      assert(_palLen < 256);
      _palette[_palLen * 4 + 0] = r;
      _palette[_palLen * 4 + 1] = g;
      _palette[_palLen * 4 + 2] = b;
      return (uint8)_palLen++;
}

void CreditsPlayer::delay(int msecs) {

      OSystem::Event event;
      uint32 start = _system->getMillis();
      do {
            while (_system->pollEvent(event)) {
                  switch (event.type) {
                  case OSystem::EVENT_QUIT:
                        SwordEngine::_systemVars.engineQuit = true;
                        break;
                  default:
                        break;
                  }
            }

#ifndef __PALM_OS__
            if (msecs > 0)
                  _system->delayMillis(10);
#endif
      } while ((_system->getMillis() < start + msecs) && !SwordEngine::_systemVars.engineQuit);
}

ArcFile::ArcFile(void) {
      _buf = NULL;
}

ArcFile::~ArcFile(void) {
      if (_buf)
            free(_buf);
}

bool ArcFile::open(const char *name) {
      File arc;
      if (!arc.open(name))
            return false;
      _bufPos = _buf = (uint8*)malloc(arc.size());
      arc.read(_buf, arc.size());
      arc.close();
      return true;
}

void ArcFile::enterPath(uint32 id) {
      _bufPos += READ_LE_UINT32(_bufPos + id * 4);
}

uint8 *ArcFile::fetchFile(uint32 fileId, uint32 *size) {
      if (size)
            *size = READ_LE_UINT32(_bufPos + (fileId + 1) * 4) - READ_LE_UINT32(_bufPos + fileId * 4);
      return _bufPos + READ_LE_UINT32(_bufPos + fileId * 4);
}

uint8 *ArcFile::decompressFile(uint32 fileId) {
      uint32 size;
      uint8 *srcBuf = fetchFile(fileId, &size);
      uint8 *dstBuf = (uint8*)malloc(READ_LE_UINT32(srcBuf));
      uint8 *srcPos = srcBuf + 4;
      uint8 *dstPos = dstBuf;
      while (srcPos < srcBuf + size) {
            uint16 len = READ_LE_UINT16(srcPos);
            memset(dstPos, 0, len);
            dstPos += len;
            srcPos += 2;
            if (srcPos < srcBuf + size) {
                  len = *srcPos++;
                  memcpy(dstPos, srcPos, len);
                  dstPos += len;
                  srcPos += len;
            }
      }
      return dstBuf;
}

} // end of namespace Sword1

Generated by  Doxygen 1.6.0   Back to index