Bläddra i källkod

image: refactor codecs so that they no longer store anything in the image

objects themselves.
undefined
Sam Hocevar 10 år sedan
förälder
incheckning
227411f337
13 ändrade filer med 169 tillägg och 293 borttagningar
  1. +3
    -1
      src/image/codec/android-image.cpp
  2. +3
    -7
      src/image/codec/dummy-image.cpp
  3. +39
    -59
      src/image/codec/gdiplus-image.cpp
  4. +3
    -7
      src/image/codec/ios-image.cpp
  5. +3
    -2
      src/image/codec/ps3-image.cpp
  6. +27
    -22
      src/image/codec/sdl-image.cpp
  7. +3
    -13
      src/image/codec/zed-image.cpp
  8. +3
    -7
      src/image/codec/zed-palette-image.cpp
  9. +21
    -92
      src/image/image-private.h
  10. +48
    -62
      src/image/image.cpp
  11. +8
    -12
      src/lol/image/image.h
  12. +4
    -4
      src/tileset.cpp
  13. +4
    -5
      test/unit/image.cpp

+ 3
- 1
src/image/codec/android-image.cpp Visa fil

@@ -35,7 +35,7 @@ extern ANativeActivity *g_activity;
* Image implementation class * Image implementation class
*/ */


DECLARE_IMAGE_CODEC(AndroidImageCodec, 100) class AndroidImageCodec : public ImageCodec
{ {
public: public:
virtual bool Load(Image *image, char const *path); virtual bool Load(Image *image, char const *path);
@@ -50,6 +50,8 @@ private:
jint *pixels; jint *pixels;
}; };


DECLARE_IMAGE_CODEC(AndroidImageCodec, 100)

bool AndroidImageCodec::Load(Image *image, char const *path) bool AndroidImageCodec::Load(Image *image, char const *path)
{ {
JNIEnv *env; JNIEnv *env;


+ 3
- 7
src/image/codec/dummy-image.cpp Visa fil

@@ -24,14 +24,15 @@ namespace lol
* Image implementation class * Image implementation class
*/ */


DECLARE_IMAGE_CODEC(DummyImageCodec, 0) class DummyImageCodec : public ImageCodec
{ {
public: public:
virtual bool Load(Image *image, char const *path); virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path); virtual bool Save(Image *image, char const *path);
virtual bool Close();
}; };


DECLARE_IMAGE_CODEC(DummyImageCodec, 0)

/* /*
* Public Image class * Public Image class
*/ */
@@ -63,10 +64,5 @@ bool DummyImageCodec::Save(Image *image, char const *path)
return true; return true;
} }


bool DummyImageCodec::Close()
{
return true;
}

} /* namespace lol */ } /* namespace lol */



+ 39
- 59
src/image/codec/gdiplus-image.cpp Visa fil

@@ -31,20 +31,15 @@ namespace lol
* Image implementation class * Image implementation class
*/ */


DECLARE_IMAGE_CODEC(GdiPlusImageCodec, 100) class GdiPlusImageCodec : public ImageCodec
{ {
public: public:
virtual bool Load(Image *image, char const *path); virtual bool Load(Image *image, char const *path);
virtual bool Save(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 * Public Image class
*/ */
@@ -64,7 +59,7 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path)
} }


Array<String> pathlist = System::GetPathList(path); Array<String> pathlist = System::GetPathList(path);
m_bitmap = nullptr; Gdiplus::Bitmap *bitmap = nullptr;
for (auto fullpath : pathlist) for (auto fullpath : pathlist)
{ {
size_t len; size_t len;
@@ -80,11 +75,11 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path)
} }


status = Gdiplus::Ok; 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 (status != Gdiplus::Ok)
{ {
#if !LOL_BUILD_RELEASE #if !LOL_BUILD_RELEASE
@@ -92,17 +87,17 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path)
Log::Error("error %d loading %s\n", Log::Error("error %d loading %s\n",
status, fullpath.C()); status, fullpath.C());
#endif #endif
delete m_bitmap; delete bitmap;
m_bitmap = nullptr; bitmap = nullptr;
} }
} }


