Browse Source

image: start reworking the Image class to properly split the pixel handling

and the codec logic.
undefined
Sam Hocevar 10 years ago
parent
commit
f455f0e2d1
14 changed files with 302 additions and 306 deletions
  1. +7
    -7
      src/image/codec/android-image.cpp
  2. +14
    -26
      src/image/codec/dummy-image.cpp
  3. +18
    -16
      src/image/codec/gdiplus-image.cpp
  4. +7
    -7
      src/image/codec/ios-image.cpp
  5. +9
    -9
      src/image/codec/ps3-image.cpp
  6. +22
    -29
      src/image/codec/sdl-image.cpp
  7. +12
    -14
      src/image/codec/zed-image.cpp
  8. +15
    -27
      src/image/codec/zed-palette-image.cpp
  9. +65
    -54
      src/image/image-private.h
  10. +82
    -67
      src/image/image.cpp
  11. +20
    -28
      src/lol/gpu/texture.h
  12. +18
    -12
      src/lol/image/image.h
  13. +5
    -3
      src/tileset.cpp
  14. +8
    -7
      test/unit/image.cpp

+ 7
- 7
src/image/codec/android-image.cpp View File

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

DECLARE_IMAGE_LOADER(AndroidImageData, 100)
DECLARE_IMAGE_CODEC(AndroidImageCodec, 100)
{
public:
virtual bool Open(char const *);
virtual bool Save(char const *);
virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path);
virtual bool Close();

virtual uint8_t *GetData() const;
@@ -50,7 +50,7 @@ private:
jint *pixels;
};

bool AndroidImageData::Open(char const *path)
bool AndroidImageCodec::Load(Image *image, char const *path)
{
JNIEnv *env;
jint res = g_activity->vm->GetEnv((void **)&env, JNI_VERSION_1_2);
@@ -109,14 +109,14 @@ bool AndroidImageData::Open(char const *path)
return true;
}

bool AndroidImageData::Save(char const *path)
bool AndroidImageCodec::Save(Image *image, char const *path)
{
UNUSED(path);

/* TODO: unimplemented */
}

bool AndroidImageData::Close()
bool AndroidImageCodec::Close()
{
JNIEnv *env;
jint res = g_activity->vm->GetEnv((void **)&env, JNI_VERSION_1_2);
@@ -141,7 +141,7 @@ bool AndroidImageData::Close()
return true;
}

uint8_t *AndroidImageData::GetData() const
uint8_t *AndroidImageCodec::GetData() const
{
return (uint8_t *)pixels;
}


+ 14
- 26
src/image/codec/dummy-image.cpp View File

@@ -24,61 +24,49 @@ namespace lol
* Image implementation class
*/

DECLARE_IMAGE_LOADER(DummyImageData, 0)
DECLARE_IMAGE_CODEC(DummyImageCodec, 0)
{
public:
virtual bool Open(char const *);
virtual bool Save(char const *);
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;
};

/*
* Public Image class
*/

bool DummyImageData::Open(char const *path)
bool DummyImageCodec::Load(Image *image, char const *path)
{
UNUSED(path);

m_size = ivec2(256);
m_format = PixelFormat::RGBA_8;
pixels = new uint8_t[256 * 256 * 4 * sizeof(*pixels)];
uint8_t *parser = pixels;
image->SetSize(ivec2(256));
u8vec4 *pixels = image->Lock<PixelFormat::RGBA_8>();
for (int j = 0; j < 256; j++)
for (int i = 0; i < 256; i++)
{
*parser++ = ((i ^ j) & 1) * 0xff;
*parser++ = (uint8_t)i;
*parser++ = (uint8_t)j;
*parser++ = (((i >> 4) ^ (j >> 4)) & 1) * 0xff;
pixels->r = ((i ^ j) & 1) * 0xff;
pixels->g = (uint8_t)i;
pixels->b = (uint8_t)j;
pixels->a = (((i >> 4) ^ (j >> 4)) & 1) * 0xff;
++pixels;
}
image->Unlock();

return true;
}

