aboutsummaryrefslogtreecommitdiff
path: root/engines/sword25/gfx
diff options
context:
space:
mode:
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;
}