Rose
Renderer.h
Go to the documentation of this file.
1 
8 #pragma once
9 
10 #include <memory>
11 #include <stack>
12 #include <SDL.h>
13 #include "Color.h"
14 #include "ScreenMetrics.h"
15 #include "Utilities.h"
16 #include "Types.h"
17 
22 namespace rose::sdl {
23 
24  class Texture;
25 
26  class GradientTexture;
27 
33  struct RenderFlip {
34  SDL_RendererFlip mFlip;
35 
37  constexpr RenderFlip() noexcept : mFlip(SDL_FLIP_NONE) {}
38 
40  constexpr explicit RenderFlip(SDL_RendererFlip flip) noexcept : mFlip(flip) {}
41  };
42 
46  class WindowDestroy {
47  public:
52  void operator()(SDL_Window *sdlWindow) {
53  SDL_DestroyWindow(sdlWindow);
54  }
55  };
56 
57  using Window = std::unique_ptr<SDL_Window, WindowDestroy>;
58 
64  class Renderer {
65  protected:
66  friend class RenderTargetGuard;
67 
72  public:
77  void operator()(SDL_Renderer *sdlRenderer) {
78  SDL_DestroyRenderer(sdlRenderer);
79  }
80  };
81 
82  using RendererPtr = std::unique_ptr<SDL_Renderer, RendererDestroy>;
83  RendererPtr mRenderer{};
84 
85  std::stack<SDL_Texture *> mTargetTextureStack{};
86 
94  [[nodiscard]] int popRenderTarget() {
95  if (mTargetTextureStack.empty())
96  return SDL_SetRenderTarget(mRenderer.get(), nullptr);
97  else {
98  mTargetTextureStack.pop();
99  if (mTargetTextureStack.empty())
100  return SDL_SetRenderTarget(mRenderer.get(), nullptr);
101  else
102  return SDL_SetRenderTarget(mRenderer.get(), mTargetTextureStack.top());
103  }
104  }
105 
111  [[nodiscard]] int pushRenderTarget(sdl::Texture &texture);
112 
117  [[nodiscard]] int pushRenderTarget() {
118  mTargetTextureStack.push(nullptr);
119  return SDL_SetRenderTarget(mRenderer.get(), nullptr);
120  }
121 
122  public:
126  Renderer() = default;
127 
128  Renderer(const Renderer &renderer) = delete;
129 
136  Renderer(Window &window, int index, Uint32 flags);
137 
142  Renderer(Renderer &&renderer) noexcept = default;
143 
144  Renderer &operator=(const Renderer &renderer) = delete;
145 
151  Renderer &operator=(Renderer &&renderer) = default;
152 
157  explicit operator bool() const noexcept { return mRenderer.operator bool(); }
158 
163  [[nodiscard]] auto get() const { return mRenderer.get(); }
164 
169  void setDrawBlendMode(SDL_BlendMode blendMode) {
170  SDL_SetRenderDrawBlendMode(mRenderer.get(), blendMode);
171  }
172 
178  Texture createTexture(Size size);
179 
188  void copyFullTexture(sdl::Texture &source, sdl::Texture &destination);
189 
194  int renderClear() { return SDL_RenderClear(mRenderer.get()); }
195 
199  void renderPresent() { SDL_RenderPresent(mRenderer.get()); }
200 
207  int renderCopy(const Texture &texture);
208 
215  int renderCopy(const Texture &texture, Rectangle dst);
216 
225  int renderCopy(const Texture &texture, Rectangle src, Rectangle dst);
226 
233  int renderCopy(GradientTexture &texture, Rectangle dst);
234 
244  int renderCopyEx(Texture &texture, Rectangle src, Rectangle dst, double angle, RenderFlip renderFlip,
245  std::optional<Position> point = std::nullopt) const;
246 
254  int fillRect(Rectangle rectangle, color::RGBA color);
255 
264  int drawLine(int x0, int y0, int x1, int y1);
265 
266  int drawPoint(const Position& position, const color::RGBA &rgba);
267 
275  template<class C>
276  int drawLines(C pointsContainer) {
277  auto *points = new SDL_Point[pointsContainer.size()];
278  auto first = pointsContainer.begin();
279  auto last = pointsContainer.end();
280  for (size_t idx = 0; idx < pointsContainer.size() && first != last; ++idx) {
281  points[idx].x = first->x();
282  points[idx].y = first->y();
283  ++first;
284  }
285  auto status = SDL_RenderDrawLines(get(), points, pointsContainer.size());
286  delete [] points;
287  return status;
288  }
289  };
290 
296  public:
301  explicit RenderTargetGuardException(const std::string &what_arg) : RoseRuntimeError(what_arg) {}
302  };
303 
310  protected:
312  bool popped{false};
313  int status{0};
314 
315  public:
316  RenderTargetGuard() = delete;
317  RenderTargetGuard(const RenderTargetGuard &) = delete;
318 
322  ~RenderTargetGuard() noexcept(false) {
323  if (!popped) {
324  status = mRenderer.popRenderTarget();
325  }
326  }
327 
334  explicit operator bool() const noexcept { return status == 0; }
335 
341  RenderTargetGuard(Renderer &renderer, Texture &texture) : mRenderer(renderer) {
342  status = mRenderer.pushRenderTarget(texture);
343  }
344 
348  void clear() {
349  status = mRenderer.popRenderTarget();
350  popped = true;
351  }
352 
361  int setRenderTarget(Texture &texture);
362  };
363 
369  public:
374  explicit DrawColorGuardException(const std::string &what_arg) : RoseRuntimeError(what_arg) {}
375  };
376 
383  protected:
385  SDL_Color mOldColor{};
386  int mStatus;
387 
388  public:
389  DrawColorGuard() = delete;
390  DrawColorGuard(const DrawColorGuard &) = delete;
391  DrawColorGuard(DrawColorGuard &&) = default;
392 
393  DrawColorGuard &operator=(const DrawColorGuard &) = delete;
394 
398  ~DrawColorGuard() noexcept(false) {
399  if (SDL_SetRenderDrawColor(mRenderer.get(), mOldColor.r, mOldColor.g, mOldColor.b, mOldColor.a)) {
400  throw DrawColorGuardException(util::StringCompositor("Call to SDL_XxxRenderDrawColor failed:",
401  SDL_GetError()));
402  }
403  }
404 
410  DrawColorGuard(Renderer &renderer, SDL_Color color);
411 
417  DrawColorGuard(Renderer &renderer, color::RGBA color);
418 
423  explicit operator bool() const noexcept { return mStatus == 0; }
424 
430  int setDrawColor(SDL_Color color);
431 
438  return setDrawColor(color.toSdlColor());
439  }
440  };
441 
448  protected:
450  SDL_Rect mOldClip{};
451 
452  public:
453  ClipRectangleGuard() = delete;
454  ClipRectangleGuard(const ClipRectangleGuard &) = delete;
455 
460  SDL_RenderSetClipRect(mRenderer.get(), &mOldClip);
461  }
462 
469  explicit ClipRectangleGuard(Renderer &renderer) : mRenderer(renderer) {
470  SDL_RenderGetClipRect(mRenderer.get(), &mOldClip);
471  }
472 
478  ClipRectangleGuard(Renderer &renderer, const SDL_Rect &clip) : mRenderer(renderer) {
479  SDL_RenderGetClipRect(mRenderer.get(), &mOldClip);
480  SDL_RenderSetClipRect(mRenderer.get(), &clip);
481  }
482 
491  ClipRectangleGuard(Renderer &renderer, int x, int y, int w, int h)
492  : ClipRectangleGuard(renderer, SDL_Rect{x, y, w, h}) {}
493 
501  ClipRectangleGuard(Renderer &renderer, const Rectangle &clip) : mRenderer(renderer) {
502  SDL_RenderGetClipRect(mRenderer.get(), &mOldClip);
503  auto rect = clip.toSdlRect();
504  SDL_RenderSetClipRect(mRenderer.get(), &rect);
505  }
506 
512  ClipRectangleGuard &operator=(SDL_Rect &clip) {
513  SDL_RenderSetClipRect(mRenderer.get(), &clip);
514  return *this;
515  }
516 
524  auto rect = clip.toSdlRect();
525  SDL_RenderSetClipRect(mRenderer.get(), &rect);
526  return *this;
527  }
528 
529  ClipRectangleGuard &intersection(Rectangle &clip) {
530  SDL_Rect current;
531  SDL_RenderGetClipRect(mRenderer.get(), &current);
532  if (SDL_RectEmpty(&current)) {
533  operator=(clip);
534  } else {
535  mOldClip = current;
536  Rectangle r{current.x, current.y, current.w, current.h};
537  current = r.intersection(clip).toSdlRect();
538  SDL_RenderSetClipRect(mRenderer.get(), &current);
539  }
540  return *this;
541  }
542  };
543 }
Store the current clip rectangle replacing it with a new clip rectangle.
Definition: Renderer.h:447
Thrown by RenderTargetGuard on errors.
Definition: Renderer.h:295
int renderClear()
Calls SDL_RenderClear on the renderer.
Definition: Renderer.h:194
std::unique_ptr< SDL_Renderer, RendererDestroy > RendererPtr
An SDL_Renderer unique pointer.
Definition: Renderer.h:82
~RenderTargetGuard() noexcept(false)
Set the old render target back on the renderer when destroyed.
Definition: Renderer.h:322
int setDrawColor(color::RGBA color)
Set the draw Color on the renderer without pushing the old color on the stack.
Definition: Renderer.h:437
A functor to destroy an SDL_Renderer.
Definition: Renderer.h:71
ClipRectangleGuard(Renderer &renderer, const SDL_Rect &clip)
Constructor.
Definition: Renderer.h:478
std::unique_ptr< SDL_Window, WindowDestroy > Window
An SDL_Window unique pointer.
Definition: Renderer.h:57
int mStatus
The status of the last SDL operation.
Definition: Renderer.h:386
int pushRenderTarget()
Set the render target to the default, and push it onto the stack.
Definition: Renderer.h:117
~DrawColorGuard() noexcept(false)
Set the old clip rectangle back on the renderer when destroyed.
Definition: Renderer.h:398
ClipRectangleGuard & operator=(Rectangle &clip)
Assign a new clip rectangle through the ClipRectangleGuard.
Definition: Renderer.h:523
Red Green Blue Alpha representation of a color.
Definition: Color.h:64
int pushRenderTarget(sdl::Texture &texture)
Set a new render target, and push it onto the stack.
Definition: Renderer.cpp:22
A functor to destroy an SDL_Window in a std::unique_ptr (rose::sdl::Window).
Definition: Renderer.h:46
void setDrawBlendMode(SDL_BlendMode blendMode)
Set the SDL_BlendMode on the renderer.
Definition: Renderer.h:169
std::string StringCompositor(Arg &&arg, Args &&... args)
Composite a pack of arguments that are streamable to a string.
Definition: Utilities.h:186
ClipRectangleGuard(Renderer &renderer, int x, int y, int w, int h)
Constructor.
Definition: Renderer.h:491
Thrown by DrawColorGuard on errors.
Definition: Renderer.h:368
An encapsulation of the SDL_Texture structure.
Definition: Texture.h:40
RenderTargetGuard(Renderer &renderer, Texture &texture)
Constructor.
Definition: Renderer.h:341
DrawColorGuardException(const std::string &what_arg)
Construct DrawColorGuardException.
Definition: Renderer.h:374
A position in integer (x, y) co-ordinates.
Definition: Types.h:95
Store the current draw color replacing it with a new draw color.
Definition: Renderer.h:382
int drawLines(C pointsContainer)
Render lines.
Definition: Renderer.h:276
int popRenderTarget()
Pop a render target off the stack.
Definition: Renderer.h:94
void operator()(SDL_Window *sdlWindow)
Call the SDL API to destroy an SDL_Window.
Definition: Renderer.h:52
Renderer & mRenderer
The renderer to which the clip rectangles are set.
Definition: Renderer.h:449
void operator()(SDL_Renderer *sdlRenderer)
Call the SDL API to destroy the renderer.
Definition: Renderer.h:77
A Widget manipulator to indicate if and how rendering a texture should be flipped.
Definition: Renderer.h:33
A composite of a Position and a Size.
Definition: Types.h:307
ClipRectangleGuard & operator=(SDL_Rect &clip)
Assign a new clip rectangle through the ClipRectangleGuard.
Definition: Renderer.h:512
auto get() const
The the underlying SDL_Renderer* for use with the SDL2 API.
Definition: Renderer.h:163
void clear()
Clear the render target so rendering will be sent to the screen backing buffer.
Definition: Renderer.h:348
~ClipRectangleGuard()
Set the old clip rectangle back on the renderer when destroyed.
Definition: Renderer.h:459
ClipRectangleGuard(Renderer &renderer)
Speculative constructor.
Definition: Renderer.h:469
Written as a workaround for an issue in the SDL2 Library.
Definition: Renderer.h:64
Class and functions that are used to access the SDL2 api.
Definition: Renderer.cpp:11
A size in integer dimensions.
Definition: Types.h:230
RenderTargetGuardException(const std::string &what_arg)
Create a RenderTargetGuardException.
Definition: Renderer.h:301
ClipRectangleGuard(Renderer &renderer, const Rectangle &clip)
Conditional constructor.
Definition: Renderer.h:501
void renderPresent()
Calls SDL_RenderPresent on the renderer.
Definition: Renderer.h:199
Store the current render target replacing it with a new render target.
Definition: Renderer.h:309
constexpr RenderFlip(SDL_RendererFlip flip) noexcept
Constructor – user specified flipping.
Definition: Renderer.h:40
constexpr SDL_Color toSdlColor() const noexcept
Convert this colour to an SDL_Color.
Definition: Color.h:97
Renderer & mRenderer
The Renderer being guarded.
Definition: Renderer.h:311
Renderer & mRenderer
The renderer to which the draw colors are set.
Definition: Renderer.h:384
Thrown when a runtime error has occurred.
Definition: Types.h:201
A gradient rendering kernel.
Definition: Texture.h:362
constexpr RenderFlip() noexcept
Default constructor – No flipping.
Definition: Renderer.h:37