bool DummyImageData::Save(char const *path)
bool DummyImageCodec::Save(Image *image, char const *path)
{
UNUSED(path);

return true;
}

bool DummyImageData::Close()
bool DummyImageCodec::Close()
{
delete[] pixels;

return true;
}

uint8_t * DummyImageData::GetData() const
{
return pixels;
}

} /* namespace lol */


+ 18
- 16
src/image/codec/gdiplus-image.cpp View File

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

DECLARE_IMAGE_LOADER(GdiPlusImageData, 100)
DECLARE_IMAGE_CODEC(GdiPlusImageCodec, 100)
{
public:
virtual bool Open(char const *);
virtual bool Save(char const *);
virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path);
virtual bool Close();

virtual uint8_t *GetData() const;
@@ -49,7 +49,7 @@ private:
* Public Image class
*/

bool GdiPlusImageData::Open(char const *path)
bool GdiPlusImageCodec::Load(Image *image, char const *path)
{
Gdiplus::Status status;
ULONG_PTR token;
@@ -110,10 +110,11 @@ bool GdiPlusImageData::Open(char const *path)
return false;
}

m_size = ivec2(m_bitmap->GetWidth(), m_bitmap->GetHeight());
m_format = PixelFormat::RGBA_8;
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, m_size.x, m_size.y);
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)
{
@@ -128,8 +129,8 @@ bool GdiPlusImageData::Open(char const *path)
* 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 < m_size.y; y++)
for (int x = 0; x < m_size.x; x++)
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];
@@ -140,7 +141,7 @@ bool GdiPlusImageData::Open(char const *path)
return true;
}