delete[] wpath; delete[] wpath;
if (m_bitmap) if (bitmap)
break; break;
} }


if (!m_bitmap) if (!bitmap)
{ {
#if !LOL_BUILD_RELEASE #if !LOL_BUILD_RELEASE
Log::Error("could not load %s\n", path); Log::Error("could not load %s\n", path);
@@ -110,33 +105,32 @@ bool GdiPlusImageCodec::Load(Image *image, char const *path)
return false; return false;
} }


image->m_data->m_size = ivec2(m_bitmap->GetWidth(), ivec2 size(bitmap->GetWidth(), bitmap->GetHeight());
m_bitmap->GetHeight()); Gdiplus::Rect rect(0, 0, size.x, size.y);
image->m_data->m_format = PixelFormat::RGBA_8; Gdiplus::BitmapData bdata;

if (bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead,
Gdiplus::Rect rect(0, 0, image->m_data->m_size.x, image->m_data->m_size.y); PixelFormat32bppARGB, &bdata) != Gdiplus::Ok)
if (m_bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead,
PixelFormat32bppARGB, &m_bdata) != Gdiplus::Ok)
{ {
#if !LOL_BUILD_RELEASE #if !LOL_BUILD_RELEASE
Log::Error("could not lock bits in %s\n", path); Log::Error("could not lock bits in %s\n", path);
#endif #endif
delete m_bitmap; delete bitmap;
return false; return false;
} }


/* 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. */
uint8_t *p = static_cast<uint8_t *>(m_bdata.Scan0); image->SetSize(size);
for (int y = 0; y < image->m_data->m_size.y; y++) u8vec4 *pixels = image->Lock<PixelFormat::RGBA_8>();
for (int x = 0; x < image->m_data->m_size.x; x++) u8vec4 *source = static_cast<u8vec4 *>(bdata.Scan0);
{ for (int y = 0; y < size.y; y++)
uint8_t tmp = p[2]; for (int x = 0; x < size.x; x++)
p[2] = p[0]; *pixels++ = (*source++).bgra;
p[0] = tmp; image->Unlock();
p += 4; bitmap->UnlockBits(&bdata);
} delete bitmap;


return true; return true;
} }
@@ -159,16 +153,16 @@ bool GdiPlusImageCodec::Save(Image *image, char const *path)
else /* if (strstr(path, ".bmp")) */ else /* if (strstr(path, ".bmp")) */
fmt = L"image/bmp"; fmt = L"image/bmp";


unsigned int num = 0, size = 0; unsigned int num = 0, encoder_size = 0;
Gdiplus::GetImageEncodersSize(&num, &size); Gdiplus::GetImageEncodersSize(&num, &encoder_size);
if (num == 0) if (num == 0)
{ {
Log::Error("no GDI+ image encoders found\n"); Log::Error("no GDI+ image encoders found\n");
return false; return false;
} }
Gdiplus::ImageCodecInfo *codecs Gdiplus::ImageCodecInfo *codecs
= (Gdiplus::ImageCodecInfo *)new uint8_t[size]; = (Gdiplus::ImageCodecInfo *)new uint8_t[encoder_size];
Gdiplus::GetImageEncoders(num, size, codecs); Gdiplus::GetImageEncoders(num, encoder_size, codecs);
CLSID clsid; CLSID clsid;
for (unsigned int i = 0; i < num; i++) for (unsigned int i = 0; i < num; i++)
{ {
@@ -190,15 +184,16 @@ bool GdiPlusImageCodec::Save(Image *image, char const *path)
return false; return false;
} }


ivec2 size = image->GetSize();

