From 06e8306aab6458e01b4356b6afa95544c64eae9d Mon Sep 17 00:00:00 2001 From: Einar Johan Trøan Sømåen Date: Mon, 18 Jun 2012 19:11:15 +0200 Subject: WINTERMUTE: Add savegame-thumbnail-support. --- engines/wintermute/Base/BImage.cpp | 98 +++++++++++++++++++++++++++++++-- engines/wintermute/Base/BImage.h | 6 +- engines/wintermute/Base/BPersistMgr.cpp | 12 +++- engines/wintermute/Base/BRenderSDL.cpp | 3 + 4 files changed, 110 insertions(+), 9 deletions(-) diff --git a/engines/wintermute/Base/BImage.cpp b/engines/wintermute/Base/BImage.cpp index 31c05226f5..6076b09963 100644 --- a/engines/wintermute/Base/BImage.cpp +++ b/engines/wintermute/Base/BImage.cpp @@ -32,6 +32,7 @@ #include "engines/wintermute/Base/BGame.h" #include "engines/wintermute/Base/BFileManager.h" #include "engines/wintermute/graphics/transparentSurface.h" +#include "engines/wintermute/utils/StringUtil.h" #include "graphics/decoders/png.h" #include "graphics/decoders/jpeg.h" #include "graphics/decoders/bmp.h" @@ -52,6 +53,7 @@ CBImage::CBImage(CBGame *inGame, FIBITMAP *bitmap): CBBase(inGame) { _palette = NULL; _surface = NULL; _decoder = NULL; + _deletableSurface = NULL; } @@ -59,6 +61,7 @@ CBImage::CBImage(CBGame *inGame, FIBITMAP *bitmap): CBBase(inGame) { CBImage::~CBImage() { /* delete _bitmap; */ delete _decoder; + delete _deletableSurface; #if 0 if (_bitmap) FreeImage_Unload(_bitmap); #endif @@ -66,8 +69,10 @@ CBImage::~CBImage() { HRESULT CBImage::loadFile(const Common::String &filename) { _filename = filename; - - if (filename.hasSuffix(".png")) { + + if (StringUtil::StartsWith(filename, "savegame:", true)) { + _decoder = new Graphics::BitmapDecoder(); + } else if (filename.hasSuffix(".png")) { _decoder = new Graphics::PNGDecoder(); } else if (filename.hasSuffix(".bmp")) { _decoder = new Graphics::BitmapDecoder(); @@ -98,6 +103,11 @@ byte CBImage::getAlphaAt(int x, int y) { return a; } +void CBImage::copyFrom(Graphics::Surface *surface) { + _surface = _deletableSurface = new Graphics::Surface(); + _deletableSurface->copyFrom(*surface); +} + ////////////////////////////////////////////////////////////////////////// HRESULT CBImage::SaveBMPFile(const char *Filename) { #if 0 @@ -131,8 +141,81 @@ HRESULT CBImage::Resize(int NewWidth, int NewHeight) { ////////////////////////////////////////////////////////////////////////// -byte *CBImage::CreateBMPBuffer(uint32 *BufferSize) { - if (!_bitmap) return NULL; +bool CBImage::writeBMPToStream(Common::WriteStream *stream) { + if (!_surface) return NULL; + + /* The following is just copied over and inverted to write-ops from the BMP-decoder */ + stream->writeByte('B'); + stream->writeByte('M'); + + /* Since we don't care during reads, we don't care during writes: */ + /* uint32 fileSize = */ stream->writeUint32LE(0); + /* uint16 res1 = */ stream->writeUint16LE(0); + /* uint16 res2 = */ stream->writeUint16LE(0); + const uint32 imageOffset = 54; + stream->writeUint32LE(imageOffset); + + const uint32 infoSize = 40; /* Windows v3 BMP */ + stream->writeUint32LE(infoSize); + + uint32 width = _surface->w; + int32 height = _surface->h; + stream->writeUint32LE(width); + stream->writeUint32LE(height); + + if (width == 0 || height == 0) + return false; + + if (height < 0) { + warning("Right-side up bitmaps not supported"); + return false; + } + + /* uint16 planes = */ stream->writeUint16LE(0); + const uint16 bitsPerPixel = 24; + stream->writeUint16LE(bitsPerPixel); + + const uint32 compression = 0; + stream->writeUint32LE(compression); + + /* uint32 imageSize = */ stream->writeUint32LE(0); + /* uint32 pixelsPerMeterX = */ stream->writeUint32LE(0); + /* uint32 pixelsPerMeterY = */ stream->writeUint32LE(0); + const uint32 paletteColorCount = 0; + stream->writeUint32LE(paletteColorCount); + /* uint32 colorsImportant = */ stream->writeUint32LE(0); + + // Start us at the beginning of the image (54 bytes in) + Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8(); + + // BGRA for 24bpp + if (bitsPerPixel == 24) + format = Graphics::PixelFormat(4, 8, 8, 8, 8, 8, 16, 24, 0); + + Graphics::Surface *surface = _surface->convertTo(format); + + int srcPitch = width * (bitsPerPixel >> 3); + const int extraDataLength = (srcPitch % 4) ? 4 - (srcPitch % 4) : 0; + + for (int32 i = height - 1; i >= 0; i--) { + for (uint32 j = 0; j < width; j++) { + byte b,g,r; + uint32 color = *(uint32*)surface->getBasePtr(j, i); + surface->format.colorToRGB(color, r, g, b); + stream->writeByte(b); + stream->writeByte(g); + stream->writeByte(r); + } + + for (int k = 0; k < extraDataLength; k++) { + stream->writeByte(0); + } + } + surface->free(); + delete surface; + return true; + + //*BufferSize = 0; #if 0 FIMEMORY *fiMem = FreeImage_OpenMemory(); FreeImage_SaveToMemory(FIF_PNG, _bitmap, fiMem); @@ -164,6 +247,13 @@ HRESULT CBImage::CopyFrom(CBImage *OrigImage, int NewWidth, int NewHeight) { _bitmap = FreeImage_Rescale(OrigImage->GetBitmap(), NewWidth, NewHeight, FILTER_BILINEAR); #endif + TransparentSurface temp(*OrigImage->_surface, false); + if (_deletableSurface) { + _deletableSurface->free(); + delete _deletableSurface; + _deletableSurface = NULL; + } + _surface = _deletableSurface = temp.scale(NewWidth, NewHeight); return S_OK; } diff --git a/engines/wintermute/Base/BImage.h b/engines/wintermute/Base/BImage.h index 90d684d01a..1161c97fa5 100644 --- a/engines/wintermute/Base/BImage.h +++ b/engines/wintermute/Base/BImage.h @@ -35,6 +35,7 @@ #include "graphics/decoders/image_decoder.h" #include "common/endian.h" #include "common/str.h" +#include "common/stream.h" struct FIBITMAP; @@ -50,16 +51,17 @@ public: const Graphics::Surface *getSurface() const { return _surface; }; const byte *getPalette() const { return _palette; } byte getAlphaAt(int x, int y); - byte *CreateBMPBuffer(uint32 *BufferSize = NULL); + bool writeBMPToStream(Common::WriteStream *stream); HRESULT Resize(int NewWidth, int NewHeight); HRESULT SaveBMPFile(const char *Filename); HRESULT CopyFrom(CBImage *OrigImage, int NewWidth = 0, int NewHeight = 0); - + void copyFrom(Graphics::Surface *surface); private: Common::String _filename; Graphics::ImageDecoder *_decoder; FIBITMAP *_bitmap; const Graphics::Surface *_surface; + Graphics::Surface *_deletableSurface; const byte *_palette; }; diff --git a/engines/wintermute/Base/BPersistMgr.cpp b/engines/wintermute/Base/BPersistMgr.cpp index 92307093ee..346a8bfa59 100644 --- a/engines/wintermute/Base/BPersistMgr.cpp +++ b/engines/wintermute/Base/BPersistMgr.cpp @@ -165,11 +165,17 @@ HRESULT CBPersistMgr::InitSave(const char *Desc) { if (Game->_cachedThumbnail) { if (Game->_cachedThumbnail->_thumbnail) { uint32 Size = 0; - byte *Buffer = Game->_cachedThumbnail->_thumbnail->CreateBMPBuffer(&Size); + Common::MemoryWriteStreamDynamic thumbStream(DisposeAfterUse::YES); + if (Game->_cachedThumbnail->_thumbnail->writeBMPToStream(&thumbStream)) { + _saveStream->writeUint32LE(thumbStream.size()); + _saveStream->write(thumbStream.getData(), thumbStream.size()); + } else { + _saveStream->writeUint32LE(0); + } - PutDWORD(Size); +/* PutDWORD(Size); if (Size > 0) _saveStream->write(Buffer, Size); - delete [] Buffer; + delete [] Buffer;*/ ThumbnailOK = true; } } diff --git a/engines/wintermute/Base/BRenderSDL.cpp b/engines/wintermute/Base/BRenderSDL.cpp index 86aa518de2..83adca59f3 100644 --- a/engines/wintermute/Base/BRenderSDL.cpp +++ b/engines/wintermute/Base/BRenderSDL.cpp @@ -399,6 +399,9 @@ HRESULT CBRenderSDL::DrawLine(int X1, int Y1, int X2, int Y2, uint32 Color) { CBImage *CBRenderSDL::TakeScreenshot() { // TODO: Fix this warning("CBRenderSDL::TakeScreenshot() - not ported yet"); + CBImage *screenshot = new CBImage(Game); + screenshot->copyFrom(_renderSurface); + return screenshot; #if 0 SDL_Rect viewport; -- cgit v1.2.3