1 /*
2 libSDL2pp - C++11 bindings/wrapper for SDL2
3 Copyright (C) 2013-2016 Dmitry Marakasov <amdmi3@amdmi3.ru>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21
22 #include <vector>
23 #include <cassert>
24
25 #include <SDL.h>
26
27 #include <SDL2pp/Renderer.hh>
28 #include <SDL2pp/Window.hh>
29 #include <SDL2pp/Exception.hh>
30 #include <SDL2pp/Texture.hh>
31
32 namespace SDL2pp {
33
Renderer(SDL_Renderer * renderer)34 Renderer::Renderer(SDL_Renderer* renderer) : renderer_(renderer) {
35 assert(renderer);
36 }
37
Renderer(Window & window,int index,Uint32 flags)38 Renderer::Renderer(Window& window, int index, Uint32 flags) {
39 if ((renderer_ = SDL_CreateRenderer(window.Get(), index, flags)) == nullptr)
40 throw Exception("SDL_CreateRenderer");
41 }
42
~Renderer()43 Renderer::~Renderer() {
44 if (renderer_ != nullptr)
45 SDL_DestroyRenderer(renderer_);
46 }
47
Renderer(Renderer && other)48 Renderer::Renderer(Renderer&& other) noexcept : renderer_(other.renderer_) {
49 other.renderer_ = nullptr;
50 }
51
operator =(Renderer && other)52 Renderer& Renderer::operator=(Renderer&& other) noexcept {
53 if (&other == this)
54 return *this;
55 if (renderer_ != nullptr)
56 SDL_DestroyRenderer(renderer_);
57 renderer_ = other.renderer_;
58 other.renderer_ = nullptr;
59 return *this;
60 }
61
Get() const62 SDL_Renderer* Renderer::Get() const {
63 return renderer_;
64 }
65
Present()66 Renderer& Renderer::Present() {
67 SDL_RenderPresent(renderer_);
68 return *this;
69 }
70
Clear()71 Renderer& Renderer::Clear() {
72 if (SDL_RenderClear(renderer_) != 0)
73 throw Exception("SDL_RenderClear");
74 return *this;
75 }
76
GetInfo(SDL_RendererInfo & info)77 void Renderer::GetInfo(SDL_RendererInfo& info) {
78 if (SDL_GetRendererInfo(renderer_, &info) != 0)
79 throw Exception("SDL_GetRendererInfo");
80 }
81
Copy(Texture & texture,const Optional<Rect> & srcrect,const Optional<Rect> & dstrect)82 Renderer& Renderer::Copy(Texture& texture, const Optional<Rect>& srcrect, const Optional<Rect>& dstrect) {
83 if (SDL_RenderCopy(renderer_, texture.Get(), srcrect ? &*srcrect : nullptr, dstrect ? &*dstrect : nullptr) != 0)
84 throw Exception("SDL_RenderCopy");
85 return *this;
86 }
87
Copy(Texture & texture,const Optional<Rect> & srcrect,const Point & dstpoint)88 Renderer& Renderer::Copy(Texture& texture, const Optional<Rect>& srcrect, const Point& dstpoint) {
89 Rect dstrect(
90 dstpoint.x,
91 dstpoint.y,
92 srcrect ? srcrect->w : texture.GetWidth(),
93 srcrect ? srcrect->h : texture.GetHeight()
94 );
95 return Copy(texture, srcrect, dstrect);
96 }
97
Copy(Texture & texture,const Optional<Rect> & srcrect,const Optional<Rect> & dstrect,double angle,const Optional<Point> & center,int flip)98 Renderer& Renderer::Copy(Texture& texture, const Optional<Rect>& srcrect, const Optional<Rect>& dstrect, double angle, const Optional<Point>& center, int flip) {
99 if (SDL_RenderCopyEx(renderer_, texture.Get(), srcrect ? &*srcrect : nullptr, dstrect ? &*dstrect : nullptr, angle, center ? &*center : nullptr, static_cast<SDL_RendererFlip>(flip)) != 0)
100 throw Exception("SDL_RenderCopyEx");
101 return *this;
102 }
103
Copy(Texture & texture,const Optional<Rect> & srcrect,const Point & dstpoint,double angle,const Optional<Point> & center,int flip)104 Renderer& Renderer::Copy(Texture& texture, const Optional<Rect>& srcrect, const Point& dstpoint, double angle, const Optional<Point>& center, int flip) {
105 Rect dstrect(
106 dstpoint.x,
107 dstpoint.y,
108 srcrect ? srcrect->w : texture.GetWidth(),
109 srcrect ? srcrect->h : texture.GetHeight()
110 );
111 return Copy(texture, srcrect, dstrect, angle, center, flip);
112 }
113
FillCopy(Texture & texture,const Optional<Rect> & srcrect,const Optional<Rect> & dstrect,const Point & offset,int flip)114 Renderer& Renderer::FillCopy(Texture& texture, const Optional<Rect>& srcrect, const Optional<Rect>& dstrect, const Point& offset, int flip) {
115 // resolve rectangles
116 Rect src = srcrect ? *srcrect : Rect(0, 0, texture.GetWidth(), texture.GetHeight());
117 Rect dst = dstrect ? *dstrect : Rect(0, 0, GetOutputWidth(), GetOutputHeight());
118
119 // rectangle for single tile
120 Rect start_tile(
121 offset.x,
122 offset.y,
123 src.w,
124 src.h
125 );
126
127 // ensure tile is leftmost and topmost
128 if (start_tile.x + start_tile.w <= 0)
129 start_tile.x += (-start_tile.x) / start_tile.w * start_tile.w;
130 if (start_tile.x > 0)
131 start_tile.x -= (start_tile.x + start_tile.w - 1) / start_tile.w * start_tile.w;
132
133 if (start_tile.y + start_tile.h <= 0)
134 start_tile.y += (-start_tile.y) / start_tile.h * start_tile.h;
135 if (start_tile.y > 0)
136 start_tile.y -= (start_tile.y + start_tile.h - 1) / start_tile.h * start_tile.h;
137
138 // paint tile array
139 for (int y = start_tile.y; y < dst.h; y += start_tile.h) {
140 for (int x = start_tile.x; x < dst.w; x += start_tile.w) {
141 Rect tile_src = src;
142 Rect tile_dst(x, y, start_tile.w, start_tile.h);
143
144 // clamp with dstrect
145 int xunderflow = -x;
146 if (xunderflow > 0) {
147 tile_src.w -= xunderflow;
148 tile_src.x += xunderflow;
149 tile_dst.w -= xunderflow;
150 tile_dst.x += xunderflow;
151 }
152
153 int yunderflow = -y;
154 if (yunderflow > 0) {
155 tile_src.h -= yunderflow;
156 tile_src.y += yunderflow;
157 tile_dst.h -= yunderflow;
158 tile_dst.y += yunderflow;
159 }
160
161 int xoverflow = tile_dst.x + tile_dst.w - dst.w;
162 if (xoverflow > 0) {
163 tile_src.w -= xoverflow;
164 tile_dst.w -= xoverflow;
165 }
166
167 int yoverflow = tile_dst.y + tile_dst.h - dst.h;
168 if (yoverflow > 0) {
169 tile_src.h -= yoverflow;
170 tile_dst.h -= yoverflow;
171 }
172
173 // make tile_dst absolute
174 tile_dst.x += dst.x;
175 tile_dst.y += dst.y;
176
177 if (flip != 0) {
178 // mirror tile_src inside src to take flipping into account
179 if (flip & SDL_FLIP_HORIZONTAL)
180 tile_src.x = src.w - tile_src.x - tile_src.w;
181
182 if (flip & SDL_FLIP_VERTICAL)
183 tile_src.y = src.h - tile_src.y - tile_src.h;
184
185 Copy(texture, tile_src, tile_dst, 0.0, NullOpt, flip);
186 } else {
187 Copy(texture, tile_src, tile_dst);
188 }
189 }
190 }
191 return *this;
192 }
193
SetDrawColor(Uint8 r,Uint8 g,Uint8 b,Uint8 a)194 Renderer& Renderer::SetDrawColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a) {
195 if (SDL_SetRenderDrawColor(renderer_, r, g, b, a) != 0)
196 throw Exception("SDL_SetRenderDrawColor");
197 return *this;
198 }
199
SetDrawColor(const Color & color)200 Renderer& Renderer::SetDrawColor(const Color& color) {
201 return SetDrawColor(color.r, color.g, color.b, color.a);
202 }
203
SetTarget()204 Renderer& Renderer::SetTarget() {
205 if (SDL_SetRenderTarget(renderer_, nullptr) != 0)
206 throw Exception("SDL_SetRenderTarget");
207 return *this;
208 }
209
SetTarget(Texture & texture)210 Renderer& Renderer::SetTarget(Texture& texture) {
211 if (SDL_SetRenderTarget(renderer_, texture.Get()) != 0)
212 throw Exception("SDL_SetRenderTarget");
213 return *this;
214 }
215
SetDrawBlendMode(SDL_BlendMode blendMode)216 Renderer& Renderer::SetDrawBlendMode(SDL_BlendMode blendMode) {
217 if (SDL_SetRenderDrawBlendMode(renderer_, blendMode) != 0)
218 throw Exception("SDL_SetRenderDrawBlendMode");
219 return *this;
220 }
221
DrawPoint(int x,int y)222 Renderer& Renderer::DrawPoint(int x, int y) {
223 if (SDL_RenderDrawPoint(renderer_, x, y) != 0)
224 throw Exception("SDL_RenderDrawPoint");
225 return *this;
226 }
227
DrawPoint(const Point & p)228 Renderer& Renderer::DrawPoint(const Point& p) {
229 DrawPoint(p.x, p.y);
230 return *this;
231 }
232
DrawPoints(const Point * points,int count)233 Renderer& Renderer::DrawPoints(const Point* points, int count) {
234 std::vector<SDL_Point> sdl_points;
235 sdl_points.reserve(static_cast<size_t>(count));
236 for (const Point* p = points; p != points + count; ++p)
237 sdl_points.emplace_back(*p);
238
239 if (SDL_RenderDrawPoints(renderer_, sdl_points.data(), count) != 0)
240 throw Exception("SDL_RenderDrawPoints");
241
242 return *this;
243 }
244
DrawLine(int x1,int y1,int x2,int y2)245 Renderer& Renderer::DrawLine(int x1, int y1, int x2, int y2) {
246 if (SDL_RenderDrawLine(renderer_, x1, y1, x2, y2) != 0)
247 throw Exception("SDL_RenderDrawLine");
248 return *this;
249 }
250
DrawLine(const Point & p1,const Point & p2)251 Renderer& Renderer::DrawLine(const Point& p1, const Point& p2) {
252 DrawLine(p1.x, p1.y, p2.x, p2.y);
253 return *this;
254 }
255
DrawLines(const Point * points,int count)256 Renderer& Renderer::DrawLines(const Point* points, int count) {
257 std::vector<SDL_Point> sdl_points;
258 sdl_points.reserve(static_cast<size_t>(count));
259 for (const Point* p = points; p != points + count; ++p)
260 sdl_points.emplace_back(*p);
261
262 if (SDL_RenderDrawLines(renderer_, sdl_points.data(), count) != 0)
263 throw Exception("SDL_RenderDrawLines");
264
265 return *this;
266 }
267
DrawRect(int x1,int y1,int x2,int y2)268 Renderer& Renderer::DrawRect(int x1, int y1, int x2, int y2) {
269 SDL_Rect rect = {x1, y1, x2 - x1 + 1, y2 - y1 + 1};
270 if (SDL_RenderDrawRect(renderer_, &rect) != 0)
271 throw Exception("SDL_RenderDrawRect");
272 return *this;
273 }
274
DrawRect(const Point & p1,const Point & p2)275 Renderer& Renderer::DrawRect(const Point& p1, const Point& p2) {
276 DrawRect(p1.x, p1.y, p2.x, p2.y);
277 return *this;
278 }
279
DrawRect(const Rect & r)280 Renderer& Renderer::DrawRect(const Rect& r) {
281 if (SDL_RenderDrawRect(renderer_, &r) != 0)
282 throw Exception("SDL_RenderDrawRect");
283 return *this;
284 }
285
DrawRects(const Rect * rects,int count)286 Renderer& Renderer::DrawRects(const Rect* rects, int count) {
287 std::vector<SDL_Rect> sdl_rects;
288 sdl_rects.reserve(static_cast<size_t>(count));
289 for (const Rect* r = rects; r != rects + count; ++r)
290 sdl_rects.emplace_back(*r);
291
292 if (SDL_RenderDrawRects(renderer_, sdl_rects.data(), count) != 0)
293 throw Exception("SDL_RenderDrawRects");
294
295 return *this;
296 }
297
FillRect(int x1,int y1,int x2,int y2)298 Renderer& Renderer::FillRect(int x1, int y1, int x2, int y2) {
299 SDL_Rect rect = {x1, y1, x2 - x1 + 1, y2 - y1 + 1};
300 if (SDL_RenderFillRect(renderer_, &rect) != 0)
301 throw Exception("SDL_RenderFillRect");
302 return *this;
303 }
304
FillRect(const Point & p1,const Point & p2)305 Renderer& Renderer::FillRect(const Point& p1, const Point& p2) {
306 FillRect(p1.x, p1.y, p2.x, p2.y);
307 return *this;
308 }
309
FillRect(const Rect & r)310 Renderer& Renderer::FillRect(const Rect& r) {
311 if (SDL_RenderFillRect(renderer_, &r) != 0)
312 throw Exception("SDL_RenderFillRect");
313 return *this;
314 }
315
FillRects(const Rect * rects,int count)316 Renderer& Renderer::FillRects(const Rect* rects, int count) {
317 std::vector<SDL_Rect> sdl_rects;
318 sdl_rects.reserve(static_cast<size_t>(count));
319 for (const Rect* r = rects; r != rects + count; ++r)
320 sdl_rects.emplace_back(*r);
321
322 if (SDL_RenderFillRects(renderer_, sdl_rects.data(), count) != 0)
323 throw Exception("SDL_RenderFillRects");
324
325 return *this;
326 }
327
ReadPixels(const Optional<Rect> & rect,Uint32 format,void * pixels,int pitch)328 void Renderer::ReadPixels(const Optional<Rect>& rect, Uint32 format, void* pixels, int pitch) {
329 if (SDL_RenderReadPixels(renderer_, rect ? &*rect : nullptr, format, pixels, pitch) != 0)
330 throw Exception("SDL_RenderReadPixels");
331 }
332
SetClipRect(const Optional<Rect> & rect)333 Renderer& Renderer::SetClipRect(const Optional<Rect>& rect) {
334 if (SDL_RenderSetClipRect(renderer_, rect ? &*rect : nullptr) != 0)
335 throw Exception("SDL_RenderSetClipRect");
336 return *this;
337 }
338
SetLogicalSize(int w,int h)339 Renderer& Renderer::SetLogicalSize(int w, int h) {
340 if (SDL_RenderSetLogicalSize(renderer_, w, h) != 0)
341 throw Exception("SDL_RenderSetLogicalSize");
342 return *this;
343 }
344
SetScale(float scaleX,float scaleY)345 Renderer& Renderer::SetScale(float scaleX, float scaleY) {
346 if (SDL_RenderSetScale(renderer_, scaleX, scaleY) != 0)
347 throw Exception("SDL_RenderSetScale");
348 return *this;
349 }
350
SetViewport(const Optional<Rect> & rect)351 Renderer& Renderer::SetViewport(const Optional<Rect>& rect) {
352 if (SDL_RenderSetViewport(renderer_, rect ? &*rect : nullptr) != 0)
353 throw Exception("SDL_RenderSetViewport");
354 return *this;
355 }
356
TargetSupported() const357 bool Renderer::TargetSupported() const {
358 return SDL_RenderTargetSupported(renderer_) == SDL_TRUE;
359 }
360
GetClipRect() const361 Optional<Rect> Renderer::GetClipRect() const {
362 SDL_Rect rect;
363 SDL_RenderGetClipRect(renderer_, &rect);
364
365 if (SDL_RectEmpty(&rect))
366 return NullOpt;
367 else
368 return Rect(rect);
369 }
370
GetLogicalSize() const371 Point Renderer::GetLogicalSize() const {
372 int w, h;
373 SDL_RenderGetLogicalSize(renderer_, &w, &h);
374 return Point(w, h);
375 }
376
GetLogicalWidth() const377 int Renderer::GetLogicalWidth() const {
378 int w;
379 SDL_RenderGetLogicalSize(renderer_, &w, nullptr);
380 return w;
381 }
382
GetLogicalHeight() const383 int Renderer::GetLogicalHeight() const {
384 int h;
385 SDL_RenderGetLogicalSize(renderer_, nullptr, &h);
386 return h;
387 }
388
GetScale(float & scalex,float & scaley) const389 void Renderer::GetScale(float& scalex, float& scaley) const {
390 SDL_RenderGetScale(renderer_, &scalex, &scaley);
391 }
392
GetXScale() const393 float Renderer::GetXScale() const {
394 float scalex;
395 SDL_RenderGetScale(renderer_, &scalex, nullptr);
396 return scalex;
397 }
398
GetYScale() const399 float Renderer::GetYScale() const {
400 float scaley;
401 SDL_RenderGetScale(renderer_, nullptr, &scaley);
402 return scaley;
403 }
404
GetViewport() const405 Rect Renderer::GetViewport() const {
406 SDL_Rect rect;
407 SDL_RenderGetViewport(renderer_, &rect);
408 return rect;
409 }
410
GetDrawBlendMode() const411 SDL_BlendMode Renderer::GetDrawBlendMode() const {
412 SDL_BlendMode mode;
413 if (SDL_GetRenderDrawBlendMode(renderer_, &mode) != 0)
414 throw Exception("SDL_GetRenderDrawBlendMode");
415 return mode;
416 }
417
GetDrawColor() const418 Color Renderer::GetDrawColor() const {
419 Color color;
420 GetDrawColor(color.r, color.g, color.b, color.a);
421 return color;
422 }
423
GetDrawColor(Uint8 & r,Uint8 & g,Uint8 & b,Uint8 & a) const424 void Renderer::GetDrawColor(Uint8& r, Uint8& g, Uint8& b, Uint8& a) const {
425 if (SDL_GetRenderDrawColor(renderer_, &r, &g, &b, &a) != 0)
426 throw Exception("SDL_GetRenderDrawColor");
427 }
428
GetOutputSize() const429 Point Renderer::GetOutputSize() const {
430 int w, h;
431 if (SDL_GetRendererOutputSize(renderer_, &w, &h) != 0)
432 throw Exception("SDL_GetRendererOutputSize");
433 return Point(w, h);
434 }
435
GetOutputWidth() const436 int Renderer::GetOutputWidth() const {
437 int w;
438 if (SDL_GetRendererOutputSize(renderer_, &w, nullptr) != 0)
439 throw Exception("SDL_GetRendererOutputSize");
440 return w;
441 }
442
GetOutputHeight() const443 int Renderer::GetOutputHeight() const {
444 int h;
445 if (SDL_GetRendererOutputSize(renderer_, nullptr, &h) != 0)
446 throw Exception("SDL_GetRendererOutputSize");
447 return h;
448 }
449
450 }
451