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