/* FIXME: we create a new image because there is no guarantee that /* FIXME: we create a new image because there is no guarantee that
* the image comes from GDI. But the engine architecture doesn't * the image comes from GDI. But the engine architecture doesn't
* allow us to save other images anyway. */ * allow us to save other images anyway. */
Gdiplus::Bitmap *b = new Gdiplus::Bitmap(image->m_data->m_size.x, Gdiplus::Bitmap *b = new Gdiplus::Bitmap(size.x, size.y,
image->m_data->m_size.y,
PixelFormat32bppARGB); PixelFormat32bppARGB);


Gdiplus::BitmapData bdata; 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, if (b->LockBits(&rect, (unsigned int)Gdiplus::ImageLockModeWrite,
PixelFormat32bppARGB, &bdata) != Gdiplus::Ok) PixelFormat32bppARGB, &bdata) != Gdiplus::Ok)
@@ -210,14 +205,12 @@ bool GdiPlusImageCodec::Save(Image *image, char const *path)
return false; return false;
} }


u8vec4 *psrc = static_cast<u8vec4 *>(m_bdata.Scan0); u8vec4 *psrc = image->Lock<PixelFormat::RGBA_8>();
u8vec4 *pdst = static_cast<u8vec4 *>(bdata.Scan0); u8vec4 *pdst = static_cast<u8vec4 *>(bdata.Scan0);
for (int y = 0; y < image->m_data->m_size.y; y++) for (int y = 0; y < size.y; y++)
for (int x = 0; x < image->m_data->m_size.x; x++) for (int x = 0; x < size.x; x++)
{
*pdst++ = (*psrc++).bgra; *pdst++ = (*psrc++).bgra;
} image->Unlock();

b->UnlockBits(&bdata); b->UnlockBits(&bdata);


if (b->Save(wpath, &clsid, NULL) != Gdiplus::Ok) if (b->Save(wpath, &clsid, NULL) != Gdiplus::Ok)
@@ -235,19 +228,6 @@ bool GdiPlusImageCodec::Save(Image *image, char const *path)
return true; 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 */ } /* namespace lol */


#endif /* defined USE_GDIPLUS */ #endif /* defined USE_GDIPLUS */


+ 3
- 7
src/image/codec/ios-image.cpp Visa fil

@@ -28,19 +28,15 @@ namespace lol
* Image implementation class * Image implementation class
*/ */


