diff --git a/CMakeLists.txt b/CMakeLists.txt index 5499b80..9586761 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,6 +99,7 @@ SET(LIBRARY_SOURCES SDL2pp/Renderer.cc SDL2pp/SDL.cc SDL2pp/Surface.cc + SDL2pp/SurfaceLock.cc SDL2pp/Texture.cc SDL2pp/TextureLock.cc SDL2pp/Wav.cc diff --git a/SDL2pp/Surface.cc b/SDL2pp/Surface.cc index 0d310c6..5aa6725 100644 --- a/SDL2pp/Surface.cc +++ b/SDL2pp/Surface.cc @@ -59,4 +59,8 @@ SDL_Surface* Surface::Get() const { return surface_; } +Surface::LockHandle Surface::Lock() { + return LockHandle(this); +} + } diff --git a/SDL2pp/Surface.hh b/SDL2pp/Surface.hh index 6079934..033de0a 100644 --- a/SDL2pp/Surface.hh +++ b/SDL2pp/Surface.hh @@ -25,6 +25,7 @@ #include struct SDL_Surface; +struct SDL_PixelFormat; namespace SDL2pp { @@ -43,6 +44,102 @@ class Surface { private: SDL_Surface* surface_; ///< Contained SDL_Texture structure +public: + //////////////////////////////////////////////////////////// + /// \brief SDL2pp::Surface lock + /// \ingroup rendering + /// + /// \details + /// For direct pixel access, SDL surface may need to be locked. + /// This class represents the lock and controls its lifetime + /// as the lock is released as soon as LockHandle is destroyed. + /// + //////////////////////////////////////////////////////////// + class LockHandle { + friend class Surface; + private: + Surface* surface_; ///< SDL2pp::Surface this lock belongs to + + private: + //////////////////////////////////////////////////////////// + /// \brief Create lock for specific SDL2pp::Texture + /// + /// \throws STL2pp::Exception + /// + /// \see http://wiki.libsdl.org/SDL_LockSurface + /// + //////////////////////////////////////////////////////////// + LockHandle(Surface* surface); + + public: + //////////////////////////////////////////////////////////// + /// \brief Create no-op lock + /// + /// \details + /// This may be initialized with real lock later with move + /// assignment operator + /// + //////////////////////////////////////////////////////////// + LockHandle(); + + //////////////////////////////////////////////////////////// + /// \brief Destructor + /// + /// \details + /// Releases the lock + /// + /// \see http://wiki.libsdl.org/SDL_UnlockSurface + /// + //////////////////////////////////////////////////////////// + ~LockHandle(); + + //////////////////////////////////////////////////////////// + /// \brief Move constructor + /// + /// \param other SDL2pp::Surface::LockHandle to move data from + /// + //////////////////////////////////////////////////////////// + LockHandle(LockHandle&& other) noexcept; + + //////////////////////////////////////////////////////////// + /// \brief Move assignment operator + /// + /// \param other SDL2pp::Surface::LockHandle to move data from + /// + /// \returns Reference to self + /// + //////////////////////////////////////////////////////////// + LockHandle& operator=(LockHandle&& other) noexcept; + + // Deleted copy constructor and assignment + LockHandle(const LockHandle& other) = delete; + LockHandle& operator=(const LockHandle& other) = delete; + + //////////////////////////////////////////////////////////// + /// \brief Get pointer to raw pixel data of locked region + /// + /// \returns Pointer to raw pixel data of locked region + /// + //////////////////////////////////////////////////////////// + void* GetPixels() const; + + //////////////////////////////////////////////////////////// + /// \brief Get pitch of locked pixel data + /// + /// \returns Number of bytes in a row of pixel data, including + /// padding between lines + /// + //////////////////////////////////////////////////////////// + int GetPitch() const; + + //////////////////////////////////////////////////////////// + /// \brief Get pixel format of the surface + /// + /// \returns Format of the pixels stored in the surface + /// + //////////////////////////////////////////////////////////// + const SDL_PixelFormat& GetFormat() const; + }; public: //////////////////////////////////////////////////////////// /// \brief Create RGB surface @@ -120,6 +217,18 @@ public: /// //////////////////////////////////////////////////////////// SDL_Surface* Get() const; + + //////////////////////////////////////////////////////////// + /// \brief Lock surface for direct pixel access + /// + /// \return Lock handle used to access pixel data and to control lock lifetime + /// + /// \throws SDL2pp::Exception + /// + /// \see http://wiki.libsdl.org/SDL_LockSurface + /// + //////////////////////////////////////////////////////////// + LockHandle Lock(); }; } diff --git a/SDL2pp/SurfaceLock.cc b/SDL2pp/SurfaceLock.cc new file mode 100644 index 0000000..162e80d --- /dev/null +++ b/SDL2pp/SurfaceLock.cc @@ -0,0 +1,79 @@ +/* + libSDL2pp - C++11 bindings/wrapper for SDL2 + Copyright (C) 2014 Dmitry Marakasov + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#include + +#include + +#include + +namespace SDL2pp { + +Surface::LockHandle::LockHandle() : surface_(nullptr) { +} + +Surface::LockHandle::LockHandle(Surface* surface) : surface_(surface) { + if (SDL_MUSTLOCK(surface_->Get())) { + if (SDL_LockSurface(surface_->Get())) + throw Exception("SDL_LockSurface failed"); + } +} + +Surface::LockHandle::LockHandle(Surface::LockHandle&& other) noexcept : surface_(other.surface_) { + other.surface_ = nullptr; +} + +Surface::LockHandle& Surface::LockHandle::operator=(Surface::LockHandle&& other) noexcept { + if (&other == this) + return *this; + + if (surface_ != nullptr) { + if (SDL_MUSTLOCK(surface_->Get())) + SDL_UnlockSurface(surface_->Get()); + } + + surface_ = other.surface_; + + other.surface_ = nullptr; + + return *this; +} + +Surface::LockHandle::~LockHandle() { + if (surface_ != nullptr) { + if (SDL_MUSTLOCK(surface_->Get())) + SDL_UnlockSurface(surface_->Get()); + } +} + +void* Surface::LockHandle::GetPixels() const { + return surface_->Get()->pixels; +} + +int Surface::LockHandle::GetPitch() const { + return surface_->Get()->pitch; +} + +const SDL_PixelFormat& Surface::LockHandle::GetFormat() const { + return *surface_->Get()->format; +} + +}