bool GdiPlusImageData::Save(char const *path)
bool GdiPlusImageCodec::Save(Image *image, char const *path)
{
ULONG_PTR token;
Gdiplus::GdiplusStartupInput input;
@@ -192,11 +193,12 @@ bool GdiPlusImageData::Save(char const *path)
/* 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(m_size.x, m_size.y,
Gdiplus::Bitmap *b = new Gdiplus::Bitmap(image->m_data->m_size.x,
image->m_data->m_size.y,
PixelFormat32bppARGB);

Gdiplus::BitmapData bdata;
Gdiplus::Rect rect(0, 0, m_size.x, m_size.y);
Gdiplus::Rect rect(0, 0, image->m_data->m_size.x, image->m_data->m_size.y);

if (b->LockBits(&rect, (unsigned int)Gdiplus::ImageLockModeWrite,
PixelFormat32bppARGB, &bdata) != Gdiplus::Ok)
@@ -210,8 +212,8 @@ bool GdiPlusImageData::Save(char const *path)

u8vec4 *psrc = static_cast<u8vec4 *>(m_bdata.Scan0);
u8vec4 *pdst = static_cast<u8vec4 *>(bdata.Scan0);
for (int y = 0; y < m_size.y; y++)
for (int x = 0; x < m_size.x; x++)
for (int y = 0; y < image->m_data->m_size.y; y++)
for (int x = 0; x < image->m_data->m_size.x; x++)
{
*pdst++ = (*psrc++).bgra;
}
@@ -233,7 +235,7 @@ bool GdiPlusImageData::Save(char const *path)
return true;
}

bool GdiPlusImageData::Close()
bool GdiPlusImageCodec::Close()
{
m_bitmap->UnlockBits(&m_bdata);
delete m_bitmap;
@@ -241,7 +243,7 @@ bool GdiPlusImageData::Close()
return true;
}

uint8_t * GdiPlusImageData::GetData() const
uint8_t * GdiPlusImageCodec::GetData() const
{
return static_cast<uint8_t *>(m_bdata.Scan0);
}


+ 7
- 7
src/image/codec/ios-image.cpp View File

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

DECLARE_IMAGE_LOADER(IosImageData, 100)
DECLARE_IMAGE_CODEC(IosImageCodec, 100)
{
public:
virtual bool Open(char const *);
virtual bool Save(char const *);
virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path);
virtual bool Close();

virtual uint8_t *GetData() const;
@@ -45,7 +45,7 @@ private:
* Public Image class
*/

bool IosImageData::Open(char const *path)
bool IosImageCodec::Load(Image *image, char const *path)
{
NSString *fullpath = [NSString stringWithUTF8String:path];
NSArray *chunks = [fullpath componentsSeparatedByString: @"/"];
@@ -84,7 +84,7 @@ bool IosImageData::Open(char const *path)
return true;
}

bool IosImageData::Save(char const *path)
bool IosImageCodec::Save(Image *image, char const *path)
{
UNUSED(path);

@@ -92,14 +92,14 @@ bool IosImageData::Save(char const *path)
return true;
}

bool IosImageData::Close()
bool IosImageCodec::Close()
{
free(pixels);

return true;
}

uint8_t * IosImageData::GetData() const
uint8_t * IosImageCodec::GetData() const
{
return pixels;
}


+ 9
- 9
src/image/codec/ps3-image.cpp View File

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

DECLARE_IMAGE_LOADER(Ps3ImageData, 100)
DECLARE_IMAGE_CODEC(Ps3ImageCodec, 100)
{
public:
virtual bool Open(char const *);
virtual bool Save(char const *);
virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path);
virtual bool Close();

virtual uint8_t *GetData() const;
@@ -49,7 +49,7 @@ private:
* Public Image class
*/

bool Ps3ImageData::Open(char const *path)
bool Ps3ImageCodec::Load(Image *image, char const *path)
{
int32_t err;

@@ -74,9 +74,9 @@ bool Ps3ImageData::Open(char const *path)
in_param.spuThreadEnable = CELL_PNGDEC_SPU_THREAD_ENABLE;
in_param.ppuThreadPriority = 1000;
in_param.spuThreadPriority = 200;
in_param.cbCtrlMallocFunc = Ps3ImageData::Malloc;
in_param.cbCtrlMallocFunc = Ps3ImageCodec::Malloc;
in_param.cbCtrlMallocArg = nullptr;
in_param.cbCtrlFreeFunc = Ps3ImageData::Free;
in_param.cbCtrlFreeFunc = Ps3ImageCodec::Free;
in_param.cbCtrlFreeArg = nullptr;
CellPngDecThreadOutParam out_param;
err = cellPngDecCreate(&hmain, &in_param, &out_param);
@@ -174,7 +174,7 @@ bool Ps3ImageData::Open(char const *path)
return true;
}

bool Ps3ImageData::Open(char const *path)
bool Ps3ImageCodec::Load(Image *image, char const *path)
{
UNUSED(path);

@@ -182,14 +182,14 @@ bool Ps3ImageData::Open(char const *path)
return true;
}

bool Ps3ImageData::Close()
bool Ps3ImageCodec::Close()
{
free(pixels);

return true;
}

uint8_t * Ps3ImageData::GetData() const
uint8_t * Ps3ImageCodec::GetData() const
{
return pixels;
}


+ 22
- 29
src/image/codec/sdl-image.cpp View File

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

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

virtual uint8_t *GetData() const;

static SDL_Surface *Create32BppSurface(ivec2 size);

private:
SDL_Surface *m_img;
SDL_Surface *m_surface;
};

/*
* Public Image class
*/

bool SdlImageData::Open(char const *path)
bool SdlImageCodec::Load(Image *image, char const *path)
{
Array<String> pathlist = System::GetPathList(path);
for (int i = 0; i < pathlist.Count(); i++)
{
m_img = IMG_Load(pathlist[i].C());
if (m_img)
m_surface = IMG_Load(pathlist[i].C());
if (m_surface)
break;
}

if (!m_img)
if (!m_surface)
{
#if !LOL_BUILD_RELEASE
Log::Error("could not load image %s\n", path);
@@ -74,42 +72,37 @@ bool SdlImageData::Open(char const *path)
return false;
}

m_size = ivec2(m_img->w, m_img->h);

if (m_img->format->BytesPerPixel != 4)
if (m_surface->format->BytesPerPixel != 4)
{
SDL_Surface *tmp = Create32BppSurface(m_size);
SDL_BlitSurface(m_img, nullptr, tmp, nullptr);
SDL_FreeSurface(m_img);
m_img = tmp;
SDL_Surface *tmp = Create32BppSurface(image->GetSize());
SDL_BlitSurface(m_surface, nullptr, tmp, nullptr);
SDL_FreeSurface(m_surface);
m_surface = tmp;
}

m_format = m_img->format->Amask ? PixelFormat::RGBA_8
: PixelFormat::RGB_8;
image->SetSize(ivec2(m_surface->w, m_surface->h));
u8vec4 *data = image->Lock<PixelFormat::RGBA_8>();
memcpy(data, m_surface->pixels, 4 * m_surface->w * m_surface->h);
image->Unlock();

return true;
}

