diff options
-rw-r--r-- | engines/gob/videoplayer.cpp | 135 | ||||
-rw-r--r-- | engines/gob/videoplayer.h | 11 | ||||
-rw-r--r-- | graphics/video/coktel_decoder.cpp | 335 | ||||
-rw-r--r-- | graphics/video/coktel_decoder.h | 13 |
4 files changed, 385 insertions, 109 deletions
diff --git a/engines/gob/videoplayer.cpp b/engines/gob/videoplayer.cpp index 174c3af506..fda5e4de2f 100644 --- a/engines/gob/videoplayer.cpp +++ b/engines/gob/videoplayer.cpp @@ -133,43 +133,44 @@ int VideoPlayer::openVideo(bool primary, const Common::String &file, Properties if (!file.compareToIgnoreCase("SQ32-03.VMD")) _woodruffCohCottWorkaround = true; } - } - if (!(properties.flags & kFlagNoVideo) && (properties.sprite >= 0)) { - bool ownSurf = (properties.sprite != Draw::kFrontSurface) && (properties.sprite != Draw::kBackSurface); - bool screenSize = properties.flags & kFlagScreenSurface; + if (!(properties.flags & kFlagNoVideo) && (properties.sprite >= 0)) { + bool ownSurf = (properties.sprite != Draw::kFrontSurface) && (properties.sprite != Draw::kBackSurface); + bool screenSize = properties.flags & kFlagScreenSurface; - if (ownSurf) { - _vm->_draw->_spritesArray[properties.sprite] = - _vm->_video->initSurfDesc(_vm->_global->_videoMode, - screenSize ? _vm->_width : video->decoder->getWidth(), - screenSize ? _vm->_height : video->decoder->getHeight(), 0); - } + if (ownSurf) { + _vm->_draw->_spritesArray[properties.sprite] = + _vm->_video->initSurfDesc(_vm->_global->_videoMode, + screenSize ? _vm->_width : video->decoder->getWidth(), + screenSize ? _vm->_height : video->decoder->getHeight(), 0); + } + + if (!_vm->_draw->_spritesArray[properties.sprite]) { + properties.sprite = -1; + video->surface.reset(); + video->decoder->setSurfaceMemory(); + video->decoder->setXY(0, 0); + } else { + video->surface = _vm->_draw->_spritesArray[properties.sprite]; + video->decoder->setSurfaceMemory(video->surface->getVidMem(), + video->surface->getWidth(), video->surface->getHeight(), 1); + + if (!ownSurf || (ownSurf && screenSize)) { + if ((properties.x >= 0) || (properties.y >= 0)) + video->decoder->setXY((properties.x < 0) ? 0xFFFF : properties.x, + (properties.y < 0) ? 0xFFFF : properties.y); + else + video->decoder->setXY(); + } else + video->decoder->setXY(0, 0); + } - if (!_vm->_draw->_spritesArray[properties.sprite]) { + } else { properties.sprite = -1; video->surface.reset(); video->decoder->setSurfaceMemory(); video->decoder->setXY(0, 0); - } else { - video->surface = _vm->_draw->_spritesArray[properties.sprite]; - video->decoder->setSurfaceMemory(video->surface->getVidMem(), - video->surface->getWidth(), video->surface->getHeight(), 1); - - if (!ownSurf || (ownSurf && screenSize)) { - if ((properties.x >= 0) && (properties.y >= 0)) - video->decoder->setXY(properties.x, properties.y); - else - video->decoder->setXY(); - } else - video->decoder->setXY(0, 0); } - - } else { - properties.sprite = -1; - video->surface.reset(); - video->decoder->setSurfaceMemory(); - video->decoder->setXY(0, 0); } if (primary) @@ -205,19 +206,16 @@ bool VideoPlayer::play(int slot, Properties &properties) { if (properties.startFrame < 0) properties.startFrame = video->decoder->getCurFrame() + 1; if (properties.lastFrame < 0) - properties.lastFrame = video->decoder->getFrameCount(); + properties.lastFrame = video->decoder->getFrameCount() - 1; if (properties.endFrame < 0) properties.endFrame = properties.lastFrame; if (properties.palFrame < 0) properties.palFrame = properties.startFrame; properties.startFrame--; - properties.lastFrame--; properties.endFrame--; properties.palFrame--; - properties.palCmd &= 0x3F; - if (primary) { _vm->_draw->_showCursor = _noCursorSwitch ? 3 : 0; @@ -229,9 +227,10 @@ bool VideoPlayer::play(int slot, Properties &properties) { properties.canceled = false; - while ((properties.startFrame != properties.lastFrame) && !properties.canceled) { - if (!playFrame(slot, properties)) - return false; + while (properties.startFrame != properties.lastFrame) { + playFrame(slot, properties); + if (properties.canceled) + break; properties.startFrame += backwards ? -1 : 1; @@ -273,7 +272,7 @@ bool VideoPlayer::playFrame(int slot, Properties &properties) { _vm->_draw->_applyPal = true; if (properties.palCmd >= 4) - ; // copyPalette(video, palStart, palEnd); + copyPalette(*video, properties.palStart, properties.palEnd); } if (modifiedPal && (properties.palCmd == 8) && (properties.sprite != Draw::kBackSurface)) @@ -312,16 +311,14 @@ bool VideoPlayer::playFrame(int slot, Properties &properties) { _vm->_video->dirtyRectsAll(); } - /* - if ((state.flags & Graphics::CoktelDecoder::kStatePalette) && (palCmd > 1)) { - copyPalette(video, palStart, palEnd); + if (video->decoder->hasPalette() && (properties.palCmd > 1)) { + copyPalette(*video, properties.palStart, properties.palEnd); - if (!_backSurf) + if (properties.sprite != Draw::kBackSurface) _vm->_video->setFullPalette(_vm->_global->_pPaletteDesc); else _vm->_draw->_applyPal = true; } - */ const Common::List<Common::Rect> &dirtyRects = video->decoder->getDirtyRects(); @@ -417,14 +414,6 @@ Common::String VideoPlayer::getFileName(int slot) const { return video->fileName; } -uint16 VideoPlayer::getFlags(int slot) const { - const Video *video = getVideoBySlot(slot); - if (!video) - return 0; - - return 0; // video->decoder->getFlags(); -} - uint32 VideoPlayer::getFrameCount(int slot) const { const Video *video = getVideoBySlot(slot); if (!video) @@ -462,7 +451,7 @@ uint16 VideoPlayer::getDefaultX(int slot) const { if (!video) return 0; - return 0; // video->decoder->getDefaultX(); + return video->decoder->getDefaultX(); } uint16 VideoPlayer::getDefaultY(int slot) const { @@ -470,23 +459,7 @@ uint16 VideoPlayer::getDefaultY(int slot) const { if (!video) return 0; - return 0; // video->decoder->getDefaultY(); -} - -uint32 VideoPlayer::getFeatures(int slot) const { - const Video *video = getVideoBySlot(slot); - if (!video) - return 0; - - return 0; // video->decoder->getFeatures(); -} - -void VideoPlayer::getState(int slot) const { - const Video *video = getVideoBySlot(slot); - if (!video) - return; - - return; // video->decoder->getState(); + return video->decoder->getDefaultY(); } bool VideoPlayer::hasExtraData(const Common::String &fileName, int slot) const { @@ -715,12 +688,6 @@ void VideoPlayer::slotCopyFrame(int slot, byte *dest, } void VideoPlayer::slotCopyPalette(int slot, int16 palStart, int16 palEnd) { -#if 0 - if ((slot < 0) || (slot >= kVideoSlotCount) || !_videoSlots[slot]) - return; - - //copyPalette(*(_videoSlots[slot]->getVideo()), palStart, palEnd); -#endif } void VideoPlayer::slotWaitEndFrame(int slot, bool onlySound) { @@ -741,31 +708,17 @@ void VideoPlayer::slotWaitEndFrame(int slot, bool onlySound) { void VideoPlayer::slotSetDoubleMode(int slot, bool doubleMode) { } -void VideoPlayer::copyPalette(Graphics::CoktelDecoder &video, int16 palStart, int16 palEnd) { - /* - if (!(video.getFeatures() & Graphics::CoktelDecoder::kFeaturesPalette)) +void VideoPlayer::copyPalette(const Video &video, int16 palStart, int16 palEnd) { + if (!video.decoder->hasPalette()) return; - */ if (palStart < 0) palStart = 0; if (palEnd < 0) palEnd = 255; - /* memcpy(((char *)(_vm->_global->_pPaletteDesc->vgaPal)) + palStart * 3, - video.getPalette() + palStart * 3, - (palEnd - palStart + 1) * 3); - */ -} - -void VideoPlayer::evalBgShading(Graphics::CoktelDecoder &video) { - /* - if (video.isSoundPlaying()) - _vm->_sound->bgShade(); - else - _vm->_sound->bgUnshade(); - */ + video.decoder->getPalette() + palStart * 3, (palEnd - palStart + 1) * 3); } } // End of namespace Gob diff --git a/engines/gob/videoplayer.h b/engines/gob/videoplayer.h index 68e05dd322..f1245bca48 100644 --- a/engines/gob/videoplayer.h +++ b/engines/gob/videoplayer.h @@ -96,7 +96,7 @@ public: void evaluateFlags(Properties &properties); int openVideo(bool primary, const Common::String &file, Properties &properties); - bool closeVideo(int slot); + bool closeVideo(int slot = 0); bool play(int slot, Properties &properties); @@ -104,16 +104,12 @@ public: Common::String getFileName(int slot = 0) const; - uint16 getFlags (int slot = 0) const; uint32 getFrameCount (int slot = 0) const; uint32 getCurrentFrame(int slot = 0) const; uint16 getWidth (int slot = 0) const; uint16 getHeight (int slot = 0) const; uint16 getDefaultX (int slot = 0) const; uint16 getDefaultY (int slot = 0) const; - uint32 getFeatures (int slot = 0) const; - - void getState(int slot = 0) const; bool hasExtraData(const Common::String &fileName, int slot = 0) const; Common::MemoryReadStream *getExtraData(const Common::String &fileName, int slot = 0); @@ -190,10 +186,7 @@ private: void checkAbort(Video &video, Properties &properties); void evalBgShading(Video &video); - // Obsolete, to be deleted - - void copyPalette(Graphics::CoktelDecoder &video, int16 palStart = -1, int16 palEnd = -1); - void evalBgShading(Graphics::CoktelDecoder &video); + void copyPalette(const Video &video, int16 palStart, int16 palEnd); }; } // End of namespace Gob diff --git a/graphics/video/coktel_decoder.cpp b/graphics/video/coktel_decoder.cpp index ebb1c9492b..c8a934d5bb 100644 --- a/graphics/video/coktel_decoder.cpp +++ b/graphics/video/coktel_decoder.cpp @@ -121,6 +121,10 @@ const Common::List<Common::Rect> &CoktelDecoder::getDirtyRects() const { return _dirtyRects; } +bool CoktelDecoder::hasPalette() const { + return (_features & kFeaturesPalette) != 0; +} + bool CoktelDecoder::hasSound() const { return _hasSound; } @@ -202,6 +206,235 @@ bool CoktelDecoder::hasDirtyPalette() const { return (_features & kFeaturesPalette) && _paletteDirty; } +void CoktelDecoder::deLZ77(byte *dest, byte *src) { + int i; + byte buf[4370]; + uint16 chunkLength; + uint32 frameLength; + uint16 bufPos1; + uint16 bufPos2; + uint16 tmp; + uint8 chunkBitField; + uint8 chunkCount; + bool mode; + + frameLength = READ_LE_UINT32(src); + src += 4; + + if ((READ_LE_UINT16(src) == 0x1234) && (READ_LE_UINT16(src + 2) == 0x5678)) { + src += 4; + bufPos1 = 273; + mode = 1; // 123Ch (cmp al, 12h) + } else { + bufPos1 = 4078; + mode = 0; // 275h (jnz +2) + } + + memset(buf, 32, bufPos1); + chunkCount = 1; + chunkBitField = 0; + + while (frameLength > 0) { + chunkCount--; + if (chunkCount == 0) { + tmp = *src++; + chunkCount = 8; + chunkBitField = tmp; + } + if (chunkBitField % 2) { + chunkBitField >>= 1; + buf[bufPos1] = *src; + *dest++ = *src++; + bufPos1 = (bufPos1 + 1) % 4096; + frameLength--; + continue; + } + chunkBitField >>= 1; + + tmp = READ_LE_UINT16(src); + src += 2; + chunkLength = ((tmp & 0xF00) >> 8) + 3; + + if ((mode && ((chunkLength & 0xFF) == 0x12)) || + (!mode && (chunkLength == 0))) + chunkLength = *src++ + 0x12; + + bufPos2 = (tmp & 0xFF) + ((tmp >> 4) & 0x0F00); + if (((tmp + chunkLength) >= 4096) || + ((chunkLength + bufPos1) >= 4096)) { + + for (i = 0; i < chunkLength; i++, dest++) { + *dest = buf[bufPos2]; + buf[bufPos1] = buf[bufPos2]; + bufPos1 = (bufPos1 + 1) % 4096; + bufPos2 = (bufPos2 + 1) % 4096; + } + + } else if (((tmp + chunkLength) < bufPos1) || + ((chunkLength + bufPos1) < bufPos2)) { + + memcpy(dest, buf + bufPos2, chunkLength); + memmove(buf + bufPos1, buf + bufPos2, chunkLength); + + dest += chunkLength; + bufPos1 += chunkLength; + bufPos2 += chunkLength; + + } else { + + for (i = 0; i < chunkLength; i++, dest++, bufPos1++, bufPos2++) { + *dest = buf[bufPos2]; + buf[bufPos1] = buf[bufPos2]; + } + + } + frameLength -= chunkLength; + + } +} + +// A whole, completely filled block +void CoktelDecoder::renderBlockWhole(const byte *src) { + Common::Rect &rect = _dirtyRects.back(); + Common::Rect drawRect = rect; + + drawRect.clip(_surface.w, _surface.h); + + byte *dst = ((byte *) _surface.pixels) + (drawRect.top * _surface.pitch) + drawRect.left; + for (int i = 0; i < drawRect.height(); i++) { + memcpy(dst, src, drawRect.width()); + + src += rect.width(); + dst += _surface.pitch; + } +} + +// A quarter-wide whole, completely filled block +void CoktelDecoder::renderBlockWhole4X(const byte *src) { + Common::Rect &rect = _dirtyRects.back(); + Common::Rect drawRect = rect; + + drawRect.clip(_surface.w, _surface.h); + + byte *dst = ((byte *) _surface.pixels) + (drawRect.top * _surface.pitch) + drawRect.left; + for (int i = 0; i < drawRect.height(); i++) { + byte *dstRow = dst; + const byte *srcRow = src; + + int16 count = drawRect.width(); + while (count >= 0) { + memset(dstRow, *srcRow, MIN<int16>(count, 4)); + + count -= 4; + dstRow += 4; + srcRow += 1; + } + + src += rect.width() / 4; + dst += _surface.pitch; + } +} + +// A half-high whole, completely filled block +void CoktelDecoder::renderBlockWhole2Y(const byte *src) { + warning("renderBlockWhole2Y"); + + Common::Rect &rect = _dirtyRects.back(); + Common::Rect drawRect = rect; + + drawRect.clip(_surface.w, _surface.h); + + int16 height = drawRect.height(); + + byte *dst = ((byte *) _surface.pixels) + (drawRect.top * _surface.pitch) + drawRect.left; + while (height > 1) { + memcpy(dst , src, drawRect.width()); + memcpy(dst + _surface.pitch, src, drawRect.width()); + + height -= 2; + src += rect.width(); + dst += 2 * _surface.pitch; + } + + if (height == 1) + memcpy(dst, src, drawRect.width()); +} + +// A sparse block +void CoktelDecoder::renderBlockSparse(const byte *src) { + Common::Rect &rect = _dirtyRects.back(); + Common::Rect drawRect = rect; + + drawRect.clip(_surface.w, _surface.h); + + byte *dst = ((byte *) _surface.pixels) + (drawRect.top * _surface.pitch) + drawRect.left; + for (int i = 0; i < drawRect.height(); i++) { + byte *dstRow = dst; + int16 pixWritten = 0; + + while (pixWritten < rect.width()) { + int16 pixCount = *src++; + + if (pixCount & 0x80) { // Data + int16 copyCount; + + pixCount = MIN((pixCount & 0x7F) + 1, rect.width() - pixWritten); + copyCount = CLIP<int16>(drawRect.width() - pixWritten, 0, pixCount); + memcpy(dstRow, src, copyCount); + + pixWritten += pixCount; + dstRow += pixCount; + src += pixCount; + } else { // "Hole" + pixWritten += pixCount + 1; + dstRow += pixCount + 1; + } + + } + + dst += _surface.pitch; + } +} + +// A half-high sparse block +void CoktelDecoder::renderBlockSparse2Y(const byte *src) { + warning("renderBlockSparse2Y"); + + Common::Rect &rect = _dirtyRects.back(); + Common::Rect drawRect = rect; + + drawRect.clip(_surface.w, _surface.h); + + byte *dst = ((byte *) _surface.pixels) + (drawRect.top * _surface.pitch) + drawRect.left; + for (int i = 0; i < drawRect.height(); i += 2) { + byte *dstRow = dst; + int16 pixWritten = 0; + + while (pixWritten < rect.width()) { + int16 pixCount = *src++; + + if (pixCount & 0x80) { // Data + int16 copyCount; + + pixCount = MIN((pixCount & 0x7F) + 1, rect.width() - pixWritten); + copyCount = CLIP<int16>(drawRect.width() - pixWritten, 0, pixCount); + memcpy(dstRow , src, pixCount); + memcpy(dstRow + _surface.pitch, src, pixCount); + + pixWritten += pixCount; + dstRow += pixCount; + src += pixCount; + } else { // "Hole" + pixWritten += pixCount + 1; + dstRow += pixCount + 1; + } + + } + + dst += _surface.pitch; + } +} + Common::Rational CoktelDecoder::getFrameRate() const { return _frameRate; } @@ -471,7 +704,7 @@ bool IMDDecoder::seek(int32 frame, int whence, bool restart) { return true; } else { - warning("Imd::seek(): Frame %d is not directly accessible", frame + 1); + warning("IMDDecoder::seek(): Frame %d is not directly accessible", frame + 1); return false; } @@ -482,6 +715,37 @@ bool IMDDecoder::seek(int32 frame, int whence, bool restart) { return true; } +void IMDDecoder::setXY(uint16 x, uint16 y) { + // Adjusting the standard coordinates + if (_stdX != -1) { + if (x != 0xFFFF) + _stdX = _stdX - _x + x; + if (y != 0xFFFF) + _stdY = _stdY - _y + y; + } + + // Going through the coordinate table as well + if (_frameCoords) { + for (uint32 i = 0; i < _frameCount; i++) { + if (_frameCoords[i].left != -1) { + if (x != 0xFFFF) { + _frameCoords[i].left = _frameCoords[i].left - _x + x; + _frameCoords[i].right = _frameCoords[i].right - _x + x; + } + if (y != 0xFFFF) { + _frameCoords[i].top = _frameCoords[i].top - _y + y; + _frameCoords[i].bottom = _frameCoords[i].bottom - _y + y; + } + } + } + } + + if (x != 0xFFFF) + _x = x; + if (y != 0xFFFF) + _y = y; +} + bool IMDDecoder::load(Common::SeekableReadStream &stream) { close(); @@ -559,7 +823,7 @@ bool IMDDecoder::loadCoordinates() { if (_version >= 3) { uint16 count = _stream->readUint16LE(); if (count > 1) { - warning("IMD: More than one standard coordinate quad found (%d)", count ); + warning("IMDDecoder::loadCoordinates(): More than one standard coordinate quad found (%d)", count); return false; } @@ -733,7 +997,6 @@ Surface *IMDDecoder::decodeNextFrame() { createSurface(); processFrame(); - renderFrame(); if (_curFrame == 0) _startTime = g_system->getMillis(); @@ -753,8 +1016,6 @@ void IMDDecoder::processFrame() { bool startSound = false; do { - calcFrameCoords(_curFrame); - cmd = _stream->readUint16LE(); if ((cmd & kCommandBreakMask) == kCommandBreak) { @@ -819,12 +1080,15 @@ void IMDDecoder::processFrame() { } } else if (cmd == kCommandVideoData) { + calcFrameCoords(_curFrame); + videoData(_stream->readUint32LE() + 2); - } else if (cmd != 0) + } else if (cmd != 0) { + calcFrameCoords(_curFrame); + videoData(cmd + 2); - else - _dirtyRects.pop_back(); + } } while (hasNextCmd); @@ -862,7 +1126,60 @@ void IMDDecoder::videoData(uint32 size) { } void IMDDecoder::renderFrame() { - // TODO + if (_dirtyRects.empty()) + return; + + Common::Rect &rect = _dirtyRects.back(); + + rect.clip(Common::Rect(_x, _y, _x + _width, _y + _height)); + if (!rect.isValidRect() || rect.isEmpty()) { + _dirtyRects.pop_back(); + return; + } + + byte *dataPtr = _frameData; + + uint8 type = *dataPtr++; + + if (type & 0x10) { // Palette data + // One byte index + int index = *dataPtr++; + // 16 entries with each 3 bytes (RGB) + memcpy(_palette + index * 3, dataPtr, MIN((255 - index) * 3, 48)); + + dataPtr += 48; + type ^= 0x10; + + _paletteDirty = true; + } + + if (type & 0x80) { + // Frame data is compressed + + type &= 0x7F; + + if ((type == 2) && (rect.width() == _surface.w)) { + // Directly uncompress onto the video surface + deLZ77((byte *) _surface.pixels, dataPtr); + return; + } + + deLZ77(_videoBuffer, dataPtr); + + dataPtr = _videoBuffer; + } + + // Evaluate the block type + if (type == 0x01) + renderBlockSparse (dataPtr); + else if (type == 0x02) + renderBlockWhole (dataPtr); + else if (type == 0x42) + renderBlockWhole4X (dataPtr); + else if ((type & 0x0F) == 0x02) + renderBlockWhole2Y (dataPtr); + else + renderBlockSparse2Y(dataPtr); } void IMDDecoder::nextSoundSlice(bool hasNextCmd) { diff --git a/graphics/video/coktel_decoder.h b/graphics/video/coktel_decoder.h index 1736132cf4..0464b8e31b 100644 --- a/graphics/video/coktel_decoder.h +++ b/graphics/video/coktel_decoder.h @@ -84,6 +84,8 @@ public: /** Return a list of rectangles that changed in the last frame. */ const Common::List<Common::Rect> &getDirtyRects() const; + bool hasPalette() const; + bool hasSound() const; bool isSoundEnabled() const; bool isSoundPlaying() const; @@ -159,8 +161,17 @@ protected: void createSurface(); void freeSurface(); + void deLZ77(byte *dest, byte *src); + + void renderBlockWhole (const byte *src); + void renderBlockWhole4X (const byte *src); + void renderBlockWhole2Y (const byte *src); + void renderBlockSparse (const byte *src); + void renderBlockSparse2Y(const byte *src); + inline void unsignedToSigned(byte *buffer, int length); +public: // FixedRateVideoDecoder interface Common::Rational getFrameRate() const; }; @@ -202,6 +213,8 @@ public: bool seek(int32 frame, int whence = SEEK_SET, bool restart = false); + void setXY(uint16 x, uint16 y); + // VideoDecoder interface bool load(Common::SeekableReadStream &stream); |