tilesets yet, but make sure the architecture will allow it.legacy
| @@ -19,17 +19,17 @@ | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| class ImageLoader | |||||
| class ImageCodec | |||||
| { | { | ||||
| friend class Image; | |||||
| friend class ImageLoader; | |||||
| friend class ImageData; | friend class ImageData; | ||||
| public: | public: | ||||
| ImageData *(*fun)(char const *path); | ImageData *(*fun)(char const *path); | ||||
| ImageLoader *next; | |||||
| ImageCodec *next; | |||||
| int priority; | int priority; | ||||
| static void RegisterLoader(ImageLoader *loader) | |||||
| static void RegisterLoader(ImageCodec *loader) | |||||
| { | { | ||||
| Helper(loader); | Helper(loader); | ||||
| } | } | ||||
| @@ -37,7 +37,7 @@ public: | |||||
| private: | private: | ||||
| static ImageData *Load(char const *path) | static ImageData *Load(char const *path) | ||||
| { | { | ||||
| ImageLoader *parser = Helper(nullptr); | |||||
| ImageCodec *parser = Helper(nullptr); | |||||
| ImageData *ret = nullptr; | ImageData *ret = nullptr; | ||||
| while (parser && !ret) | while (parser && !ret) | ||||
| @@ -49,14 +49,14 @@ private: | |||||
| return ret; | return ret; | ||||
| } | } | ||||
| static ImageLoader *Helper(ImageLoader *set) | |||||
| static ImageCodec *Helper(ImageCodec *set) | |||||
| { | { | ||||
| static ImageLoader *loaders = nullptr; | |||||
| static ImageCodec *loaders = nullptr; | |||||
| if (!set) | if (!set) | ||||
| return loaders; | return loaders; | ||||
| ImageLoader **parser = &loaders; | |||||
| ImageCodec **parser = &loaders; | |||||
| while (*parser && (*parser)->priority > set->priority) | while (*parser && (*parser)->priority > set->priority) | ||||
| parser = &(*parser)->next; | parser = &(*parser)->next; | ||||
| set->next = *parser; | set->next = *parser; | ||||
| @@ -69,8 +69,15 @@ private: | |||||
| class ImageData | class ImageData | ||||
| { | { | ||||
| friend class Image; | friend class Image; | ||||
| friend class ImageLoader; | |||||
| public: | public: | ||||
| inline ImageData() | |||||
| : m_size(0, 0), | |||||
| m_format(PixelFormat::Unknown), | |||||
| m_refcount(0) | |||||
| { } | |||||
| virtual ~ImageData() {} | virtual ~ImageData() {} | ||||
| virtual bool Open(char const *) = 0; | virtual bool Open(char const *) = 0; | ||||
| @@ -81,6 +88,7 @@ public: | |||||
| protected: | protected: | ||||
| ivec2 m_size; | ivec2 m_size; | ||||
| PixelFormat m_format; | PixelFormat m_format; | ||||
| int m_refcount; | |||||
| }; | }; | ||||
| #define REGISTER_IMAGE_LOADER(name) \ | #define REGISTER_IMAGE_LOADER(name) \ | ||||
| @@ -88,12 +96,12 @@ protected: | |||||
| Register##name(); | Register##name(); | ||||
| #define DECLARE_IMAGE_LOADER(name, prio) \ | #define DECLARE_IMAGE_LOADER(name, prio) \ | ||||
| template<typename T> class name##ImageLoader : public ImageLoader \ | |||||
| template<typename T> class name##ImageCodec : public ImageCodec \ | |||||
| { \ | { \ | ||||
| public: \ | public: \ | ||||
| name##ImageLoader() \ | |||||
| name##ImageCodec() \ | |||||
| { \ | { \ | ||||
| static ImageLoader loader; \ | |||||
| static ImageCodec loader; \ | |||||
| loader.fun = Load; \ | loader.fun = Load; \ | ||||
| loader.priority = prio; \ | loader.priority = prio; \ | ||||
| RegisterLoader(&loader); \ | RegisterLoader(&loader); \ | ||||
| @@ -110,10 +118,10 @@ protected: | |||||
| } \ | } \ | ||||
| }; \ | }; \ | ||||
| class name; \ | class name; \ | ||||
| name##ImageLoader<name> name##ImageLoaderInstance; \ | |||||
| name##ImageCodec<name> name##ImageCodecInstance; \ | |||||
| void Register##name() \ | void Register##name() \ | ||||
| { \ | { \ | ||||
| (void)&name##ImageLoaderInstance; \ | |||||
| (void)&name##ImageCodecInstance; \ | |||||
| } \ | } \ | ||||
| class name : public ImageData | class name : public ImageData | ||||
| @@ -20,18 +20,18 @@ using namespace std; | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| /* HACK: We cannot make this an ImageCodec member function, because the | |||||
| * REGISTER_IMAGE_LOADER macro forward-declares free functions from | |||||
| * the "lol" namespace. An apparent bug in Visual Studio's compiler | |||||
| * makes it think these functions are actually in the top-level | |||||
| * namespace when the forward declaration is in a class member function. | |||||
| * To avoid the problem, we make the forward declaration in a free | |||||
| * function. | |||||
| * The bug was reported to Microsoft and fixed by them, but the fix | |||||
| * is not yet available. | |||||
| * https://connect.microsoft.com/VisualStudio/feedback/details/730878/ */ | |||||
| static bool RegisterAllLoaders() | static bool RegisterAllLoaders() | ||||
| { | { | ||||
| /* HACK: We cannot make this an ImageLoader member function, because the | |||||
| * REGISTER_IMAGE_LOADER macro forward-declares free functions from | |||||
| * the "lol" namespace. An apparent bug in Visual Studio's compiler | |||||
| * makes it think these functions are actually in the top-level | |||||
| * namespace when the forward declaration is in a class member function. | |||||
| * To avoid the problem, we make the forward declaration in a free | |||||
| * function. | |||||
| * The bug was reported to Microsoft and fixed by them, but the fix | |||||
| * is not yet available. | |||||
| * https://connect.microsoft.com/VisualStudio/feedback/details/730878/ */ | |||||
| #if defined __ANDROID__ | #if defined __ANDROID__ | ||||
| REGISTER_IMAGE_LOADER(AndroidImageData) | REGISTER_IMAGE_LOADER(AndroidImageData) | ||||
| #endif | #endif | ||||
| @@ -53,23 +53,72 @@ static bool RegisterAllLoaders() | |||||
| } | } | ||||
| /* | /* | ||||
| * Static image loader | |||||
| * Our static image loader | |||||
| */ | */ | ||||
| Image *Image::Create(char const *path) | |||||
| static class ImageLoader | |||||
| { | |||||
| public: | |||||
| Image *Create(char const *path); | |||||
| void Destroy(Image *img); | |||||
| private: | |||||
| Map<String, Image *> m_images; | |||||
| } | |||||
| image_loader; | |||||
| Image *ImageLoader::Create(char const *path) | |||||
| { | { | ||||
| /* Initialise loaders (see above) */ | /* Initialise loaders (see above) */ | ||||
| static bool init = RegisterAllLoaders(); | static bool init = RegisterAllLoaders(); | ||||
| UNUSED(init); | UNUSED(init); | ||||
| Image *ret = new Image(); | |||||
| ret->m_data = ImageLoader::Load(path); | |||||
| return ret; | |||||
| /* Is our image already in the bank? If so, no need to create it. */ | |||||
| Image *img; | |||||
| if (m_images.HasKey(path)) | |||||
| { | |||||
| img = m_images[path]; | |||||
| } | |||||
| else | |||||
| { | |||||
| img = new Image(); | |||||
| img->m_data = ImageCodec::Load(path); | |||||
| m_images[path] = img; | |||||
| } | |||||
| ++img->m_data->m_refcount; | |||||
| return img; | |||||
| } | |||||
| void ImageLoader::Destroy(Image *img) | |||||
| { | |||||
| ASSERT(img->m_data->m_refcount > 0); | |||||
| if (--img->m_data->m_refcount == 0) | |||||
| { | |||||
| /* FIXME: unload images etc. here */ | |||||
| /* XXX: we’re gonna hit a problem here because we didn’t keep | |||||
| * the image path within the object, so unless we store it | |||||
| * ourselves we’re good for a O(n) lookup… which we can’t do | |||||
| * on Map objects anyway. */ | |||||
| /* TODO: 1. remove image from Map | |||||
| 2. delete img; */ | |||||
| } | |||||
| } | |||||
| /* | |||||
| * Static image methods | |||||
| */ | |||||
| Image *Image::Create(char const *path) | |||||
| { | |||||
| return image_loader.Create(path); | |||||
| } | } | ||||
| void Image::Destroy(Image *img) | void Image::Destroy(Image *img) | ||||
| { | { | ||||
| delete img; | |||||
| return image_loader.Destroy(img); | |||||
| } | } | ||||
| /* | /* | ||||
| @@ -23,6 +23,8 @@ namespace lol | |||||
| class Image | class Image | ||||
| { | { | ||||
| friend class ImageLoader; | |||||
| public: | public: | ||||
| static Image *Create(char const *path); | static Image *Create(char const *path); | ||||
| static void Destroy(Image *img); | static void Destroy(Image *img); | ||||