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); | |||||
| } | } | ||||
| } | } | ||||