PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/engines/lure/animseq.cpp

http://github.com/scummvm/scummvm
C++ | 280 lines | 177 code | 49 blank | 54 comment | 62 complexity | 967aee8e0d1df186b6b67a9bbc434a1c MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1, GPL-2.0
  1. /* ScummVM - Graphic Adventure Engine
  2. *
  3. * ScummVM is the legal property of its developers, whose names
  4. * are too numerous to list here. Please refer to the COPYRIGHT
  5. * file distributed with this source distribution.
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version 2
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. *
  21. */
  22. #include "lure/animseq.h"
  23. #include "lure/decode.h"
  24. #include "lure/events.h"
  25. #include "lure/lure.h"
  26. #include "lure/palette.h"
  27. #include "lure/sound.h"
  28. #include "common/endian.h"
  29. namespace Lure {
  30. // delay
  31. // Delays for a given number of milliseconds. If it returns true, it indicates that
  32. // Escape has been pressed, and the introduction should be aborted.
  33. AnimAbortType AnimationSequence::delay(uint32 milliseconds) {
  34. Events &events = Events::getReference();
  35. uint32 delayCtr = g_system->getMillis() + milliseconds;
  36. while (g_system->getMillis() < delayCtr) {
  37. while (events.pollEvent()) {
  38. if ((events.type() == Common::EVENT_KEYDOWN) && (events.event().kbd.ascii != 0)) {
  39. if (events.event().kbd.keycode == Common::KEYCODE_ESCAPE)
  40. return ABORT_END_INTRO;
  41. else
  42. return ABORT_NEXT_SCENE;
  43. } else if (events.type() == Common::EVENT_LBUTTONDOWN) {
  44. return ABORT_NEXT_SCENE;
  45. } else if ((events.type() == Common::EVENT_QUIT) || (events.type() == Common::EVENT_RTL)) {
  46. return ABORT_END_INTRO;
  47. } else if (events.type() == Common::EVENT_MAINMENU) {
  48. return ABORT_NONE;
  49. }
  50. }
  51. uint32 delayAmount = delayCtr - g_system->getMillis();
  52. if (delayAmount > 10) delayAmount = 10;
  53. g_system->delayMillis(delayAmount);
  54. }
  55. return ABORT_NONE;
  56. }
  57. // egaDecodeFrame
  58. // Decodes a single frame of a EGA animation sequence
  59. void AnimationSequence::egaDecodeFrame(byte *&pPixels) {
  60. Screen &screen = Screen::getReference();
  61. byte *screenData = screen.screen_raw();
  62. // Skip over the list of blocks that are changed
  63. int numBlocks = *pPixels++;
  64. pPixels += numBlocks;
  65. // Loop through the list of same/changed pixel ranges
  66. int len = *pPixels++;
  67. int offset = MENUBAR_Y_SIZE * FULL_SCREEN_WIDTH *
  68. EGA_NUM_LAYERS / EGA_PIXELS_PER_BYTE;
  69. while ((offset += len) < FULL_SCREEN_WIDTH * FULL_SCREEN_HEIGHT / 2) {
  70. int repeatLen = *pPixels++;
  71. if (repeatLen > 0) {
  72. byte *pDest = screenData + (offset / EGA_NUM_LAYERS) * EGA_PIXELS_PER_BYTE;
  73. // Copy over the following bytes - each four bytes contain the four
  74. // planes worth of data for 8 sequential pixels
  75. while (repeatLen-- > 0) {
  76. int planeNum = offset % EGA_NUM_LAYERS;
  77. byte v = *pPixels++;
  78. for (int bitCtr = 0; bitCtr < 8; ++bitCtr, v <<= 1) {
  79. if ((v & 0x80) != 0)
  80. *(pDest + bitCtr) |= 1 << planeNum;
  81. else
  82. *(pDest + bitCtr) &= ~(1 << planeNum);
  83. }
  84. if ((++offset % EGA_NUM_LAYERS) == 0)
  85. pDest += EGA_PIXELS_PER_BYTE;
  86. }
  87. }
  88. // Get next skip bytes length
  89. len = *pPixels++;
  90. }
  91. }
  92. // vgaDecodeFrame
  93. // Decodes a single frame of a VGA animation sequence
  94. void AnimationSequence::vgaDecodeFrame(byte *&pPixels, byte *&pLines) {
  95. Screen &screen = Screen::getReference();
  96. byte *screenData = screen.screen_raw();
  97. uint16 screenPos = 0;
  98. uint16 len;
  99. while (screenPos < SCREEN_SIZE) {
  100. // Get line length
  101. len = (uint16) *pLines++;
  102. if (len == 0) {
  103. len = READ_LE_UINT16(pLines);
  104. pLines += 2;
  105. }
  106. // Move the splice over
  107. memcpy(screenData, pPixels, len);
  108. screenData += len;
  109. screenPos += len;
  110. pPixels += len;
  111. // Get the offset inc amount
  112. len = (uint16) *pLines++;
  113. if (len == 0) {
  114. len = READ_LE_UINT16(pLines);
  115. pLines += 2;
  116. }
  117. screenData += len;
  118. screenPos += len;
  119. }
  120. }
  121. AnimationSequence::AnimationSequence(uint16 screenId, Palette &palette, bool fadeIn, int frameDelay,
  122. const AnimSoundSequence *soundList): _screenId(screenId), _palette(palette),
  123. _frameDelay(frameDelay), _soundList(soundList) {
  124. Screen &screen = Screen::getReference();
  125. PictureDecoder decoder;
  126. Disk &d = Disk::getReference();
  127. // Get the data and decode it. Note that VGA decompression is used
  128. // even if the decompressed contents is actually EGA data
  129. MemoryBlock *data = d.getEntry(_screenId);
  130. _decodedData = decoder.vgaDecode(data, MAX_ANIM_DECODER_BUFFER_SIZE);
  131. delete data;
  132. _isEGA = LureEngine::getReference().isEGA();
  133. if (_isEGA) {
  134. // Setup for EGA animation
  135. _lineRefs = NULL;
  136. // Reset the palette and clear the screen for EGA decoding
  137. screen.setPaletteEmpty(RES_PALETTE_ENTRIES);
  138. screen.screen().empty();
  139. // Load the screen - each four bytes contain the four planes
  140. // worth of data for 8 sequential pixels
  141. byte *pSrc = _decodedData->data();
  142. byte *pDest = screen.screen().data().data() +
  143. (FULL_SCREEN_WIDTH * MENUBAR_Y_SIZE);
  144. for (int ctr = 0; ctr < FULL_SCREEN_WIDTH * (FULL_SCREEN_HEIGHT -
  145. MENUBAR_Y_SIZE) / 8; ++ctr, pDest += EGA_PIXELS_PER_BYTE) {
  146. for (int planeCtr = 0; planeCtr < EGA_NUM_LAYERS; ++planeCtr, ++pSrc) {
  147. byte v = *pSrc;
  148. for (int bitCtr = 0; bitCtr < 8; ++bitCtr, v <<= 1) {
  149. if ((v & 0x80) != 0)
  150. *(pDest + bitCtr) |= 1 << planeCtr;
  151. }
  152. }
  153. }
  154. screen.update();
  155. screen.setPalette(&_palette, 0, _palette.numEntries());
  156. // Set pointers for animation
  157. _pPixels = pSrc;
  158. _pPixelsEnd = _decodedData->data() + _decodedData->size() - 1;
  159. _pLines = NULL;
  160. _pLinesEnd = NULL;
  161. } else {
  162. // Setup for VGA animation
  163. _lineRefs = d.getEntry(_screenId + 1);
  164. // Reset the palette and set the initial starting screen
  165. screen.setPaletteEmpty(RES_PALETTE_ENTRIES);
  166. screen.screen().data().copyFrom(_decodedData, 0, 0, FULL_SCREEN_HEIGHT * FULL_SCREEN_WIDTH);
  167. screen.update();
  168. // Set the palette
  169. if (fadeIn) screen.paletteFadeIn(&_palette);
  170. else screen.setPalette(&_palette, 0, _palette.numEntries());
  171. // Set up frame pointers
  172. _pPixels = _decodedData->data() + SCREEN_SIZE;
  173. _pPixelsEnd = _decodedData->data() + _decodedData->size() - 1;
  174. _pLines = _lineRefs->data();
  175. _pLinesEnd = _lineRefs->data() + _lineRefs->size() - 1;
  176. }
  177. }
  178. AnimationSequence::~AnimationSequence() {
  179. delete _lineRefs;
  180. delete _decodedData;
  181. // Renable GMM saving/loading now that the animation is done
  182. LureEngine::getReference()._saveLoadAllowed = true;
  183. }
  184. // show
  185. // Main method for displaying the animation
  186. AnimAbortType AnimationSequence::show() {
  187. Screen &screen = Screen::getReference();
  188. AnimAbortType result;
  189. const AnimSoundSequence *soundFrame = _soundList;
  190. int frameCtr = 0;
  191. // Disable GMM saving/loading whilst animation is running
  192. LureEngine::getReference()._saveLoadAllowed = false;
  193. // Loop through displaying the animations
  194. while (_pPixels < _pPixelsEnd) {
  195. if ((soundFrame != NULL) && (frameCtr == 0))
  196. Sound.musicInterface_Play(
  197. Sound.isRoland() ? soundFrame->rolandSoundId : soundFrame->adlibSoundId,
  198. soundFrame->channelNum);
  199. if (_isEGA)
  200. egaDecodeFrame(_pPixels);
  201. else {
  202. if (_pLines >= _pLinesEnd) break;
  203. vgaDecodeFrame(_pPixels, _pLines);
  204. }
  205. // Make the decoded frame visible
  206. screen.update();
  207. result = delay(_frameDelay * 1000 / 50);
  208. if (result != ABORT_NONE) return result;
  209. if ((soundFrame != NULL) && (++frameCtr == soundFrame->numFrames)) {
  210. frameCtr = 0;
  211. ++soundFrame;
  212. if (soundFrame->numFrames == 0) soundFrame = NULL;
  213. }
  214. }
  215. return ABORT_NONE;
  216. }
  217. bool AnimationSequence::step() {
  218. Screen &screen = Screen::getReference();
  219. if (_pPixels >= _pPixelsEnd) return false;
  220. if (_isEGA)
  221. egaDecodeFrame(_pPixels);
  222. else {
  223. if (_pLines >= _pLinesEnd) return false;
  224. vgaDecodeFrame(_pPixels, _pLines);
  225. }
  226. // Make the decoded frame visible
  227. screen.update();
  228. screen.setPalette(&_palette);
  229. return true;
  230. }
  231. } // End of namespace Lure