and the codec logic.undefined
@@ -35,11 +35,11 @@ extern ANativeActivity *g_activity; | |||||
* Image implementation class | * Image implementation class | ||||
*/ | */ | ||||
DECLARE_IMAGE_LOADER(AndroidImageData, 100) | |||||
DECLARE_IMAGE_CODEC(AndroidImageCodec, 100) | |||||
{ | { | ||||
public: | 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 bool Close(); | ||||
virtual uint8_t *GetData() const; | virtual uint8_t *GetData() const; | ||||
@@ -50,7 +50,7 @@ private: | |||||
jint *pixels; | jint *pixels; | ||||
}; | }; | ||||
bool AndroidImageData::Open(char const *path) | |||||
bool AndroidImageCodec::Load(Image *image, char const *path) | |||||
{ | { | ||||
JNIEnv *env; | JNIEnv *env; | ||||
jint res = g_activity->vm->GetEnv((void **)&env, JNI_VERSION_1_2); | jint res = g_activity->vm->GetEnv((void **)&env, JNI_VERSION_1_2); | ||||
@@ -109,14 +109,14 @@ bool AndroidImageData::Open(char const *path) | |||||
return true; | return true; | ||||
} | } | ||||
bool AndroidImageData::Save(char const *path) | |||||
bool AndroidImageCodec::Save(Image *image, char const *path) | |||||
{ | { | ||||
UNUSED(path); | UNUSED(path); | ||||
/* TODO: unimplemented */ | /* TODO: unimplemented */ | ||||
} | } | ||||
bool AndroidImageData::Close() | |||||
bool AndroidImageCodec::Close() | |||||
{ | { | ||||
JNIEnv *env; | JNIEnv *env; | ||||
jint res = g_activity->vm->GetEnv((void **)&env, JNI_VERSION_1_2); | jint res = g_activity->vm->GetEnv((void **)&env, JNI_VERSION_1_2); | ||||
@@ -141,7 +141,7 @@ bool AndroidImageData::Close() | |||||
return true; | return true; | ||||
} | } | ||||
uint8_t *AndroidImageData::GetData() const | |||||
uint8_t *AndroidImageCodec::GetData() const | |||||
{ | { | ||||
return (uint8_t *)pixels; | return (uint8_t *)pixels; | ||||
} | } | ||||
@@ -24,61 +24,49 @@ namespace lol | |||||
* Image implementation class | * Image implementation class | ||||
*/ | */ | ||||
DECLARE_IMAGE_LOADER(DummyImageData, 0) | |||||
DECLARE_IMAGE_CODEC(DummyImageCodec, 0) | |||||
{ | { | ||||
public: | 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 bool Close(); | ||||
virtual uint8_t *GetData() const; | |||||
private: | |||||
uint8_t *pixels; | |||||
}; | }; | ||||
/* | /* | ||||
* Public Image class | * Public Image class | ||||
*/ | */ | ||||
bool DummyImageData::Open(char const *path) | |||||
bool DummyImageCodec::Load(Image *image, char const *path) | |||||
{ | { | ||||
UNUSED(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 j = 0; j < 256; j++) | ||||
for (int i = 0; i < 256; i++) | 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; | return true; | ||||
} | } | ||||
bool DummyImageData::Save(char const *path) | |||||
bool DummyImageCodec::Save(Image *image, char const *path) | |||||
{ | { | ||||
UNUSED(path); | UNUSED(path); | ||||
return true; | return true; | ||||
} | } | ||||
bool DummyImageData::Close() | |||||
bool DummyImageCodec::Close() | |||||
{ | { | ||||
delete[] pixels; | |||||
return true; | return true; | ||||
} | } | ||||
uint8_t * DummyImageData::GetData() const | |||||
{ | |||||
return pixels; | |||||
} | |||||
} /* namespace lol */ | } /* namespace lol */ | ||||
@@ -31,11 +31,11 @@ namespace lol | |||||
* Image implementation class | * Image implementation class | ||||
*/ | */ | ||||
DECLARE_IMAGE_LOADER(GdiPlusImageData, 100) | |||||
DECLARE_IMAGE_CODEC(GdiPlusImageCodec, 100) | |||||
{ | { | ||||
public: | 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 bool Close(); | ||||
virtual uint8_t *GetData() const; | virtual uint8_t *GetData() const; | ||||
@@ -49,7 +49,7 @@ private: | |||||
* Public Image class | * Public Image class | ||||
*/ | */ | ||||
bool GdiPlusImageData::Open(char const *path) | |||||
bool GdiPlusImageCodec::Load(Image *image, char const *path) | |||||
{ | { | ||||
Gdiplus::Status status; | Gdiplus::Status status; | ||||
ULONG_PTR token; | ULONG_PTR token; | ||||
@@ -110,10 +110,11 @@ bool GdiPlusImageData::Open(char const *path) | |||||
return false; | 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, | if (m_bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead, | ||||
PixelFormat32bppARGB, &m_bdata) != Gdiplus::Ok) | 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 | * 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); | 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]; | uint8_t tmp = p[2]; | ||||
p[2] = p[0]; | p[2] = p[0]; | ||||
@@ -140,7 +141,7 @@ bool GdiPlusImageData::Open(char const *path) | |||||
return true; | return true; | ||||
} | } | ||||
bool GdiPlusImageData::Save(char const *path) | |||||
bool GdiPlusImageCodec::Save(Image *image, char const *path) | |||||
{ | { | ||||
ULONG_PTR token; | ULONG_PTR token; | ||||
Gdiplus::GdiplusStartupInput input; | 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 | /* 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(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); | PixelFormat32bppARGB); | ||||
Gdiplus::BitmapData bdata; | 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, | if (b->LockBits(&rect, (unsigned int)Gdiplus::ImageLockModeWrite, | ||||
PixelFormat32bppARGB, &bdata) != Gdiplus::Ok) | PixelFormat32bppARGB, &bdata) != Gdiplus::Ok) | ||||
@@ -210,8 +212,8 @@ bool GdiPlusImageData::Save(char const *path) | |||||
u8vec4 *psrc = static_cast<u8vec4 *>(m_bdata.Scan0); | u8vec4 *psrc = static_cast<u8vec4 *>(m_bdata.Scan0); | ||||
u8vec4 *pdst = static_cast<u8vec4 *>(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; | *pdst++ = (*psrc++).bgra; | ||||
} | } | ||||
@@ -233,7 +235,7 @@ bool GdiPlusImageData::Save(char const *path) | |||||
return true; | return true; | ||||
} | } | ||||
bool GdiPlusImageData::Close() | |||||
bool GdiPlusImageCodec::Close() | |||||
{ | { | ||||
m_bitmap->UnlockBits(&m_bdata); | m_bitmap->UnlockBits(&m_bdata); | ||||
delete m_bitmap; | delete m_bitmap; | ||||
@@ -241,7 +243,7 @@ bool GdiPlusImageData::Close() | |||||
return true; | return true; | ||||
} | } | ||||
uint8_t * GdiPlusImageData::GetData() const | |||||
uint8_t * GdiPlusImageCodec::GetData() const | |||||
{ | { | ||||
return static_cast<uint8_t *>(m_bdata.Scan0); | return static_cast<uint8_t *>(m_bdata.Scan0); | ||||
} | } | ||||
@@ -28,11 +28,11 @@ namespace lol | |||||
* Image implementation class | * Image implementation class | ||||
*/ | */ | ||||
DECLARE_IMAGE_LOADER(IosImageData, 100) | |||||
DECLARE_IMAGE_CODEC(IosImageCodec, 100) | |||||
{ | { | ||||
public: | 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 bool Close(); | ||||
virtual uint8_t *GetData() const; | virtual uint8_t *GetData() const; | ||||
@@ -45,7 +45,7 @@ private: | |||||
* Public Image class | * Public Image class | ||||
*/ | */ | ||||
bool IosImageData::Open(char const *path) | |||||
bool IosImageCodec::Load(Image *image, char const *path) | |||||
{ | { | ||||
NSString *fullpath = [NSString stringWithUTF8String:path]; | NSString *fullpath = [NSString stringWithUTF8String:path]; | ||||
NSArray *chunks = [fullpath componentsSeparatedByString: @"/"]; | NSArray *chunks = [fullpath componentsSeparatedByString: @"/"]; | ||||
@@ -84,7 +84,7 @@ bool IosImageData::Open(char const *path) | |||||
return true; | return true; | ||||
} | } | ||||
bool IosImageData::Save(char const *path) | |||||
bool IosImageCodec::Save(Image *image, char const *path) | |||||
{ | { | ||||
UNUSED(path); | UNUSED(path); | ||||
@@ -92,14 +92,14 @@ bool IosImageData::Save(char const *path) | |||||
return true; | return true; | ||||
} | } | ||||
bool IosImageData::Close() | |||||
bool IosImageCodec::Close() | |||||
{ | { | ||||
free(pixels); | free(pixels); | ||||
return true; | return true; | ||||
} | } | ||||
uint8_t * IosImageData::GetData() const | |||||
uint8_t * IosImageCodec::GetData() const | |||||
{ | { | ||||
return pixels; | return pixels; | ||||
} | } | ||||
@@ -30,11 +30,11 @@ namespace lol | |||||
* Image implementation class | * Image implementation class | ||||
*/ | */ | ||||
DECLARE_IMAGE_LOADER(Ps3ImageData, 100) | |||||
DECLARE_IMAGE_CODEC(Ps3ImageCodec, 100) | |||||
{ | { | ||||
public: | 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 bool Close(); | ||||
virtual uint8_t *GetData() const; | virtual uint8_t *GetData() const; | ||||
@@ -49,7 +49,7 @@ private: | |||||
* Public Image class | * Public Image class | ||||
*/ | */ | ||||
bool Ps3ImageData::Open(char const *path) | |||||
bool Ps3ImageCodec::Load(Image *image, char const *path) | |||||
{ | { | ||||
int32_t err; | int32_t err; | ||||
@@ -74,9 +74,9 @@ bool Ps3ImageData::Open(char const *path) | |||||
in_param.spuThreadEnable = CELL_PNGDEC_SPU_THREAD_ENABLE; | in_param.spuThreadEnable = CELL_PNGDEC_SPU_THREAD_ENABLE; | ||||
in_param.ppuThreadPriority = 1000; | in_param.ppuThreadPriority = 1000; | ||||
in_param.spuThreadPriority = 200; | in_param.spuThreadPriority = 200; | ||||
in_param.cbCtrlMallocFunc = Ps3ImageData::Malloc; | |||||
in_param.cbCtrlMallocFunc = Ps3ImageCodec::Malloc; | |||||
in_param.cbCtrlMallocArg = nullptr; | in_param.cbCtrlMallocArg = nullptr; | ||||
in_param.cbCtrlFreeFunc = Ps3ImageData::Free; | |||||
in_param.cbCtrlFreeFunc = Ps3ImageCodec::Free; | |||||
in_param.cbCtrlFreeArg = nullptr; | in_param.cbCtrlFreeArg = nullptr; | ||||
CellPngDecThreadOutParam out_param; | CellPngDecThreadOutParam out_param; | ||||
err = cellPngDecCreate(&hmain, &in_param, &out_param); | err = cellPngDecCreate(&hmain, &in_param, &out_param); | ||||
@@ -174,7 +174,7 @@ bool Ps3ImageData::Open(char const *path) | |||||
return true; | return true; | ||||
} | } | ||||
bool Ps3ImageData::Open(char const *path) | |||||
bool Ps3ImageCodec::Load(Image *image, char const *path) | |||||
{ | { | ||||
UNUSED(path); | UNUSED(path); | ||||
@@ -182,14 +182,14 @@ bool Ps3ImageData::Open(char const *path) | |||||
return true; | return true; | ||||
} | } | ||||
bool Ps3ImageData::Close() | |||||
bool Ps3ImageCodec::Close() | |||||
{ | { | ||||
free(pixels); | free(pixels); | ||||
return true; | return true; | ||||
} | } | ||||
uint8_t * Ps3ImageData::GetData() const | |||||
uint8_t * Ps3ImageCodec::GetData() const | |||||
{ | { | ||||
return pixels; | return pixels; | ||||
} | } | ||||
@@ -37,36 +37,34 @@ namespace lol | |||||
* Image implementation class | * Image implementation class | ||||
*/ | */ | ||||
DECLARE_IMAGE_LOADER(SdlImageData, 50) | |||||
DECLARE_IMAGE_CODEC(SdlImageCodec, 50) | |||||
{ | { | ||||
public: | 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 bool Close(); | ||||
virtual uint8_t *GetData() const; | |||||
static SDL_Surface *Create32BppSurface(ivec2 size); | static SDL_Surface *Create32BppSurface(ivec2 size); | ||||
private: | private: | ||||
SDL_Surface *m_img; | |||||
SDL_Surface *m_surface; | |||||
}; | }; | ||||
/* | /* | ||||
* Public Image class | * Public Image class | ||||
*/ | */ | ||||
bool SdlImageData::Open(char const *path) | |||||
bool SdlImageCodec::Load(Image *image, char const *path) | |||||
{ | { | ||||
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_img = IMG_Load(pathlist[i].C()); | |||||
if (m_img) | |||||
m_surface = IMG_Load(pathlist[i].C()); | |||||
if (m_surface) | |||||
break; | break; | ||||
} | } | ||||
if (!m_img) | |||||
if (!m_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); | ||||
@@ -74,42 +72,37 @@ bool SdlImageData::Open(char const *path) | |||||
return false; | 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; | 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; | return ret == 0; | ||||
} | } | ||||
bool SdlImageData::Close() | |||||
bool SdlImageCodec::Close() | |||||
{ | { | ||||
SDL_FreeSurface(m_img); | |||||
SDL_FreeSurface(m_surface); | |||||
return true; | 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; | uint32_t rmask, gmask, bmask, amask; | ||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN | #if SDL_BYTEORDER == SDL_BIG_ENDIAN | ||||
@@ -25,11 +25,11 @@ namespace lol | |||||
* Image implementation class | * Image implementation class | ||||
*/ | */ | ||||
DECLARE_IMAGE_LOADER(ZedImageData, 0) | |||||
DECLARE_IMAGE_CODEC(ZedImageCodec, 0) | |||||
{ | { | ||||
public: | 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 bool Close(); | ||||
virtual uint8_t *GetData() const; | virtual uint8_t *GetData() const; | ||||
@@ -51,7 +51,7 @@ private: | |||||
* Public Image class | * Public Image class | ||||
*/ | */ | ||||
bool ZedImageData::Open(char const *path) | |||||
bool ZedImageCodec::Load(Image *image, char const *path) | |||||
{ | { | ||||
if (!lol::String(path).EndsWith(".RSC")) | if (!lol::String(path).EndsWith(".RSC")) | ||||
return false; | return false; | ||||
@@ -239,10 +239,8 @@ bool ZedImageData::Open(char const *path) | |||||
tex_size <<= 1; | tex_size <<= 1; | ||||
//Prepare final imqge | //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 | //Data refactor stage | ||||
ivec2 pos = ivec2(0); | 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++) | 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; | 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++; | j++; | ||||
} | } | ||||
} | } | ||||
image->Unlock(); | |||||
return true; | return true; | ||||
} | } | ||||
bool ZedImageData::Save(char const *path) | |||||
bool ZedImageCodec::Save(Image *image, char const *path) | |||||
{ | { | ||||
UNUSED(path); | UNUSED(path); | ||||
/* FIXME: do we need to implement this? */ | /* FIXME: do we need to implement this? */ | ||||
return true; | return true; | ||||
} | } | ||||
bool ZedImageData::Close() | |||||
bool ZedImageCodec::Close() | |||||
{ | { | ||||
delete[] m_pixels; | |||||
return true; | return true; | ||||
} | } | ||||
uint8_t * ZedImageData::GetData() const | |||||
uint8_t * ZedImageCodec::GetData() const | |||||
{ | { | ||||
return m_pixels; | return m_pixels; | ||||
} | } | ||||
@@ -24,24 +24,19 @@ namespace lol | |||||
* Image implementation class | * Image implementation class | ||||
*/ | */ | ||||
DECLARE_IMAGE_LOADER(ZedPaletteImageData, 0) | |||||
DECLARE_IMAGE_CODEC(ZedPaletteImageCodec, 0) | |||||
{ | { | ||||
public: | 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 bool Close(); | ||||
virtual uint8_t *GetData() const; | |||||
private: | |||||
uint8_t *m_pixels; | |||||
}; | }; | ||||
/* | /* | ||||
* Public Image class | * Public Image class | ||||
*/ | */ | ||||
bool ZedPaletteImageData::Open(char const *path) | |||||
bool ZedPaletteImageCodec::Load(Image *image, char const *path) | |||||
{ | { | ||||
if (!lol::String(path).EndsWith(".pal")) | if (!lol::String(path).EndsWith(".pal")) | ||||
return false; | return false; | ||||
@@ -61,47 +56,40 @@ bool ZedPaletteImageData::Open(char const *path) | |||||
int32_t tex_size = 2; | int32_t tex_size = 2; | ||||
while (tex_size < tex_sqrt) | while (tex_size < tex_sqrt) | ||||
tex_size <<= 1; | tex_size <<= 1; | ||||
m_size = ivec2(tex_size); | |||||
image->m_data->m_size = ivec2(tex_size); | |||||
#else | #else | ||||
int32_t tex_sqrt = file_size / 3; | int32_t tex_sqrt = file_size / 3; | ||||
int32_t tex_size = 2; | int32_t tex_size = 2; | ||||
while (tex_size < tex_sqrt) | while (tex_size < tex_sqrt) | ||||
tex_size <<= 1; | tex_size <<= 1; | ||||
m_size = ivec2(tex_size, 1); | |||||
image->SetSize(ivec2(tex_size, 1)); | |||||
#endif | #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();) | 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; | return true; | ||||
} | } | ||||
bool ZedPaletteImageData::Save(char const *path) | |||||
bool ZedPaletteImageCodec::Save(Image *image, char const *path) | |||||
{ | { | ||||
UNUSED(path); | UNUSED(path); | ||||
/* FIXME: do we need to implement this? */ | /* FIXME: do we need to implement this? */ | ||||
return true; | return true; | ||||
} | } | ||||
bool ZedPaletteImageData::Close() | |||||
bool ZedPaletteImageCodec::Close() | |||||
{ | { | ||||
delete[] m_pixels; | |||||
return true; | return true; | ||||
} | } | ||||
uint8_t * ZedPaletteImageData::GetData() const | |||||
{ | |||||
return m_pixels; | |||||
} | |||||
} /* namespace lol */ | } /* namespace lol */ | ||||
@@ -9,8 +9,8 @@ | |||||
// | // | ||||
// | // | ||||
// The ImageData class | |||||
// ------------------- | |||||
// The ImageCodecData class | |||||
// ------------------------ | |||||
// | // | ||||
#if !defined __LOL_IMAGE_PRIVATE_H__ | #if !defined __LOL_IMAGE_PRIVATE_H__ | ||||
@@ -19,103 +19,114 @@ | |||||
namespace lol | 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 | class ImageCodec | ||||
{ | { | ||||
friend class ImageBank; | friend class ImageBank; | ||||
friend class ImageData; | |||||
friend class ImageCodecData; | |||||
public: | 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: | 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 *Helper(ImageCodec *set) | ||||
{ | { | ||||
static ImageCodec *loaders = nullptr; | |||||
static ImageCodec *codec_list = nullptr; | |||||
if (!set) | 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; | return nullptr; | ||||
} | } | ||||
}; | }; | ||||
class ImageData | |||||
/* | |||||
* Codec-specific data that is stored in some images | |||||
*/ | |||||
class ImageCodecData | |||||
{ | { | ||||
friend class Image; | friend class Image; | ||||
friend class ImageBank; | friend class ImageBank; | ||||
public: | 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; } | 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(); \ | extern void Register##name(); \ | ||||
Register##name(); | Register##name(); | ||||
#define DECLARE_IMAGE_LOADER(name, prio) \ | |||||
#define DECLARE_IMAGE_CODEC(name, prio) \ | |||||
template<typename T> class name##ImageCodec : public ImageCodec \ | template<typename T> class name##ImageCodec : public ImageCodec \ | ||||
{ \ | { \ | ||||
public: \ | public: \ | ||||
name##ImageCodec() \ | 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; \ | return ret; \ | ||||
} \ | } \ | ||||
}; \ | }; \ | ||||
@@ -125,7 +136,7 @@ protected: | |||||
{ \ | { \ | ||||
(void)&name##ImageCodecInstance; \ | (void)&name##ImageCodecInstance; \ | ||||
} \ | } \ | ||||
class name : public ImageData | |||||
class name : public ImageCodecData | |||||
} /* namespace lol */ | } /* namespace lol */ | ||||
@@ -21,7 +21,7 @@ namespace lol | |||||
{ | { | ||||
/* HACK: We cannot make this an ImageCodec member function, because the | /* 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 | * the "lol" namespace. An apparent bug in Visual Studio's compiler | ||||
* makes it think these functions are actually in the top-level | * makes it think these functions are actually in the top-level | ||||
* namespace when the forward declaration is in a class member function. | * 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 | * 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 RegisterAllLoaders() | |||||
static bool RegisterAllCodecs() | |||||
{ | { | ||||
#if defined __ANDROID__ | #if defined __ANDROID__ | ||||
REGISTER_IMAGE_LOADER(AndroidImageData) | |||||
REGISTER_IMAGE_CODEC(AndroidImageCodec) | |||||
#endif | #endif | ||||
REGISTER_IMAGE_LOADER(DummyImageData) | |||||
REGISTER_IMAGE_CODEC(DummyImageCodec) | |||||
#if defined USE_GDIPLUS | #if defined USE_GDIPLUS | ||||
REGISTER_IMAGE_LOADER(GdiPlusImageData) | |||||
REGISTER_IMAGE_CODEC(GdiPlusImageCodec) | |||||
#endif | #endif | ||||
#if defined __APPLE__ && defined __MACH__ && defined __arm__ | #if defined __APPLE__ && defined __MACH__ && defined __arm__ | ||||
REGISTER_IMAGE_LOADER(IosImageData) | |||||
REGISTER_IMAGE_CODEC(IosImageCodec) | |||||
#endif | #endif | ||||
#if defined __CELLOS_LV2__ | #if defined __CELLOS_LV2__ | ||||
REGISTER_IMAGE_LOADER(Ps3ImageData) | |||||
REGISTER_IMAGE_CODEC(Ps3ImageCodec) | |||||
#endif | #endif | ||||
#if defined USE_SDL_IMAGE | #if defined USE_SDL_IMAGE | ||||
REGISTER_IMAGE_LOADER(SdlImageData) | |||||
REGISTER_IMAGE_CODEC(SdlImageCodec) | |||||
#endif | #endif | ||||
REGISTER_IMAGE_LOADER(ZedImageData) | |||||
REGISTER_IMAGE_LOADER(ZedPaletteImageData) | |||||
REGISTER_IMAGE_CODEC(ZedImageCodec) | |||||
REGISTER_IMAGE_CODEC(ZedPaletteImageCodec) | |||||
return true; | return true; | ||||
} | } | ||||
@@ -63,8 +63,6 @@ static class ImageBank | |||||
public: | public: | ||||
void Init(); | void Init(); | ||||
Image *Create(char const *path); | Image *Create(char const *path); | ||||
bool Store(Image *img); | |||||
Image *Load(char const *path); | |||||
void Unref(Image *img); | void Unref(Image *img); | ||||
@@ -75,51 +73,27 @@ g_image_bank; | |||||
void ImageBank::Init() | void ImageBank::Init() | ||||
{ | { | ||||
/* Initialise loaders (see above) */ | |||||
static bool init = RegisterAllLoaders(); | |||||
/* Initialise codecs (see above) */ | |||||
static bool init = RegisterAllCodecs(); | |||||
UNUSED(init); | UNUSED(init); | ||||
} | } | ||||
Image *ImageBank::Create(char const *path) | 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; | ++img->m_data->m_refcount; | ||||
return img; | 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) | void ImageBank::Unref(Image *img) | ||||
{ | { | ||||
ASSERT(img->m_data->m_refcount > 0); | ASSERT(img->m_data->m_refcount > 0); | ||||
@@ -145,24 +119,19 @@ Image *Image::Create(char const *path) | |||||
return g_image_bank.Create(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 | * 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() | void Image::Destroy() | ||||
@@ -172,7 +141,10 @@ void Image::Destroy() | |||||
bool Image::Save(char const *path) | 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 | ivec2 Image::GetSize() const | ||||
@@ -180,30 +152,73 @@ ivec2 Image::GetSize() const | |||||
return m_data->m_size; | 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 | PixelFormat Image::GetFormat() const | ||||
{ | { | ||||
return m_data->m_format; | 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 */ | } /* namespace lol */ | ||||
@@ -19,38 +19,30 @@ | |||||
namespace lol | namespace lol | ||||
{ | { | ||||
struct PixelFormat | |||||
enum class PixelFormat | |||||
{ | { | ||||
/* XXX: make sure to update texture.cpp when this changes */ | /* 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; | |||||
} | } | ||||
}; | }; | ||||
@@ -21,31 +21,37 @@ | |||||
namespace lol | 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 | class Image | ||||
{ | { | ||||
friend class ImageBank; | friend class ImageBank; | ||||
friend class ImageCodec; | |||||
public: | 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); | bool Save(char const *path); | ||||
void Destroy(); | void Destroy(); | ||||
ivec2 GetSize() const; | |||||
PixelFormat GetFormat() 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; | bool RetrieveTiles(Array<ivec2, ivec2>& tiles) const; | ||||
private: | private: | ||||
Image(char const* path); | |||||
~Image(); | |||||
class ImageData *m_data; | class ImageData *m_data; | ||||
String m_path; | String m_path; | ||||
}; | }; | ||||
@@ -202,12 +202,13 @@ void TileSet::TickDraw(float seconds) | |||||
else if (m_data->m_image) | else if (m_data->m_image) | ||||
{ | { | ||||
PixelFormat format = m_data->m_image->GetFormat(); | PixelFormat format = m_data->m_image->GetFormat(); | ||||
int planes = format.BytesPerPixel(); | |||||
int planes = BytesPerPixel(format); | |||||
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 = 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) | if (w != m_data->m_image_size.x || h != m_data->m_image_size.y) | ||||
{ | { | ||||
uint8_t *tmp = new uint8_t[planes * w * h]; | 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, | pixels + planes * m_data->m_image_size.x * line, | ||||
planes * m_data->m_image_size.x); | planes * m_data->m_image_size.x); | ||||
pixels = tmp; | pixels = tmp; | ||||
resized = false; | |||||
} | } | ||||
m_data->m_texture = new Texture(ivec2(w, h), format); | m_data->m_texture = new Texture(ivec2(w, h), format); | ||||
m_data->m_texture->SetData(pixels); | m_data->m_texture->SetData(pixels); | ||||
if (pixels != m_data->m_image->GetData()) | |||||
if (resized) | |||||
delete[] pixels; | delete[] pixels; | ||||
m_data->m_image->Destroy(); | m_data->m_image->Destroy(); | ||||
m_data->m_image = nullptr; | m_data->m_image = nullptr; | ||||
@@ -30,17 +30,18 @@ LOLUNIT_FIXTURE(ImageTest) | |||||
LOLUNIT_ASSERT_EQUAL(size.x, 256); | LOLUNIT_ASSERT_EQUAL(size.x, 256); | ||||
LOLUNIT_ASSERT_EQUAL(size.y, 16); | LOLUNIT_ASSERT_EQUAL(size.y, 16); | ||||
uint8_t *data = image->GetData(); | |||||
u8vec4 *data = image->Lock<PixelFormat::RGBA_8>(); | |||||
LOLUNIT_ASSERT(data); | 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(); | image->Destroy(); | ||||
} | } | ||||
}; | }; | ||||