DECLARE_IMAGE_CODEC(IosImageCodec, 100) class IosImageCodec : public ImageCodec
{ {
public: public:
virtual bool Load(Image *image, char const *path); virtual bool Load(Image *image, char const *path);
virtual bool Save(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 * Public Image class
*/ */


+ 3
- 2
src/image/codec/ps3-image.cpp Visa fil

@@ -30,7 +30,7 @@ namespace lol
* Image implementation class * Image implementation class
*/ */


DECLARE_IMAGE_CODEC(Ps3ImageCodec, 100) class Ps3ImageCodec : public ImageCodec
{ {
public: public:
virtual bool Load(Image *image, char const *path); virtual bool Load(Image *image, char const *path);
@@ -42,9 +42,10 @@ public:
private: private:
static void* Malloc(uint32_t size, void* data) { return malloc(size); }; static void* Malloc(uint32_t size, void* data) { return malloc(size); };
static int32_t Free(void* ptr, void* data) { free(ptr); return 0; }; static int32_t Free(void* ptr, void* data) { free(ptr); return 0; };
uint8_t *pixels;
}; };


DECLARE_IMAGE_CODEC(Ps3ImageCodec, 100)

/* /*
* Public Image class * Public Image class
*/ */


+ 27
- 22
src/image/codec/sdl-image.cpp Visa fil

@@ -37,34 +37,34 @@ namespace lol
* Image implementation class * Image implementation class
*/ */


DECLARE_IMAGE_CODEC(SdlImageCodec, 50) class SdlImageCodec : public ImageCodec
{ {
public: public:
virtual bool Load(Image *image, char const *path); virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path); virtual bool Save(Image *image, char const *path);
virtual bool Close();


static SDL_Surface *Create32BppSurface(ivec2 size); static SDL_Surface *Create32BppSurface(ivec2 size);

private:
SDL_Surface *m_surface;
}; };


DECLARE_IMAGE_CODEC(SdlImageCodec, 50)

/* /*
* Public Image class * Public Image class
*/ */


bool SdlImageCodec::Load(Image *image, char const *path) bool SdlImageCodec::Load(Image *image, char const *path)
{ {
SDL_Surface *surface = nullptr;

Array<String> pathlist = System::GetPathList(path); Array<String> pathlist = System::GetPathList(path);
for (int i = 0; i < pathlist.Count(); i++) for (int i = 0; i < pathlist.Count(); i++)
{ {
m_surface = IMG_Load(pathlist[i].C()); surface = IMG_Load(pathlist[i].C());
if (m_surface) if (surface)
break; break;
} }


if (!m_surface) if (!surface)
{ {
#if !LOL_BUILD_RELEASE #if !LOL_BUILD_RELEASE
Log::Error("could not load image %s\n", path); Log::Error("could not load image %s\n", path);
@@ -72,34 +72,39 @@ bool SdlImageCodec::Load(Image *image, char const *path)
return false; 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_Surface *tmp = Create32BppSurface(size);
SDL_BlitSurface(m_surface, nullptr, tmp, nullptr); SDL_BlitSurface(surface, nullptr, tmp, nullptr);
SDL_FreeSurface(m_surface); SDL_FreeSurface(surface);
m_surface = tmp; surface = tmp;
} }


image->SetSize(ivec2(m_surface->w, m_surface->h)); image->SetSize(size);
u8vec4 *data = image->Lock<PixelFormat::RGBA_8>(); 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(); image->Unlock();


SDL_FreeSurface(surface);

return true; return true;
} }


bool SdlImageCodec::Save(Image *image, char const *path) 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() int ret = SDL_SaveBMP(surface, path);
{ SDL_FreeSurface(surface);
SDL_FreeSurface(m_surface);


return true; return ret == 0;
} }


SDL_Surface *SdlImageCodec::Create32BppSurface(ivec2 size) SDL_Surface *SdlImageCodec::Create32BppSurface(ivec2 size)


+ 3
- 13
src/image/codec/zed-image.cpp Visa fil

@@ -25,14 +25,12 @@ namespace lol
* Image implementation class * Image implementation class
*/ */


DECLARE_IMAGE_CODEC(ZedImageCodec, 0) class ZedImageCodec : public ImageCodec
{ {
public: public:
virtual bool Load(Image *image, char const *path); virtual bool Load(Image *image, char const *path);
virtual bool Save(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) virtual bool RetrieveTiles(Array<ivec2, ivec2>& tiles)
{ {
bool result = m_tiles.Count() > 0; bool result = m_tiles.Count() > 0;
@@ -47,6 +45,8 @@ private:
Array<ivec2, ivec2> m_tiles; Array<ivec2, ivec2> m_tiles;
}; };


DECLARE_IMAGE_CODEC(ZedImageCodec, 0)

/* /*
* Public Image class * Public Image class
*/ */
@@ -307,15 +307,5 @@ bool ZedImageCodec::Save(Image *image, char const *path)
return true; return true;
} }


bool ZedImageCodec::Close()
{
return true;
}

uint8_t * ZedImageCodec::GetData() const
{
return m_pixels;
}

} /* namespace lol */ } /* namespace lol */



+ 3
- 7
src/image/codec/zed-palette-image.cpp Visa fil

@@ -24,14 +24,15 @@ namespace lol
* Image implementation class * Image implementation class
*/ */


DECLARE_IMAGE_CODEC(ZedPaletteImageCodec, 0) class ZedPaletteImageCodec : public ImageCodec
{ {
public: public:
virtual bool Load(Image *image, char const *path); virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path); virtual bool Save(Image *image, char const *path);
virtual bool Close();
}; };


