diff --git a/src/Makefile.am b/src/Makefile.am index 27d332cd..08e25f3c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -54,7 +54,7 @@ liblol_core_headers = \ lol/sys/threadtypes.h lol/sys/timer.h \ \ lol/image/all.h \ - lol/image/pixel.h lol/image/color.h lol/image/image.h lol/image/movie.h \ + lol/image/pixel.h lol/image/color.h lol/image/image.h lol/image/resource.h lol/image/movie.h \ \ lol/gpu/all.h \ lol/gpu/shader.h lol/gpu/indexbuffer.h lol/gpu/vertexbuffer.h \ @@ -115,6 +115,7 @@ liblol_core_sources = \ sys/init.cpp sys/file.cpp sys/hacks.cpp \ sys/thread.cpp sys/threadtypes.cpp sys/getopt.cpp \ \ + image/resource.cpp image/resource-private.h \ image/image.cpp image/image-private.h image/kernel.cpp image/pixel.cpp \ image/crop.cpp image/resample.cpp image/noise.cpp image/combine.cpp \ image/codec/gdiplus-image.cpp image/codec/imlib2-image.cpp \ diff --git a/src/image/codec/android-image.cpp b/src/image/codec/android-image.cpp index 3de43606..0364b23b 100644 --- a/src/image/codec/android-image.cpp +++ b/src/image/codec/android-image.cpp @@ -21,7 +21,7 @@ extern "C" { #include } -#include "../../image/image-private.h" +#include "../../image/resource-private.h" namespace lol { @@ -32,12 +32,12 @@ extern ANativeActivity *g_activity; * Image implementation class */ -class AndroidImageCodec : public ImageCodec +class AndroidImageCodec : public ResourceCodec { public: virtual char const *GetName() { return ""; } - virtual bool Load(Image *image, char const *path); - virtual bool Save(Image *image, char const *path); + virtual ResourceCodecData* Load(char const *path); + virtual bool Save(char const *path, ResourceCodecData* data); virtual bool Close(); virtual uint8_t *GetData() const; @@ -50,7 +50,7 @@ private: DECLARE_IMAGE_CODEC(AndroidImageCodec, 100) -bool AndroidImageCodec::Load(Image *image, char const *path) +ResourceCodecData* AndroidImageCodec::Load(char const *path) { JNIEnv *env; jint res = g_activity->vm->GetEnv((void **)&env, JNI_VERSION_1_2); @@ -106,12 +106,12 @@ bool AndroidImageCodec::Load(Image *image, char const *path) } m_format = PixelFormat::RGBA_8; - return true; + return new ResourceCodecData(); } -bool AndroidImageCodec::Save(Image *image, char const *path) +bool AndroidImageCodec::Save(char const *path, ResourceCodecData* data) { - UNUSED(path); + UNUSED(path, data); /* TODO: unimplemented */ } diff --git a/src/image/codec/dummy-image.cpp b/src/image/codec/dummy-image.cpp index 6f4c21e9..12319dc0 100644 --- a/src/image/codec/dummy-image.cpp +++ b/src/image/codec/dummy-image.cpp @@ -10,7 +10,7 @@ #include -#include "../../image/image-private.h" +#include "../../image/resource-private.h" namespace lol { @@ -19,12 +19,12 @@ namespace lol * Image implementation class */ -class DummyImageCodec : public ImageCodec +class DummyImageCodec : public ResourceCodec { public: virtual char const *GetName() { return ""; } - virtual bool Load(Image *image, char const *path); - virtual bool Save(Image *image, char const *path); + virtual ResourceCodecData* Load(char const *path); + virtual bool Save(char const *path, ResourceCodecData* data); }; //Priority 0 because it's supposed to be the last one @@ -34,11 +34,13 @@ DECLARE_IMAGE_CODEC(DummyImageCodec, 0) * Public Image class */ -bool DummyImageCodec::Load(Image *image, char const *path) +ResourceCodecData* DummyImageCodec::Load(char const *path) { - UNUSED(path); + if (strcmp("DUMMY", path)) + return nullptr; - image->SetSize(ivec2(256)); + auto data = new ResourceImageData(new Image(ivec2(256))); + auto image = data->m_image; u8vec4 *pixels = image->Lock(), *tmp = pixels; for (int j = 0; j < 256; j++) for (int i = 0; i < 256; i++) @@ -51,13 +53,12 @@ bool DummyImageCodec::Load(Image *image, char const *path) } image->Unlock(pixels); - //return false, because we're not supposed to be here. - return false; + return data; } -bool DummyImageCodec::Save(Image *image, char const *path) +bool DummyImageCodec::Save(char const *path, ResourceCodecData* data) { - UNUSED(path); + UNUSED(path, data); return false; } diff --git a/src/image/codec/gdiplus-image.cpp b/src/image/codec/gdiplus-image.cpp index d94b86f3..f8b2ae33 100644 --- a/src/image/codec/gdiplus-image.cpp +++ b/src/image/codec/gdiplus-image.cpp @@ -26,7 +26,7 @@ using std::max; #if LOL_USE_GDIPLUS -#include "../../image/image-private.h" +#include "../../image/resource-private.h" namespace lol { @@ -35,12 +35,12 @@ namespace lol * Image implementation class */ -class GdiPlusImageCodec : public ImageCodec +class GdiPlusImageCodec : public ResourceCodec { public: virtual char const *GetName() { return ""; } - virtual bool Load(Image *image, char const *path); - virtual bool Save(Image *image, char const *path); + virtual ResourceCodecData* Load(char const *path); + virtual bool Save(char const *path, ResourceCodecData* data); }; DECLARE_IMAGE_CODEC(GdiPlusImageCodec, 100) @@ -49,7 +49,7 @@ DECLARE_IMAGE_CODEC(GdiPlusImageCodec, 100) * Public Image class */ -bool GdiPlusImageCodec::Load(Image *image, char const *path) +ResourceCodecData* GdiPlusImageCodec::Load(char const *path) { Gdiplus::Status status; ULONG_PTR token; @@ -58,7 +58,7 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) if (status != Gdiplus::Ok) { msg::error("error %d while initialising GDI+\n", status); - return false; + return nullptr; } array pathlist = sys::get_path_list(path); @@ -99,7 +99,7 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) if (!bitmap) { msg::error("could not load %s\n", path); - return false; + return nullptr; } ivec2 size(bitmap->GetWidth(), bitmap->GetHeight()); @@ -110,13 +110,14 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) { msg::error("could not lock bits in %s\n", path); delete bitmap; - return false; + return nullptr; } /* FIXME: GDI+ doesn't know about RGBA, only ARGB. And OpenGL doesn't * know about ARGB, only RGBA. So we swap bytes. We could also fix * this in the shader. */ - image->SetSize(size); + auto data = new ResourceImageData(new Image(ivec2(size))); + auto image = data->m_image; u8vec4 *pdst = image->Lock(); u8vec4 *psrc = static_cast(bdata.Scan0); for (int n = 0; n < size.x * size.y; n++) @@ -126,11 +127,15 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) bitmap->UnlockBits(&bdata); delete bitmap; - return true; + return data; } -bool GdiPlusImageCodec::Save(Image *image, char const *path) +bool GdiPlusImageCodec::Save(char const *path, ResourceCodecData* data) { + auto data_image = dynamic_cast(data); + if (data_image == nullptr) + return false; + ULONG_PTR token; Gdiplus::GdiplusStartupInput input; Gdiplus::GdiplusStartup(&token, &input, nullptr); @@ -178,6 +183,7 @@ bool GdiPlusImageCodec::Save(Image *image, char const *path) return false; } + auto image = data_image->m_image; ivec2 size = image->GetSize(); Gdiplus::Bitmap *b = new Gdiplus::Bitmap(size.x, size.y, diff --git a/src/image/codec/ios-image.cpp b/src/image/codec/ios-image.cpp index 51962450..33368308 100644 --- a/src/image/codec/ios-image.cpp +++ b/src/image/codec/ios-image.cpp @@ -16,7 +16,7 @@ #import -#include "../../image/image-private.h" +#include "../../image/resource-private.h" namespace lol { @@ -25,12 +25,12 @@ namespace lol * Image implementation class */ -class IosImageCodec : public ImageCodec +class IosImageCodec : public ResourceCodec { public: virtual char const *GetName() { return ""; } - virtual bool Load(Image *image, char const *path); - virtual bool Save(Image *image, char const *path); + virtual ResourceCodecData* Load(char const *path); + virtual bool Save(char const *path, ResourceCodecData* data); }; DECLARE_IMAGE_CODEC(IosImageCodec, 100) @@ -39,7 +39,7 @@ DECLARE_IMAGE_CODEC(IosImageCodec, 100) * Public Image class */ -bool IosImageCodec::Load(Image *image, char const *path) +ResourceCodecData* IosImageCodec::Load(char const *path) { NSString *fullpath = [NSString stringWithUTF8String:path]; NSArray *chunks = [fullpath componentsSeparatedByString: @"/"]; @@ -54,7 +54,7 @@ bool IosImageCodec::Load(Image *image, char const *path) #if !LOL_BUILD_RELEASE msg::error("could not load %s\n", path); #endif - return false; + return nullptr; } int w = CGImageGetWidth(image.CGImage); @@ -75,12 +75,12 @@ bool IosImageCodec::Load(Image *image, char const *path) [image release]; [pngdata release]; - return true; + return new ResourceCodecData(); } -bool IosImageCodec::Save(Image *image, char const *path) +bool IosImageCodec::Save(char const *path, ResourceCodecData* data) { - UNUSED(path); + UNUSED(path, data); /* TODO: unimplemented */ return true; diff --git a/src/image/codec/oric-image.cpp b/src/image/codec/oric-image.cpp index a7bdf413..348b59fb 100644 --- a/src/image/codec/oric-image.cpp +++ b/src/image/codec/oric-image.cpp @@ -12,7 +12,7 @@ #include -#include "../../image/image-private.h" +#include "../../image/resource-private.h" namespace lol { @@ -27,12 +27,12 @@ namespace lol * Image implementation class */ -class OricImageCodec : public ImageCodec +class OricImageCodec : public ResourceCodec { public: virtual char const *GetName() { return ""; } - virtual bool Load(Image *image, char const *path); - virtual bool Save(Image *image, char const *path); + virtual ResourceCodecData* Load(char const *path); + virtual bool Save(char const *path, ResourceCodecData* data); private: static String ReadScreen(char const *name); @@ -45,7 +45,7 @@ DECLARE_IMAGE_CODEC(OricImageCodec, 100) * Public Image class */ -bool OricImageCodec::Load(Image *image, char const *path) +ResourceCodecData* OricImageCodec::Load(char const *path) { static u8vec4 const pal[8] = { @@ -61,9 +61,10 @@ bool OricImageCodec::Load(Image *image, char const *path) String screen = ReadScreen(path); if (screen.count() == 0) - return false; + return nullptr; - image->SetSize(ivec2(WIDTH, screen.count() * 6 / WIDTH)); + auto data = new ResourceImageData(new Image(ivec2(WIDTH, screen.count() * 6 / WIDTH))); + auto image = data->m_image; u8vec4 *pixels = image->Lock(); @@ -102,12 +103,16 @@ bool OricImageCodec::Load(Image *image, char const *path) image->Unlock(pixels); - return true; + return data; } -bool OricImageCodec::Save(Image *image, char const *path) +bool OricImageCodec::Save(char const *path, ResourceCodecData* data) { - int len = strlen(path); + auto data_image = dynamic_cast(data); + if (data_image == nullptr) + return false; + + int len = (int)strlen(path); if (len < 4 || path[len - 4] != '.' || toupper(path[len - 3]) != 'T' || toupper(path[len - 2]) != 'A' @@ -124,6 +129,7 @@ bool OricImageCodec::Save(Image *image, char const *path) result << (uint8_t)name[0]; result << 0; + auto image = data_image->m_image; Image tmp; ivec2 size = image->GetSize(); if (size.x != WIDTH) @@ -481,7 +487,7 @@ void OricImageCodec::WriteScreen(Image &image, array &result) for (int y = 0; y < size.y; y++) for (int x = 0; x < size.x; x++) for (int c = 0; c < 3; c++) - src[x][y][c] = 0xffff * pixels[y * size.x + x][2 - c]; + src[x][y][c] = 0xffff * (int32_t)pixels[y * size.x + x][2 - c]; /* Let the fun begin */ for (int y = 0; y < size.y; y++) diff --git a/src/image/codec/sdl-image.cpp b/src/image/codec/sdl-image.cpp index abdbc324..8b97d18e 100644 --- a/src/image/codec/sdl-image.cpp +++ b/src/image/codec/sdl-image.cpp @@ -25,7 +25,7 @@ # include #endif -#include "../../image/image-private.h" +#include "../../image/resource-private.h" namespace lol { @@ -34,19 +34,19 @@ namespace lol * Image implementation class */ -class SdlImageCodec : public ImageCodec +class SdlImageCodec : public ResourceCodec { public: virtual char const *GetName() { return ""; } - virtual bool Load(Image *image, char const *path); - virtual bool Save(Image *image, char const *path); + virtual ResourceCodecData* Load(char const *path); + virtual bool Save(char const *path, ResourceCodecData* data); static SDL_Surface *Create32BppSurface(ivec2 size); }; DECLARE_IMAGE_CODEC(SdlImageCodec, 50) -bool SdlImageCodec::Load(Image *image, char const *path) +ResourceCodecData* SdlImageCodec::Load(char const *path) { SDL_Surface *surface = nullptr; @@ -75,24 +75,30 @@ bool SdlImageCodec::Load(Image *image, char const *path) surface = tmp; } - image->SetSize(size); - u8vec4 *data = image->Lock(); - memcpy(data, surface->pixels, 4 * size.x * size.y); - image->Unlock(data); + auto data = new ResourceImageData(new Image(size)); + auto image = data->m_image; + u8vec4 *pixel_data = image->Lock(); + memcpy(pixel_data, surface->pixels, 4 * size.x * size.y); + image->Unlock(pixel_data); SDL_FreeSurface(surface); - return true; + return data; } -bool SdlImageCodec::Save(Image *image, char const *path) +bool SdlImageCodec::Save(char const *path, ResourceCodecData* data) { + auto data_image = dynamic_cast(data); + if (data_image == nullptr) + return false; + + auto image = data_image->m_image; ivec2 size = image->GetSize(); SDL_Surface *surface = Create32BppSurface(size); - u8vec4 *data = image->Lock(); - memcpy(surface->pixels, data, 4 * size.x * size.y); - image->Unlock(data); + u8vec4 *pixel_data = image->Lock(); + memcpy(surface->pixels, pixel_data, 4 * size.x * size.y); + image->Unlock(pixel_data); int ret = SDL_SaveBMP(surface, path); SDL_FreeSurface(surface); diff --git a/src/image/codec/zed-image.cpp b/src/image/codec/zed-image.cpp index e4a0e0e9..91ee8c6b 100644 --- a/src/image/codec/zed-image.cpp +++ b/src/image/codec/zed-image.cpp @@ -11,7 +11,7 @@ #include -#include "../../image/image-private.h" +#include "../../image/resource-private.h" namespace lol { @@ -20,24 +20,12 @@ namespace lol * Image implementation class */ -class ZedImageCodec : public ImageCodec +class ZedImageCodec : public ResourceCodec { public: virtual char const *GetName() { return ""; } - virtual bool Load(Image *image, char const *path); - virtual bool Save(Image *image, char const *path); - - virtual bool RetrieveTiles(array& tiles) - { - bool result = m_tiles.count() > 0; - tiles += m_tiles; - m_tiles.empty(); - return result; - } - -private: - // - array m_tiles; + virtual ResourceCodecData* Load(char const *path); + virtual bool Save(char const *path, ResourceCodecData* data); }; DECLARE_IMAGE_CODEC(ZedImageCodec, 10) @@ -46,10 +34,10 @@ DECLARE_IMAGE_CODEC(ZedImageCodec, 10) * Public Image class */ -bool ZedImageCodec::Load(Image *image, char const *path) +ResourceCodecData* ZedImageCodec::Load(char const *path) { if (!lol::String(path).ends_with(".RSC")) - return false; + return nullptr; // Compacter definition struct CompactSecondary @@ -142,7 +130,9 @@ bool ZedImageCodec::Load(Image *image, char const *path) } file_offset << file_size; - m_tiles.reserve(file_count); + // + array tiles; + tiles.reserve(file_count); Compacter2d compacter; compacter.StepSetup(8, 8, 10); @@ -151,6 +141,7 @@ bool ZedImageCodec::Load(Image *image, char const *path) array file_convert; file_convert.reserve(file_size); array available_sizes; + //got through all the files and store them for (int i = 0; i < file_count; i++) { file_pos = file_offset[i]; @@ -187,8 +178,10 @@ bool ZedImageCodec::Load(Image *image, char const *path) //Prepare buffer and tiles infos int32_t convert_pos = file_convert.count(); ivec2 size = ivec2(size_x, size_y); - compacter.Store(m_tiles.count(), ivec2(size_x, size_y)); - m_tiles.push(ivec2(file_convert.count(), data_length), ivec2(size_x, size_y)); + //store tile in compacter + compacter.Store(tiles.count(), ivec2(size_x, size_y)); + //push tile on the stack + tiles.push(ivec2(file_convert.count(), data_length), ivec2(size_x, size_y)); file_convert.resize(convert_pos + data_length); //Retrieve actual datas @@ -233,8 +226,9 @@ bool ZedImageCodec::Load(Image *image, char const *path) while (tex_size < tex_sqrt) tex_size <<= 1; - //Prepare final imqge - image->SetSize(ivec2(tex_size)); + //Prepare final image + auto data = new ResourceTilesetData(new Image(ivec2(tex_size))); + auto image = data->m_image; uint8_t *pixels = image->Lock(); //Data refactor stage @@ -255,8 +249,8 @@ bool ZedImageCodec::Load(Image *image, char const *path) compacter.m_primary[j].m_count--; int i = compacter.m_primary[j].m_secondary[k].m_tiles.pop(); - int32_t file_off = m_tiles[i].m1[0]; - ivec2 t_size = m_tiles[i].m2; + int32_t file_off = tiles[i].m1[0]; + ivec2 t_size = tiles[i].m2; ASSERT(pos.y + t_size.y < tex_size); @@ -277,7 +271,7 @@ bool ZedImageCodec::Load(Image *image, char const *path) } //Register new pos and move to next - m_tiles[i].m1 = pos; + tiles[i].m1 = pos; pos.x += t_size.x; } } @@ -292,12 +286,14 @@ bool ZedImageCodec::Load(Image *image, char const *path) } image->Unlock(pixels); - return true; + data->m_tiles = tiles; + + return data; } -bool ZedImageCodec::Save(Image *image, char const *path) +bool ZedImageCodec::Save(char const *path, ResourceCodecData* data) { - UNUSED(path); + UNUSED(path, data); /* FIXME: do we need to implement this? */ return true; } diff --git a/src/image/codec/zed-palette-image.cpp b/src/image/codec/zed-palette-image.cpp index baeac2f4..a0363962 100644 --- a/src/image/codec/zed-palette-image.cpp +++ b/src/image/codec/zed-palette-image.cpp @@ -10,7 +10,7 @@ #include -#include "../../image/image-private.h" +#include "../../image/resource-private.h" namespace lol { @@ -19,12 +19,12 @@ namespace lol * Image implementation class */ -class ZedPaletteImageCodec : public ImageCodec +class ZedPaletteImageCodec : public ResourceCodec { public: virtual char const *GetName() { return ""; } - virtual bool Load(Image *image, char const *path); - virtual bool Save(Image *image, char const *path); + virtual ResourceCodecData* Load(char const *path); + virtual bool Save(char const *path, ResourceCodecData* data); }; DECLARE_IMAGE_CODEC(ZedPaletteImageCodec, 10) @@ -33,10 +33,10 @@ DECLARE_IMAGE_CODEC(ZedPaletteImageCodec, 10) * Public Image class */ -bool ZedPaletteImageCodec::Load(Image *image, char const *path) +ResourceCodecData* ZedPaletteImageCodec::Load(char const *path) { if (!lol::String(path).ends_with(".pal")) - return false; + return nullptr; File file; file.Open(path, FileAccess::Read, true); @@ -53,13 +53,15 @@ bool ZedPaletteImageCodec::Load(Image *image, char const *path) int32_t tex_size = 2; while (tex_size < tex_sqrt) tex_size <<= 1; - image->m_data->m_size = ivec2(tex_size); + auto data = new ResourceImageData(new Image(ivec2(tex_size))); + auto image = data->m_image; #else int32_t tex_sqrt = file_size / 3; int32_t tex_size = 2; while (tex_size < tex_sqrt) tex_size <<= 1; - image->SetSize(ivec2(tex_size, 1)); + auto data = new ResourceImageData(new Image(ivec2(tex_size, 1))); + auto image = data->m_image; #endif u8vec4 *pixels = image->Lock(); @@ -73,12 +75,12 @@ bool ZedPaletteImageCodec::Load(Image *image, char const *path) } image->Unlock(pixels); - return true; + return data; } -bool ZedPaletteImageCodec::Save(Image *image, char const *path) +bool ZedPaletteImageCodec::Save(char const *path, ResourceCodecData* data) { - UNUSED(path); + UNUSED(path, data); /* FIXME: do we need to implement this? */ return true; } diff --git a/src/image/image-private.h b/src/image/image-private.h index 2c65191b..a700a857 100644 --- a/src/image/image-private.h +++ b/src/image/image-private.h @@ -66,38 +66,5 @@ public: PixelFormat m_format; }; -class ImageCodec -{ -public: - virtual char const *GetName() { return ""; } - virtual bool Load(Image *image, char const *path) = 0; - virtual bool Save(Image *image, char const *path) = 0; - - /* TODO: this should become more fine-grained */ - int m_priority; -}; - -#define REGISTER_IMAGE_CODEC(name) \ - extern ImageCodec *Register##name(); \ - { \ - /* Insert image codecs in a sorted list */ \ - ImageCodec *codec = Register##name(); \ - int i = 0, prio = codec->m_priority; \ - for ( ; i < codeclist.count(); ++i) \ - { \ - if (codeclist[i]->m_priority <= prio) \ - break; \ - } \ - codeclist.insert(codec, i); \ - } - -#define DECLARE_IMAGE_CODEC(name, priority) \ - ImageCodec *Register##name() \ - { \ - ImageCodec *ret = new name(); \ - ret->m_priority = priority; \ - return ret; \ - } - } /* namespace lol */ diff --git a/src/image/image.cpp b/src/image/image.cpp index 06f9fd65..c96bc17e 100644 --- a/src/image/image.cpp +++ b/src/image/image.cpp @@ -19,61 +19,6 @@ namespace lol { -/* HACK: We cannot make this an ImageLoader member function, because the - * REGISTER_IMAGE_CODEC 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 RegisterAllCodecs(array &codeclist) -{ -#if defined __ANDROID__ - REGISTER_IMAGE_CODEC(AndroidImageCodec) -#endif -#if defined LOL_USE_GDIPLUS - REGISTER_IMAGE_CODEC(GdiPlusImageCodec) -#endif -#if defined __APPLE__ && defined __MACH__ && defined __arm__ - REGISTER_IMAGE_CODEC(IosImageCodec) -#endif -#if defined LOL_USE_SDL_IMAGE - REGISTER_IMAGE_CODEC(SdlImageCodec) -#endif -#if defined LOL_USE_IMLIB2 - REGISTER_IMAGE_CODEC(Imlib2ImageCodec) -#endif - REGISTER_IMAGE_CODEC(DummyImageCodec) - REGISTER_IMAGE_CODEC(ZedImageCodec) - REGISTER_IMAGE_CODEC(ZedPaletteImageCodec) - REGISTER_IMAGE_CODEC(OricImageCodec) - - return true; -} - -/* - * Our static image loader - */ - -static class ImageLoader -{ - friend class Image; - -public: - inline ImageLoader() - { - RegisterAllCodecs(m_codecs); - } - -private: - array m_codecs; - map m_images; -} -g_image_loader; - /* * Public Image class */ @@ -117,77 +62,59 @@ Image::~Image() delete m_data; } -void Image::DummyFill() -{ - //TODO: This is not very beautiful - for (auto codec : g_image_loader.m_codecs) - { - if (String(codec->GetName()).contains("Dummy")) - { - codec->Load(this, nullptr); - return; - } - } -} - -void Image::Copy(uint8_t* pixels, ivec2 const& size, PixelFormat fmt) +void Image::Copy(uint8_t* src_pixels, ivec2 const& size, PixelFormat fmt) { ASSERT(fmt != PixelFormat::Unknown); SetSize(size); SetFormat(fmt); - memcpy(m_data->m_pixels[(int)fmt]->data(), pixels, + memcpy(m_data->m_pixels[(int)fmt]->data(), src_pixels, size.x * size.y * BytesPerPixel(fmt)); } -void Image::Copy(Image const &other) +void Image::Copy(Image const &src) { - ivec2 size = other.GetSize(); - PixelFormat fmt = other.GetFormat(); + ivec2 size = src.GetSize(); + PixelFormat fmt = src.GetFormat(); SetSize(size); if (fmt != PixelFormat::Unknown) { SetFormat(fmt); memcpy(m_data->m_pixels[(int)fmt]->data(), - other.m_data->m_pixels[(int)fmt]->data(), + src.m_data->m_pixels[(int)fmt]->data(), size.x * size.y * BytesPerPixel(fmt)); } } +void Image::DummyFill() +{ + Load("DUMMY"); +} + bool Image::Load(char const *path) { - ImageCodec* last_codec = nullptr; - for (auto codec : g_image_loader.m_codecs) + auto resource = ResourceLoader::Load(path); + if (resource == nullptr) + return false; + + auto image_resource = dynamic_cast(resource); + if (image_resource == nullptr) { - last_codec = codec; - if (codec->Load(this, path)) - { - msg::info("Image::Load: Codec %s succesfully loaded %s.\n", codec->GetName(), path); - return true; - } + delete image_resource; + return false; } - //Log error, because we shouldn't be here - msg::error("Image::Load: Last codec %s, Error loading image %s.\n", last_codec->GetName(), path); - return false; + Copy(*image_resource->m_image); + delete image_resource; + return true; } bool Image::Save(char const *path) { - ImageCodec* last_codec = nullptr; - for (auto codec : g_image_loader.m_codecs) - { - last_codec = codec; - if (codec->Save(this, path)) - { - msg::info("Image::Save: Codec %s succesfully saved %s.\n", codec->GetName(), path); - return true; - } - } - - //Log error, because we shouldn't be here - msg::error("Image::Save: Last codec %s, Error saving image %s.\n", last_codec->GetName(), path); - return false; + auto data = new ResourceImageData(new Image(*this)); + auto result = ResourceLoader::Save(path, data); + delete data; + return result; } ivec2 Image::GetSize() const @@ -281,12 +208,5 @@ void Image::Unlock(void const *pixels) ASSERT(pixels == m_data->m_pixels[(int)m_data->m_format]->data()); } -bool Image::RetrieveTiles(array& tiles) const -{ - /* TODO: re-implement this */ - //return m_data->m_codecdata->RetrieveTiles(tiles); - return false; -} - } /* namespace lol */ diff --git a/src/image/resource-private.h b/src/image/resource-private.h new file mode 100644 index 00000000..593aea7f --- /dev/null +++ b/src/image/resource-private.h @@ -0,0 +1,57 @@ +// +// Lol Engine +// +// Copyright: (c) 2016—2017 Sam Hocevar +// Copyright © 2016—2017 Benjamin “Touky” Huet +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the Do What The Fuck You Want To +// Public License, Version 2, as published by Sam Hocevar. See +// http://www.wtfpl.net/ for more details. +// + +#pragma once + +// +// The ResourceCodecData class +// ------------------------ +// + +namespace lol +{ + + class ResourceCodec + { + public: + virtual char const *GetName() { return ""; } + virtual ResourceCodecData* Load(char const *path) = 0; + virtual bool Save(char const *path, ResourceCodecData* data) = 0; + + /* TODO: this should become more fine-grained */ + int m_priority; + }; + +#define REGISTER_IMAGE_CODEC(name) \ + extern ResourceCodec *Register##name(); \ + { \ + /* Insert image codecs in a sorted list */ \ + ResourceCodec *codec = Register##name(); \ + int i = 0, prio = codec->m_priority; \ + for ( ; i < codeclist.count(); ++i) \ + { \ + if (codeclist[i]->m_priority <= prio) \ + break; \ + } \ + codeclist.insert(codec, i); \ + } + +#define DECLARE_IMAGE_CODEC(name, priority) \ + ResourceCodec *Register##name() \ + { \ + ResourceCodec *ret = new name(); \ + ret->m_priority = priority; \ + return ret; \ + } + +} /* namespace lol */ + diff --git a/src/image/resource.cpp b/src/image/resource.cpp new file mode 100644 index 00000000..36a1b8ae --- /dev/null +++ b/src/image/resource.cpp @@ -0,0 +1,121 @@ +// +// Lol Engine +// +// Copyright © 2016—2017 Sam Hocevar +// Copyright © 2016—2017 Benjamin “Touky” Huet +// +// Lol Engine is free software. It comes without any warranty, to +// the extent permitted by applicable law. You can redistribute it +// and/or modify it under the terms of the Do What the Fuck You Want +// to Public License, Version 2, as published by the WTFPL Task Force. +// See http://www.wtfpl.net/ for more details. +// + +#include + +#include "resource-private.h" + +#include /* for std::swap */ + +namespace lol +{ + +/* HACK: We cannot make this an ImageLoader member function, because the +* REGISTER_IMAGE_CODEC 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 RegisterAllCodecs(array &codeclist) +{ +#if defined __ANDROID__ + REGISTER_IMAGE_CODEC(AndroidImageCodec) +#endif +#if defined LOL_USE_GDIPLUS + REGISTER_IMAGE_CODEC(GdiPlusImageCodec) +#endif +#if defined __APPLE__ && defined __MACH__ && defined __arm__ + REGISTER_IMAGE_CODEC(IosImageCodec) +#endif +#if defined LOL_USE_SDL_IMAGE + REGISTER_IMAGE_CODEC(SdlImageCodec) +#endif +#if defined LOL_USE_IMLIB2 + REGISTER_IMAGE_CODEC(Imlib2ImageCodec) +#endif + REGISTER_IMAGE_CODEC(ZedImageCodec) + REGISTER_IMAGE_CODEC(ZedPaletteImageCodec) + REGISTER_IMAGE_CODEC(OricImageCodec) + + REGISTER_IMAGE_CODEC(DummyImageCodec) + + return true; +} + +/* +* Our static image loader +*/ + +static class StaticResourceLoader +{ + friend class ResourceLoader; + +public: + inline StaticResourceLoader() + { + RegisterAllCodecs(m_codecs); + } + +private: + array m_codecs; +} +g_resource_loader; + +/* +* The public resource loader +*/ + +ResourceCodecData* ResourceLoader::Load(char const *path) +{ + ResourceCodec* last_codec = nullptr; + for (auto codec : g_resource_loader.m_codecs) + { + last_codec = codec; + auto data = codec->Load(path); + if (data != nullptr) + { + msg::info("Image::Load: Codec %s succesfully loaded %s.\n", codec->GetName(), path); + return data; + } + } + + //Log error, because we shouldn't be here + msg::error("Image::Load: Last codec %s, Error loading resource %s.\n", last_codec->GetName(), path); + return false; +} + +bool ResourceLoader::Save(char const *path, ResourceCodecData* data) +{ + ResourceCodec* last_codec = nullptr; + for (auto codec : g_resource_loader.m_codecs) + { + last_codec = codec; + if (codec->Save(path, data)) + { + msg::info("Image::Save: Codec %s succesfully saved %s.\n", codec->GetName(), path); + return true; + } + } + + //Log error, because we shouldn't be here + msg::error("Image::Save: Last codec %s, Error saving resource %s.\n", last_codec->GetName(), path); + return false; +} + + +} /* namespace lol */ + diff --git a/src/lol-core.vcxproj b/src/lol-core.vcxproj index c961ddf5..7d924d56 100644 --- a/src/lol-core.vcxproj +++ b/src/lol-core.vcxproj @@ -148,6 +148,7 @@ + @@ -238,6 +239,7 @@ + @@ -285,6 +287,7 @@ + @@ -397,4 +400,4 @@ - + \ No newline at end of file diff --git a/src/lol/image/all.h b/src/lol/image/all.h index e704eb30..3375d56c 100644 --- a/src/lol/image/all.h +++ b/src/lol/image/all.h @@ -15,5 +15,6 @@ #include #include #include +#include #include diff --git a/src/lol/image/image.h b/src/lol/image/image.h index 24d06d07..42fffa15 100644 --- a/src/lol/image/image.h +++ b/src/lol/image/image.h @@ -106,9 +106,6 @@ public: template void Unlock2D(array2d const &); - /* XXX: this does not belong here */ - bool RetrieveTiles(array& tiles) const; - /* Image processing kernels */ static array2d BayerKernel(ivec2 size); static array2d HalftoneKernel(ivec2 size); diff --git a/src/lol/image/resource.h b/src/lol/image/resource.h new file mode 100644 index 00000000..f8be8bf5 --- /dev/null +++ b/src/lol/image/resource.h @@ -0,0 +1,74 @@ +// +// Lol Engine +// +// Copyright © 2016—2017 Sam Hocevar +// Copyright © 2016—2017 Benjamin “Touky” Huet +// +// Lol Engine is free software. It comes without any warranty, to +// the extent permitted by applicable law. You can redistribute it +// and/or modify it under the terms of the Do What the Fuck You Want +// to Public License, Version 2, as published by the WTFPL Task Force. +// See http://www.wtfpl.net/ for more details. +// + +#pragma once + +// +// The Resource class +// --------------- +// + +#include +#include +#include +#include + +namespace lol +{ + //ResourceCodecData ----------------------------------------------------------- + class ResourceCodecData + { + public: + ResourceCodecData() { } + virtual ~ResourceCodecData() { } + }; + + //ResourceImageData ----------------------------------------------------------- + class ResourceImageData : public ResourceCodecData + { + public: + ResourceImageData(Image* image) + { + m_image = image; + } + + virtual ~ResourceImageData() + { + if (m_image) + delete m_image; + } + + Image* m_image = nullptr; + }; + + //ResourceImageData ----------------------------------------------------------- + class ResourceTilesetData : public ResourceImageData + { + public: + ResourceTilesetData(Image* image) + : ResourceImageData(image) + { } + + array m_tiles; + }; + + //ResourceLoader -------------------------------------------------------------- + class ResourceLoader + { + public: + static ResourceCodecData* Load(char const *path); + static bool Save(char const *path, ResourceCodecData* data); + }; + +} /* namespace lol */ + diff --git a/src/platform/sdl/sdlinput.cpp b/src/platform/sdl/sdlinput.cpp index 795ca32b..74a3366b 100644 --- a/src/platform/sdl/sdlinput.cpp +++ b/src/platform/sdl/sdlinput.cpp @@ -278,10 +278,10 @@ void SdlInputData::Tick(float seconds) # endif { //Lock management -# if defined SDLOL_CapsLock && defined SDLOL_ScrollLock && defined SDLOL_NumLockClear case SDLOL_CapsLock: case SDLOL_ScrollLock: case SDLOL_NumLockClear: +# if defined SDLOL_CapsLock && defined SDLOL_ScrollLock && defined SDLOL_NumLockClear //Update status on key down only if (event.type == SDL_KEYDOWN) { diff --git a/src/sys/init.cpp b/src/sys/init.cpp index 6600dbdd..974aa9e1 100644 --- a/src/sys/init.cpp +++ b/src/sys/init.cpp @@ -104,6 +104,13 @@ void init(int argc, char *argv[], rootdir += "../src/"; /* FIXME: use SEPARATOR? */ add_data_dir(rootdir); + /* This data dir is for submodule support stuff */ + rootdir = solutiondir; + if (rootdir.count() && rootdir.last() != SEPARATOR) + rootdir += SEPARATOR; + rootdir += "./lol/src/"; /* FIXME: use SEPARATOR? */ + add_data_dir(rootdir); + /* This data dir is for project-specific stuff */ rootdir = projectdir; if (rootdir.count() && rootdir.last() != SEPARATOR) diff --git a/src/textureimage.cpp b/src/textureimage.cpp index f3d6f3ed..1ef46289 100644 --- a/src/textureimage.cpp +++ b/src/textureimage.cpp @@ -57,7 +57,19 @@ TextureImage::~TextureImage() void TextureImage::Init(char const *path) { - Init(path, new Image(path)); + Init(path, ResourceLoader::Load(path)); +} + +void TextureImage::Init(char const *path, ResourceCodecData* loaded_data) +{ + //Load image if available + auto image_data = dynamic_cast(loaded_data); + if (image_data != nullptr) + { + Init(path, new Image(*image_data->m_image)); + } + + delete image_data; } void TextureImage::Init(char const *path, Image* image) diff --git a/src/textureimage.h b/src/textureimage.h index 307c33d7..b798bbef 100644 --- a/src/textureimage.h +++ b/src/textureimage.h @@ -18,6 +18,7 @@ // zero, the texture is freed. // +#include #include #include @@ -43,6 +44,7 @@ public: protected: void Init(char const *path); + virtual void Init(char const *path, ResourceCodecData* loaded_data); virtual void Init(char const *path, Image* image); protected: diff --git a/src/tileset.cpp b/src/tileset.cpp index fb952d2d..0f5aa981 100644 --- a/src/tileset.cpp +++ b/src/tileset.cpp @@ -46,25 +46,25 @@ protected: */ TileSet::TileSet(char const *path) - : TextureImage(path), + : m_tileset_data(new TileSetData()), + m_palette(nullptr), + TextureImage(path) +{ +} + +TileSet::TileSet(char const *path, Image* image) + : TextureImage(path, image), m_tileset_data(new TileSetData()), m_palette(nullptr) { - array tiles; - if (m_data->m_image->RetrieveTiles(tiles)) - for (int i = 0; i < tiles.count(); i++) - define_tile(ibox2(tiles[0].m1, tiles[0].m1 + tiles[0].m2)); } -TileSet::TileSet(char const *path, Image* image) - : TextureImage(path, image), +TileSet::TileSet(char const *path, Image* image, array& tiles) + : TextureImage(path, image), m_tileset_data(new TileSetData()), m_palette(nullptr) { - array tiles; - if (m_data->m_image->RetrieveTiles(tiles)) - for (int i = 0; i < tiles.count(); i++) - define_tile(ibox2(tiles[0].m1, tiles[0].m1 + tiles[0].m2)); + define_tile(tiles); } TileSet::TileSet(char const *path, ivec2 size, ivec2 count) @@ -118,6 +118,20 @@ TileSet::~TileSet() delete m_tileset_data; } +void TileSet::Init(char const *path, ResourceCodecData* loaded_data) +{ + //Load tileset if available + auto tileset_data = dynamic_cast(loaded_data); + if (tileset_data != nullptr) + { + define_tile(tileset_data->m_tiles); + } + + m_data->m_name = String(" ") + path; + + super::Init(path, loaded_data); +} + void TileSet::Init(char const *path, Image* image) { super::Init(path, image); @@ -132,6 +146,11 @@ char const *TileSet::GetName() } //New methods ----------------------------------------------------------------- +void TileSet::clear_all() +{ + m_tileset_data->m_tiles.empty(); +} + int TileSet::define_tile(ibox2 rect) { m_tileset_data->m_tiles.push(rect, @@ -152,6 +171,18 @@ void TileSet::define_tile(ivec2 count) } } +void TileSet::define_tile(array& tiles) +{ + for (int i = 0; i < tiles.count(); i++) + define_tile(tiles[i]); +} + +void TileSet::define_tile(array& tiles) +{ + for (int i = 0; i < tiles.count(); i++) + define_tile(ibox2(tiles[i].m1, tiles[i].m1 + tiles[i].m2)); +} + int TileSet::GetTileCount() const { return m_tileset_data->m_tiles.count(); diff --git a/src/tileset.h b/src/tileset.h index 5855c5e2..cb5348e7 100644 --- a/src/tileset.h +++ b/src/tileset.h @@ -43,6 +43,7 @@ class TileSet : public TextureImage public: TileSet(char const *path); TileSet(char const *path, Image* image); + TileSet(char const *path, Image* image, array& tiles); /* Old style: path to PNG file */ TileSet(char const *path, ivec2 size, ivec2 count); @@ -51,6 +52,7 @@ public: virtual ~TileSet(); protected: + virtual void Init(char const *path, ResourceCodecData* loaded_data); virtual void Init(char const *path, Image* image); public: @@ -58,8 +60,11 @@ public: virtual char const *GetName(); /* New methods */ + void clear_all(); int define_tile(ibox2 rect); void define_tile(ivec2 count); + void define_tile(array& tiles); + void define_tile(array& tiles); int GetTileCount() const; ivec2 GetTileSize(int tileid) const; ibox2 GetTilePixel(int tileid) const;