bool SdlImageData::Save(char const *path)
bool SdlImageCodec::Save(Image *image, char const *path)
{
int ret = SDL_SaveBMP(m_img, path);
int ret = SDL_SaveBMP(m_surface, path);

return ret == 0;
}

bool SdlImageData::Close()
bool SdlImageCodec::Close()
{
SDL_FreeSurface(m_img);
SDL_FreeSurface(m_surface);

return true;
}

uint8_t * SdlImageData::GetData() const
{
return (uint8_t *)m_img->pixels;
}

SDL_Surface *SdlImageData::Create32BppSurface(ivec2 size)
SDL_Surface *SdlImageCodec::Create32BppSurface(ivec2 size)
{
uint32_t rmask, gmask, bmask, amask;
#if SDL_BYTEORDER == SDL_BIG_ENDIAN


+ 12
- 14
src/image/codec/zed-image.cpp View File

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

DECLARE_IMAGE_LOADER(ZedImageData, 0)
DECLARE_IMAGE_CODEC(ZedImageCodec, 0)
{
public:
virtual bool Open(char const *);
virtual bool Save(char const *);
virtual bool Load(Image *image, char const *path);
virtual bool Save(Image *image, char const *path);
virtual bool Close();

virtual uint8_t *GetData() const;
@@ -51,7 +51,7 @@ private:
* Public Image class
*/

bool ZedImageData::Open(char const *path)
bool ZedImageCodec::Load(Image *image, char const *path)
{
if (!lol::String(path).EndsWith(".RSC"))
return false;
@@ -239,10 +239,8 @@ bool ZedImageData::Open(char const *path)
tex_size <<= 1;

//Prepare final imqge
m_size = ivec2(tex_size);
m_format = PixelFormat::Y_8;
m_pixels = new uint8_t[tex_size * tex_size * 1 * sizeof(*m_pixels)];
uint8_t *image = m_pixels;
image->SetSize(ivec2(tex_size));
uint8_t *pixels = image->Lock<PixelFormat::Y_8>();

//Data refactor stage
ivec2 pos = ivec2(0);
@@ -278,7 +276,7 @@ bool ZedImageData::Open(char const *path)
for (int x_cur = 0; x_cur < t_size.x / 4; x_cur++)
{
int32_t img_pos = img_off + pass + 4 * x_cur + y_cur * (int32_t)tex_size;
image[img_pos] = file_convert[file_off++];
pixels[img_pos] = file_convert[file_off++];
}
}
}
@@ -297,24 +295,24 @@ bool ZedImageData::Open(char const *path)
j++;
}
}
image->Unlock();

return true;
}

bool ZedImageData::Save(char const *path)
bool ZedImageCodec::Save(Image *image, char const *path)
{
UNUSED(path);
/* FIXME: do we need to implement this? */
return true;
}

bool ZedImageData::Close()
bool ZedImageCodec::Close()
{
delete[] m_pixels;

return true;
}

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


+ 15
- 27
src/image/codec/zed-palette-image.cpp View File

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

DECLARE_IMAGE_LOADER(ZedPaletteImageData, 0)
DECLARE_IMAGE_CODEC(ZedPaletteImageCodec, 0)
{
public:
virtual bool Open(char const *);
virtual bool Save(char const *);
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 *m_pixels;
};

/*
* Public Image class
*/

