aboutsummaryrefslogtreecommitdiff
path: root/engines/sword25/gfx
diff options
context:
space:
mode:
authormd52011-05-13 18:49:14 +0300
committermd52011-05-13 18:49:14 +0300
commit3ec466853aabad51423c2bf15a83ba7a89c5b73a (patch)
treeaa27aeb53d8a50f75a69f1b1043c0a0706b708e5 /engines/sword25/gfx
parentbd2bfe85c97189e72199e5d0554ec4bd192a80b2 (diff)
downloadscummvm-rg350-3ec466853aabad51423c2bf15a83ba7a89c5b73a.tar.gz
scummvm-rg350-3ec466853aabad51423c2bf15a83ba7a89c5b73a.tar.bz2
scummvm-rg350-3ec466853aabad51423c2bf15a83ba7a89c5b73a.zip
SWORD25: Replaced the PNG thumbnail encoding code, used in saved games
- Savegame thumbnails are now created using a flat image format, instead of PNG. This allows us to remove the PNG encoding code used in the engine. Note that the saved games we create cannot be used with the original engine anyway, so this change does not break savegame compatibility with the original game (it's already broken). - Compatibility is preserved with older saved games that were made with ScummVM. - Moved the embedded thumbnail reading code out of the PNG loader class, to stop it from needlessly checking every PNG file. - With this change, libpng is no longer required for the sword25 engine
Diffstat (limited to 'engines/sword25/gfx')
-rw-r--r--engines/sword25/gfx/image/pngloader.cpp51
-rw-r--r--engines/sword25/gfx/image/renderedimage.cpp88
-rw-r--r--engines/sword25/gfx/screenshot.cpp71
3 files changed, 88 insertions, 122 deletions
diff --git a/engines/sword25/gfx/image/pngloader.cpp b/engines/sword25/gfx/image/pngloader.cpp
index 64bb9fef6a..6f370d8861 100644
--- a/engines/sword25/gfx/image/pngloader.cpp
+++ b/engines/sword25/gfx/image/pngloader.cpp
@@ -46,51 +46,6 @@
namespace Sword25 {
-/**
- * Load a NULL-terminated string from the given stream.
- */
-static Common::String loadString(Common::ReadStream &in, uint maxSize = 999) {
- Common::String result;
-
- while (!in.eos() && (result.size() < maxSize)) {
- char ch = (char)in.readByte();
- if (ch == '\0')
- break;
-
- result += ch;
- }
-
- return result;
-}
-
-/**
- * Check if the given data is a savegame, and if so, locate the
- * offset to the image data.
- * @return offset to image data if fileDataPtr contains a savegame; 0 otherwise
- */
-static uint findEmbeddedPNG(const byte *fileDataPtr, uint fileSize) {
- if (fileSize < 100)
- return 0;
- if (memcmp(fileDataPtr, "BS25SAVEGAME", 12))
- return 0;
-
- // Read in the header
- Common::MemoryReadStream stream(fileDataPtr, fileSize);
- stream.seek(0, SEEK_SET);
-
- // Read header information of savegame
- uint compressedGamedataSize;
- loadString(stream); // Marker
- loadString(stream); // Version
- loadString(stream); // Description
- Common::String gameSize = loadString(stream);
- compressedGamedataSize = atoi(gameSize.c_str());
- loadString(stream);
-
- // Return the offset of where the thumbnail starts
- return static_cast<uint>(stream.pos() + compressedGamedataSize);
-}
-
#ifndef USE_INTERNAL_PNG_DECODER
static void png_user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
const byte **ref = (const byte **)png_get_io_ptr(png_ptr);
@@ -232,8 +187,7 @@ bool PNGLoader::doDecodeImage(const byte *fileDataPtr, uint fileSize, byte *&unc
}
bool PNGLoader::decodeImage(const byte *fileDataPtr, uint fileSize, byte *&uncompressedDataPtr, int &width, int &height, int &pitch) {
- uint pngOffset = findEmbeddedPNG(fileDataPtr, fileSize);
- return doDecodeImage(fileDataPtr + pngOffset, fileSize - pngOffset, uncompressedDataPtr, width, height, pitch);
+ return doDecodeImage(fileDataPtr, fileSize, uncompressedDataPtr, width, height, pitch);
}
#ifndef USE_INTERNAL_PNG_DECODER
@@ -280,8 +234,7 @@ bool PNGLoader::doImageProperties(const byte *fileDataPtr, uint fileSize, int &w
}
bool PNGLoader::imageProperties(const byte *fileDataPtr, uint fileSize, int &width, int &height) {
- uint pngOffset = findEmbeddedPNG(fileDataPtr, fileSize);
- return doImageProperties(fileDataPtr + pngOffset, fileSize - pngOffset, width, height);
+ return doImageProperties(fileDataPtr, fileSize, width, height);
}
#else
diff --git a/engines/sword25/gfx/image/renderedimage.cpp b/engines/sword25/gfx/image/renderedimage.cpp
index ba858e88d4..44d32f03f7 100644
--- a/engines/sword25/gfx/image/renderedimage.cpp
+++ b/engines/sword25/gfx/image/renderedimage.cpp
@@ -54,6 +54,75 @@ static Common::String generateSavegameFilename(uint slotID) {
// CONSTRUCTION / DESTRUCTION
// -----------------------------------------------------------------------------
+/**
+ * Load a NULL-terminated string from the given stream.
+ */
+static Common::String loadString(Common::SeekableReadStream &in, uint maxSize = 999) {
+ Common::String result;
+
+ while (!in.eos() && (result.size() < maxSize)) {
+ char ch = (char)in.readByte();
+ if (ch == '\0')
+ break;
+
+ result += ch;
+ }
+
+ return result;
+}
+
+static byte *readSavegameThumbnail(const Common::String &filename, uint &fileSize, bool &isPNG) {
+ byte *pFileData;
+ Common::SaveFileManager *sfm = g_system->getSavefileManager();
+ int slotNum = atoi(filename.c_str() + filename.size() - 3);
+ Common::InSaveFile *file = sfm->openForLoading(generateSavegameFilename(slotNum));
+
+ // Seek to the actual PNG image
+ loadString(*file); // Marker (BS25SAVEGAME)
+ loadString(*file); // Version
+ loadString(*file); // Description
+ uint32 compressedGamedataSize = atoi(loadString(*file).c_str());
+ loadString(*file); // Uncompressed game data size
+ file->skip(compressedGamedataSize); // Skip the game data and move to the thumbnail itself
+ uint32 thumbnailStart = file->pos();
+
+ fileSize = file->size() - thumbnailStart;
+
+ // Check if the thumbnail is in our own format, or a PNG file.
+ uint32 header = file->readUint32BE();
+ isPNG = (header != MKTAG('S','C','R','N'));
+ file->seek(-4, SEEK_CUR);
+
+ pFileData = new byte[fileSize];
+ file->read(pFileData, fileSize);
+ delete file;
+
+ return pFileData;
+}
+
+// TODO: Move this method into a more generic image loading class, together with the PNG reading code
+static bool decodeThumbnail(const byte *pFileData, uint fileSize, byte *&pUncompressedData, int &width, int &height, int &pitch) {
+ const byte *src = pFileData + 4; // skip header
+ width = READ_LE_UINT16(src); src += 2;
+ height = READ_LE_UINT16(src); src += 2;
+ pitch = width * 4;
+
+ uint32 totalSize = pitch * height;
+ pUncompressedData = new byte[totalSize];
+ uint32 *dst = (uint32 *)pUncompressedData; // treat as uint32, for pixelformat output
+ const Graphics::PixelFormat format = Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24);
+ byte r, g, b;
+
+ for (uint32 i = 0; i < totalSize / 4; i++) {
+ r = *src++;
+ g = *src++;
+ b = *src++;
+ *dst++ = format.RGBToColor(r, g, b);
+ }
+
+ return true;
+}
+
RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
_data(0),
_width(0),
@@ -69,15 +138,10 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
byte *pFileData;
uint fileSize;
+ bool isPNG = true;
+
if (filename.hasPrefix("/saves")) {
- // A savegame thumbnail
- Common::SaveFileManager *sfm = g_system->getSavefileManager();
- int slotNum = atoi(filename.c_str() + filename.size() - 3);
- Common::InSaveFile *file = sfm->openForLoading(generateSavegameFilename(slotNum));
- fileSize = file->size();
- pFileData = new byte[fileSize];
- file->read(pFileData, fileSize);
- delete file;
+ pFileData = readSavegameThumbnail(filename, fileSize, isPNG);
} else {
pFileData = pPackage->getFile(filename, &fileSize);
}
@@ -98,7 +162,12 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
// Uncompress the image
int pitch;
- if (!PNGLoader::decodeImage(pFileData, fileSize, _data, _width, _height, pitch)) {
+ if (isPNG)
+ result = PNGLoader::decodeImage(pFileData, fileSize, _data, _width, _height, pitch);
+ else
+ result = decodeThumbnail(pFileData, fileSize, _data, _width, _height, pitch);
+
+ if (!result) {
error("Could not decode image.");
delete[] pFileData;
return;
@@ -109,7 +178,6 @@ RenderedImage::RenderedImage(const Common::String &filename, bool &result) :
_doCleanup = true;
- result = true;
return;
}
diff --git a/engines/sword25/gfx/screenshot.cpp b/engines/sword25/gfx/screenshot.cpp
index a5516d051f..bfe732a596 100644
--- a/engines/sword25/gfx/screenshot.cpp
+++ b/engines/sword25/gfx/screenshot.cpp
@@ -36,83 +36,28 @@
#include "common/textconsole.h"
#include "sword25/gfx/screenshot.h"
#include "sword25/kernel/filesystemutil.h"
-#include <png.h>
namespace Sword25 {
-#include "common/pack-start.h"
-struct RGB_PIXEL {
- byte red;
- byte green;
- byte blue;
-} PACKED_STRUCT;
-#include "common/pack-end.h"
-
-void userWriteFn(png_structp png_ptr, png_bytep data, png_size_t length) {
- static_cast<Common::WriteStream *>(png_get_io_ptr(png_ptr))->write(data, length);
-}
-
-void userFlushFn(png_structp png_ptr) {
-}
-
bool Screenshot::saveToFile(Graphics::Surface *data, Common::WriteStream *stream) {
- // Reserve buffer space
- RGB_PIXEL *pixelBuffer = new RGB_PIXEL[data->w * data->h];
-
// Convert the RGBA data to RGB
const byte *pSrc = (const byte *)data->getBasePtr(0, 0);
- RGB_PIXEL *pDest = pixelBuffer;
+
+ // Write our own custom header
+ stream->writeUint32BE(MKTAG('S','C','R','N')); // SCRN, short for "Screenshot"
+ stream->writeUint16LE(data->w);
+ stream->writeUint16LE(data->h);
for (uint y = 0; y < data->h; y++) {
for (uint x = 0; x < data->w; x++) {
uint32 srcPixel = READ_LE_UINT32(pSrc);
pSrc += sizeof(uint32);
- pDest->red = (srcPixel >> 16) & 0xff;
- pDest->green = (srcPixel >> 8) & 0xff;
- pDest->blue = srcPixel & 0xff;
- ++pDest;
+ stream->writeByte((srcPixel >> 16) & 0xff); // R
+ stream->writeByte((srcPixel >> 8) & 0xff); // G
+ stream->writeByte(srcPixel & 0xff); // B
}
}
- png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (!png_ptr)
- error("Could not create PNG write-struct.");
-
- png_infop info_ptr = png_create_info_struct(png_ptr);
- if (!info_ptr)
- error("Could not create PNG info-struct.");
-
- // The compression buffer must be large enough to the entire image.
- // This ensures that only an IDAT chunk is created.
- // When buffer size is used 110% of the raw data size to be sure.
- png_set_compression_buffer_size(png_ptr, (data->w * data->h * 3 * 110) / 100);
-
- // Initialise PNG-Info structure
- png_set_IHDR(png_ptr, info_ptr,
- data->w, // Width
- data->h, // Height
- 8, // Bits depth
- PNG_COLOR_TYPE_RGB, // Color type
- PNG_INTERLACE_NONE, // No interlacing
- PNG_COMPRESSION_TYPE_DEFAULT, // Compression type
- PNG_FILTER_TYPE_DEFAULT); // Filter Type
-
- // Rowpointer erstellen
- png_bytep *rowPointers = new png_bytep[data->h];
- for (uint i = 0; i < data->h; i++) {
- rowPointers[i] = (png_bytep)&pixelBuffer[data->w * i];
- }
- png_set_rows(png_ptr, info_ptr, &rowPointers[0]);
-
- // Write out the png data to the file
- png_set_write_fn(png_ptr, (void *)stream, userWriteFn, userFlushFn);
- png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL);
-
- png_destroy_write_struct(&png_ptr, &info_ptr);
-
- delete[] pixelBuffer;
- delete[] rowPointers;
-
return true;
}