objects themselves.undefined
| @@ -35,7 +35,7 @@ extern ANativeActivity *g_activity; | |||
| * Image implementation class | |||
| */ | |||
| DECLARE_IMAGE_CODEC(AndroidImageCodec, 100) | |||
| class AndroidImageCodec : public ImageCodec | |||
| { | |||
| public: | |||
| virtual bool Load(Image *image, char const *path); | |||
| @@ -50,6 +50,8 @@ private: | |||
| jint *pixels; | |||
| }; | |||
| DECLARE_IMAGE_CODEC(AndroidImageCodec, 100) | |||
| bool AndroidImageCodec::Load(Image *image, char const *path) | |||
| { | |||
| JNIEnv *env; | |||
| @@ -24,14 +24,15 @@ namespace lol | |||
| * Image implementation class | |||
| */ | |||
| DECLARE_IMAGE_CODEC(DummyImageCodec, 0) | |||
| class DummyImageCodec : public ImageCodec | |||
| { | |||
| public: | |||
| virtual bool Load(Image *image, char const *path); | |||
| virtual bool Save(Image *image, char const *path); | |||
| virtual bool Close(); | |||
| }; | |||
| DECLARE_IMAGE_CODEC(DummyImageCodec, 0) | |||
| /* | |||
| * Public Image class | |||
| */ | |||
| @@ -63,10 +64,5 @@ bool DummyImageCodec::Save(Image *image, char const *path) | |||
| return true; | |||
| } | |||
| bool DummyImageCodec::Close() | |||
| { | |||
| return true; | |||
| } | |||
| } /* namespace lol */ | |||
| @@ -31,20 +31,15 @@ namespace lol | |||
| * Image implementation class | |||
| */ | |||
| DECLARE_IMAGE_CODEC(GdiPlusImageCodec, 100) | |||
| class GdiPlusImageCodec : public ImageCodec | |||
| { | |||
| public: | |||
| virtual bool Load(Image *image, char const *path); | |||
| virtual bool Save(Image *image, char const *path); | |||
| virtual bool Close(); | |||
| virtual uint8_t *GetData() const; | |||
| private: | |||
| Gdiplus::Bitmap *m_bitmap; | |||
| Gdiplus::BitmapData m_bdata; | |||
| }; | |||
| DECLARE_IMAGE_CODEC(GdiPlusImageCodec, 100) | |||
| /* | |||
| * Public Image class | |||
| */ | |||
| @@ -64,7 +59,7 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) | |||
| } | |||
| Array<String> pathlist = System::GetPathList(path); | |||
| m_bitmap = nullptr; | |||
| Gdiplus::Bitmap *bitmap = nullptr; | |||
| for (auto fullpath : pathlist) | |||
| { | |||
| size_t len; | |||
| @@ -80,11 +75,11 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) | |||
| } | |||
| status = Gdiplus::Ok; | |||
| m_bitmap = Gdiplus::Bitmap::FromFile(wpath, 0); | |||
| bitmap = Gdiplus::Bitmap::FromFile(wpath, 0); | |||
| if (m_bitmap) | |||
| if (bitmap) | |||
| { | |||
| status = m_bitmap->GetLastStatus(); | |||
| status = bitmap->GetLastStatus(); | |||
| if (status != Gdiplus::Ok) | |||
| { | |||
| #if !LOL_BUILD_RELEASE | |||
| @@ -92,17 +87,17 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) | |||
| Log::Error("error %d loading %s\n", | |||
| status, fullpath.C()); | |||
| #endif | |||
| delete m_bitmap; | |||
| m_bitmap = nullptr; | |||
| delete bitmap; | |||
| bitmap = nullptr; | |||
| } | |||
| } | |||
| delete[] wpath; | |||
| if (m_bitmap) | |||
| if (bitmap) | |||
| break; | |||
| } | |||
| if (!m_bitmap) | |||
| if (!bitmap) | |||
| { | |||
| #if !LOL_BUILD_RELEASE | |||
| Log::Error("could not load %s\n", path); | |||
| @@ -110,33 +105,32 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path) | |||
| return false; | |||
| } | |||
| image->m_data->m_size = ivec2(m_bitmap->GetWidth(), | |||
| m_bitmap->GetHeight()); | |||
| image->m_data->m_format = PixelFormat::RGBA_8; | |||
| Gdiplus::Rect rect(0, 0, image->m_data->m_size.x, image->m_data->m_size.y); | |||
| if (m_bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead, | |||
| PixelFormat32bppARGB, &m_bdata) != Gdiplus::Ok) | |||
| ivec2 size(bitmap->GetWidth(), bitmap->GetHeight()); | |||
| Gdiplus::Rect rect(0, 0, size.x, size.y); | |||
| Gdiplus::BitmapData bdata; | |||
| if (bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead, | |||
| PixelFormat32bppARGB, &bdata) != Gdiplus::Ok) | |||
| { | |||
| #if !LOL_BUILD_RELEASE | |||
| Log::Error("could not lock bits in %s\n", path); | |||
| #endif | |||
| delete m_bitmap; | |||
| delete bitmap; | |||
| return false; | |||
| } | |||
| /* 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. */ | |||
| uint8_t *p = static_cast<uint8_t *>(m_bdata.Scan0); | |||
| for (int y = 0; y < image->m_data->m_size.y; y++) | |||
| for (int x = 0; x < image->m_data->m_size.x; x++) | |||
| { | |||
| uint8_t tmp = p[2]; | |||
| p[2] = p[0]; | |||
| p[0] = tmp; | |||
| p += 4; | |||
| } | |||
| image->SetSize(size); | |||
| u8vec4 *pixels = image->Lock<PixelFormat::RGBA_8>(); | |||
| u8vec4 *source = static_cast<u8vec4 *>(bdata.Scan0); | |||
| for (int y = 0; y < size.y; y++) | |||
| for (int x = 0; x < size.x; x++) | |||
| *pixels++ = (*source++).bgra; | |||
| image->Unlock(); | |||
| bitmap->UnlockBits(&bdata); | |||
| delete bitmap; | |||
| return true; | |||
| } | |||
| @@ -159,16 +153,16 @@ bool GdiPlusImageCodec::Save(Image *image, char const *path) | |||
| else /* if (strstr(path, ".bmp")) */ | |||
| fmt = L"image/bmp"; | |||
| unsigned int num = 0, size = 0; | |||
| Gdiplus::GetImageEncodersSize(&num, &size); | |||
| unsigned int num = 0, encoder_size = 0; | |||
| Gdiplus::GetImageEncodersSize(&num, &encoder_size); | |||
| if (num == 0) | |||
| { | |||
| Log::Error("no GDI+ image encoders found\n"); | |||
| return false; | |||
| } | |||
| Gdiplus::ImageCodecInfo *codecs | |||
| = (Gdiplus::ImageCodecInfo *)new uint8_t[size]; | |||
| Gdiplus::GetImageEncoders(num, size, codecs); | |||
| = (Gdiplus::ImageCodecInfo *)new uint8_t[encoder_size]; | |||
| Gdiplus::GetImageEncoders(num, encoder_size, codecs); | |||
| CLSID clsid; | |||
| for (unsigned int i = 0; i < num; i++) | |||
| { | |||
| @@ -190,15 +184,16 @@ bool GdiPlusImageCodec::Save(Image *image, char const *path) | |||
| return false; | |||
| } | |||
| ivec2 size = image->GetSize(); | |||
| /* FIXME: we create a new image because there is no guarantee that | |||
| * the image comes from GDI. But the engine architecture doesn't | |||
| * allow us to save other images anyway. */ | |||
| Gdiplus::Bitmap *b = new Gdiplus::Bitmap(image->m_data->m_size.x, | |||
| image->m_data->m_size.y, | |||
| Gdiplus::Bitmap *b = new Gdiplus::Bitmap(size.x, size.y, | |||
| PixelFormat32bppARGB); | |||
| Gdiplus::BitmapData bdata; | |||
| Gdiplus::Rect rect(0, 0, image->m_data->m_size.x, image->m_data->m_size.y); | |||
| Gdiplus::Rect rect(0, 0, size.x, size.y); | |||
| if (b->LockBits(&rect, (unsigned int)Gdiplus::ImageLockModeWrite, | |||
| PixelFormat32bppARGB, &bdata) != Gdiplus::Ok) | |||
| @@ -210,14 +205,12 @@ bool GdiPlusImageCodec::Save(Image *image, char const *path) | |||
| return false; | |||
| } | |||
| u8vec4 *psrc = static_cast<u8vec4 *>(m_bdata.Scan0); | |||
| u8vec4 *psrc = image->Lock<PixelFormat::RGBA_8>(); | |||
| u8vec4 *pdst = static_cast<u8vec4 *>(bdata.Scan0); | |||
| for (int y = 0; y < image->m_data->m_size.y; y++) | |||
| for (int x = 0; x < image->m_data->m_size.x; x++) | |||
| { | |||
| for (int y = 0; y < size.y; y++) | |||
| for (int x = 0; x < size.x; x++) | |||
| *pdst++ = (*psrc++).bgra; | |||
| } | |||
| image->Unlock(); | |||
| b->UnlockBits(&bdata); | |||
| if (b->Save(wpath, &clsid, NULL) != Gdiplus::Ok) | |||
| @@ -235,19 +228,6 @@ bool GdiPlusImageCodec::Save(Image *image, char const *path) | |||
| return true; | |||
| } | |||
| bool GdiPlusImageCodec::Close() | |||
| { | |||
| m_bitmap->UnlockBits(&m_bdata); | |||
| delete m_bitmap; | |||
| return true; | |||
| } | |||
| uint8_t * GdiPlusImageCodec::GetData() const | |||
| { | |||
| return static_cast<uint8_t *>(m_bdata.Scan0); | |||
| } | |||
| } /* namespace lol */ | |||
| #endif /* defined USE_GDIPLUS */ | |||
| @@ -28,19 +28,15 @@ namespace lol | |||
| * Image implementation class | |||
| */ | |||
| DECLARE_IMAGE_CODEC(IosImageCodec, 100) | |||
| class IosImageCodec : public ImageCodec | |||
| { | |||
| public: | |||
| virtual bool Load(Image *image, char const *path); | |||
| virtual bool Save(Image *image, char const *path); | |||
| virtual bool Close(); | |||
| virtual uint8_t *GetData() const; | |||
| private: | |||
| uint8_t *pixels; | |||
| }; | |||
| DECLARE_IMAGE_CODEC(IosImageCodec, 100) | |||
| /* | |||
| * Public Image class | |||
| */ | |||
| @@ -30,7 +30,7 @@ namespace lol | |||
| * Image implementation class | |||
| */ | |||
| DECLARE_IMAGE_CODEC(Ps3ImageCodec, 100) | |||
| class Ps3ImageCodec : public ImageCodec | |||
| { | |||
| public: | |||
| virtual bool Load(Image *image, char const *path); | |||
| @@ -42,9 +42,10 @@ public: | |||
| private: | |||
| static void* Malloc(uint32_t size, void* data) { return malloc(size); }; | |||
| static int32_t Free(void* ptr, void* data) { free(ptr); return 0; }; | |||
| uint8_t *pixels; | |||
| }; | |||
| DECLARE_IMAGE_CODEC(Ps3ImageCodec, 100) | |||
| /* | |||
| * Public Image class | |||
| */ | |||
| @@ -37,34 +37,34 @@ namespace lol | |||
| * Image implementation class | |||
| */ | |||
| DECLARE_IMAGE_CODEC(SdlImageCodec, 50) | |||
| class SdlImageCodec : public ImageCodec | |||
| { | |||
| public: | |||
| virtual bool Load(Image *image, char const *path); | |||
| virtual bool Save(Image *image, char const *path); | |||
| virtual bool Close(); | |||
| static SDL_Surface *Create32BppSurface(ivec2 size); | |||
| private: | |||
| SDL_Surface *m_surface; | |||
| }; | |||
| DECLARE_IMAGE_CODEC(SdlImageCodec, 50) | |||
| /* | |||
| * Public Image class | |||
| */ | |||
| bool SdlImageCodec::Load(Image *image, char const *path) | |||
| { | |||
| SDL_Surface *surface = nullptr; | |||
| Array<String> pathlist = System::GetPathList(path); | |||
| for (int i = 0; i < pathlist.Count(); i++) | |||
| { | |||
| m_surface = IMG_Load(pathlist[i].C()); | |||
| if (m_surface) | |||
| surface = IMG_Load(pathlist[i].C()); | |||
| if (surface) | |||
| break; | |||
| } | |||
| if (!m_surface) | |||
| if (!surface) | |||
| { | |||
| #if !LOL_BUILD_RELEASE | |||
| Log::Error("could not load image %s\n", path); | |||
| @@ -72,34 +72,39 @@ bool SdlImageCodec::Load(Image *image, char const *path) | |||
| return false; | |||
| } | |||
| if (m_surface->format->BytesPerPixel != 4) | |||
| ivec2 size(surface->w, surface->h); | |||
| if (surface->format->BytesPerPixel != 4) | |||
| { | |||
| SDL_Surface *tmp = Create32BppSurface(image->GetSize()); | |||
| SDL_BlitSurface(m_surface, nullptr, tmp, nullptr); | |||
| SDL_FreeSurface(m_surface); | |||
| m_surface = tmp; | |||
| SDL_Surface *tmp = Create32BppSurface(size); | |||
| SDL_BlitSurface(surface, nullptr, tmp, nullptr); | |||
| SDL_FreeSurface(surface); | |||
| surface = tmp; | |||
| } | |||
| image->SetSize(ivec2(m_surface->w, m_surface->h)); | |||
| image->SetSize(size); | |||
| u8vec4 *data = image->Lock<PixelFormat::RGBA_8>(); | |||
| memcpy(data, m_surface->pixels, 4 * m_surface->w * m_surface->h); | |||
| memcpy(data, surface->pixels, 4 * size.x * size.y); | |||
| image->Unlock(); | |||
| SDL_FreeSurface(surface); | |||
| return true; | |||
| } | |||
| bool SdlImageCodec::Save(Image *image, char const *path) | |||
| { | |||
| int ret = SDL_SaveBMP(m_surface, path); | |||
| ivec2 size = image->GetSize(); | |||
| SDL_Surface *surface = Create32BppSurface(size); | |||
| return ret == 0; | |||
| } | |||
| u8vec4 *data = image->Lock<PixelFormat::RGBA_8>(); | |||
| memcpy(surface->pixels, data, 4 * size.x * size.y); | |||
| image->Unlock(); | |||
| bool SdlImageCodec::Close() | |||
| { | |||
| SDL_FreeSurface(m_surface); | |||
| int ret = SDL_SaveBMP(surface, path); | |||
| SDL_FreeSurface(surface); | |||
| return true; | |||
| return ret == 0; | |||
| } | |||
| SDL_Surface *SdlImageCodec::Create32BppSurface(ivec2 size) | |||
| @@ -25,14 +25,12 @@ namespace lol | |||
| * Image implementation class | |||
| */ | |||
| DECLARE_IMAGE_CODEC(ZedImageCodec, 0) | |||
| class ZedImageCodec : public ImageCodec | |||
| { | |||
| public: | |||
| virtual bool Load(Image *image, char const *path); | |||
| virtual bool Save(Image *image, char const *path); | |||
| virtual bool Close(); | |||
| virtual uint8_t *GetData() const; | |||
| virtual bool RetrieveTiles(Array<ivec2, ivec2>& tiles) | |||
| { | |||
| bool result = m_tiles.Count() > 0; | |||
| @@ -47,6 +45,8 @@ private: | |||
| Array<ivec2, ivec2> m_tiles; | |||
| }; | |||
| DECLARE_IMAGE_CODEC(ZedImageCodec, 0) | |||
| /* | |||
| * Public Image class | |||
| */ | |||
| @@ -307,15 +307,5 @@ bool ZedImageCodec::Save(Image *image, char const *path) | |||
| return true; | |||
| } | |||
| bool ZedImageCodec::Close() | |||
| { | |||
| return true; | |||
| } | |||
| uint8_t * ZedImageCodec::GetData() const | |||
| { | |||
| return m_pixels; | |||
| } | |||
| } /* namespace lol */ | |||
| @@ -24,14 +24,15 @@ namespace lol | |||
| * Image implementation class | |||
| */ | |||
| DECLARE_IMAGE_CODEC(ZedPaletteImageCodec, 0) | |||
| class ZedPaletteImageCodec : public ImageCodec | |||
| { | |||
| public: | |||
| virtual bool Load(Image *image, char const *path); | |||
| virtual bool Save(Image *image, char const *path); | |||
| virtual bool Close(); | |||
| }; | |||
| DECLARE_IMAGE_CODEC(ZedPaletteImageCodec, 0) | |||
| /* | |||
| * Public Image class | |||
| */ | |||
| @@ -86,10 +87,5 @@ bool ZedPaletteImageCodec::Save(Image *image, char const *path) | |||
| return true; | |||
| } | |||
| bool ZedPaletteImageCodec::Close() | |||
| { | |||
| return true; | |||
| } | |||
| } /* namespace lol */ | |||
| @@ -22,121 +22,50 @@ namespace lol | |||
| class ImageData | |||
| { | |||
| friend class Image; | |||
| friend class ImageBank; | |||
| friend class ImageCodec; | |||
| public: | |||
| ImageData() | |||
| : m_size(0, 0), | |||
| m_format(PixelFormat::Unknown), | |||
| m_refcount(0), | |||
| m_codecdata(nullptr) | |||
| m_format(PixelFormat::Unknown) | |||
| {} | |||
| ivec2 m_size; | |||
| Map<int, void *> m_pixels; | |||
| PixelFormat m_format; | |||
| int m_refcount; | |||
| /* protected: */ /* FIXME: fix the ImageCodec subclasses access rights */ | |||
| class ImageCodecData *m_codecdata; | |||
| }; | |||
| class ImageCodec | |||
| { | |||
| friend class ImageBank; | |||
| friend class ImageCodecData; | |||
| public: | |||
| bool (*m_tryload)(Image *image, char const *path); | |||
| ImageCodec *m_next; | |||
| int m_priority; | |||
| static void RegisterCodec(ImageCodec *codec) | |||
| { | |||
| Helper(codec); | |||
| } | |||
| private: | |||
| static void Load(Image *image, char const *path) | |||
| { | |||
| ImageCodec *codec = Helper(nullptr); | |||
| bool success = false; | |||
| while (codec && !success) | |||
| { | |||
| success = codec->m_tryload(image, path); | |||
| codec = codec->m_next; | |||
| } | |||
| } | |||
| static ImageCodec *Helper(ImageCodec *set) | |||
| { | |||
| static ImageCodec *codec_list = nullptr; | |||
| if (!set) | |||
| return codec_list; | |||
| ImageCodec **codec = &codec_list; | |||
| while (*codec && (*codec)->m_priority > set->m_priority) | |||
| codec = &(*codec)->m_next; | |||
| set->m_next = *codec; | |||
| *codec = set; | |||
| return nullptr; | |||
| } | |||
| }; | |||
| /* | |||
| * Codec-specific data that is stored in some images | |||
| */ | |||
| class ImageCodecData | |||
| { | |||
| friend class Image; | |||
| friend class ImageBank; | |||
| public: | |||
| inline ImageCodecData() {} | |||
| virtual ~ImageCodecData() {} | |||
| virtual bool Load(Image *, char const *) = 0; | |||
| virtual bool Save(Image *, char const *) = 0; | |||
| virtual bool Load(Image *image, char const *path) = 0; | |||
| virtual bool Save(Image *image, char const *path) = 0; | |||
| virtual bool RetrieveTiles(Array<ivec2, ivec2>& tiles) { return false; } | |||
| /* TODO: this should become more fine-grained */ | |||
| int m_priority; | |||
| }; | |||
| #define REGISTER_IMAGE_CODEC(name) \ | |||
| extern void Register##name(); \ | |||
| Register##name(); | |||
| #define DECLARE_IMAGE_CODEC(name, prio) \ | |||
| template<typename T> class name##ImageCodec : public ImageCodec \ | |||
| extern ImageCodec *Register##name(); \ | |||
| { \ | |||
| public: \ | |||
| name##ImageCodec() \ | |||
| { \ | |||
| static ImageCodec codec; \ | |||
| codec.m_tryload = Load; \ | |||
| codec.m_priority = prio; \ | |||
| RegisterCodec(&codec); \ | |||
| } \ | |||
| static bool Load(Image *image, char const *path) \ | |||
| /* Insert image codecs in a sorted list */ \ | |||
| ImageCodec *codec = Register##name(); \ | |||
| int i = 0, prio = codec->m_priority; \ | |||
| for ( ; i < codeclist.Count(); ++i) \ | |||
| { \ | |||
| T *codecdata = new T(); \ | |||
| bool ret = codecdata->Load(image, path); \ | |||
| delete codecdata; \ | |||
| return ret; \ | |||
| if (codeclist[i]->m_priority <= prio) \ | |||
| break; \ | |||
| } \ | |||
| }; \ | |||
| class name; \ | |||
| name##ImageCodec<name> name##ImageCodecInstance; \ | |||
| void Register##name() \ | |||
| codeclist.Insert(codec, i); \ | |||
| } | |||
| #define DECLARE_IMAGE_CODEC(name, priority) \ | |||
| ImageCodec *Register##name() \ | |||
| { \ | |||
| (void)&name##ImageCodecInstance; \ | |||
| } \ | |||
| class name : public ImageCodecData | |||
| ImageCodec *ret = new name(); \ | |||
| ret->m_priority = priority; \ | |||
| return ret; \ | |||
| } | |||
| } /* namespace lol */ | |||
| @@ -30,7 +30,7 @@ namespace lol | |||
| * 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() | |||
| static bool RegisterAllCodecs(Array<ImageCodec *> &codeclist) | |||
| { | |||
| #if defined __ANDROID__ | |||
| REGISTER_IMAGE_CODEC(AndroidImageCodec) | |||
| @@ -61,90 +61,74 @@ static bool RegisterAllCodecs() | |||
| static class ImageBank | |||
| { | |||
| public: | |||
| void Init(); | |||
| Image *Create(char const *path); | |||
| ImageBank(); | |||
| void Unref(Image *img); | |||
| bool Load(Image *image, char const *path); | |||
| bool Save(Image *image, char const *path); | |||
| private: | |||
| Array<ImageCodec *> m_codecs; | |||
| Map<String, Image *> m_images; | |||
| } | |||
| g_image_bank; | |||
| void ImageBank::Init() | |||
| ImageBank::ImageBank() | |||
| { | |||
| /* Initialise codecs (see above) */ | |||
| static bool init = RegisterAllCodecs(); | |||
| UNUSED(init); | |||
| RegisterAllCodecs(m_codecs); | |||
| } | |||
| Image *ImageBank::Create(char const *path) | |||
| bool ImageBank::Load(Image *image, char const *path) | |||
| { | |||
| Init(); | |||
| /* Is our image already in the bank? If so, no need to create it. */ | |||
| if (!m_images.HasKey(path)) | |||
| { | |||
| m_images[path] = new Image(); | |||
| ImageCodec::Load(m_images[path], path); | |||
| } | |||
| Image *img = m_images[path]; | |||
| ++img->m_data->m_refcount; | |||
| return img; | |||
| /* FIXME: priority is ignored */ | |||
| for (auto codec : m_codecs) | |||
| if (codec->Load(image, path)) | |||
| return true; | |||
| return false; | |||
| } | |||
| void ImageBank::Unref(Image *img) | |||
| bool ImageBank::Save(Image *image, char const *path) | |||
| { | |||
| ASSERT(img->m_data->m_refcount > 0); | |||
| if (--img->m_data->m_refcount == 0) | |||
| { | |||
| /* FIXME: unload images etc. here */ | |||
| /* XXX: we’re gonna hit a problem here because we didn’t keep | |||
| * the image path within the object, so unless we store it | |||
| * ourselves we’re good for a O(n) lookup… which we can’t do | |||
| * on Map objects anyway. */ | |||
| /* TODO: 1. remove image from Map | |||
| 2. delete img; */ | |||
| } | |||
| /* FIXME: priority is ignored */ | |||
| for (auto codec : m_codecs) | |||
| if (codec->Save(image, path)) | |||
| return true; | |||
| return false; | |||
| } | |||
| /* | |||
| * Static image methods | |||
| * Public Image class | |||
| */ | |||
| Image *Image::Create(char const *path) | |||
| Image::Image() | |||
| : m_data(new ImageData()) | |||
| { | |||
| return g_image_bank.Create(path); | |||
| } | |||
| /* | |||
| * Public Image class | |||
| */ | |||
| Image::Image(char const *path) | |||
| : m_data(new ImageData()) | |||
| { | |||
| Load(path); | |||
| } | |||
| Image::Image() | |||
| Image::Image(ivec2 size) | |||
| : m_data(new ImageData()) | |||
| { | |||
| SetSize(size); | |||
| } | |||
| Image::~Image() | |||
| { | |||
| delete m_data->m_codecdata; | |||
| delete m_data; | |||
| } | |||
| void Image::Destroy() | |||
| bool Image::Load(char const *path) | |||
| { | |||
| g_image_bank.Unref(this); | |||
| return g_image_bank.Load(this, path); | |||
| } | |||
| bool Image::Save(char const *path) | |||
| { | |||
| /* FIXME: add autoloading of save codecs */ | |||
| if (!m_data->m_codecdata) | |||
| return false; | |||
| return m_data->m_codecdata->Save(this, path); | |||
| return g_image_bank.Save(this, path); | |||
| } | |||
| ivec2 Image::GetSize() const | |||
| @@ -177,13 +161,6 @@ PixelFormat Image::GetFormat() const | |||
| return m_data->m_format; | |||
| } | |||
| void *Image::LockGeneric() | |||
| { | |||
| ASSERT(m_data->m_format != PixelFormat::Unknown); | |||
| return m_data->m_pixels[(int)m_data->m_format]; | |||
| } | |||
| /* The Lock() method and its explicit specialisations */ | |||
| template<PixelFormat T> | |||
| typename PixelType<T>::type *Image::Lock() | |||
| @@ -195,19 +172,28 @@ typename PixelType<T>::type *Image::Lock() | |||
| if (!m_data->m_pixels.HasKey((int)T)) | |||
| { | |||
| m_data->m_pixels[(int)T] = | |||
| new typename PixelType<T>::type(m_data->m_size.x * m_data->m_size.y); | |||
| new typename PixelType<T>::type[m_data->m_size.x * m_data->m_size.y]; | |||
| } | |||
| return (typename PixelType<T>::type *)m_data->m_pixels[(int)T]; | |||
| } | |||
| template typename PixelType<PixelFormat::Y_8>::type * | |||
| template PixelType<PixelFormat::Y_8>::type * | |||
| Image::Lock<PixelFormat::Y_8>(); | |||
| template typename PixelType<PixelFormat::RGB_8>::type * | |||
| template PixelType<PixelFormat::RGB_8>::type * | |||
| Image::Lock<PixelFormat::RGB_8>(); | |||
| template typename PixelType<PixelFormat::RGBA_8>::type * | |||
| template PixelType<PixelFormat::RGBA_8>::type * | |||
| Image::Lock<PixelFormat::RGBA_8>(); | |||
| /* Special case for the "any" format */ | |||
| template<> | |||
| void *Image::Lock<PixelFormat::Unknown>() | |||
| { | |||
| ASSERT(m_data->m_format != PixelFormat::Unknown); | |||
| return m_data->m_pixels[(int)m_data->m_format]; | |||
| } | |||
| void Image::Unlock() | |||
| { | |||
| /* TODO: ensure we are actually unlocking something we locked */ | |||
| @@ -216,9 +202,9 @@ void Image::Unlock() | |||
| bool Image::RetrieveTiles(Array<ivec2, ivec2>& tiles) const | |||
| { | |||
| if (!m_data->m_codecdata) | |||
| return false; | |||
| return m_data->m_codecdata->RetrieveTiles(tiles); | |||
| /* TODO: re-implement this */ | |||
| //return m_data->m_codecdata->RetrieveTiles(tiles); | |||
| return false; | |||
| } | |||
| } /* namespace lol */ | |||
| @@ -21,7 +21,6 @@ | |||
| namespace lol | |||
| { | |||
| /* FIXME: is it possible to avoid the cast to int here? */ | |||
| template <PixelFormat T> struct PixelType { typedef void type; }; | |||
| template<> struct PixelType<PixelFormat::Y_8> { typedef uint8_t type; }; | |||
| template<> struct PixelType<PixelFormat::RGB_8> { typedef u8vec3 type; }; | |||
| @@ -29,31 +28,28 @@ template<> struct PixelType<PixelFormat::RGBA_8> { typedef u8vec4 type; }; | |||
| class Image | |||
| { | |||
| friend class ImageBank; | |||
| friend class ImageCodec; | |||
| public: | |||
| Image(); | |||
| Image(ivec2 size); | |||
| /* XXX: use of this ctor should be discouraged, as it will not | |||
| * return information about a possible error. */ | |||
| Image(char const *path); | |||
| ~Image(); | |||
| static Image *Create(char const *path); | |||
| bool Load(char const *path); | |||
| bool Save(char const *path); | |||
| void Destroy(); | |||
| ivec2 GetSize() const; | |||
| void SetSize(ivec2); | |||
| PixelFormat GetFormat() const; | |||
| void *LockGeneric(); | |||
| template<PixelFormat T> typename PixelType<T>::type *Lock(); | |||
| void Unlock(); | |||
| ivec2 GetSize() const; | |||
| void SetSize(ivec2); | |||
| bool RetrieveTiles(Array<ivec2, ivec2>& tiles) const; | |||
| private: | |||
| class ImageData *m_data; | |||
| String m_path; | |||
| }; | |||
| } /* namespace lol */ | |||
| @@ -140,7 +140,7 @@ TileSet::TileSet(char const *path, Image* image, ivec2 size, ivec2 count) | |||
| void TileSet::Init(char const *path) | |||
| { | |||
| Init(path, Image::Create(path)); | |||
| Init(path, new Image(path)); | |||
| } | |||
| void TileSet::Init(char const *path, Image* image) | |||
| @@ -190,7 +190,7 @@ void TileSet::TickDraw(float seconds) | |||
| { | |||
| if (m_data->m_image) | |||
| { | |||
| m_data->m_image->Destroy(); | |||
| delete m_data->m_image; | |||
| m_data->m_image = nullptr; | |||
| } | |||
| else | |||
| @@ -207,7 +207,7 @@ void TileSet::TickDraw(float seconds) | |||
| int w = m_data->m_texture_size.x; | |||
| int h = m_data->m_texture_size.y; | |||
| uint8_t *pixels = (uint8_t *)m_data->m_image->LockGeneric(); | |||
| uint8_t *pixels = (uint8_t *)m_data->m_image->Lock<PixelFormat::Unknown>(); | |||
| bool resized = false; | |||
| if (w != m_data->m_image_size.x || h != m_data->m_image_size.y) | |||
| { | |||
| @@ -225,7 +225,7 @@ void TileSet::TickDraw(float seconds) | |||
| if (resized) | |||
| delete[] pixels; | |||
| m_data->m_image->Destroy(); | |||
| delete m_data->m_image; | |||
| m_data->m_image = nullptr; | |||
| } | |||
| } | |||
| @@ -24,13 +24,13 @@ LOLUNIT_FIXTURE(ImageTest) | |||
| { | |||
| LOLUNIT_TEST(OpenImage) | |||
| { | |||
| Image *image = Image::Create("data/gradient.png"); | |||
| Image image("data/gradient.png"); | |||
| ivec2 size = image->GetSize(); | |||
| ivec2 size = image.GetSize(); | |||
| LOLUNIT_ASSERT_EQUAL(size.x, 256); | |||
| LOLUNIT_ASSERT_EQUAL(size.y, 16); | |||
| u8vec4 *data = image->Lock<PixelFormat::RGBA_8>(); | |||
| u8vec4 *data = image.Lock<PixelFormat::RGBA_8>(); | |||
| LOLUNIT_ASSERT(data); | |||
| LOLUNIT_ASSERT_EQUAL((int)data[0].r, 0x00); | |||
| @@ -41,8 +41,7 @@ LOLUNIT_FIXTURE(ImageTest) | |||
| LOLUNIT_ASSERT_EQUAL((int)data[255].g, 0xff); | |||
| LOLUNIT_ASSERT_EQUAL((int)data[255].b, 0xff); | |||
| image->Unlock(); | |||
| image->Destroy(); | |||
| image.Unlock(); | |||
| } | |||
| }; | |||