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