bool ZedPaletteImageData::Open(char const *path)
bool ZedPaletteImageCodec::Load(Image *image, char const *path)
{
if (!lol::String(path).EndsWith(".pal"))
return false;
@@ -61,47 +56,40 @@ bool ZedPaletteImageData::Open(char const *path)
int32_t tex_size = 2;
while (tex_size < tex_sqrt)
tex_size <<= 1;
m_size = ivec2(tex_size);
image->m_data->m_size = ivec2(tex_size);
#else
int32_t tex_sqrt = file_size / 3;
int32_t tex_size = 2;
while (tex_size < tex_sqrt)
tex_size <<= 1;
m_size = ivec2(tex_size, 1);
image->SetSize(ivec2(tex_size, 1));
#endif

m_format = PixelFormat::RGBA_8;
m_pixels = new uint8_t[tex_size * tex_size * 4 * sizeof(*m_pixels)];
uint8_t *parser = m_pixels;
u8vec4 *pixels = image->Lock<PixelFormat::RGBA_8>();
for (int i = 0; i < file_buffer.Count();)
{
*parser++ = file_buffer[i++];
*parser++ = file_buffer[i++];
*parser++ = file_buffer[i++];
*parser++ = (i == 0) ? 0 : 255;
pixels->r = file_buffer[i++];
pixels->g = file_buffer[i++];
pixels->b = file_buffer[i++];
pixels->a = (i == 0) ? 0 : 255;
++pixels;
}
image->Unlock();

return true;
}

bool ZedPaletteImageData::Save(char const *path)
bool ZedPaletteImageCodec::Save(Image *image, char const *path)
{
UNUSED(path);
/* FIXME: do we need to implement this? */
return true;
}

bool ZedPaletteImageData::Close()
bool ZedPaletteImageCodec::Close()
{
delete[] m_pixels;

return true;
}

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

} /* namespace lol */


+ 65
- 54
src/image/image-private.h View File

@@ -9,8 +9,8 @@
//

//
// The ImageData class
// -------------------
// The ImageCodecData class
// ------------------------
//

#if !defined __LOL_IMAGE_PRIVATE_H__
@@ -19,103 +19,114 @@
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)
{}

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 ImageData;
friend class ImageCodecData;

public:
ImageData *(*fun)(char const *path);
ImageCodec *next;
int priority;
bool (*m_tryload)(Image *image, char const *path);
ImageCodec *m_next;
int m_priority;

static void RegisterLoader(ImageCodec *loader)
static void RegisterCodec(ImageCodec *codec)
{
Helper(loader);
Helper(codec);
}

private:
static ImageData *Load(char const *path)
static void Load(Image *image, char const *path)
{
ImageCodec *parser = Helper(nullptr);
ImageData *ret = nullptr;
ImageCodec *codec = Helper(nullptr);
bool success = false;

while (parser && !ret)
while (codec && !success)
{
ret = parser->fun(path);
parser = parser->next;
success = codec->m_tryload(image, path);
codec = codec->m_next;
}

return ret;
}

static ImageCodec *Helper(ImageCodec *set)
{
static ImageCodec *loaders = nullptr;
static ImageCodec *codec_list = nullptr;

if (!set)
return loaders;
return codec_list;

ImageCodec **parser = &loaders;
while (*parser && (*parser)->priority > set->priority)
parser = &(*parser)->next;
set->next = *parser;
*parser = set;
ImageCodec **codec = &codec_list;
while (*codec && (*codec)->m_priority > set->m_priority)
codec = &(*codec)->m_next;
set->m_next = *codec;
*codec = set;

return nullptr;
}
};

class ImageData
/*
* Codec-specific data that is stored in some images
*/
class ImageCodecData
{
friend class Image;
friend class ImageBank;

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

virtual ~ImageData() {}
inline ImageCodecData() {}
virtual ~ImageCodecData() {}

virtual bool Open(char const *) = 0;
virtual bool Save(char const *) = 0;
virtual bool Close() = 0;
virtual bool Load(Image *, char const *) = 0;
virtual bool Save(Image *, char const *) = 0;

virtual uint8_t *GetData() const = 0;
virtual bool RetrieveTiles(Array<ivec2, ivec2>& tiles) { return false; }

protected:
ivec2 m_size;
PixelFormat m_format;
int m_refcount;
};

