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