DECLARE_IMAGE_CODEC(ZedPaletteImageCodec, 0)

/* /*
* Public Image class * Public Image class
*/ */
@@ -86,10 +87,5 @@ bool ZedPaletteImageCodec::Save(Image *image, char const *path)
return true; return true;
} }


bool ZedPaletteImageCodec::Close()
{
return true;
}

} /* namespace lol */ } /* namespace lol */



+ 21
- 92
src/image/image-private.h Visa fil

@@ -22,121 +22,50 @@ namespace lol
class ImageData class ImageData
{ {
friend class Image; friend class Image;
friend class ImageBank;
friend class ImageCodec;


public: public:
ImageData() ImageData()
: m_size(0, 0), : m_size(0, 0),
m_format(PixelFormat::Unknown), m_format(PixelFormat::Unknown)
m_refcount(0),
m_codecdata(nullptr)
{} {}


ivec2 m_size; ivec2 m_size;


Map<int, void *> m_pixels; Map<int, void *> m_pixels;
PixelFormat m_format; PixelFormat m_format;

int m_refcount;

/* protected: */ /* FIXME: fix the ImageCodec subclasses access rights */
class ImageCodecData *m_codecdata;
}; };


class ImageCodec 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: public:
inline ImageCodecData() {} virtual bool Load(Image *image, char const *path) = 0;
virtual ~ImageCodecData() {} virtual bool Save(Image *image, char const *path) = 0;

virtual bool Load(Image *, char const *) = 0;
virtual bool Save(Image *, char const *) = 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) \ #define REGISTER_IMAGE_CODEC(name) \
extern void Register##name(); \ extern ImageCodec *Register##name(); \
Register##name();

#define DECLARE_IMAGE_CODEC(name, prio) \
template<typename T> class name##ImageCodec : public ImageCodec \
{ \ { \
public: \ /* Insert image codecs in a sorted list */ \
name##ImageCodec() \ ImageCodec *codec = Register##name(); \
{ \ int i = 0, prio = codec->m_priority; \
static ImageCodec codec; \ for ( ; i < codeclist.Count(); ++i) \
codec.m_tryload = Load; \
codec.m_priority = prio; \
RegisterCodec(&codec); \
} \
static bool Load(Image *image, char const *path) \
{ \ { \
T *codecdata = new T(); \ if (codeclist[i]->m_priority <= prio) \
bool ret = codecdata->Load(image, path); \ break; \
delete codecdata; \
return ret; \
} \ } \
}; \ codeclist.Insert(codec, i); \
class name; \ }
name##ImageCodec<name> name##ImageCodecInstance; \ #define DECLARE_IMAGE_CODEC(name, priority) \
void Register##name() \ ImageCodec *Register##name() \
{ \ { \
(void)&name##ImageCodecInstance; \ ImageCodec *ret = new name(); \
} \ ret->m_priority = priority; \
class name : public ImageCodecData return ret; \
}


} /* namespace lol */ } /* namespace lol */




+ 48
- 62
src/image/image.cpp Visa fil

