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 | class AndroidImageCodec : public ImageCodec | ||||
{ | { | ||||
public: | public: | ||||
virtual char const *GetName() { return "<AndroidImageCodec>"; } | |||||
virtual bool Load(Image *image, char const *path); | virtual bool Load(Image *image, char const *path); | ||||
virtual bool Save(Image *image, char const *path); | virtual bool Save(Image *image, char const *path); | ||||
virtual bool Close(); | virtual bool Close(); | ||||
@@ -22,10 +22,12 @@ namespace lol | |||||
class DummyImageCodec : public ImageCodec | class DummyImageCodec : public ImageCodec | ||||
{ | { | ||||
public: | public: | ||||
virtual char const *GetName() { return "<DummyImageCodec>"; } | |||||
virtual bool Load(Image *image, char const *path); | virtual bool Load(Image *image, char const *path); | ||||
virtual bool Save(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) | DECLARE_IMAGE_CODEC(DummyImageCodec, 0) | ||||
/* | /* | ||||
@@ -49,14 +51,15 @@ bool DummyImageCodec::Load(Image *image, char const *path) | |||||
} | } | ||||
image->Unlock(pixels); | 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) | bool DummyImageCodec::Save(Image *image, char const *path) | ||||
{ | { | ||||
UNUSED(path); | UNUSED(path); | ||||
return true; | |||||
return false; | |||||
} | } | ||||
} /* namespace lol */ | } /* namespace lol */ | ||||
@@ -36,6 +36,7 @@ namespace lol | |||||
class GdiPlusImageCodec : public ImageCodec | class GdiPlusImageCodec : public ImageCodec | ||||
{ | { | ||||
public: | public: | ||||
virtual char const *GetName() { return "<GdiPlusImageCodec>"; } | |||||
virtual bool Load(Image *image, char const *path); | virtual bool Load(Image *image, char const *path); | ||||
virtual bool Save(Image *image, char const *path); | virtual bool Save(Image *image, char const *path); | ||||
}; | }; | ||||
@@ -26,6 +26,7 @@ namespace lol | |||||
class IosImageCodec : public ImageCodec | class IosImageCodec : public ImageCodec | ||||
{ | { | ||||
public: | public: | ||||
virtual char const *GetName() { return "<IosImageCodec>"; } | |||||
virtual bool Load(Image *image, char const *path); | virtual bool Load(Image *image, char const *path); | ||||
virtual bool Save(Image *image, char const *path); | virtual bool Save(Image *image, char const *path); | ||||
}; | }; | ||||
@@ -30,6 +30,7 @@ namespace lol | |||||
class OricImageCodec : public ImageCodec | class OricImageCodec : public ImageCodec | ||||
{ | { | ||||
public: | public: | ||||
virtual char const *GetName() { return "<OricImageCodec>"; } | |||||
virtual bool Load(Image *image, char const *path); | virtual bool Load(Image *image, char const *path); | ||||
virtual bool Save(Image *image, char const *path); | virtual bool Save(Image *image, char const *path); | ||||
@@ -35,6 +35,7 @@ namespace lol | |||||
class SdlImageCodec : public ImageCodec | class SdlImageCodec : public ImageCodec | ||||
{ | { | ||||
public: | public: | ||||
virtual char const *GetName() { return "<SdlImageCodec>"; } | |||||
virtual bool Load(Image *image, char const *path); | virtual bool Load(Image *image, char const *path); | ||||
virtual bool Save(Image *image, char const *path); | virtual bool Save(Image *image, char const *path); | ||||
@@ -23,6 +23,7 @@ namespace lol | |||||
class ZedImageCodec : public ImageCodec | class ZedImageCodec : public ImageCodec | ||||
{ | { | ||||
public: | public: | ||||
virtual char const *GetName() { return "<ZedImageCodec>"; } | |||||
virtual bool Load(Image *image, char const *path); | virtual bool Load(Image *image, char const *path); | ||||
virtual bool Save(Image *image, char const *path); | virtual bool Save(Image *image, char const *path); | ||||
@@ -39,7 +40,7 @@ private: | |||||
array<ivec2, ivec2> m_tiles; | array<ivec2, ivec2> m_tiles; | ||||
}; | }; | ||||
DECLARE_IMAGE_CODEC(ZedImageCodec, 0) | |||||
DECLARE_IMAGE_CODEC(ZedImageCodec, 10) | |||||
/* | /* | ||||
* Public Image class | * Public Image class | ||||
@@ -22,11 +22,12 @@ namespace lol | |||||
class ZedPaletteImageCodec : public ImageCodec | class ZedPaletteImageCodec : public ImageCodec | ||||
{ | { | ||||
public: | public: | ||||
virtual char const *GetName() { return "<ZedPaletteImageCodec>"; } | |||||
virtual bool Load(Image *image, char const *path); | virtual bool Load(Image *image, char const *path); | ||||
virtual bool Save(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 | * Public Image class | ||||
@@ -69,6 +69,7 @@ public: | |||||
class ImageCodec | class ImageCodec | ||||
{ | { | ||||
public: | public: | ||||
virtual char const *GetName() { return "<ImageCodec>"; } | |||||
virtual bool Load(Image *image, char const *path) = 0; | virtual bool Load(Image *image, char const *path) = 0; | ||||
virtual bool Save(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) | Image::Image (Image const &other) | ||||
: m_data(new ImageData()) | : 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) | Image & Image::operator =(Image other) | ||||
@@ -127,19 +117,67 @@ Image::~Image() | |||||
delete m_data; | 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) | bool Image::Load(char const *path) | ||||
{ | { | ||||
ImageCodec* last_codec = nullptr; | |||||
for (auto codec : g_image_loader.m_codecs) | for (auto codec : g_image_loader.m_codecs) | ||||
{ | |||||
last_codec = codec; | |||||
if (codec->Load(this, path)) | if (codec->Load(this, path)) | ||||
{ | |||||
Log::Info("Image::Load: Codec %s succesfully loaded %s.\n", codec->GetName(), path); | |||||
return true; | 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; | return false; | ||||
} | } | ||||
bool Image::Save(char const *path) | bool Image::Save(char const *path) | ||||
{ | { | ||||
ImageCodec* last_codec = nullptr; | |||||
for (auto codec : g_image_loader.m_codecs) | for (auto codec : g_image_loader.m_codecs) | ||||
{ | |||||
last_codec = codec; | |||||
if (codec->Save(this, path)) | if (codec->Save(this, path)) | ||||
{ | |||||
Log::Info("Image::Save: Codec %s succesfully saved %s.\n", codec->GetName(), path); | |||||
return true; | 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; | return false; | ||||
} | } | ||||
@@ -56,6 +56,7 @@ enum class EdiffAlgorithm : uint8_t | |||||
Lite, | Lite, | ||||
}; | }; | ||||
//Image ----------------------------------------------------------------------- | |||||
class Image | class Image | ||||
{ | { | ||||
public: | public: | ||||
@@ -70,6 +71,8 @@ public: | |||||
Image & operator =(Image other); | Image & operator =(Image other); | ||||
~Image(); | ~Image(); | ||||
void DummyFill(); | |||||
void Copy(Image const &other); | |||||
bool Load(char const *path); | bool Load(char const *path); | ||||
bool Save(char const *path); | bool Save(char const *path); | ||||
@@ -18,8 +18,8 @@ | |||||
#include <lol/base/all.h> | #include <lol/base/all.h> | ||||
#include <lol/math/all.h> | #include <lol/math/all.h> | ||||
#include <lol/algorithm/all.h> | #include <lol/algorithm/all.h> | ||||
#include <lol/sys/all.h> | |||||
#include <lol/image/all.h> | #include <lol/image/all.h> | ||||
#include <lol/sys/all.h> | |||||
#include <lol/gpu/all.h> | #include <lol/gpu/all.h> | ||||
#include <lol/debug/all.h> | #include <lol/debug/all.h> | ||||
@@ -113,21 +113,16 @@ protected: | |||||
class BaseThreadManager : public Entity | class BaseThreadManager : public Entity | ||||
{ | { | ||||
public: | public: | ||||
char const *GetName() { return "<BaseThreadManager>"; } | |||||
BaseThreadManager(int thread_count); | BaseThreadManager(int thread_count); | ||||
BaseThreadManager(int thread_count, int thread_min); | BaseThreadManager(int thread_count, int thread_min); | ||||
~BaseThreadManager(); | ~BaseThreadManager(); | ||||
char const *GetName() { return "<BaseThreadManager>"; } | |||||
//Initialize, Ticker::Ref and start the thread | //Initialize, Ticker::Ref and start the thread | ||||
bool Start(); | bool Start(); | ||||
//Stop the threads | //Stop the threads | ||||
bool Stop(); | 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: | protected: | ||||
//Thread addition | //Thread addition | ||||
void AddThreads(int nb); | void AddThreads(int nb); | ||||
@@ -25,6 +25,7 @@ namespace lol | |||||
class DefaultThreadManager : public BaseThreadManager | class DefaultThreadManager : public BaseThreadManager | ||||
{ | { | ||||
public: | public: | ||||
char const *GetName() { return "<DefaultThreadManager>"; } | |||||
DefaultThreadManager(int thread_count) | DefaultThreadManager(int thread_count) | ||||
: BaseThreadManager(thread_count, thread_count) | : BaseThreadManager(thread_count, thread_count) | ||||
{ } | { } | ||||
@@ -32,8 +33,6 @@ public: | |||||
: BaseThreadManager(thread_count, thread_min) | : BaseThreadManager(thread_count, thread_min) | ||||
{ } | { } | ||||
char const *GetName() { return "<DefaultThreadManager>"; } | |||||
//Work stuff | //Work stuff | ||||
bool AddJob(ThreadJob* job); | bool AddJob(ThreadJob* job); | ||||
bool GetWorkResult(array<ThreadJob*>& results); | bool GetWorkResult(array<ThreadJob*>& results); | ||||
@@ -70,7 +69,8 @@ protected: | |||||
bool m_updated = false; | 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 | class FileUpdateTester : public BaseThreadManager | ||||
{ | { | ||||
typedef BaseThreadManager super; | typedef BaseThreadManager super; | ||||
@@ -80,9 +80,9 @@ public: | |||||
bool m_updated = false; | bool m_updated = false; | ||||
}; | }; | ||||
public: | public: | ||||
char const *GetName() { return "<FileUpdateTester>"; } | |||||
FileUpdateTester() : BaseThreadManager(1) { } | FileUpdateTester() : BaseThreadManager(1) { } | ||||
~FileUpdateTester() { } | ~FileUpdateTester() { } | ||||
char const *GetName() { return "<FileUpdateTester>"; } | |||||
//------------------------------------------------------------------------- | //------------------------------------------------------------------------- | ||||
FileUpdateTester::Status* RegisterFile(String const& path); | FileUpdateTester::Status* RegisterFile(String const& path); | ||||
@@ -94,5 +94,97 @@ private: | |||||
map<String, Status*> m_files; | 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 */ | } /* namespace lol */ | ||||
@@ -166,10 +166,8 @@ void BaseThreadManager::TickGame(float seconds) | |||||
{ | { | ||||
ThreadJob* job = result[i]; | ThreadJob* job = result[i]; | ||||
if (job->GetJobType() == ThreadJobType::WORK_DONE) | if (job->GetJobType() == ThreadJobType::WORK_DONE) | ||||
{ | |||||
job->SetJobType(ThreadJobType::WORK_FETCHED); | job->SetJobType(ThreadJobType::WORK_FETCHED); | ||||
TreatResult(job); | |||||
} | |||||
TreatResult(job); | |||||
} | } | ||||
} | } | ||||