diff options
author | Sven Hesse | 2011-01-16 16:29:43 +0000 |
---|---|---|
committer | Sven Hesse | 2011-01-16 16:29:43 +0000 |
commit | 32b94cc236c5c0d0ec4bf73d7bf87bd2e3c67bc9 (patch) | |
tree | f69e73df7e0d42ae18dec50ec3e55d72a4fb89f3 /graphics/video/coktel_decoder.cpp | |
parent | b451d3b51c7b9c1db0e4203791793020f330cb07 (diff) | |
download | scummvm-rg350-32b94cc236c5c0d0ec4bf73d7bf87bd2e3c67bc9.tar.gz scummvm-rg350-32b94cc236c5c0d0ec4bf73d7bf87bd2e3c67bc9.tar.bz2 scummvm-rg350-32b94cc236c5c0d0ec4bf73d7bf87bd2e3c67bc9.zip |
VIDEO: Implement internal-codec 16bit VMDs
svn-id: r55263
Diffstat (limited to 'graphics/video/coktel_decoder.cpp')
-rw-r--r-- | graphics/video/coktel_decoder.cpp | 238 |
1 files changed, 171 insertions, 67 deletions
diff --git a/graphics/video/coktel_decoder.cpp b/graphics/video/coktel_decoder.cpp index b750660b2d..8abb7eb261 100644 --- a/graphics/video/coktel_decoder.cpp +++ b/graphics/video/coktel_decoder.cpp @@ -426,27 +426,27 @@ void CoktelDecoder::deRLE(byte *&destPtr, const byte *&srcPtr, int16 destLen, in } // A whole, completely filled block -void CoktelDecoder::renderBlockWhole(const byte *src, Common::Rect &rect) { +void CoktelDecoder::renderBlockWhole(Surface &dstSurf, const byte *src, Common::Rect &rect) { Common::Rect srcRect = rect; - rect.clip(_surface.w, _surface.h); + rect.clip(dstSurf.w, dstSurf.h); - byte *dst = (byte *)_surface.pixels + (rect.top * _surface.pitch) + rect.left * _surface.bytesPerPixel; + byte *dst = (byte *)dstSurf.pixels + (rect.top * dstSurf.pitch) + rect.left * dstSurf.bytesPerPixel; for (int i = 0; i < rect.height(); i++) { - memcpy(dst, src, rect.width() * _surface.bytesPerPixel); + memcpy(dst, src, rect.width() * dstSurf.bytesPerPixel); - src += srcRect.width() * _surface.bytesPerPixel; - dst += _surface.pitch; + src += srcRect.width() * dstSurf.bytesPerPixel; + dst += dstSurf.pitch; } } // A quarter-wide whole, completely filled block -void CoktelDecoder::renderBlockWhole4X(const byte *src, Common::Rect &rect) { +void CoktelDecoder::renderBlockWhole4X(Surface &dstSurf, const byte *src, Common::Rect &rect) { Common::Rect srcRect = rect; - rect.clip(_surface.w, _surface.h); + rect.clip(dstSurf.w, dstSurf.h); - byte *dst = (byte *)_surface.pixels + (rect.top * _surface.pitch) + rect.left; + byte *dst = (byte *)dstSurf.pixels + (rect.top * dstSurf.pitch) + rect.left; for (int i = 0; i < rect.height(); i++) { byte *dstRow = dst; const byte *srcRow = src; @@ -461,26 +461,26 @@ void CoktelDecoder::renderBlockWhole4X(const byte *src, Common::Rect &rect) { } src += srcRect.width() / 4; - dst += _surface.pitch; + dst += dstSurf.pitch; } } // A half-high whole, completely filled block -void CoktelDecoder::renderBlockWhole2Y(const byte *src, Common::Rect &rect) { +void CoktelDecoder::renderBlockWhole2Y(Surface &dstSurf, const byte *src, Common::Rect &rect) { Common::Rect srcRect = rect; - rect.clip(_surface.w, _surface.h); + rect.clip(dstSurf.w, dstSurf.h); int16 height = rect.height(); - byte *dst = (byte *)_surface.pixels + (rect.top * _surface.pitch) + rect.left; + byte *dst = (byte *)dstSurf.pixels + (rect.top * dstSurf.pitch) + rect.left; while (height > 1) { memcpy(dst , src, rect.width()); - memcpy(dst + _surface.pitch, src, rect.width()); + memcpy(dst + dstSurf.pitch, src, rect.width()); height -= 2; src += srcRect.width(); - dst += 2 * _surface.pitch; + dst += 2 * dstSurf.pitch; } if (height == 1) @@ -488,12 +488,12 @@ void CoktelDecoder::renderBlockWhole2Y(const byte *src, Common::Rect &rect) { } // A sparse block -void CoktelDecoder::renderBlockSparse(const byte *src, Common::Rect &rect) { +void CoktelDecoder::renderBlockSparse(Surface &dstSurf, const byte *src, Common::Rect &rect) { Common::Rect srcRect = rect; - rect.clip(_surface.w, _surface.h); + rect.clip(dstSurf.w, dstSurf.h); - byte *dst = (byte *)_surface.pixels + (rect.top * _surface.pitch) + rect.left; + byte *dst = (byte *)dstSurf.pixels + (rect.top * dstSurf.pitch) + rect.left; for (int i = 0; i < rect.height(); i++) { byte *dstRow = dst; int16 pixWritten = 0; @@ -518,19 +518,19 @@ void CoktelDecoder::renderBlockSparse(const byte *src, Common::Rect &rect) { } - dst += _surface.pitch; + dst += dstSurf.pitch; } } // A half-high sparse block -void CoktelDecoder::renderBlockSparse2Y(const byte *src, Common::Rect &rect) { +void CoktelDecoder::renderBlockSparse2Y(Surface &dstSurf, const byte *src, Common::Rect &rect) { warning("renderBlockSparse2Y"); Common::Rect srcRect = rect; - rect.clip(_surface.w, _surface.h); + rect.clip(dstSurf.w, dstSurf.h); - byte *dst = (byte *)_surface.pixels + (rect.top * _surface.pitch) + rect.left; + byte *dst = (byte *)dstSurf.pixels + (rect.top * dstSurf.pitch) + rect.left; for (int i = 0; i < rect.height(); i += 2) { byte *dstRow = dst; int16 pixWritten = 0; @@ -544,7 +544,7 @@ void CoktelDecoder::renderBlockSparse2Y(const byte *src, Common::Rect &rect) { pixCount = MIN((pixCount & 0x7F) + 1, srcRect.width() - pixWritten); copyCount = CLIP<int16>(rect.width() - pixWritten, 0, pixCount); memcpy(dstRow , src, pixCount); - memcpy(dstRow + _surface.pitch, src, pixCount); + memcpy(dstRow + dstSurf.pitch, src, pixCount); pixWritten += pixCount; dstRow += pixCount; @@ -556,16 +556,16 @@ void CoktelDecoder::renderBlockSparse2Y(const byte *src, Common::Rect &rect) { } - dst += _surface.pitch; + dst += dstSurf.pitch; } } -void CoktelDecoder::renderBlockRLE(const byte *src, Common::Rect &rect) { +void CoktelDecoder::renderBlockRLE(Surface &dstSurf, const byte *src, Common::Rect &rect) { Common::Rect srcRect = rect; - rect.clip(_surface.w, _surface.h); + rect.clip(dstSurf.w, dstSurf.h); - byte *dst = (byte *)_surface.pixels + (rect.top * _surface.pitch) + rect.left; + byte *dst = (byte *)dstSurf.pixels + (rect.top * dstSurf.pitch) + rect.left; for (int i = 0; i < rect.height(); i++) { byte *dstRow = dst; int16 pixWritten = 0; @@ -597,7 +597,7 @@ void CoktelDecoder::renderBlockRLE(const byte *src, Common::Rect &rect) { } - dst += _surface.pitch; + dst += dstSurf.pitch; } } @@ -1386,15 +1386,15 @@ bool IMDDecoder::renderFrame(Common::Rect &rect) { // Evaluate the block type if (type == 0x01) - renderBlockSparse (dataPtr, rect); + renderBlockSparse (_surface, dataPtr, rect); else if (type == 0x02) - renderBlockWhole (dataPtr, rect); + renderBlockWhole (_surface, dataPtr, rect); else if (type == 0x42) - renderBlockWhole4X (dataPtr, rect); + renderBlockWhole4X (_surface, dataPtr, rect); else if ((type & 0x0F) == 0x02) - renderBlockWhole2Y (dataPtr, rect); + renderBlockWhole2Y (_surface, dataPtr, rect); else - renderBlockSparse2Y(dataPtr, rect); + renderBlockSparse2Y(_surface, dataPtr, rect); return true; } @@ -1534,8 +1534,10 @@ VMDDecoder::VMDDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : _videoBuffer [0] = 0; _videoBuffer [1] = 0; + _videoBuffer [2] = 0; _videoBufferLen[0] = 0; _videoBufferLen[1] = 0; + _videoBufferLen[2] = 0; } VMDDecoder::~VMDDecoder() { @@ -1566,6 +1568,9 @@ bool VMDDecoder::seek(int32 frame, int whence, bool restart) { } void VMDDecoder::setXY(uint16 x, uint16 y) { + if (_blitMode == 1) + x *= _bytesPerPixel; + for (uint32 i = 0; i < _frameCount; i++) { for (int j = 0; j < _partsPerFrame; j++) { @@ -1756,18 +1761,13 @@ bool VMDDecoder::assessVideoProperties() { else if ((_bytesPerPixel == 2) || (_bytesPerPixel == 3)) { int n = (_flags & 0x80) ? 2 : 3; - _blitMode = n - 1; + _blitMode = _bytesPerPixel - 1; _bytesPerPixel = n; _isPaletted = false; } - if ((_bytesPerPixel > 1) && !_externalCodec) { - warning("VMDDecoder::assessVideoProperties(): TODO: Internal _bytesPerPixel == %d", _bytesPerPixel); - return false; - } - - if (_blitMode != 0) + if (_blitMode == 1) _width /= _bytesPerPixel; if (_hasVideo) { @@ -1782,9 +1782,15 @@ bool VMDDecoder::assessVideoProperties() { _videoBufferSize = suggestedVideoBufferSize; } - for (int i = 0; i < 2; i++) { + for (int i = 0; i < 3; i++) { _videoBuffer[i] = new byte[_videoBufferSize]; memset(_videoBuffer[i], 0, _videoBufferSize); + + _8bppSurface[i].w = _width * _bytesPerPixel; + _8bppSurface[i].h = _height; + _8bppSurface[i].pitch = _width * _bytesPerPixel; + _8bppSurface[i].pixels = _videoBuffer[i]; + _8bppSurface[i].bytesPerPixel = 1; } } @@ -1955,6 +1961,7 @@ void VMDDecoder::close() { delete[] _videoBuffer[0]; delete[] _videoBuffer[1]; + delete[] _videoBuffer[2]; delete _codec; @@ -1990,8 +1997,10 @@ void VMDDecoder::close() { _videoBufferSize = 0; _videoBuffer [0] = 0; _videoBuffer [1] = 0; + _videoBuffer [2] = 0; _videoBufferLen[0] = 0; _videoBufferLen[1] = 0; + _videoBufferLen[2] = 0; _externalCodec = false; _codec = 0; @@ -2156,14 +2165,38 @@ void VMDDecoder::processFrame() { } bool VMDDecoder::renderFrame(Common::Rect &rect) { - if (!rect.isValidRect()) - // Invalid rendering area - return false; + Common::Rect realRect = rect; + Common::Rect fakeRect = rect; - // Clip the rendering area to the video's visible area - rect.clip(Common::Rect(_x, _y, _x + _width, _y + _height)); - if (!rect.isValidRect() || rect.isEmpty()) - // Result is empty => nothing to do + if (_blitMode == 1) { + realRect = Common::Rect(rect.left / _bytesPerPixel, rect.top, + rect.right / _bytesPerPixel, rect.bottom); + + realRect = Common::Rect(realRect.left - _x / _bytesPerPixel, realRect.top - _y, + realRect.right - _x / _bytesPerPixel, realRect.bottom - _y); + + fakeRect = Common::Rect(fakeRect.left - _x, fakeRect.top - _y, + fakeRect.right - _x, fakeRect.bottom - _y); + } + + if (_blitMode == 2) { + fakeRect = Common::Rect(rect.left * _bytesPerPixel, rect.top, + rect.right * _bytesPerPixel, rect.bottom); + + realRect = Common::Rect(realRect.left - _x, realRect.top - _y, + realRect.right - _x, realRect.bottom - _y); + + fakeRect = Common::Rect(fakeRect.left - _x * _bytesPerPixel, fakeRect.top - _y, + fakeRect.right - _x * _bytesPerPixel, fakeRect.bottom - _y); + } + + + realRect.clip(Common::Rect(_width, _height)); + fakeRect.clip(Common::Rect(_width * _bytesPerPixel, _height)); + + if (!realRect.isValidRect() || realRect.isEmpty()) + return false; + if (!fakeRect.isValidRect() || realRect.isEmpty()) return false; if (_externalCodec) { @@ -2178,18 +2211,13 @@ bool VMDDecoder::renderFrame(Common::Rect &rect) { rect = Common::Rect(_x, _y, _x + codecSurf->w, _y + codecSurf->h); rect.clip(Common::Rect(_x, _y, _x + _width, _y + _height)); - renderBlockWhole((const byte *) codecSurf->pixels, rect); + renderBlockWhole(_surface, (const byte *) codecSurf->pixels, rect); return true; } - if (_blitMode > 0) { - // TODO - warning("_blitMode == %d", _blitMode); - return false; - } - - byte *dataPtr = _videoBuffer[0]; - uint32 dataSize = _videoBufferLen[0] - 1; + uint8 srcBuffer = 0; + byte *dataPtr = _videoBuffer[srcBuffer]; + uint32 dataSize = _videoBufferLen[srcBuffer] - 1; uint8 type = *dataPtr++; @@ -2198,36 +2226,109 @@ bool VMDDecoder::renderFrame(Common::Rect &rect) { type &= 0x7F; - if ((type == 2) && (rect.width() == _surface.w) && (_x == 0)) { + if ((type == 2) && (rect.width() == _surface.w) && (_x == 0) && (_blitMode == 0)) { // Directly uncompress onto the video surface deLZ77((byte *)_surface.pixels + (_y * _surface.pitch), dataPtr, dataSize, _surface.w * _surface.h * _surface.bytesPerPixel); return true; } - _videoBufferLen[1] = deLZ77(_videoBuffer[1], dataPtr, dataSize, _videoBufferSize); + srcBuffer = 1; + _videoBufferLen[srcBuffer] = + deLZ77(_videoBuffer[srcBuffer], dataPtr, dataSize, _videoBufferSize); - dataPtr = _videoBuffer[1]; - dataSize = _videoBufferLen[1]; + dataPtr = _videoBuffer[srcBuffer]; + dataSize = _videoBufferLen[srcBuffer]; + } + + Common::Rect *blockRect = &fakeRect; + Surface *surface = &_surface; + if (_blitMode == 0) { + *blockRect = Common::Rect(blockRect->left + _x, blockRect->top + _y, + blockRect->right + _x, blockRect->bottom + _y); + } else { + surface = &_8bppSurface[2]; } // Evaluate the block type if (type == 0x01) - renderBlockSparse (dataPtr, rect); + renderBlockSparse (*surface, dataPtr, *blockRect); else if (type == 0x02) - renderBlockWhole (dataPtr, rect); + renderBlockWhole (*surface, dataPtr, *blockRect); else if (type == 0x03) - renderBlockRLE (dataPtr, rect); + renderBlockRLE (*surface, dataPtr, *blockRect); else if (type == 0x42) - renderBlockWhole4X (dataPtr, rect); + renderBlockWhole4X (*surface, dataPtr, *blockRect); else if ((type & 0x0F) == 0x02) - renderBlockWhole2Y (dataPtr, rect); + renderBlockWhole2Y (*surface, dataPtr, *blockRect); else - renderBlockSparse2Y(dataPtr, rect); + renderBlockSparse2Y(*surface, dataPtr, *blockRect); + if (_blitMode > 0) { + if (_bytesPerPixel == 2) + blit16(*surface, *blockRect); + else if (_bytesPerPixel == 3) + blit24(*surface, *blockRect); + + if (_blitMode == 1) + *blockRect = Common::Rect(blockRect->left + _x / _bytesPerPixel, blockRect->top + _y, + blockRect->right + _x / _bytesPerPixel, blockRect->bottom + _y); + else + *blockRect = Common::Rect(blockRect->left + _x, blockRect->top + _y, + blockRect->right + _x, blockRect->bottom + _y); + } + + rect = *blockRect; return true; } +void VMDDecoder::blit16(const Surface &srcSurf, Common::Rect &rect) { + rect = Common::Rect(rect.left / 2, rect.top, rect.right / 2, rect.bottom); + + Common::Rect srcRect = rect; + + rect.clip(_surface.w, _surface.h); + + PixelFormat pixelFormat = getPixelFormat(); + + uint16 x = _x; + if (_blitMode == 1) + x /= 4; + + const byte *src = (byte *)srcSurf.pixels + + (srcRect.top * srcSurf.pitch) + srcRect.left * _bytesPerPixel; + byte *dst = (byte *)_surface.pixels + + ((_y + rect.top) * _surface.pitch) + (x + rect.left) * _surface.bytesPerPixel; + + for (int i = 0; i < rect.height(); i++) { + const byte *srcRow = src; + byte *dstRow = dst; + + for (int j = 0; j < rect.width(); j++, srcRow += 2, dstRow += _surface.bytesPerPixel) { + uint16 data = READ_LE_UINT16(srcRow); + + byte r = ((data & 0x7C00) >> 10) << 3; + byte g = ((data & 0x03E0) >> 5) << 3; + byte b = ((data & 0x001F) >> 0) << 3; + + uint32 c = pixelFormat.RGBToColor(r, g, b); + if ((r == 0) && (g == 0) && (b == 0)) + c = 0; + + if (_surface.bytesPerPixel == 2) + *((uint16 *)dstRow) = (uint16) c; + } + + src += srcSurf .pitch; + dst += _surface.pitch; + } +} + +void VMDDecoder::blit24(const Surface &srcSurf, Common::Rect &rect) { + warning("TODO: blit24"); + return; +} + void VMDDecoder::emptySoundSlice(uint32 size) { byte *sound = soundEmpty(size); @@ -2475,6 +2576,9 @@ PixelFormat VMDDecoder::getPixelFormat() const { if (_externalCodec && _codec) return _codec->getPixelFormat(); + if (_blitMode > 0) + return g_system->getScreenFormat(); + return PixelFormat::createFormatCLUT8(); } |