Moved ImageLoader to ResourceLoader, so that loading is extensible. i.e. here: Zed image loader now loads up a tileset instead of being a hacked image loader. Goal is to support more funky stuff (wad, pak .....)legacy
| @@ -54,7 +54,7 @@ liblol_core_headers = \ | |||||
| lol/sys/threadtypes.h lol/sys/timer.h \ | lol/sys/threadtypes.h lol/sys/timer.h \ | ||||
| \ | \ | ||||
| lol/image/all.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/all.h \ | ||||
| lol/gpu/shader.h lol/gpu/indexbuffer.h lol/gpu/vertexbuffer.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/init.cpp sys/file.cpp sys/hacks.cpp \ | ||||
| sys/thread.cpp sys/threadtypes.cpp sys/getopt.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/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/crop.cpp image/resample.cpp image/noise.cpp image/combine.cpp \ | ||||
| image/codec/gdiplus-image.cpp image/codec/imlib2-image.cpp \ | image/codec/gdiplus-image.cpp image/codec/imlib2-image.cpp \ | ||||
| @@ -21,7 +21,7 @@ extern "C" { | |||||
| #include <android_native_app_glue.h> | #include <android_native_app_glue.h> | ||||
| } | } | ||||
| #include "../../image/image-private.h" | |||||
| #include "../../image/resource-private.h" | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| @@ -32,12 +32,12 @@ extern ANativeActivity *g_activity; | |||||
| * Image implementation class | * Image implementation class | ||||
| */ | */ | ||||
| class AndroidImageCodec : public ImageCodec | |||||
| class AndroidImageCodec : public ResourceCodec | |||||
| { | { | ||||
| public: | public: | ||||
| virtual char const *GetName() { return "<AndroidImageCodec>"; } | virtual char const *GetName() { return "<AndroidImageCodec>"; } | ||||
| 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 bool Close(); | ||||
| virtual uint8_t *GetData() const; | virtual uint8_t *GetData() const; | ||||
| @@ -50,7 +50,7 @@ private: | |||||
| DECLARE_IMAGE_CODEC(AndroidImageCodec, 100) | DECLARE_IMAGE_CODEC(AndroidImageCodec, 100) | ||||
| bool AndroidImageCodec::Load(Image *image, char const *path) | |||||
| ResourceCodecData* AndroidImageCodec::Load(char const *path) | |||||
| { | { | ||||
| JNIEnv *env; | JNIEnv *env; | ||||
| jint res = g_activity->vm->GetEnv((void **)&env, JNI_VERSION_1_2); | 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; | 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 */ | /* TODO: unimplemented */ | ||||
| } | } | ||||
| @@ -10,7 +10,7 @@ | |||||
| #include <lol/engine-internal.h> | #include <lol/engine-internal.h> | ||||
| #include "../../image/image-private.h" | |||||
| #include "../../image/resource-private.h" | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| @@ -19,12 +19,12 @@ namespace lol | |||||
| * Image implementation class | * Image implementation class | ||||
| */ | */ | ||||
| class DummyImageCodec : public ImageCodec | |||||
| class DummyImageCodec : public ResourceCodec | |||||
| { | { | ||||
| public: | public: | ||||
| virtual char const *GetName() { return "<DummyImageCodec>"; } | virtual char const *GetName() { return "<DummyImageCodec>"; } | ||||
| 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 | //Priority 0 because it's supposed to be the last one | ||||
| @@ -34,11 +34,13 @@ DECLARE_IMAGE_CODEC(DummyImageCodec, 0) | |||||
| * Public Image class | * 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<PixelFormat::RGBA_8>(), *tmp = pixels; | u8vec4 *pixels = image->Lock<PixelFormat::RGBA_8>(), *tmp = pixels; | ||||
| for (int j = 0; j < 256; j++) | for (int j = 0; j < 256; j++) | ||||
| for (int i = 0; i < 256; i++) | for (int i = 0; i < 256; i++) | ||||
| @@ -51,13 +53,12 @@ bool DummyImageCodec::Load(Image *image, char const *path) | |||||
| } | } | ||||
| image->Unlock(pixels); | 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; | return false; | ||||
| } | } | ||||
| @@ -26,7 +26,7 @@ using std::max; | |||||
| #if LOL_USE_GDIPLUS | #if LOL_USE_GDIPLUS | ||||
| #include "../../image/image-private.h" | |||||
| #include "../../image/resource-private.h" | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| @@ -35,12 +35,12 @@ namespace lol | |||||
| * Image implementation class | * Image implementation class | ||||
| */ | */ | ||||
| class GdiPlusImageCodec : public ImageCodec | |||||
| class GdiPlusImageCodec : public ResourceCodec | |||||
| { | { | ||||
| public: | public: | ||||
| virtual char const *GetName() { return "<GdiPlusImageCodec>"; } | virtual char const *GetName() { return "<GdiPlusImageCodec>"; } | ||||
| 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) | DECLARE_IMAGE_CODEC(GdiPlusImageCodec, 100) | ||||
| @@ -49,7 +49,7 @@ DECLARE_IMAGE_CODEC(GdiPlusImageCodec, 100) | |||||
| * Public Image class | * Public Image class | ||||
| */ | */ | ||||
| bool GdiPlusImageCodec::Load(Image *image, char const *path) | |||||
| ResourceCodecData* GdiPlusImageCodec::Load(char const *path) | |||||
| { | { | ||||
| Gdiplus::Status status; | Gdiplus::Status status; | ||||
| ULONG_PTR token; | ULONG_PTR token; | ||||
| @@ -58,7 +58,7 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) | |||||
| if (status != Gdiplus::Ok) | if (status != Gdiplus::Ok) | ||||
| { | { | ||||
| msg::error("error %d while initialising GDI+\n", status); | msg::error("error %d while initialising GDI+\n", status); | ||||
| return false; | |||||
| return nullptr; | |||||
| } | } | ||||
| array<String> pathlist = sys::get_path_list(path); | array<String> pathlist = sys::get_path_list(path); | ||||
| @@ -99,7 +99,7 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) | |||||
| if (!bitmap) | if (!bitmap) | ||||
| { | { | ||||
| msg::error("could not load %s\n", path); | msg::error("could not load %s\n", path); | ||||
| return false; | |||||
| return nullptr; | |||||
| } | } | ||||
| ivec2 size(bitmap->GetWidth(), bitmap->GetHeight()); | 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); | msg::error("could not lock bits in %s\n", path); | ||||
| delete bitmap; | delete bitmap; | ||||
| return false; | |||||
| return nullptr; | |||||
| } | } | ||||
| /* FIXME: GDI+ doesn't know about RGBA, only ARGB. And OpenGL doesn't | /* 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 | * know about ARGB, only RGBA. So we swap bytes. We could also fix | ||||
| * this in the shader. */ | * this in the shader. */ | ||||
| image->SetSize(size); | |||||
| auto data = new ResourceImageData(new Image(ivec2(size))); | |||||
| auto image = data->m_image; | |||||
| u8vec4 *pdst = image->Lock<PixelFormat::RGBA_8>(); | u8vec4 *pdst = image->Lock<PixelFormat::RGBA_8>(); | ||||
| u8vec4 *psrc = static_cast<u8vec4 *>(bdata.Scan0); | u8vec4 *psrc = static_cast<u8vec4 *>(bdata.Scan0); | ||||
| for (int n = 0; n < size.x * size.y; n++) | 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); | bitmap->UnlockBits(&bdata); | ||||
| delete bitmap; | 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<ResourceImageData*>(data); | |||||
| if (data_image == nullptr) | |||||
| return false; | |||||
| ULONG_PTR token; | ULONG_PTR token; | ||||
| Gdiplus::GdiplusStartupInput input; | Gdiplus::GdiplusStartupInput input; | ||||
| Gdiplus::GdiplusStartup(&token, &input, nullptr); | Gdiplus::GdiplusStartup(&token, &input, nullptr); | ||||
| @@ -178,6 +183,7 @@ bool GdiPlusImageCodec::Save(Image *image, char const *path) | |||||
| return false; | return false; | ||||
| } | } | ||||
| auto image = data_image->m_image; | |||||
| ivec2 size = image->GetSize(); | ivec2 size = image->GetSize(); | ||||
| Gdiplus::Bitmap *b = new Gdiplus::Bitmap(size.x, size.y, | Gdiplus::Bitmap *b = new Gdiplus::Bitmap(size.x, size.y, | ||||
| @@ -16,7 +16,7 @@ | |||||
| #import <UIKit/UIKit.h> | #import <UIKit/UIKit.h> | ||||
| #include "../../image/image-private.h" | |||||
| #include "../../image/resource-private.h" | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| @@ -25,12 +25,12 @@ namespace lol | |||||
| * Image implementation class | * Image implementation class | ||||
| */ | */ | ||||
| class IosImageCodec : public ImageCodec | |||||
| class IosImageCodec : public ResourceCodec | |||||
| { | { | ||||
| public: | public: | ||||
| virtual char const *GetName() { return "<IosImageCodec>"; } | virtual char const *GetName() { return "<IosImageCodec>"; } | ||||
| 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) | DECLARE_IMAGE_CODEC(IosImageCodec, 100) | ||||
| @@ -39,7 +39,7 @@ DECLARE_IMAGE_CODEC(IosImageCodec, 100) | |||||
| * Public Image class | * Public Image class | ||||
| */ | */ | ||||
| bool IosImageCodec::Load(Image *image, char const *path) | |||||
| ResourceCodecData* IosImageCodec::Load(char const *path) | |||||
| { | { | ||||
| NSString *fullpath = [NSString stringWithUTF8String:path]; | NSString *fullpath = [NSString stringWithUTF8String:path]; | ||||
| NSArray *chunks = [fullpath componentsSeparatedByString: @"/"]; | NSArray *chunks = [fullpath componentsSeparatedByString: @"/"]; | ||||
| @@ -54,7 +54,7 @@ bool IosImageCodec::Load(Image *image, char const *path) | |||||
| #if !LOL_BUILD_RELEASE | #if !LOL_BUILD_RELEASE | ||||
| msg::error("could not load %s\n", path); | msg::error("could not load %s\n", path); | ||||
| #endif | #endif | ||||
| return false; | |||||
| return nullptr; | |||||
| } | } | ||||
| int w = CGImageGetWidth(image.CGImage); | int w = CGImageGetWidth(image.CGImage); | ||||
| @@ -75,12 +75,12 @@ bool IosImageCodec::Load(Image *image, char const *path) | |||||
| [image release]; | [image release]; | ||||
| [pngdata 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 */ | /* TODO: unimplemented */ | ||||
| return true; | return true; | ||||
| @@ -12,7 +12,7 @@ | |||||
| #include <cctype> | #include <cctype> | ||||
| #include "../../image/image-private.h" | |||||
| #include "../../image/resource-private.h" | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| @@ -27,12 +27,12 @@ namespace lol | |||||
| * Image implementation class | * Image implementation class | ||||
| */ | */ | ||||
| class OricImageCodec : public ImageCodec | |||||
| class OricImageCodec : public ResourceCodec | |||||
| { | { | ||||
| public: | public: | ||||
| virtual char const *GetName() { return "<OricImageCodec>"; } | virtual char const *GetName() { return "<OricImageCodec>"; } | ||||
| 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: | private: | ||||
| static String ReadScreen(char const *name); | static String ReadScreen(char const *name); | ||||
| @@ -45,7 +45,7 @@ DECLARE_IMAGE_CODEC(OricImageCodec, 100) | |||||
| * Public Image class | * Public Image class | ||||
| */ | */ | ||||
| bool OricImageCodec::Load(Image *image, char const *path) | |||||
| ResourceCodecData* OricImageCodec::Load(char const *path) | |||||
| { | { | ||||
| static u8vec4 const pal[8] = | static u8vec4 const pal[8] = | ||||
| { | { | ||||
| @@ -61,9 +61,10 @@ bool OricImageCodec::Load(Image *image, char const *path) | |||||
| String screen = ReadScreen(path); | String screen = ReadScreen(path); | ||||
| if (screen.count() == 0) | 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<PixelFormat::RGBA_8>(); | u8vec4 *pixels = image->Lock<PixelFormat::RGBA_8>(); | ||||
| @@ -102,12 +103,16 @@ bool OricImageCodec::Load(Image *image, char const *path) | |||||
| image->Unlock(pixels); | 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<ResourceImageData*>(data); | |||||
| if (data_image == nullptr) | |||||
| return false; | |||||
| int len = (int)strlen(path); | |||||
| if (len < 4 || path[len - 4] != '.' | if (len < 4 || path[len - 4] != '.' | ||||
| || toupper(path[len - 3]) != 'T' | || toupper(path[len - 3]) != 'T' | ||||
| || toupper(path[len - 2]) != 'A' | || toupper(path[len - 2]) != 'A' | ||||
| @@ -124,6 +129,7 @@ bool OricImageCodec::Save(Image *image, char const *path) | |||||
| result << (uint8_t)name[0]; | result << (uint8_t)name[0]; | ||||
| result << 0; | result << 0; | ||||
| auto image = data_image->m_image; | |||||
| Image tmp; | Image tmp; | ||||
| ivec2 size = image->GetSize(); | ivec2 size = image->GetSize(); | ||||
| if (size.x != WIDTH) | if (size.x != WIDTH) | ||||
| @@ -481,7 +487,7 @@ void OricImageCodec::WriteScreen(Image &image, array<uint8_t> &result) | |||||
| for (int y = 0; y < size.y; y++) | for (int y = 0; y < size.y; y++) | ||||
| for (int x = 0; x < size.x; x++) | for (int x = 0; x < size.x; x++) | ||||
| for (int c = 0; c < 3; c++) | 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 */ | /* Let the fun begin */ | ||||
| for (int y = 0; y < size.y; y++) | for (int y = 0; y < size.y; y++) | ||||
| @@ -25,7 +25,7 @@ | |||||
| # include <SDL_image.h> | # include <SDL_image.h> | ||||
| #endif | #endif | ||||
| #include "../../image/image-private.h" | |||||
| #include "../../image/resource-private.h" | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| @@ -34,19 +34,19 @@ namespace lol | |||||
| * Image implementation class | * Image implementation class | ||||
| */ | */ | ||||
| class SdlImageCodec : public ImageCodec | |||||
| class SdlImageCodec : public ResourceCodec | |||||
| { | { | ||||
| public: | public: | ||||
| virtual char const *GetName() { return "<SdlImageCodec>"; } | virtual char const *GetName() { return "<SdlImageCodec>"; } | ||||
| 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); | static SDL_Surface *Create32BppSurface(ivec2 size); | ||||
| }; | }; | ||||
| DECLARE_IMAGE_CODEC(SdlImageCodec, 50) | DECLARE_IMAGE_CODEC(SdlImageCodec, 50) | ||||
| bool SdlImageCodec::Load(Image *image, char const *path) | |||||
| ResourceCodecData* SdlImageCodec::Load(char const *path) | |||||
| { | { | ||||
| SDL_Surface *surface = nullptr; | SDL_Surface *surface = nullptr; | ||||
| @@ -75,24 +75,30 @@ bool SdlImageCodec::Load(Image *image, char const *path) | |||||
| surface = tmp; | surface = tmp; | ||||
| } | } | ||||
| image->SetSize(size); | |||||
| u8vec4 *data = image->Lock<PixelFormat::RGBA_8>(); | |||||
| 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<PixelFormat::RGBA_8>(); | |||||
| memcpy(pixel_data, surface->pixels, 4 * size.x * size.y); | |||||
| image->Unlock(pixel_data); | |||||
| SDL_FreeSurface(surface); | 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<ResourceImageData*>(data); | |||||
| if (data_image == nullptr) | |||||
| return false; | |||||
| auto image = data_image->m_image; | |||||
| ivec2 size = image->GetSize(); | ivec2 size = image->GetSize(); | ||||
| SDL_Surface *surface = Create32BppSurface(size); | SDL_Surface *surface = Create32BppSurface(size); | ||||
| u8vec4 *data = image->Lock<PixelFormat::RGBA_8>(); | |||||
| memcpy(surface->pixels, data, 4 * size.x * size.y); | |||||
| image->Unlock(data); | |||||
| u8vec4 *pixel_data = image->Lock<PixelFormat::RGBA_8>(); | |||||
| memcpy(surface->pixels, pixel_data, 4 * size.x * size.y); | |||||
| image->Unlock(pixel_data); | |||||
| int ret = SDL_SaveBMP(surface, path); | int ret = SDL_SaveBMP(surface, path); | ||||
| SDL_FreeSurface(surface); | SDL_FreeSurface(surface); | ||||
| @@ -11,7 +11,7 @@ | |||||
| #include <lol/engine-internal.h> | #include <lol/engine-internal.h> | ||||
| #include "../../image/image-private.h" | |||||
| #include "../../image/resource-private.h" | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| @@ -20,24 +20,12 @@ namespace lol | |||||
| * Image implementation class | * Image implementation class | ||||
| */ | */ | ||||
| class ZedImageCodec : public ImageCodec | |||||
| class ZedImageCodec : public ResourceCodec | |||||
| { | { | ||||
| public: | public: | ||||
| virtual char const *GetName() { return "<ZedImageCodec>"; } | virtual char const *GetName() { return "<ZedImageCodec>"; } | ||||
| virtual bool Load(Image *image, char const *path); | |||||
| virtual bool Save(Image *image, char const *path); | |||||
| virtual bool RetrieveTiles(array<ivec2, ivec2>& tiles) | |||||
| { | |||||
| bool result = m_tiles.count() > 0; | |||||
| tiles += m_tiles; | |||||
| m_tiles.empty(); | |||||
| return result; | |||||
| } | |||||
| private: | |||||
| //<Pos, Size> | |||||
| array<ivec2, ivec2> m_tiles; | |||||
| virtual ResourceCodecData* Load(char const *path); | |||||
| virtual bool Save(char const *path, ResourceCodecData* data); | |||||
| }; | }; | ||||
| DECLARE_IMAGE_CODEC(ZedImageCodec, 10) | DECLARE_IMAGE_CODEC(ZedImageCodec, 10) | ||||
| @@ -46,10 +34,10 @@ DECLARE_IMAGE_CODEC(ZedImageCodec, 10) | |||||
| * Public Image class | * Public Image class | ||||
| */ | */ | ||||
| bool ZedImageCodec::Load(Image *image, char const *path) | |||||
| ResourceCodecData* ZedImageCodec::Load(char const *path) | |||||
| { | { | ||||
| if (!lol::String(path).ends_with(".RSC")) | if (!lol::String(path).ends_with(".RSC")) | ||||
| return false; | |||||
| return nullptr; | |||||
| // Compacter definition | // Compacter definition | ||||
| struct CompactSecondary | struct CompactSecondary | ||||
| @@ -142,7 +130,9 @@ bool ZedImageCodec::Load(Image *image, char const *path) | |||||
| } | } | ||||
| file_offset << file_size; | file_offset << file_size; | ||||
| m_tiles.reserve(file_count); | |||||
| //<Pos, Size> | |||||
| array<ivec2, ivec2> tiles; | |||||
| tiles.reserve(file_count); | |||||
| Compacter2d compacter; | Compacter2d compacter; | ||||
| compacter.StepSetup(8, 8, 10); | compacter.StepSetup(8, 8, 10); | ||||
| @@ -151,6 +141,7 @@ bool ZedImageCodec::Load(Image *image, char const *path) | |||||
| array<uint8_t> file_convert; | array<uint8_t> file_convert; | ||||
| file_convert.reserve(file_size); | file_convert.reserve(file_size); | ||||
| array<ivec2> available_sizes; | array<ivec2> available_sizes; | ||||
| //got through all the files and store them | |||||
| for (int i = 0; i < file_count; i++) | for (int i = 0; i < file_count; i++) | ||||
| { | { | ||||
| file_pos = file_offset[i]; | file_pos = file_offset[i]; | ||||
| @@ -187,8 +178,10 @@ bool ZedImageCodec::Load(Image *image, char const *path) | |||||
| //Prepare buffer and tiles infos | //Prepare buffer and tiles infos | ||||
| int32_t convert_pos = file_convert.count(); | int32_t convert_pos = file_convert.count(); | ||||
| ivec2 size = ivec2(size_x, size_y); | 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); | file_convert.resize(convert_pos + data_length); | ||||
| //Retrieve actual datas | //Retrieve actual datas | ||||
| @@ -233,8 +226,9 @@ bool ZedImageCodec::Load(Image *image, char const *path) | |||||
| while (tex_size < tex_sqrt) | while (tex_size < tex_sqrt) | ||||
| tex_size <<= 1; | 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<PixelFormat::Y_8>(); | uint8_t *pixels = image->Lock<PixelFormat::Y_8>(); | ||||
| //Data refactor stage | //Data refactor stage | ||||
| @@ -255,8 +249,8 @@ bool ZedImageCodec::Load(Image *image, char const *path) | |||||
| compacter.m_primary[j].m_count--; | compacter.m_primary[j].m_count--; | ||||
| int i = compacter.m_primary[j].m_secondary[k].m_tiles.pop(); | 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); | 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 | //Register new pos and move to next | ||||
| m_tiles[i].m1 = pos; | |||||
| tiles[i].m1 = pos; | |||||
| pos.x += t_size.x; | pos.x += t_size.x; | ||||
| } | } | ||||
| } | } | ||||
| @@ -292,12 +286,14 @@ bool ZedImageCodec::Load(Image *image, char const *path) | |||||
| } | } | ||||
| image->Unlock(pixels); | 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? */ | /* FIXME: do we need to implement this? */ | ||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -10,7 +10,7 @@ | |||||
| #include <lol/engine-internal.h> | #include <lol/engine-internal.h> | ||||
| #include "../../image/image-private.h" | |||||
| #include "../../image/resource-private.h" | |||||
| namespace lol | namespace lol | ||||
| { | { | ||||
| @@ -19,12 +19,12 @@ namespace lol | |||||
| * Image implementation class | * Image implementation class | ||||
| */ | */ | ||||
| class ZedPaletteImageCodec : public ImageCodec | |||||
| class ZedPaletteImageCodec : public ResourceCodec | |||||
| { | { | ||||
| public: | public: | ||||
| virtual char const *GetName() { return "<ZedPaletteImageCodec>"; } | virtual char const *GetName() { return "<ZedPaletteImageCodec>"; } | ||||
| 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) | DECLARE_IMAGE_CODEC(ZedPaletteImageCodec, 10) | ||||
| @@ -33,10 +33,10 @@ DECLARE_IMAGE_CODEC(ZedPaletteImageCodec, 10) | |||||
| * Public Image class | * Public Image class | ||||
| */ | */ | ||||
| bool ZedPaletteImageCodec::Load(Image *image, char const *path) | |||||
| ResourceCodecData* ZedPaletteImageCodec::Load(char const *path) | |||||
| { | { | ||||
| if (!lol::String(path).ends_with(".pal")) | if (!lol::String(path).ends_with(".pal")) | ||||
| return false; | |||||
| return nullptr; | |||||
| File file; | File file; | ||||
| file.Open(path, FileAccess::Read, true); | file.Open(path, FileAccess::Read, true); | ||||
| @@ -53,13 +53,15 @@ bool ZedPaletteImageCodec::Load(Image *image, char const *path) | |||||
| int32_t tex_size = 2; | int32_t tex_size = 2; | ||||
| while (tex_size < tex_sqrt) | while (tex_size < tex_sqrt) | ||||
| tex_size <<= 1; | 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 | #else | ||||
| int32_t tex_sqrt = file_size / 3; | int32_t tex_sqrt = file_size / 3; | ||||
| int32_t tex_size = 2; | int32_t tex_size = 2; | ||||
| while (tex_size < tex_sqrt) | while (tex_size < tex_sqrt) | ||||
| tex_size <<= 1; | 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 | #endif | ||||
| u8vec4 *pixels = image->Lock<PixelFormat::RGBA_8>(); | u8vec4 *pixels = image->Lock<PixelFormat::RGBA_8>(); | ||||
| @@ -73,12 +75,12 @@ bool ZedPaletteImageCodec::Load(Image *image, char const *path) | |||||
| } | } | ||||
| image->Unlock(pixels); | 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? */ | /* FIXME: do we need to implement this? */ | ||||
| return true; | return true; | ||||
| } | } | ||||
| @@ -66,38 +66,5 @@ public: | |||||
| PixelFormat m_format; | PixelFormat m_format; | ||||
| }; | }; | ||||
| class ImageCodec | |||||
| { | |||||
| public: | |||||
| virtual char const *GetName() { return "<ImageCodec>"; } | |||||
| 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 */ | } /* namespace lol */ | ||||
| @@ -19,61 +19,6 @@ | |||||
| namespace lol | 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<ImageCodec *> &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<ImageCodec *> m_codecs; | |||||
| map<String, Image *> m_images; | |||||
| } | |||||
| g_image_loader; | |||||
| /* | /* | ||||
| * Public Image class | * Public Image class | ||||
| */ | */ | ||||
| @@ -117,77 +62,59 @@ Image::~Image() | |||||
| delete m_data; | 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); | ASSERT(fmt != PixelFormat::Unknown); | ||||
| SetSize(size); | SetSize(size); | ||||
| SetFormat(fmt); | 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)); | 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); | SetSize(size); | ||||
| if (fmt != PixelFormat::Unknown) | if (fmt != PixelFormat::Unknown) | ||||
| { | { | ||||
| SetFormat(fmt); | SetFormat(fmt); | ||||
| memcpy(m_data->m_pixels[(int)fmt]->data(), | 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)); | size.x * size.y * BytesPerPixel(fmt)); | ||||
| } | } | ||||
| } | } | ||||
| void Image::DummyFill() | |||||
| { | |||||
| Load("DUMMY"); | |||||
| } | |||||
| bool Image::Load(char const *path) | 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<ResourceImageData*>(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) | 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 | 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()); | ASSERT(pixels == m_data->m_pixels[(int)m_data->m_format]->data()); | ||||
| } | } | ||||
| bool Image::RetrieveTiles(array<ivec2, ivec2>& tiles) const | |||||
| { | |||||
| /* TODO: re-implement this */ | |||||
| //return m_data->m_codecdata->RetrieveTiles(tiles); | |||||
| return false; | |||||
| } | |||||
| } /* namespace lol */ | } /* namespace lol */ | ||||
| @@ -0,0 +1,57 @@ | |||||
| // | |||||
| // Lol Engine | |||||
| // | |||||
| // Copyright: (c) 2016—2017 Sam Hocevar <sam@hocevar.net> | |||||
| // Copyright © 2016—2017 Benjamin “Touky” Huet <huet.benjamin@gmail.com> | |||||
| // | |||||
| // 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 "<ResourceCodec>"; } | |||||
| 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 */ | |||||
| @@ -0,0 +1,121 @@ | |||||
| // | |||||
| // Lol Engine | |||||
| // | |||||
| // Copyright © 2016—2017 Sam Hocevar <sam@hocevar.net> | |||||
| // Copyright © 2016—2017 Benjamin “Touky” Huet <huet.benjamin@gmail.com> | |||||
| // | |||||
| // 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 <lol/engine-internal.h> | |||||
| #include "resource-private.h" | |||||
| #include <algorithm> /* 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<ResourceCodec *> &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<ResourceCodec *> 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 */ | |||||
| @@ -148,6 +148,7 @@ | |||||
| <ClCompile Include="image\noise.cpp" /> | <ClCompile Include="image\noise.cpp" /> | ||||
| <ClCompile Include="image\pixel.cpp" /> | <ClCompile Include="image\pixel.cpp" /> | ||||
| <ClCompile Include="image\resample.cpp" /> | <ClCompile Include="image\resample.cpp" /> | ||||
| <ClCompile Include="image\resource.cpp" /> | |||||
| <ClCompile Include="input\controller.cpp" /> | <ClCompile Include="input\controller.cpp" /> | ||||
| <ClCompile Include="input\input.cpp" /> | <ClCompile Include="input\input.cpp" /> | ||||
| <ClCompile Include="light.cpp" /> | <ClCompile Include="light.cpp" /> | ||||
| @@ -238,6 +239,7 @@ | |||||
| <ClInclude Include="forge.h" /> | <ClInclude Include="forge.h" /> | ||||
| <ClInclude Include="gradient.h" /> | <ClInclude Include="gradient.h" /> | ||||
| <ClInclude Include="image\image-private.h" /> | <ClInclude Include="image\image-private.h" /> | ||||
| <ClInclude Include="image\resource-private.h" /> | |||||
| <ClInclude Include="input\controller.h" /> | <ClInclude Include="input\controller.h" /> | ||||
| <ClInclude Include="input\input.h" /> | <ClInclude Include="input\input.h" /> | ||||
| <ClInclude Include="input\input_internal.h" /> | <ClInclude Include="input\input_internal.h" /> | ||||
| @@ -285,6 +287,7 @@ | |||||
| <ClInclude Include="lol\image\image.h" /> | <ClInclude Include="lol\image\image.h" /> | ||||
| <ClInclude Include="lol\image\movie.h" /> | <ClInclude Include="lol\image\movie.h" /> | ||||
| <ClInclude Include="lol\image\pixel.h" /> | <ClInclude Include="lol\image\pixel.h" /> | ||||
| <ClInclude Include="lol\image\resource.h" /> | |||||
| <ClInclude Include="lol\math\all.h" /> | <ClInclude Include="lol\math\all.h" /> | ||||
| <ClInclude Include="lol\math\arraynd.h" /> | <ClInclude Include="lol\math\arraynd.h" /> | ||||
| <ClInclude Include="lol\math\bigint.h" /> | <ClInclude Include="lol\math\bigint.h" /> | ||||
| @@ -397,4 +400,4 @@ | |||||
| <ImportGroup Label="ExtensionTargets"> | <ImportGroup Label="ExtensionTargets"> | ||||
| <Import Project="$(LolDir)\build\msbuild\lolfx.targets" /> | <Import Project="$(LolDir)\build\msbuild\lolfx.targets" /> | ||||
| </ImportGroup> | </ImportGroup> | ||||
| </Project> | |||||
| </Project> | |||||
| @@ -15,5 +15,6 @@ | |||||
| #include <lol/image/pixel.h> | #include <lol/image/pixel.h> | ||||
| #include <lol/image/color.h> | #include <lol/image/color.h> | ||||
| #include <lol/image/image.h> | #include <lol/image/image.h> | ||||
| #include <lol/image/resource.h> | |||||
| #include <lol/image/movie.h> | #include <lol/image/movie.h> | ||||
| @@ -106,9 +106,6 @@ public: | |||||
| template<typename T> | template<typename T> | ||||
| void Unlock2D(array2d<T> const &); | void Unlock2D(array2d<T> const &); | ||||
| /* XXX: this does not belong here */ | |||||
| bool RetrieveTiles(array<ivec2, ivec2>& tiles) const; | |||||
| /* Image processing kernels */ | /* Image processing kernels */ | ||||
| static array2d<float> BayerKernel(ivec2 size); | static array2d<float> BayerKernel(ivec2 size); | ||||
| static array2d<float> HalftoneKernel(ivec2 size); | static array2d<float> HalftoneKernel(ivec2 size); | ||||
| @@ -0,0 +1,74 @@ | |||||
| // | |||||
| // Lol Engine | |||||
| // | |||||
| // Copyright © 2016—2017 Sam Hocevar <sam@hocevar.net> | |||||
| // Copyright © 2016—2017 Benjamin “Touky” Huet <huet.benjamin@gmail.com> | |||||
| // | |||||
| // 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 <lol/math/arraynd.h> | |||||
| #include <lol/math/vector.h> | |||||
| #include <lol/math/geometry.h> | |||||
| #include <lol/image/pixel.h> | |||||
| 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<ivec2, ivec2> m_tiles; | |||||
| }; | |||||
| //ResourceLoader -------------------------------------------------------------- | |||||
| class ResourceLoader | |||||
| { | |||||
| public: | |||||
| static ResourceCodecData* Load(char const *path); | |||||
| static bool Save(char const *path, ResourceCodecData* data); | |||||
| }; | |||||
| } /* namespace lol */ | |||||
| @@ -278,10 +278,10 @@ void SdlInputData::Tick(float seconds) | |||||
| # endif | # endif | ||||
| { | { | ||||
| //Lock management | //Lock management | ||||
| # if defined SDLOL_CapsLock && defined SDLOL_ScrollLock && defined SDLOL_NumLockClear | |||||
| case SDLOL_CapsLock: | case SDLOL_CapsLock: | ||||
| case SDLOL_ScrollLock: | case SDLOL_ScrollLock: | ||||
| case SDLOL_NumLockClear: | case SDLOL_NumLockClear: | ||||
| # if defined SDLOL_CapsLock && defined SDLOL_ScrollLock && defined SDLOL_NumLockClear | |||||
| //Update status on key down only | //Update status on key down only | ||||
| if (event.type == SDL_KEYDOWN) | if (event.type == SDL_KEYDOWN) | ||||
| { | { | ||||
| @@ -104,6 +104,13 @@ void init(int argc, char *argv[], | |||||
| rootdir += "../src/"; /* FIXME: use SEPARATOR? */ | rootdir += "../src/"; /* FIXME: use SEPARATOR? */ | ||||
| add_data_dir(rootdir); | 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 */ | /* This data dir is for project-specific stuff */ | ||||
| rootdir = projectdir; | rootdir = projectdir; | ||||
| if (rootdir.count() && rootdir.last() != SEPARATOR) | if (rootdir.count() && rootdir.last() != SEPARATOR) | ||||
| @@ -57,7 +57,19 @@ TextureImage::~TextureImage() | |||||
| void TextureImage::Init(char const *path) | 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<ResourceImageData*>(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) | void TextureImage::Init(char const *path, Image* image) | ||||
| @@ -18,6 +18,7 @@ | |||||
| // zero, the texture is freed. | // zero, the texture is freed. | ||||
| // | // | ||||
| #include <lol/image/resource.h> | |||||
| #include <lol/image/image.h> | #include <lol/image/image.h> | ||||
| #include <lol/gpu/texture.h> | #include <lol/gpu/texture.h> | ||||
| @@ -43,6 +44,7 @@ public: | |||||
| protected: | protected: | ||||
| void Init(char const *path); | void Init(char const *path); | ||||
| virtual void Init(char const *path, ResourceCodecData* loaded_data); | |||||
| virtual void Init(char const *path, Image* image); | virtual void Init(char const *path, Image* image); | ||||
| protected: | protected: | ||||
| @@ -46,25 +46,25 @@ protected: | |||||
| */ | */ | ||||
| TileSet::TileSet(char const *path) | 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_tileset_data(new TileSetData()), | ||||
| m_palette(nullptr) | m_palette(nullptr) | ||||
| { | { | ||||
| array<ivec2, ivec2> 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<ivec2, ivec2>& tiles) | |||||
| : TextureImage(path, image), | |||||
| m_tileset_data(new TileSetData()), | m_tileset_data(new TileSetData()), | ||||
| m_palette(nullptr) | m_palette(nullptr) | ||||
| { | { | ||||
| array<ivec2, ivec2> 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) | TileSet::TileSet(char const *path, ivec2 size, ivec2 count) | ||||
| @@ -118,6 +118,20 @@ TileSet::~TileSet() | |||||
| delete m_tileset_data; | delete m_tileset_data; | ||||
| } | } | ||||
| void TileSet::Init(char const *path, ResourceCodecData* loaded_data) | |||||
| { | |||||
| //Load tileset if available | |||||
| auto tileset_data = dynamic_cast<ResourceTilesetData*>(loaded_data); | |||||
| if (tileset_data != nullptr) | |||||
| { | |||||
| define_tile(tileset_data->m_tiles); | |||||
| } | |||||
| m_data->m_name = String("<tileset> ") + path; | |||||
| super::Init(path, loaded_data); | |||||
| } | |||||
| void TileSet::Init(char const *path, Image* image) | void TileSet::Init(char const *path, Image* image) | ||||
| { | { | ||||
| super::Init(path, image); | super::Init(path, image); | ||||
| @@ -132,6 +146,11 @@ char const *TileSet::GetName() | |||||
| } | } | ||||
| //New methods ----------------------------------------------------------------- | //New methods ----------------------------------------------------------------- | ||||
| void TileSet::clear_all() | |||||
| { | |||||
| m_tileset_data->m_tiles.empty(); | |||||
| } | |||||
| int TileSet::define_tile(ibox2 rect) | int TileSet::define_tile(ibox2 rect) | ||||
| { | { | ||||
| m_tileset_data->m_tiles.push(rect, | m_tileset_data->m_tiles.push(rect, | ||||
| @@ -152,6 +171,18 @@ void TileSet::define_tile(ivec2 count) | |||||
| } | } | ||||
| } | } | ||||
| void TileSet::define_tile(array<ibox2>& tiles) | |||||
| { | |||||
| for (int i = 0; i < tiles.count(); i++) | |||||
| define_tile(tiles[i]); | |||||
| } | |||||
| void TileSet::define_tile(array<ivec2, ivec2>& 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 | int TileSet::GetTileCount() const | ||||
| { | { | ||||
| return m_tileset_data->m_tiles.count(); | return m_tileset_data->m_tiles.count(); | ||||
| @@ -43,6 +43,7 @@ class TileSet : public TextureImage | |||||
| public: | public: | ||||
| TileSet(char const *path); | TileSet(char const *path); | ||||
| TileSet(char const *path, Image* image); | TileSet(char const *path, Image* image); | ||||
| TileSet(char const *path, Image* image, array<ivec2, ivec2>& tiles); | |||||
| /* Old style: path to PNG file */ | /* Old style: path to PNG file */ | ||||
| TileSet(char const *path, ivec2 size, ivec2 count); | TileSet(char const *path, ivec2 size, ivec2 count); | ||||
| @@ -51,6 +52,7 @@ public: | |||||
| virtual ~TileSet(); | virtual ~TileSet(); | ||||
| protected: | protected: | ||||
| virtual void Init(char const *path, ResourceCodecData* loaded_data); | |||||
| virtual void Init(char const *path, Image* image); | virtual void Init(char const *path, Image* image); | ||||
| public: | public: | ||||
| @@ -58,8 +60,11 @@ public: | |||||
| virtual char const *GetName(); | virtual char const *GetName(); | ||||
| /* New methods */ | /* New methods */ | ||||
| void clear_all(); | |||||
| int define_tile(ibox2 rect); | int define_tile(ibox2 rect); | ||||
| void define_tile(ivec2 count); | void define_tile(ivec2 count); | ||||
| void define_tile(array<ibox2>& tiles); | |||||
| void define_tile(array<ivec2, ivec2>& tiles); | |||||
| int GetTileCount() const; | int GetTileCount() const; | ||||
| ivec2 GetTileSize(int tileid) const; | ivec2 GetTileSize(int tileid) const; | ||||
| ibox2 GetTilePixel(int tileid) const; | ibox2 GetTilePixel(int tileid) const; | ||||