From a3afb1a9ca765b6e5e19654827129a556f4c260f Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Sun, 2 Mar 2014 03:17:47 -0400 Subject: [PATCH] Refactored the ImageData decoding/encoding backends a bit --- CMakeLists.txt | 1 + .../love-framework.xcodeproj/project.pbxproj | 4 ++ src/modules/image/magpie/DevilHandler.cpp | 32 +++++----- src/modules/image/magpie/DevilHandler.h | 19 +++--- src/modules/image/magpie/FormatHandler.cpp | 62 +++++++++++++++++++ src/modules/image/magpie/FormatHandler.h | 28 ++++++--- src/modules/image/magpie/Image.cpp | 13 ++-- src/modules/image/magpie/Image.h | 9 +++ src/modules/image/magpie/ImageData.cpp | 55 +++++++++++----- src/modules/image/magpie/ImageData.h | 13 +++- 10 files changed, 179 insertions(+), 57 deletions(-) create mode 100644 src/modules/image/magpie/FormatHandler.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c8af83674..f5b00344e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -341,6 +341,7 @@ set(LOVE_SRC_MODULE_IMAGE_MAGPIE src/modules/image/magpie/ddsHandler.h src/modules/image/magpie/DevilHandler.cpp src/modules/image/magpie/DevilHandler.h + src/modules/image/magpie/FormatHandler.cpp src/modules/image/magpie/FormatHandler.h src/modules/image/magpie/Image.cpp src/modules/image/magpie/Image.h diff --git a/platform/macosx/love-framework.xcodeproj/project.pbxproj b/platform/macosx/love-framework.xcodeproj/project.pbxproj index 3f245a0f0..839b1a9ce 100644 --- a/platform/macosx/love-framework.xcodeproj/project.pbxproj +++ b/platform/macosx/love-framework.xcodeproj/project.pbxproj @@ -289,6 +289,7 @@ FAC86E641724552C00EED715 /* wrap_Quad.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC86E621724552C00EED715 /* wrap_Quad.h */; }; FAC86E6B1724555D00EED715 /* Quad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAC86E671724555D00EED715 /* Quad.cpp */; }; FAC86E6C1724555D00EED715 /* Quad.h in Headers */ = {isa = PBXBuildFile; fileRef = FAC86E681724555D00EED715 /* Quad.h */; }; + FADD58DD18C30367005FC3BF /* FormatHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FADD58DC18C30367005FC3BF /* FormatHandler.cpp */; }; FAE010DB170DDE99006F29D0 /* ddsinfo.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE010D8170DDE99006F29D0 /* ddsinfo.h */; }; FAE010DC170DDE99006F29D0 /* ddsparse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAE010D9170DDE99006F29D0 /* ddsparse.cpp */; }; FAE010DD170DDE99006F29D0 /* ddsparse.h in Headers */ = {isa = PBXBuildFile; fileRef = FAE010DA170DDE99006F29D0 /* ddsparse.h */; }; @@ -847,6 +848,7 @@ FAC86E621724552C00EED715 /* wrap_Quad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Quad.h; sourceTree = ""; }; FAC86E671724555D00EED715 /* Quad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Quad.cpp; sourceTree = ""; }; FAC86E681724555D00EED715 /* Quad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Quad.h; sourceTree = ""; }; + FADD58DC18C30367005FC3BF /* FormatHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FormatHandler.cpp; sourceTree = ""; }; FAE010D8170DDE99006F29D0 /* ddsinfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ddsinfo.h; sourceTree = ""; }; FAE010D9170DDE99006F29D0 /* ddsparse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ddsparse.cpp; sourceTree = ""; }; FAE010DA170DDE99006F29D0 /* ddsparse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ddsparse.h; sourceTree = ""; }; @@ -1088,6 +1090,7 @@ FAE010DF170DE25E006F29D0 /* ddsHandler.h */, 1AA7781A230065F346E2313A /* DevilHandler.cpp */, 283342E174613897621A43F1 /* DevilHandler.h */, + FADD58DC18C30367005FC3BF /* FormatHandler.cpp */, FA0CDE3B1710F9A50056E8D7 /* FormatHandler.h */, 505F23A73BFE250833D650E4 /* Image.cpp */, 68616BD516DB124312B47EB3 /* Image.h */, @@ -2267,6 +2270,7 @@ FA08F66816C7548200F007B5 /* wrap_WheelJoint.cpp in Sources */, FA08F66916C7548200F007B5 /* wrap_World.cpp in Sources */, FA08F66A16C7549200F007B5 /* Sound.cpp in Sources */, + FADD58DD18C30367005FC3BF /* FormatHandler.cpp in Sources */, FA08F66B16C7549200F007B5 /* SoundData.cpp in Sources */, FA08F66C16C7549200F007B5 /* wrap_Decoder.cpp in Sources */, FA08F66D16C7549200F007B5 /* wrap_Sound.cpp in Sources */, diff --git a/src/modules/image/magpie/DevilHandler.cpp b/src/modules/image/magpie/DevilHandler.cpp index dede18fdc..74abd813b 100644 --- a/src/modules/image/magpie/DevilHandler.cpp +++ b/src/modules/image/magpie/DevilHandler.cpp @@ -23,15 +23,10 @@ // LOVE #include "common/Exception.h" #include "common/math.h" -#include "thread/threads.h" // DevIL #include -using love::thread::Lock; - -static Mutex *devilMutex = 0; - namespace love { namespace image @@ -44,21 +39,22 @@ static inline void ilxClearErrors() while (ilGetError() != IL_NO_ERROR); } -void DevilHandler::init() +DevilHandler::DevilHandler() + : mutex(nullptr) { + // There should only ever be one DevilHandler object (owned by the Image + // module), so we can use the global initialization function here. ilInit(); ilEnable(IL_ORIGIN_SET); ilOriginFunc(IL_ORIGIN_UPPER_LEFT); } -void DevilHandler::quit() +DevilHandler::~DevilHandler() { ilShutDown(); - if (devilMutex) - { - delete devilMutex; - devilMutex = 0; - } + + if (mutex) + delete mutex; } bool DevilHandler::canDecode(love::filesystem::FileData * /*data*/) @@ -85,10 +81,10 @@ bool DevilHandler::canEncode(ImageData::Format format) DevilHandler::DecodedImage DevilHandler::decode(love::filesystem::FileData *data) { - if (!devilMutex) - devilMutex = thread::newMutex(); + if (!mutex) + mutex = love::thread::newMutex(); - Lock lock(devilMutex); + love::thread::Lock lock(mutex); ILuint image = ilGenImage(); ilBindImage(image); @@ -140,10 +136,10 @@ DevilHandler::DecodedImage DevilHandler::decode(love::filesystem::FileData *data DevilHandler::EncodedImage DevilHandler::encode(const DecodedImage &img, ImageData::Format format) { - if (!devilMutex) - devilMutex = thread::newMutex(); + if (!mutex) + mutex = love::thread::newMutex(); - Lock lock(devilMutex); + love::thread::Lock lock(mutex); ILuint tempimage = ilGenImage(); ilBindImage(tempimage); diff --git a/src/modules/image/magpie/DevilHandler.h b/src/modules/image/magpie/DevilHandler.h index 5d1e85019..d1f833abc 100644 --- a/src/modules/image/magpie/DevilHandler.h +++ b/src/modules/image/magpie/DevilHandler.h @@ -24,6 +24,7 @@ // LOVE #include "filesystem/FileData.h" #include "FormatHandler.h" +#include "thread/threads.h" namespace love { @@ -39,16 +40,20 @@ class DevilHandler : public FormatHandler { public: - static void init(); - static void quit(); - // Implements FormatHandler. - static bool canDecode(love::filesystem::FileData *data); - static bool canEncode(ImageData::Format format); + DevilHandler(); + virtual ~DevilHandler(); - static DecodedImage decode(love::filesystem::FileData *data); - static EncodedImage encode(const DecodedImage &img, ImageData::Format format); + virtual bool canDecode(love::filesystem::FileData *data); + virtual bool canEncode(ImageData::Format format); + + virtual DecodedImage decode(love::filesystem::FileData *data); + virtual EncodedImage encode(const DecodedImage &img, ImageData::Format format); + +private: + + Mutex *mutex; }; // DevilHandler diff --git a/src/modules/image/magpie/FormatHandler.cpp b/src/modules/image/magpie/FormatHandler.cpp new file mode 100644 index 000000000..d50e24008 --- /dev/null +++ b/src/modules/image/magpie/FormatHandler.cpp @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2006-2014 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +// LOVE +#include "FormatHandler.h" +#include "common/Exception.h" + +namespace love +{ +namespace image +{ +namespace magpie +{ + +FormatHandler::FormatHandler() +{ +} + +FormatHandler::~FormatHandler() +{ +} + +bool FormatHandler::canDecode(love::filesystem::FileData* /*data*/) +{ + return false; +} + +bool FormatHandler::canEncode(ImageData::Format /*format*/) +{ + return false; +} + +FormatHandler::DecodedImage FormatHandler::decode(love::filesystem::FileData* /*data*/) +{ + throw love::Exception("Image decoding is not implemented for this format backend."); +} + +FormatHandler::EncodedImage FormatHandler::encode(const DecodedImage& /*img*/, ImageData::Format /*format*/) +{ + throw love::Exception("Image encoding is not implemented for this format backend."); +} + +} // magpie +} // image +} // love diff --git a/src/modules/image/magpie/FormatHandler.h b/src/modules/image/magpie/FormatHandler.h index f953e97e3..f115fced6 100644 --- a/src/modules/image/magpie/FormatHandler.h +++ b/src/modules/image/magpie/FormatHandler.h @@ -24,6 +24,7 @@ // LOVE #include "image/ImageData.h" #include "filesystem/FileData.h" +#include "common/Object.h" namespace love { @@ -34,8 +35,9 @@ namespace magpie /** * Base class for all ImageData encoder/decoder library interfaces. + * We inherit from love::Object to take advantage of reference counting... **/ -class FormatHandler +class FormatHandler : public love::Object { public: @@ -56,26 +58,32 @@ public: EncodedImage() : size(0), data(0) {} }; - // Lets pretend we have virtual static methods... + /** + * The default constructor is called when the Image module is initialized. + **/ + FormatHandler(); /** - * Determines whether a particular FileData can be decoded by this handler. - * @param data The data to decode. + * The destructor is called when the Image module is uninitialized. **/ - // virtual static bool canDecode(love::filesystem::FileData *data) = 0; + virtual ~FormatHandler(); /** - * Determines whether this handler can encode to a particular format. - * @param format The format to encode to. + * Whether this format handler can decode a particular FileData. **/ - // virtual static bool canEncode(ImageData::Format format) = 0; + virtual bool canDecode(love::filesystem::FileData *data); + + /** + * Whether this format handler can encode to a particular format. + **/ + virtual bool canEncode(ImageData::Format format); /** * Decodes an image from its encoded form into raw pixel data. * @param data The encoded data to decode. * @return The decoded pixel data. **/ - // virtual static DecodedImage decode(love::filesystem::FileData *data) = 0; + virtual DecodedImage decode(love::filesystem::FileData *data); /** * Encodes an image from raw pixel data into a particular format. @@ -83,7 +91,7 @@ public: * @param format The format to encode to. * @return The encoded image data. **/ - // virtual static EncodedImage encode(const DecodedImage &img, ImageData::Format format) = 0; + virtual EncodedImage encode(const DecodedImage &img, ImageData::Format format); }; // FormatHandler diff --git a/src/modules/image/magpie/Image.cpp b/src/modules/image/magpie/Image.cpp index 7eb8d2519..3953aefdd 100644 --- a/src/modules/image/magpie/Image.cpp +++ b/src/modules/image/magpie/Image.cpp @@ -34,12 +34,15 @@ namespace magpie Image::Image() { - DevilHandler::init(); + formatHandlers.push_back(new DevilHandler); } Image::~Image() { - DevilHandler::quit(); + // ImageData objects reference the FormatHandlers in our list, so we should + // release them instead of deleting them completely here. + for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it) + (*it)->release(); } const char *Image::getName() const @@ -49,17 +52,17 @@ const char *Image::getName() const love::image::ImageData *Image::newImageData(love::filesystem::FileData *data) { - return new ImageData(data); + return new ImageData(formatHandlers, data); } love::image::ImageData *Image::newImageData(int width, int height) { - return new ImageData(width, height); + return new ImageData(formatHandlers, width, height); } love::image::ImageData *Image::newImageData(int width, int height, void *data, bool own) { - return new ImageData(width, height, data, own); + return new ImageData(formatHandlers, width, height, data, own); } love::image::CompressedData *Image::newCompressedData(love::filesystem::FileData *data) diff --git a/src/modules/image/magpie/Image.h b/src/modules/image/magpie/Image.h index 4385e6635..75adfc479 100644 --- a/src/modules/image/magpie/Image.h +++ b/src/modules/image/magpie/Image.h @@ -23,6 +23,10 @@ // LOVE #include "image/Image.h" +#include "FormatHandler.h" + +// C++ +#include namespace love { @@ -54,6 +58,11 @@ public: bool isCompressed(love::filesystem::FileData *data); +private: + + // Image format handlers we can use for decoding and encoding ImageData. + std::list formatHandlers; + }; // Image } // magpie diff --git a/src/modules/image/magpie/ImageData.cpp b/src/modules/image/magpie/ImageData.cpp index db614abbb..7864b55e9 100644 --- a/src/modules/image/magpie/ImageData.cpp +++ b/src/modules/image/magpie/ImageData.cpp @@ -18,11 +18,9 @@ * 3. This notice may not be removed or altered from any source distribution. **/ +// LOVE #include "ImageData.h" -#include "FormatHandler.h" -#include "DevilHandler.h" - namespace love { namespace image @@ -30,23 +28,36 @@ namespace image namespace magpie { -ImageData::ImageData(love::filesystem::FileData *data) +ImageData::ImageData(std::list formats, love::filesystem::FileData *data) + : formatHandlers(formats) { + for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it) + (*it)->retain(); + decode(data); } -ImageData::ImageData(int width, int height) +ImageData::ImageData(std::list formats, int width, int height) + : formatHandlers(formats) { + for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it) + (*it)->retain(); + this->width = width; this->height = height; + create(width, height); // Set to black/transparency. memset(data, 0, width*height*sizeof(pixel)); } -ImageData::ImageData(int width, int height, void *data, bool own) +ImageData::ImageData(std::list formats, int width, int height, void *data, bool own) + : formatHandlers(formats) { + for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it) + (*it)->retain(); + this->width = width; this->height = height; @@ -59,6 +70,9 @@ ImageData::ImageData(int width, int height, void *data, bool own) ImageData::~ImageData() { delete[] data; + + for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it) + (*it)->release(); } void ImageData::create(int width, int height, void *data) @@ -80,16 +94,23 @@ void ImageData::decode(love::filesystem::FileData *data) { FormatHandler::DecodedImage decodedimage; - if (DevilHandler::canDecode(data)) - decodedimage = DevilHandler::decode(data); - else + for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it) + { + if ((*it)->canDecode(data)) + { + decodedimage = (*it)->decode(data); + break; + } + } + + if (decodedimage.data == nullptr) throw love::Exception("Could not decode image: unrecognized format."); // The decoder *must* output a 32 bits-per-pixel image. if (decodedimage.size != decodedimage.width*decodedimage.height*sizeof(pixel)) { delete[] decodedimage.data; - throw love::Exception("Coult not convert image!"); + throw love::Exception("Could not convert image!"); } if (this->data) @@ -114,15 +135,21 @@ void ImageData::encode(love::filesystem::File *f, ImageData::Format format) rawimage.size = width*height*sizeof(pixel); rawimage.data = data; - if (DevilHandler::canEncode(format)) - encodedimage = DevilHandler::encode(rawimage, format); - else + for (auto it = formatHandlers.begin(); it != formatHandlers.end(); ++it) + { + if ((*it)->canEncode(format)) + { + encodedimage = (*it)->encode(rawimage, format); + break; + } + } + + if (encodedimage.data == nullptr) throw love::Exception("Image format has no suitable encoder."); } try { - f->open(love::filesystem::File::WRITE); f->write(encodedimage.data, encodedimage.size); f->close(); diff --git a/src/modules/image/magpie/ImageData.h b/src/modules/image/magpie/ImageData.h index b7ccbf346..298e82423 100644 --- a/src/modules/image/magpie/ImageData.h +++ b/src/modules/image/magpie/ImageData.h @@ -22,9 +22,13 @@ #define LOVE_IMAGE_MAGPIE_IMAGE_DATA_H // LOVE +#include "FormatHandler.h" #include "filesystem/File.h" #include "image/ImageData.h" +// C++ +#include + namespace love { namespace image @@ -36,9 +40,9 @@ class ImageData : public love::image::ImageData { public: - ImageData(love::filesystem::FileData *data); - ImageData(int width, int height); - ImageData(int width, int height, void *data, bool own); + ImageData(std::list formats, love::filesystem::FileData *data); + ImageData(std::list formats, int width, int height); + ImageData(std::list formats, int width, int height, void *data, bool own); virtual ~ImageData(); // Implements image::ImageData. @@ -52,6 +56,9 @@ private: // Decode and load an encoded format. void decode(love::filesystem::FileData *data); + // Image format handlers we can use for decoding and encoding. + std::list formatHandlers; + }; // ImageData } // magpie