|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- //
- // Lol Engine
- //
- // Copyright © 2010—2015 Sam Hocevar <sam@hocevar.net>
- //
- // Lol Engine is free software. It comes without any warranty, to
- // the extent permitted by applicable law. You can redistribute it
- // and/or modify it under the terms of the Do What the Fuck You Want
- // to Public License, Version 2, as published by the WTFPL Task Force.
- // See http://www.wtfpl.net/ for more details.
- //
-
- #include <lol/engine-internal.h>
-
- #include "image-private.h"
-
- #include <algorithm> /* for std::swap */
-
- namespace lol
- {
-
- /* HACK: We cannot make this an ImageLoader member function, because the
- * REGISTER_IMAGE_CODEC macro forward-declares free functions from
- * the "lol" namespace. An apparent bug in Visual Studio's compiler
- * makes it think these functions are actually in the top-level
- * namespace when the forward declaration is in a class member function.
- * To avoid the problem, we make the forward declaration in a free
- * function.
- * 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(array<ImageCodec *> &codeclist)
- {
- #if defined __ANDROID__
- REGISTER_IMAGE_CODEC(AndroidImageCodec)
- #endif
- #if defined USE_GDIPLUS
- REGISTER_IMAGE_CODEC(GdiPlusImageCodec)
- #endif
- #if defined __APPLE__ && defined __MACH__ && defined __arm__
- REGISTER_IMAGE_CODEC(IosImageCodec)
- #endif
- #if defined USE_SDL_IMAGE
- REGISTER_IMAGE_CODEC(SdlImageCodec)
- #endif
- #if defined USE_IMLIB2
- REGISTER_IMAGE_CODEC(Imlib2ImageCodec)
- #endif
- REGISTER_IMAGE_CODEC(DummyImageCodec)
- REGISTER_IMAGE_CODEC(ZedImageCodec)
- REGISTER_IMAGE_CODEC(ZedPaletteImageCodec)
- REGISTER_IMAGE_CODEC(OricImageCodec)
-
- return true;
- }
-
- /*
- * Our static image loader
- */
-
- static class ImageLoader
- {
- friend class Image;
-
- public:
- inline ImageLoader()
- {
- RegisterAllCodecs(m_codecs);
- }
-
- private:
- array<ImageCodec *> m_codecs;
- map<String, Image *> m_images;
- }
- g_image_loader;
-
- /*
- * Public Image class
- */
-
- Image::Image()
- : m_data(new ImageData())
- {
- }
-
- Image::Image(char const *path)
- : m_data(new ImageData())
- {
- Load(path);
- }
-
- Image::Image(ivec2 size)
- : m_data(new ImageData())
- {
- SetSize(size);
- }
-
- Image::Image (Image const &other)
- : m_data(new ImageData())
- {
- Copy(other);
- }
-
- Image & Image::operator =(Image other)
- {
- /* Since the argument is passed by value, we’re assured it’s a new
- * object and we can safely swap our m_data pointers. */
- std::swap(m_data, other.m_data);
- return *this;
- }
-
- Image::~Image()
- {
- for (int k : m_data->m_pixels.keys())
- delete m_data->m_pixels[k];
-
- 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(uint8_t* pixels, ivec2 const& size, PixelFormat fmt)
- {
- ASSERT(fmt != PixelFormat::Unknown);
- SetSize(size);
- SetFormat(fmt);
- memcpy(m_data->m_pixels[(int)fmt]->data(), pixels,
- size.x * size.y * BytesPerPixel(fmt));
- }
-
- 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))
- {
- msg::info("Image::Load: Codec %s succesfully loaded %s.\n", codec->GetName(), path);
- return true;
- }
- }
-
- //Log error, because we shouldn't be here
- msg::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))
- {
- msg::info("Image::Save: Codec %s succesfully saved %s.\n", codec->GetName(), path);
- return true;
- }
- }
-
- //Log error, because we shouldn't be here
- msg::error("Image::Save: Last codec %s, Error saving image %s.\n", last_codec->GetName(), path);
- return false;
- }
-
- ivec2 Image::GetSize() const
- {
- return m_data->m_size;
- }
-
- void Image::SetSize(ivec2 size)
- {
- ASSERT(size.x > 0);
- ASSERT(size.y > 0);
-
- if (m_data->m_size != size)
- {
- for (int k : m_data->m_pixels.keys())
- {
- delete m_data->m_pixels[k];
- m_data->m_pixels[k] = nullptr;
- }
-
- m_data->m_format = PixelFormat::Unknown;
- }
-
- m_data->m_size = size;
- }
-
- /* Wrap-around mode for some operations */
- WrapMode Image::GetWrapX() const
- {
- return m_data->m_wrap_x;
- }
-
- WrapMode Image::GetWrapY() const
- {
- return m_data->m_wrap_y;
- }
-
- void Image::SetWrap(WrapMode wrap_x, WrapMode wrap_y)
- {
- m_data->m_wrap_x = wrap_x;
- m_data->m_wrap_y = wrap_y;
- }
-
- /* The Lock() method */
- template<PixelFormat T> typename PixelType<T>::type *Image::Lock()
- {
- SetFormat(T);
-
- return (typename PixelType<T>::type *)m_data->m_pixels[(int)T]->data();
- }
-
- /* The Lock2D() method */
- void *Image::Lock2DHelper(PixelFormat T)
- {
- SetFormat(T);
-
- return m_data->m_pixels[(int)T]->data2d();
- }
-
- template<typename T>
- void Image::Unlock2D(array2d<T> const &array)
- {
- ASSERT(m_data->m_pixels.has_key((int)m_data->m_format));
- ASSERT(array.data() == m_data->m_pixels[(int)m_data->m_format]->data());
- }
-
- /* Explicit specialisations for the above templates */
- #define _T(T) \
- template PixelType<T>::type *Image::Lock<T>(); \
- template array2d<PixelType<T>::type> &Image::Lock2D<T>(); \
- template void Image::Unlock2D(array2d<PixelType<T>::type> const &array);
- _T(PixelFormat::Y_8)
- _T(PixelFormat::RGB_8)
- _T(PixelFormat::RGBA_8)
- _T(PixelFormat::Y_F32)
- _T(PixelFormat::RGB_F32)
- _T(PixelFormat::RGBA_F32)
- #undef _T
-
- /* Special case for the "any" format: return the last active buffer */
- void *Image::Lock()
- {
- ASSERT(m_data->m_format != PixelFormat::Unknown);
-
- return m_data->m_pixels[(int)m_data->m_format]->data();
- }
-
- void Image::Unlock(void const *pixels)
- {
- ASSERT(m_data->m_pixels.has_key((int)m_data->m_format));
- ASSERT(pixels == m_data->m_pixels[(int)m_data->m_format]->data());
- }
-
- bool Image::RetrieveTiles(array<ivec2, ivec2>& tiles) const
- {
- /* TODO: re-implement this */
- //return m_data->m_codecdata->RetrieveTiles(tiles);
- return false;
- }
-
- } /* namespace lol */
-
|