Преглед изворни кода

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

and the codec logic.
undefined
Sam Hocevar пре 10 година
родитељ
комит
f455f0e2d1
14 измењених фајлова са 302 додато и 306 уклоњено
  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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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 Прегледај датотеку

@@ -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…
Откажи
Сачувај