#define REGISTER_IMAGE_LOADER(name) \
#define REGISTER_IMAGE_CODEC(name) \
extern void Register##name(); \
Register##name();

#define DECLARE_IMAGE_LOADER(name, prio) \
#define DECLARE_IMAGE_CODEC(name, prio) \
template<typename T> class name##ImageCodec : public ImageCodec \
{ \
public: \
name##ImageCodec() \
{ \
static ImageCodec loader; \
loader.fun = Load; \
loader.priority = prio; \
RegisterLoader(&loader); \
static ImageCodec codec; \
codec.m_tryload = Load; \
codec.m_priority = prio; \
RegisterCodec(&codec); \
} \
static ImageData *Load(char const *path) \
static bool Load(Image *image, char const *path) \
{ \
T *ret = new T(); \
if (!ret->Open(path)) \
{ \
delete ret; \
return nullptr; \
} \
T *codecdata = new T(); \
bool ret = codecdata->Load(image, path); \
delete codecdata; \
return ret; \
} \
}; \
@@ -125,7 +136,7 @@ protected:
{ \
(void)&name##ImageCodecInstance; \
} \
class name : public ImageData
class name : public ImageCodecData

} /* namespace lol */



+ 82
- 67
src/image/image.cpp View File

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

/* HACK: We cannot make this an ImageCodec member function, because the
* REGISTER_IMAGE_LOADER macro forward-declares free functions from
* 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.
@@ -30,26 +30,26 @@ 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 RegisterAllLoaders()
static bool RegisterAllCodecs()
{
#if defined __ANDROID__
REGISTER_IMAGE_LOADER(AndroidImageData)
REGISTER_IMAGE_CODEC(AndroidImageCodec)
#endif
REGISTER_IMAGE_LOADER(DummyImageData)
REGISTER_IMAGE_CODEC(DummyImageCodec)
#if defined USE_GDIPLUS
REGISTER_IMAGE_LOADER(GdiPlusImageData)
REGISTER_IMAGE_CODEC(GdiPlusImageCodec)
#endif
#if defined __APPLE__ && defined __MACH__ && defined __arm__
REGISTER_IMAGE_LOADER(IosImageData)
REGISTER_IMAGE_CODEC(IosImageCodec)
#endif
#if defined __CELLOS_LV2__
REGISTER_IMAGE_LOADER(Ps3ImageData)
REGISTER_IMAGE_CODEC(Ps3ImageCodec)
#endif
#if defined USE_SDL_IMAGE
REGISTER_IMAGE_LOADER(SdlImageData)
REGISTER_IMAGE_CODEC(SdlImageCodec)
#endif
REGISTER_IMAGE_LOADER(ZedImageData)
REGISTER_IMAGE_LOADER(ZedPaletteImageData)
REGISTER_IMAGE_CODEC(ZedImageCodec)
REGISTER_IMAGE_CODEC(ZedPaletteImageCodec)

return true;
}
@@ -63,8 +63,6 @@ static class ImageBank
public:
void Init();
Image *Create(char const *path);
bool Store(Image *img);
Image *Load(char const *path);

void Unref(Image *img);

@@ -75,51 +73,27 @@ g_image_bank;

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

Image *ImageBank::Create(char const *path)
{
/* Is our image already in the bank? If so, no need to create it. */
Image *img;
Init();

if (m_images.HasKey(path))
{
img = m_images[path];
}
else
/* Is our image already in the bank? If so, no need to create it. */
if (!m_images.HasKey(path))
{
img = Load(path);
m_images[path] = img;
m_images[path] = new Image();
ImageCodec::Load(m_images[path], path);
}

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

Image *ImageBank::Load(char const *path)
{
Init();

Image *img = new Image(path);
img->m_data = ImageCodec::Load(img->GetPath().C());
return img;
}

bool ImageBank::Store(Image *img)
{
/* Is our image already in the bank? If so, no need to create it. */
if (m_images.HasKey(img->GetPath().C()))
return false;

m_images[img->GetPath().C()] = img;

++img->m_data->m_refcount;
return true;
}

