PageRenderTime 53ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/engines/sci/video/seq_decoder.cpp

http://github.com/scummvm/scummvm
C++ | 237 lines | 167 code | 39 blank | 31 comment | 28 complexity | d7f71a54b6d51e5af533848182638712 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 "common/endian.h"
  23. #include "common/stream.h"
  24. #include "common/system.h"
  25. #include "common/textconsole.h"
  26. #include "graphics/surface.h"
  27. #include "sci/video/seq_decoder.h"
  28. namespace Sci {
  29. enum seqPalTypes {
  30. kSeqPalVariable = 0,
  31. kSeqPalConstant = 1
  32. };
  33. enum seqFrameTypes {
  34. kSeqFrameFull = 0,
  35. kSeqFrameDiff = 1
  36. };
  37. SEQDecoder::SEQDecoder(uint frameDelay) : _frameDelay(frameDelay) {
  38. }
  39. SEQDecoder::~SEQDecoder() {
  40. close();
  41. }
  42. bool SEQDecoder::loadStream(Common::SeekableReadStream *stream) {
  43. close();
  44. addTrack(new SEQVideoTrack(stream, _frameDelay));
  45. return true;
  46. }
  47. SEQDecoder::SEQVideoTrack::SEQVideoTrack(Common::SeekableReadStream *stream, uint frameDelay) {
  48. assert(stream);
  49. assert(frameDelay != 0);
  50. _fileStream = stream;
  51. _frameDelay = frameDelay;
  52. _curFrame = -1;
  53. _surface = new Graphics::Surface();
  54. _surface->create(SEQ_SCREEN_WIDTH, SEQ_SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8());
  55. _frameCount = _fileStream->readUint16LE();
  56. // Set initial palette
  57. readPaletteChunk(_fileStream->readUint32LE());
  58. }
  59. SEQDecoder::SEQVideoTrack::~SEQVideoTrack() {
  60. delete _fileStream;
  61. _surface->free();
  62. delete _surface;
  63. }
  64. void SEQDecoder::SEQVideoTrack::readPaletteChunk(uint16 chunkSize) {
  65. byte *paletteData = new byte[chunkSize];
  66. _fileStream->read(paletteData, chunkSize);
  67. // SCI1.1 palette
  68. byte palFormat = paletteData[32];
  69. uint16 palColorStart = READ_LE_UINT16(paletteData + 25);
  70. uint16 palColorCount = READ_LE_UINT16(paletteData + 29);
  71. int palOffset = 37;
  72. memset(_palette, 0, 256 * 3);
  73. for (uint16 colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) {
  74. if (palFormat == kSeqPalVariable)
  75. palOffset++;
  76. _palette[colorNo * 3 + 0] = paletteData[palOffset++];
  77. _palette[colorNo * 3 + 1] = paletteData[palOffset++];
  78. _palette[colorNo * 3 + 2] = paletteData[palOffset++];
  79. }
  80. _dirtyPalette = true;
  81. delete[] paletteData;
  82. }
  83. const Graphics::Surface *SEQDecoder::SEQVideoTrack::decodeNextFrame() {
  84. int16 frameWidth = _fileStream->readUint16LE();
  85. int16 frameHeight = _fileStream->readUint16LE();
  86. int16 frameLeft = _fileStream->readUint16LE();
  87. int16 frameTop = _fileStream->readUint16LE();
  88. byte colorKey = _fileStream->readByte();
  89. byte frameType = _fileStream->readByte();
  90. _fileStream->skip(2);
  91. uint16 frameSize = _fileStream->readUint16LE();
  92. _fileStream->skip(2);
  93. uint16 rleSize = _fileStream->readUint16LE();
  94. _fileStream->skip(6);
  95. uint32 offset = _fileStream->readUint32LE();
  96. _fileStream->seek(offset);
  97. if (frameType == kSeqFrameFull) {
  98. byte *dst = (byte *)_surface->getBasePtr(frameLeft, frameTop);
  99. byte *linebuf = new byte[frameWidth];
  100. do {
  101. _fileStream->read(linebuf, frameWidth);
  102. memcpy(dst, linebuf, frameWidth);
  103. dst += SEQ_SCREEN_WIDTH;
  104. } while (--frameHeight);
  105. delete[] linebuf;
  106. } else {
  107. byte *buf = new byte[frameSize];
  108. _fileStream->read(buf, frameSize);
  109. decodeFrame(buf, rleSize, buf + rleSize, frameSize - rleSize, (byte *)_surface->getBasePtr(0, frameTop), frameLeft, frameWidth, frameHeight, colorKey);
  110. delete[] buf;
  111. }
  112. _curFrame++;
  113. return _surface;
  114. }
  115. #define WRITE_TO_BUFFER(n) \
  116. if (writeRow * SEQ_SCREEN_WIDTH + writeCol + (n) > SEQ_SCREEN_WIDTH * height) { \
  117. warning("SEQ player: writing out of bounds, aborting"); \
  118. return false; \
  119. } \
  120. if (litPos + (n) > litSize) { \
  121. warning("SEQ player: reading out of bounds, aborting"); \
  122. } \
  123. memcpy(dest + writeRow * SEQ_SCREEN_WIDTH + writeCol, litData + litPos, n);
  124. bool SEQDecoder::SEQVideoTrack::decodeFrame(byte *rleData, int rleSize, byte *litData, int litSize, byte *dest, int left, int width, int height, int colorKey) {
  125. int writeRow = 0;
  126. int writeCol = left;
  127. int litPos = 0;
  128. int rlePos = 0;
  129. while (rlePos < rleSize) {
  130. int op = rleData[rlePos++];
  131. if ((op & 0xc0) == 0xc0) {
  132. op &= 0x3f;
  133. if (op == 0) {
  134. // Go to next line in target buffer
  135. writeRow++;
  136. writeCol = left;
  137. } else {
  138. // Skip bytes on current line
  139. writeCol += op;
  140. }
  141. } else if (op & 0x80) {
  142. op &= 0x3f;
  143. if (op == 0) {
  144. // Copy remainder of current line
  145. int rem = width - (writeCol - left);
  146. WRITE_TO_BUFFER(rem);
  147. writeRow++;
  148. writeCol = left;
  149. litPos += rem;
  150. } else {
  151. // Copy bytes
  152. WRITE_TO_BUFFER(op);
  153. writeCol += op;
  154. litPos += op;
  155. }
  156. } else {
  157. uint16 count = ((op & 7) << 8) | rleData[rlePos++];
  158. switch (op >> 3) {
  159. case 2:
  160. // Skip bytes
  161. writeCol += count;
  162. break;
  163. case 3:
  164. // Copy bytes
  165. WRITE_TO_BUFFER(count);
  166. writeCol += count;
  167. litPos += count;
  168. break;
  169. case 6: {
  170. // Copy rows
  171. if (count == 0)
  172. count = height - writeRow;
  173. for (int i = 0; i < count; i++) {
  174. WRITE_TO_BUFFER(width);
  175. litPos += width;
  176. writeRow++;
  177. }
  178. break;
  179. }
  180. case 7:
  181. // Skip rows
  182. if (count == 0)
  183. count = height - writeRow;
  184. writeRow += count;
  185. break;
  186. default:
  187. warning("Unsupported operation %i encountered", op >> 3);
  188. return false;
  189. }
  190. }
  191. }
  192. return true;
  193. }
  194. const byte *SEQDecoder::SEQVideoTrack::getPalette() const {
  195. _dirtyPalette = false;
  196. return _palette;
  197. }
  198. } // End of namespace Sci