SDLSurfacePtr.hh 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. #ifndef SDLSURFACEPTR_HH
  2. #define SDLSURFACEPTR_HH
  3. #include "MemBuffer.hh"
  4. #include "InitException.hh"
  5. #include <SDL.h>
  6. #include <algorithm>
  7. #include <memory>
  8. #include <new>
  9. #include <cassert>
  10. #include <cstdlib>
  11. /** Wrapper around a SDL_Surface.
  12. *
  13. * Makes sure SDL_FreeSurface() is called when this object goes out of scope.
  14. * It's modeled after std::unique_ptr, so it has the usual get(), reset() and
  15. * release() methods. Like unique_ptr it can be moved but not copied.
  16. *
  17. * In addition to the SDL_Surface pointer, this wrapper also (optionally)
  18. * manages an extra memory buffer. Normally SDL_CreateRGBSurface() will
  19. * allocate/free an internal memory buffer for the surface. On construction
  20. * of the surface this buffer will be zero-initialized. Though in many cases
  21. * the surface will immediately be overwritten (so zero-initialization is
  22. * only extra overhead). It's possible to avoid this by creating the surface
  23. * using SDL_CreateRGBSurfaceFrom(). Though the downside of this is that you
  24. * have to manage the lifetime of the memory buffer yourself. And that's
  25. * exactly what this wrapper can do.
  26. *
  27. * As a bonus this wrapper has a getLinePtr() method to hide some of the
  28. * casting. But apart from this it doesn't try to abstract any SDL
  29. * functionality.
  30. */
  31. class SDLSurfacePtr
  32. {
  33. public:
  34. SDLSurfacePtr(const SDLSurfacePtr&) = delete;
  35. SDLSurfacePtr& operator=(const SDLSurfacePtr&) = delete;
  36. /** Create a (software) surface with uninitialized pixel content.
  37. * throws: bad_alloc (no need to check for nullptr). */
  38. SDLSurfacePtr(unsigned width, unsigned height, unsigned depth,
  39. Uint32 rMask, Uint32 gMask, Uint32 bMask, Uint32 aMask)
  40. {
  41. assert((depth % 8) == 0);
  42. unsigned pitch = width * (depth >> 3);
  43. unsigned size = height * pitch;
  44. buffer.resize(size);
  45. surface = SDL_CreateRGBSurfaceFrom(
  46. buffer.data(), width, height, depth, pitch,
  47. rMask, gMask, bMask, aMask);
  48. if (!surface) throw std::bad_alloc();
  49. }
  50. explicit SDLSurfacePtr(SDL_Surface* surface_ = nullptr)
  51. : surface(surface_)
  52. {
  53. }
  54. SDLSurfacePtr(SDLSurfacePtr&& other) noexcept
  55. : surface(other.surface)
  56. , buffer(std::move(other.buffer))
  57. {
  58. other.surface = nullptr;
  59. }
  60. ~SDLSurfacePtr()
  61. {
  62. if (surface) SDL_FreeSurface(surface);
  63. }
  64. void reset(SDL_Surface* surface_ = nullptr)
  65. {
  66. SDLSurfacePtr temp(surface_);
  67. temp.swap(*this);
  68. }
  69. SDL_Surface* get()
  70. {
  71. return surface;
  72. }
  73. const SDL_Surface* get() const
  74. {
  75. return surface;
  76. }
  77. void swap(SDLSurfacePtr& other) noexcept
  78. {
  79. std::swap(surface, other.surface);
  80. std::swap(buffer, other.buffer );
  81. }
  82. SDLSurfacePtr& operator=(SDLSurfacePtr&& other) noexcept
  83. {
  84. std::swap(surface, other.surface);
  85. std::swap(buffer, other.buffer);
  86. return *this;
  87. }
  88. SDL_Surface& operator*()
  89. {
  90. return *surface;
  91. }
  92. const SDL_Surface& operator*() const
  93. {
  94. return *surface;
  95. }
  96. SDL_Surface* operator->()
  97. {
  98. return surface;
  99. }
  100. const SDL_Surface* operator->() const
  101. {
  102. return surface;
  103. }
  104. explicit operator bool() const
  105. {
  106. return get() != nullptr;
  107. }
  108. void* getLinePtr(unsigned y)
  109. {
  110. assert(y < unsigned(surface->h));
  111. return static_cast<Uint8*>(surface->pixels) + y * surface->pitch;
  112. }
  113. const void* getLinePtr(unsigned y) const
  114. {
  115. return const_cast<SDLSurfacePtr*>(this)->getLinePtr(y);
  116. }
  117. private:
  118. SDL_Surface* surface;
  119. openmsx::MemBuffer<char> buffer;
  120. };
  121. struct SDLDestroyTexture {
  122. void operator()(SDL_Texture* t) { SDL_DestroyTexture(t); }
  123. };
  124. using SDLTexturePtr = std::unique_ptr<SDL_Texture, SDLDestroyTexture>;
  125. struct SDLDestroyRenderer {
  126. void operator()(SDL_Renderer* r) { SDL_DestroyRenderer(r); }
  127. };
  128. using SDLRendererPtr = std::unique_ptr<SDL_Renderer, SDLDestroyRenderer>;
  129. struct SDLDestroyWindow {
  130. void operator()(SDL_Window* w) { SDL_DestroyWindow(w); }
  131. };
  132. using SDLWindowPtr = std::unique_ptr<SDL_Window, SDLDestroyWindow>;
  133. struct SDLFreeFormat {
  134. void operator()(SDL_PixelFormat* p) { SDL_FreeFormat(p); }
  135. };
  136. using SDLAllocFormatPtr = std::unique_ptr<SDL_PixelFormat, SDLFreeFormat>;
  137. struct SDLFreeWav {
  138. void operator()(Uint8* w) { SDL_FreeWAV(w); }
  139. };
  140. using SDLWavPtr = std::unique_ptr<Uint8, SDLFreeWav>;
  141. template<Uint32 FLAGS>
  142. class SDLSubSystemInitializer
  143. {
  144. public:
  145. SDLSubSystemInitializer(const SDLSubSystemInitializer&) = delete;
  146. SDLSubSystemInitializer& operator=(const SDLSubSystemInitializer&) = delete;
  147. SDLSubSystemInitializer() {
  148. // SDL internally ref-counts sub-system initialization, so we
  149. // don't need to worry about it here.
  150. if (SDL_InitSubSystem(FLAGS) < 0) {
  151. throw openmsx::InitException(
  152. "SDL init failed (", FLAGS, "): ", SDL_GetError());
  153. }
  154. }
  155. ~SDLSubSystemInitializer() {
  156. SDL_QuitSubSystem(FLAGS);
  157. }
  158. };
  159. #endif