void ImageBank::Unref(Image *img)
{
ASSERT(img->m_data->m_refcount > 0);
@@ -145,24 +119,19 @@ Image *Image::Create(char const *path)
return g_image_bank.Create(path);
}

Image *Image::Load(char const *path)
{
return g_image_bank.Load(path);
}

bool Image::Store(Image *img)
{
return g_image_bank.Store(img);
}

/*
* Public Image class
*/

Image::Image(char const* path)
: m_data(nullptr)
Image::Image()
: m_data(new ImageData())
{
m_path = path;
}

Image::~Image()
{
delete m_data->m_codecdata;
delete m_data;
}

void Image::Destroy()
@@ -172,7 +141,10 @@ void Image::Destroy()

bool Image::Save(char const *path)
{
return m_data->Save(path);
/* FIXME: add autoloading of save codecs */
if (!m_data->m_codecdata)
return false;
return m_data->m_codecdata->Save(this, path);
}

ivec2 Image::GetSize() const
@@ -180,30 +152,73 @@ ivec2 Image::GetSize() const
return m_data->m_size;
}

void Image::SetSize(ivec2 size)
{
if (m_data->m_size != size)
{
/* FIXME: delete data or resize it */
if (m_data->m_format != PixelFormat::Unknown)
{
m_data->m_pixels.Remove((int)m_data->m_format);
}
}
m_data->m_size = size;

/* FIXME: don’t do this! */
if (m_data->m_format != PixelFormat::Unknown)
{
Lock<PixelFormat::RGBA_8>();
Unlock();
}
}

PixelFormat Image::GetFormat() const
{
return m_data->m_format;
}

uint8_t *Image::GetData() const
void *Image::LockGeneric()
{
return m_data->GetData();
ASSERT(m_data->m_format != PixelFormat::Unknown);

return m_data->m_pixels[(int)m_data->m_format];
}

String Image::GetPath() const
/* The Lock() method and its explicit specialisations */
template<PixelFormat T>
typename PixelType<T>::type *Image::Lock()
{
return m_path;
/* TODO: convert data if this doesn’t match */
ASSERT(m_data->m_format == T || m_data->m_format == PixelFormat::Unknown);
m_data->m_format = (PixelFormat)T;

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);
}

return (typename PixelType<T>::type *)m_data->m_pixels[(int)T];
}

bool Image::RetrieveTiles(Array<ivec2, ivec2>& tiles) const
template typename PixelType<PixelFormat::Y_8>::type *
Image::Lock<PixelFormat::Y_8>();
template typename PixelType<PixelFormat::RGB_8>::type *
Image::Lock<PixelFormat::RGB_8>();
template typename PixelType<PixelFormat::RGBA_8>::type *
Image::Lock<PixelFormat::RGBA_8>();

void Image::Unlock()
{
return m_data->RetrieveTiles(tiles);
/* TODO: ensure we are actually unlocking something we locked */
ASSERT(m_data->m_pixels.HasKey((int)m_data->m_format));
}

Image::~Image()
bool Image::RetrieveTiles(Array<ivec2, ivec2>& tiles) const
{
m_data->Close();
delete m_data;
if (!m_data->m_codecdata)
return false;
return m_data->m_codecdata->RetrieveTiles(tiles);
}

} /* namespace lol */


+ 20
- 28
src/lol/gpu/texture.h View File

