Inverted image/all.h and thread/all.h to ensure build Added Image::DummyFill that uses DummyImageCodec to fill empty image Added Log:: Error/Info in image Load/Saveundefined
@@ -33,6 +33,7 @@ extern ANativeActivity *g_activity; | |||
class AndroidImageCodec : public ImageCodec | |||
{ | |||
public: | |||
virtual char const *GetName() { return "<AndroidImageCodec>"; } | |||
virtual bool Load(Image *image, char const *path); | |||
virtual bool Save(Image *image, char const *path); | |||
virtual bool Close(); | |||
@@ -22,10 +22,12 @@ namespace lol | |||
class DummyImageCodec : public ImageCodec | |||
{ | |||
public: | |||
virtual char const *GetName() { return "<DummyImageCodec>"; } | |||
virtual bool Load(Image *image, char const *path); | |||
virtual bool Save(Image *image, char const *path); | |||
}; | |||
//Priority 0 because it's supposed to be the last one | |||
DECLARE_IMAGE_CODEC(DummyImageCodec, 0) | |||
/* | |||
@@ -49,14 +51,15 @@ bool DummyImageCodec::Load(Image *image, char const *path) | |||
} | |||
image->Unlock(pixels); | |||
return true; | |||
//return false, because we're not supposed to be here. | |||
return false; | |||
} | |||
bool DummyImageCodec::Save(Image *image, char const *path) | |||
{ | |||
UNUSED(path); | |||
return true; | |||
return false; | |||
} | |||
} /* namespace lol */ | |||
@@ -36,6 +36,7 @@ namespace lol | |||
class GdiPlusImageCodec : public ImageCodec | |||
{ | |||
public: | |||
virtual char const *GetName() { return "<GdiPlusImageCodec>"; } | |||
virtual bool Load(Image *image, char const *path); | |||
virtual bool Save(Image *image, char const *path); | |||
}; | |||
@@ -26,6 +26,7 @@ namespace lol | |||
class IosImageCodec : public ImageCodec | |||
{ | |||
public: | |||
virtual char const *GetName() { return "<IosImageCodec>"; } | |||
virtual bool Load(Image *image, char const *path); | |||
virtual bool Save(Image *image, char const *path); | |||
}; | |||
@@ -30,6 +30,7 @@ namespace lol | |||
class OricImageCodec : public ImageCodec | |||
{ | |||
public: | |||
virtual char const *GetName() { return "<OricImageCodec>"; } | |||
virtual bool Load(Image *image, char const *path); | |||
virtual bool Save(Image *image, char const *path); | |||
@@ -35,6 +35,7 @@ namespace lol | |||
class SdlImageCodec : public ImageCodec | |||
{ | |||
public: | |||
virtual char const *GetName() { return "<SdlImageCodec>"; } | |||
virtual bool Load(Image *image, char const *path); | |||
virtual bool Save(Image *image, char const *path); | |||
@@ -23,6 +23,7 @@ namespace lol | |||
class ZedImageCodec : public ImageCodec | |||
{ | |||
public: | |||
virtual char const *GetName() { return "<ZedImageCodec>"; } | |||
virtual bool Load(Image *image, char const *path); | |||
virtual bool Save(Image *image, char const *path); | |||
@@ -39,7 +40,7 @@ private: | |||
array<ivec2, ivec2> m_tiles; | |||
}; | |||
DECLARE_IMAGE_CODEC(ZedImageCodec, 0) | |||
DECLARE_IMAGE_CODEC(ZedImageCodec, 10) | |||
/* | |||
* Public Image class | |||
@@ -22,11 +22,12 @@ namespace lol | |||
class ZedPaletteImageCodec : public ImageCodec | |||
{ | |||
public: | |||
virtual char const *GetName() { return "<ZedPaletteImageCodec>"; } | |||
virtual bool Load(Image *image, char const *path); | |||
virtual bool Save(Image *image, char const *path); | |||
}; | |||
DECLARE_IMAGE_CODEC(ZedPaletteImageCodec, 0) | |||
DECLARE_IMAGE_CODEC(ZedPaletteImageCodec, 10) | |||
/* | |||
* Public Image class | |||
@@ -69,6 +69,7 @@ public: | |||
class ImageCodec | |||
{ | |||
public: | |||
virtual char const *GetName() { return "<ImageCodec>"; } | |||
virtual bool Load(Image *image, char const *path) = 0; | |||
virtual bool Save(Image *image, char const *path) = 0; | |||
@@ -98,17 +98,7 @@ Image::Image(ivec2 size) | |||
Image::Image (Image const &other) | |||
: m_data(new ImageData()) | |||
{ | |||
ivec2 size = other.GetSize(); | |||
PixelFormat fmt = other.GetFormat(); | |||
SetSize(size); | |||
if (fmt != PixelFormat::Unknown) | |||
{ | |||
SetFormat(fmt); | |||
memcpy(m_data->m_pixels[(int)fmt]->data(), | |||
other.m_data->m_pixels[(int)fmt]->data(), | |||
size.x * size.y * BytesPerPixel(fmt)); | |||
} | |||
Copy(other); | |||
} | |||
Image & Image::operator =(Image other) | |||
@@ -127,19 +117,67 @@ Image::~Image() | |||
delete m_data; | |||
} | |||
void Image::DummyFill() | |||
{ | |||
//TODO: This is not very beautiful | |||
for (auto codec : g_image_loader.m_codecs) | |||
{ | |||
if (String(codec->GetName()).Contains("Dummy")) | |||
{ | |||
codec->Load(this, nullptr); | |||
return; | |||
} | |||
} | |||
} | |||
void Image::Copy(Image const &other) | |||
{ | |||
ivec2 size = other.GetSize(); | |||
PixelFormat fmt = other.GetFormat(); | |||
SetSize(size); | |||
if (fmt != PixelFormat::Unknown) | |||
{ | |||
SetFormat(fmt); | |||
memcpy(m_data->m_pixels[(int)fmt]->data(), | |||
other.m_data->m_pixels[(int)fmt]->data(), | |||
size.x * size.y * BytesPerPixel(fmt)); | |||
} | |||
} | |||
bool Image::Load(char const *path) | |||
{ | |||
ImageCodec* last_codec = nullptr; | |||
for (auto codec : g_image_loader.m_codecs) | |||
{ | |||
last_codec = codec; | |||
if (codec->Load(this, path)) | |||
{ | |||
Log::Info("Image::Load: Codec %s succesfully loaded %s.\n", codec->GetName(), path); | |||
return true; | |||
} | |||
} | |||
//Log error, because we shouldn't be here | |||
Log::Error("Image::Load: Last codec %s, Error loading image %s.\n", last_codec->GetName(), path); | |||
return false; | |||
} | |||
bool Image::Save(char const *path) | |||
{ | |||
ImageCodec* last_codec = nullptr; | |||
for (auto codec : g_image_loader.m_codecs) | |||
{ | |||
last_codec = codec; | |||
if (codec->Save(this, path)) | |||
{ | |||
Log::Info("Image::Save: Codec %s succesfully saved %s.\n", codec->GetName(), path); | |||
return true; | |||
} | |||
} | |||
//Log error, because we shouldn't be here | |||
Log::Error("Image::Save: Last codec %s, Error saving image %s.\n", last_codec->GetName(), path); | |||
return false; | |||
} | |||
@@ -56,6 +56,7 @@ enum class EdiffAlgorithm : uint8_t | |||
Lite, | |||
}; | |||
//Image ----------------------------------------------------------------------- | |||
class Image | |||
{ | |||
public: | |||
@@ -70,6 +71,8 @@ public: | |||
Image & operator =(Image other); | |||
~Image(); | |||
void DummyFill(); | |||
void Copy(Image const &other); | |||
bool Load(char const *path); | |||
bool Save(char const *path); | |||
@@ -18,8 +18,8 @@ | |||
#include <lol/base/all.h> | |||
#include <lol/math/all.h> | |||
#include <lol/algorithm/all.h> | |||
#include <lol/sys/all.h> | |||
#include <lol/image/all.h> | |||
#include <lol/sys/all.h> | |||
#include <lol/gpu/all.h> | |||
#include <lol/debug/all.h> | |||
@@ -113,21 +113,16 @@ protected: | |||
class BaseThreadManager : public Entity | |||
{ | |||
public: | |||
char const *GetName() { return "<BaseThreadManager>"; } | |||
BaseThreadManager(int thread_count); | |||
BaseThreadManager(int thread_count, int thread_min); | |||
~BaseThreadManager(); | |||
char const *GetName() { return "<BaseThreadManager>"; } | |||
//Initialize, Ticker::Ref and start the thread | |||
bool Start(); | |||
//Stop the threads | |||
bool Stop(); | |||
//Children class intergace | |||
virtual bool AddJob(ThreadJob* job) { ASSERT(false); return false; } | |||
virtual bool GetWorkResult(array<ThreadJob*>& results) { ASSERT(false); return false; } | |||
protected: | |||
//Thread addition | |||
void AddThreads(int nb); | |||
@@ -25,6 +25,7 @@ namespace lol | |||
class DefaultThreadManager : public BaseThreadManager | |||
{ | |||
public: | |||
char const *GetName() { return "<DefaultThreadManager>"; } | |||
DefaultThreadManager(int thread_count) | |||
: BaseThreadManager(thread_count, thread_count) | |||
{ } | |||
@@ -32,8 +33,6 @@ public: | |||
: BaseThreadManager(thread_count, thread_min) | |||
{ } | |||
char const *GetName() { return "<DefaultThreadManager>"; } | |||
//Work stuff | |||
bool AddJob(ThreadJob* job); | |||
bool GetWorkResult(array<ThreadJob*>& results); | |||
@@ -70,7 +69,8 @@ protected: | |||
bool m_updated = false; | |||
}; | |||
//Test the files registered and warns when they update ------------------------ | |||
//FileUpdateTester ------------------------------------------------------------ | |||
//Test the files registered and warns when they update | |||
class FileUpdateTester : public BaseThreadManager | |||
{ | |||
typedef BaseThreadManager super; | |||
@@ -80,9 +80,9 @@ public: | |||
bool m_updated = false; | |||
}; | |||
public: | |||
char const *GetName() { return "<FileUpdateTester>"; } | |||
FileUpdateTester() : BaseThreadManager(1) { } | |||
~FileUpdateTester() { } | |||
char const *GetName() { return "<FileUpdateTester>"; } | |||
//------------------------------------------------------------------------- | |||
FileUpdateTester::Status* RegisterFile(String const& path); | |||
@@ -94,5 +94,97 @@ private: | |||
map<String, Status*> m_files; | |||
}; | |||
//AsyncImageJob --------------------------------------------------------------- | |||
class AsyncImageJob : public ThreadJob | |||
{ | |||
public: | |||
AsyncImageJob() | |||
: ThreadJob(ThreadJobType::NONE) | |||
{ | |||
m_path = String(); | |||
} | |||
AsyncImageJob(String path) | |||
: ThreadJob(ThreadJobType::WORK_TODO) | |||
{ | |||
m_path = path; | |||
} | |||
String const& GetPath() { return m_path; } | |||
Image const& GetImage() { return m_image; } | |||
protected: | |||
virtual bool DoWork() | |||
{ | |||
return m_image.Load(m_path.C()); | |||
} | |||
String m_path; | |||
Image m_image; | |||
}; | |||
//AsyncImageLoader ------------------------------------------------------------ | |||
//Load images asynchronously, automatically updating the dummy image | |||
class AsyncImageLoader : public BaseThreadManager | |||
{ | |||
public: | |||
char const *GetName() { return "<AsyncImageLoader>"; } | |||
AsyncImageLoader(int thread_count) | |||
: BaseThreadManager(thread_count, 0) | |||
{ | |||
m_dummy_image.DummyFill(); | |||
} | |||
~AsyncImageLoader() | |||
{ } | |||
//Returns a dummy image, and start a job to load the image on a thread | |||
Image* Load(const lol::String& path) | |||
{ | |||
//Create a job | |||
AsyncImageJob* job = new AsyncImageJob(path); | |||
//Create a dummy image | |||
Image* image = new Image(m_dummy_image); | |||
//Link the two | |||
m_images[path] = image; | |||
//Add job | |||
AddWork(job); | |||
//return Dummy image | |||
return image; | |||
} | |||
bool CheckStatus(Image* image) | |||
{ | |||
if (m_loaded_images.find(image) != INDEX_NONE) | |||
{ | |||
m_loaded_images.remove_item(image); | |||
return true; | |||
} | |||
return false; | |||
} | |||
protected: | |||
virtual void TreatResult(ThreadJob* result) | |||
{ | |||
AsyncImageJob* job = dynamic_cast<AsyncImageJob*>(result); | |||
ASSERT(job); | |||
//Copy image if work is OK | |||
if (job->GetJobType() != ThreadJobType::WORK_FAILED) | |||
{ | |||
Image* src = m_images[job->GetPath()]; | |||
m_images.remove(job->GetPath()); | |||
src->Copy(job->GetImage()); | |||
m_loaded_images.PushUnique(src); | |||
} | |||
else | |||
{ | |||
Log::Error("AsyncImageJob FAILED. See load image error above.\n"); | |||
} | |||
//Delete all that | |||
delete(result); | |||
} | |||
private: | |||
Image m_dummy_image; | |||
map<String, Image*> m_images; | |||
array<Image*> m_loaded_images; | |||
}; | |||
} /* namespace lol */ | |||
@@ -166,10 +166,8 @@ void BaseThreadManager::TickGame(float seconds) | |||
{ | |||
ThreadJob* job = result[i]; | |||
if (job->GetJobType() == ThreadJobType::WORK_DONE) | |||
{ | |||
job->SetJobType(ThreadJobType::WORK_FETCHED); | |||
TreatResult(job); | |||
} | |||
TreatResult(job); | |||
} | |||
} | |||