@@ -30,7 +30,7 @@ namespace lol
* The bug was reported to Microsoft and fixed by them, but the fix * The bug was reported to Microsoft and fixed by them, but the fix
* is not yet available. * is not yet available.
* https://connect.microsoft.com/VisualStudio/feedback/details/730878/ */ * https://connect.microsoft.com/VisualStudio/feedback/details/730878/ */
static bool RegisterAllCodecs() static bool RegisterAllCodecs(Array<ImageCodec *> &codeclist)
{ {
#if defined __ANDROID__ #if defined __ANDROID__
REGISTER_IMAGE_CODEC(AndroidImageCodec) REGISTER_IMAGE_CODEC(AndroidImageCodec)
@@ -61,90 +61,74 @@ static bool RegisterAllCodecs()
static class ImageBank static class ImageBank
{ {
public: public:
void Init(); ImageBank();
Image *Create(char const *path);


void Unref(Image *img); bool Load(Image *image, char const *path);
bool Save(Image *image, char const *path);


private: private:
Array<ImageCodec *> m_codecs;
Map<String, Image *> m_images; Map<String, Image *> m_images;
} }
g_image_bank; g_image_bank;


void ImageBank::Init() ImageBank::ImageBank()
{ {
/* Initialise codecs (see above) */ RegisterAllCodecs(m_codecs);
static bool init = RegisterAllCodecs();
UNUSED(init);
} }


Image *ImageBank::Create(char const *path) bool ImageBank::Load(Image *image, char const *path)
{ {
Init(); /* FIXME: priority is ignored */

for (auto codec : m_codecs)
/* Is our image already in the bank? If so, no need to create it. */ if (codec->Load(image, path))
if (!m_images.HasKey(path)) return true;
{ return false;
m_images[path] = new Image();
ImageCodec::Load(m_images[path], path);
}

Image *img = m_images[path];
++img->m_data->m_refcount;
return img;
} }


void ImageBank::Unref(Image *img) bool ImageBank::Save(Image *image, char const *path)
{ {
ASSERT(img->m_data->m_refcount > 0); /* FIXME: priority is ignored */
if (--img->m_data->m_refcount == 0) for (auto codec : m_codecs)
{ if (codec->Save(image, path))
/* FIXME: unload images etc. here */ return true;
/* XXX: we’re gonna hit a problem here because we didn’t keep return false;
* the image path within the object, so unless we store it
* ourselves we’re good for a O(n) lookup… which we can’t do
* on Map objects anyway. */
/* TODO: 1. remove image from Map
2. delete img; */
}
} }



/* /*
* Static image methods * Public Image class
*/ */


Image *Image::Create(char const *path) Image::Image()
: m_data(new ImageData())
{ {
return g_image_bank.Create(path);
} }


/* Image::Image(char const *path)
* Public Image class : m_data(new ImageData())
*/ {
Load(path);
}


Image::Image() Image::Image(ivec2 size)
: m_data(new ImageData()) : m_data(new ImageData())
{ {
SetSize(size);
} }


Image::~Image() Image::~Image()
{ {
delete m_data->m_codecdata;
delete m_data; 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) bool Image::Save(char const *path)
{ {
/* FIXME: add autoloading of save codecs */ return g_image_bank.Save(this, path);
if (!m_data->m_codecdata)
return false;
return m_data->m_codecdata->Save(this, path);
} }


ivec2 Image::GetSize() const ivec2 Image::GetSize() const
@@ -177,13 +161,6 @@ PixelFormat Image::GetFormat() const
return m_data->m_format; 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 */ /* The Lock() method and its explicit specialisations */
template<PixelFormat T> template<PixelFormat T>
typename PixelType<T>::type *Image::Lock() typename PixelType<T>::type *Image::Lock()
@@ -195,19 +172,28 @@ typename PixelType<T>::type *Image::Lock()
if (!m_data->m_pixels.HasKey((int)T)) if (!m_data->m_pixels.HasKey((int)T))
{ {
m_data->m_pixels[(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]; 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>(); Image::Lock<PixelFormat::Y_8>();
template typename PixelType<PixelFormat::RGB_8>::type * template PixelType<PixelFormat::RGB_8>::type *
Image::Lock<PixelFormat::RGB_8>(); Image::Lock<PixelFormat::RGB_8>();
template typename PixelType<PixelFormat::RGBA_8>::type * template PixelType<PixelFormat::RGBA_8>::type *
Image::Lock<PixelFormat::RGBA_8>(); 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() void Image::Unlock()
{ {
/* TODO: ensure we are actually unlocking something we locked */ /* TODO: ensure we are actually unlocking something we locked */
@@ -216,9 +202,9 @@ void Image::Unlock()


bool Image::RetrieveTiles(Array<ivec2, ivec2>& tiles) const bool Image::RetrieveTiles(Array<ivec2, ivec2>& tiles) const
{ {
if (!m_data->m_codecdata) /* TODO: re-implement this */
return false; //return m_data->m_codecdata->RetrieveTiles(tiles);
return m_data->m_codecdata->RetrieveTiles(tiles); return false;
} }


} /* namespace lol */ } /* namespace lol */


+ 8
- 12
src/lol/image/image.h Visa fil

@@ -21,7 +21,6 @@
namespace lol namespace lol
{ {


/* FIXME: is it possible to avoid the cast to int here? */
template <PixelFormat T> struct PixelType { typedef void type; }; template <PixelFormat T> struct PixelType { typedef void type; };
template<> struct PixelType<PixelFormat::Y_8> { typedef uint8_t type; }; template<> struct PixelType<PixelFormat::Y_8> { typedef uint8_t type; };
template<> struct PixelType<PixelFormat::RGB_8> { typedef u8vec3 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 class Image
{ {
friend class ImageBank;
friend class ImageCodec;

public: public:
Image(); 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(); ~Image();


static Image *Create(char const *path); bool Load(char const *path);

bool Save(char const *path); bool Save(char const *path);
void Destroy(); ivec2 GetSize() const;
void SetSize(ivec2);


PixelFormat GetFormat() const; PixelFormat GetFormat() const;
void *LockGeneric();
template<PixelFormat T> typename PixelType<T>::type *Lock(); template<PixelFormat T> typename PixelType<T>::type *Lock();
void Unlock(); void Unlock();


ivec2 GetSize() const;
void SetSize(ivec2);

bool RetrieveTiles(Array<ivec2, ivec2>& tiles) const; bool RetrieveTiles(Array<ivec2, ivec2>& tiles) const;


private: private:
class ImageData *m_data; class ImageData *m_data;
String m_path;
}; };


} /* namespace lol */ } /* namespace lol */


+ 4
- 4
src/tileset.cpp Visa fil

@@ -140,7 +140,7 @@ TileSet::TileSet(char const *path, Image* image, ivec2 size, ivec2 count)


void TileSet::Init(char const *path) void TileSet::Init(char const *path)
{ {
Init(path, Image::Create(path)); Init(path, new Image(path));
} }


void TileSet::Init(char const *path, Image* image) void TileSet::Init(char const *path, Image* image)
@@ -190,7 +190,7 @@ void TileSet::TickDraw(float seconds)
{ {
if (m_data->m_image) if (m_data->m_image)
{ {
m_data->m_image->Destroy(); delete m_data->m_image;
m_data->m_image = nullptr; m_data->m_image = nullptr;
} }
else else
@@ -207,7 +207,7 @@ void TileSet::TickDraw(float seconds)
int w = m_data->m_texture_size.x; int w = m_data->m_texture_size.x;
int h = m_data->m_texture_size.y; 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; bool resized = false;
if (w != m_data->m_image_size.x || h != m_data->m_image_size.y) 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) if (resized)
delete[] pixels; delete[] pixels;
m_data->m_image->Destroy(); delete m_data->m_image;
m_data->m_image = nullptr; m_data->m_image = nullptr;
} }
} }


+ 4
- 5
test/unit/image.cpp Visa fil

@@ -24,13 +24,13 @@ LOLUNIT_FIXTURE(ImageTest)
{ {
LOLUNIT_TEST(OpenImage) 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.x, 256);
LOLUNIT_ASSERT_EQUAL(size.y, 16); 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(data);


LOLUNIT_ASSERT_EQUAL((int)data[0].r, 0x00); 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].g, 0xff);
LOLUNIT_ASSERT_EQUAL((int)data[255].b, 0xff); LOLUNIT_ASSERT_EQUAL((int)data[255].b, 0xff);


image->Unlock(); image.Unlock();
image->Destroy();
} }
}; };




||||||
x
 
000:0
Laddar…
Avbryt
Spara