@@ -19,38 +19,30 @@
namespace lol
{

struct PixelFormat
enum class PixelFormat
{
/* XXX: make sure to update texture.cpp when this changes */
enum Value
{
Unknown = 0,
RGB_8,
RGBA_8,
ARGB_8,
ABGR_8,
Y_8,
}
m_value;

inline PixelFormat() : m_value(Unknown) {}
inline PixelFormat(Value v) : m_value(v) {}
inline operator Value() { return m_value; }
Unknown = 0,
RGB_8,
RGBA_8,
ARGB_8,
ABGR_8,
Y_8,
};

inline uint8_t BytesPerPixel()
static inline uint8_t BytesPerPixel(PixelFormat format)
{
switch (format)
{
switch (m_value)
{
case Y_8:
return 1;
case RGB_8:
return 3;
case RGBA_8:
case ARGB_8:
case ABGR_8:
default:
return 4;
}
case PixelFormat::Y_8:
return 1;
case PixelFormat::RGB_8:
return 3;
case PixelFormat::RGBA_8:
case PixelFormat::ARGB_8:
case PixelFormat::ABGR_8:
default:
return 4;
}
};



+ 18
- 12
src/lol/image/image.h View File

@@ -21,31 +21,37 @@
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; };
template<> struct PixelType<PixelFormat::RGBA_8> { typedef u8vec4 type; };

class Image
{
friend class ImageBank;
friend class ImageCodec;

public:
//Create/Load/Store image into bank. THREAD: NOT SAFE
static Image* Create(char const *path);
//Create/Load image into bank. THREAD: SAFE
static Image* Load(char const *path);
//Store image into bank. THREAD: NOT SAFE
static bool Store(Image *img);
Image();
~Image();

static Image *Create(char const *path);

bool Save(char const *path);
void Destroy();

ivec2 GetSize() const;
PixelFormat GetFormat() const;
uint8_t *GetData() const;
String GetPath() 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:
Image(char const* path);
~Image();

class ImageData *m_data;
String m_path;
};


+ 5
- 3
src/tileset.cpp View File

@@ -202,12 +202,13 @@ void TileSet::TickDraw(float seconds)
else if (m_data->m_image)
{
PixelFormat format = m_data->m_image->GetFormat();
int planes = format.BytesPerPixel();
int planes = BytesPerPixel(format);

int w = m_data->m_texture_size.x;
int h = m_data->m_texture_size.y;

uint8_t *pixels = m_data->m_image->GetData();
uint8_t *pixels = (uint8_t *)m_data->m_image->LockGeneric();
bool resized = false;
if (w != m_data->m_image_size.x || h != m_data->m_image_size.y)
{
uint8_t *tmp = new uint8_t[planes * w * h];
@@ -216,12 +217,13 @@ void TileSet::TickDraw(float seconds)
pixels + planes * m_data->m_image_size.x * line,
planes * m_data->m_image_size.x);
pixels = tmp;
resized = false;
}

m_data->m_texture = new Texture(ivec2(w, h), format);
m_data->m_texture->SetData(pixels);

if (pixels != m_data->m_image->GetData())
if (resized)
delete[] pixels;
m_data->m_image->Destroy();
m_data->m_image = nullptr;


+ 8
- 7
test/unit/image.cpp View File

@@ -30,17 +30,18 @@ LOLUNIT_FIXTURE(ImageTest)
LOLUNIT_ASSERT_EQUAL(size.x, 256);
LOLUNIT_ASSERT_EQUAL(size.y, 16);

uint8_t *data = image->GetData();
u8vec4 *data = image->Lock<PixelFormat::RGBA_8>();
LOLUNIT_ASSERT(data);

LOLUNIT_ASSERT_EQUAL((int)data[0], 0x00);
LOLUNIT_ASSERT_EQUAL((int)data[1], 0x00);
LOLUNIT_ASSERT_EQUAL((int)data[2], 0x00);
LOLUNIT_ASSERT_EQUAL((int)data[0].r, 0x00);
LOLUNIT_ASSERT_EQUAL((int)data[0].g, 0x00);
LOLUNIT_ASSERT_EQUAL((int)data[0].b, 0x00);

LOLUNIT_ASSERT_EQUAL((int)data[255 * 4 + 0], 0xff);
LOLUNIT_ASSERT_EQUAL((int)data[255 * 4 + 1], 0xff);
LOLUNIT_ASSERT_EQUAL((int)data[255 * 4 + 2], 0xff);
LOLUNIT_ASSERT_EQUAL((int)data[255].r, 0xff);
LOLUNIT_ASSERT_EQUAL((int)data[255].g, 0xff);
LOLUNIT_ASSERT_EQUAL((int)data[255].b, 0xff);

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


Loading…
Cancel
Save