Rose
GraphicsModel.h
Go to the documentation of this file.
1 
9 #pragma once
10 
11 #include "Configuration.h"
12 
13 #include <SDL.h>
14 
15 #include <memory>
16 #include <functional>
17 #include <Utilities.h>
18 #include "Visual.h"
19 #include "Color.h"
20 #include "Texture.h"
21 #include "CommonSignals.h"
22 
23 
24 namespace rose {
25  class Application;
26 }
27 
28 namespace rose::gm {
29 
34  public:
39  void operator()(SDL_Window *sdlWindow) {
40  SDL_DestroyWindow(sdlWindow);
41  }
42  };
43 
44  using SdlWindow = std::unique_ptr<SDL_Window, SdlWindowDestroy>;
45 
49  enum class RoseErrorCode {
50  OK,
51  ROSE_EXCEPTION,
52  SDL_WINDOW_CREATE,
53  SDL_RENDERER_CREATE,
54  XDG_PATH_FAIL,
55  };
56 
62  struct RenderFlip {
63  SDL_RendererFlip mFlip;
64 
66  constexpr RenderFlip() noexcept: mFlip(SDL_FLIP_NONE) {}
67 
69  constexpr explicit RenderFlip(SDL_RendererFlip flip) noexcept: mFlip(flip) {}
70  };
71 
76  class Context {
77  friend class RenderTargetGuard;
78 
79  protected:
84  public:
89  void operator()(SDL_Renderer *sdlRenderer) {
90  SDL_DestroyRenderer(sdlRenderer);
91  }
92  };
93 
94  using RendererPtr = std::unique_ptr<SDL_Renderer, RendererDestroy>;
95  RendererPtr mRenderer{};
96 
97  SDL_Texture *mCurrentRenderTarget{nullptr};
98 
99  public:
100 
101  Context() = default;
102 
103  Context(const Context &context) = delete;
104 
105  Context(Context &&context) noexcept = default;
106 
107  Context &operator=(const Context &context) = delete;
108 
109  Context &operator=(Context &&context) = default;
110 
111  explicit Context(SdlWindow &window, int index, Uint32 flags) : Context()
112  { mRenderer.reset(SDL_CreateRenderer(window.get(), index, flags)); }
113 
115  explicit operator bool() const noexcept { return mRenderer.operator bool(); }
116 
118  [[nodiscard]] auto get() const { return mRenderer.get(); }
119 
121  void setDrawBlendMode(SDL_BlendMode blendMode) {
122  SDL_SetRenderDrawBlendMode(mRenderer.get(), blendMode);
123  }
124 
133  void copyFullTexture(Texture &source, Texture &destination);
134 
136  int renderClear() { return SDL_RenderClear(mRenderer.get()); }
137 
139  void renderPresent() { SDL_RenderPresent(mRenderer.get()); }
140 
147  int renderCopy(const Texture &texture);
148 
156  int renderCopy(const Texture &texture, Rectangle dst);
157 
166  int renderCopy(const Texture &texture, Rectangle src, Rectangle dst);
167 
177  int renderCopyEx(Texture &texture, Rectangle src, Rectangle dst, double angle, RenderFlip renderFlip,
178  std::optional<Position<int>> point = std::nullopt) const;
179 
185  int setDrawColor(color::RGBA color);
186 
193  return setDrawColor(color.toRGBA());
194  }
195 
202  int fillRect(Rectangle rect, color::RGBA color);
203 
209  int drawPoint(const Position<int> &p, const color::RGBA &color);
210 
211  int drawLine(const Position<int> &p0, const Position<int> &p1);
212  };
213 
218  class RenderTargetGuardException : public std::runtime_error {
219  public:
224  explicit RenderTargetGuardException(const std::string &what_arg) : std::runtime_error(what_arg) {}
225 
226  explicit RenderTargetGuardException(const char *what_arg) : std::runtime_error(what_arg) {}
227  };
228 
233  class DrawColorGuardException : public std::runtime_error {
234  public:
235  explicit DrawColorGuardException(const std::string &what_arg) : std::runtime_error(what_arg) {}
236 
237  explicit DrawColorGuardException(const char *what_arg) : std::runtime_error(what_arg) {}
238  };
239 
246  protected:
248  bool popped{false};
249  SDL_Texture *mLastTexture{nullptr};
250  int status{0};
251 
252  public:
253  RenderTargetGuard() = delete;
254  RenderTargetGuard(const RenderTargetGuard &) = delete;
255 
259  ~RenderTargetGuard() noexcept(false);
260 
267  explicit operator bool() const noexcept { return status == 0; }
268 
274  RenderTargetGuard(Context &context, Texture &texture);
275 
284  int setRenderTarget(Texture &texture);
285  };
286 
293  protected:
295  SDL_Color mOldColor{};
296  int mStatus;
297 
298  public:
299  DrawColorGuard() = delete;
300  DrawColorGuard(const DrawColorGuard &) = delete;
301  DrawColorGuard(DrawColorGuard &&) = default;
302 
303  DrawColorGuard &operator=(const DrawColorGuard &) = delete;
304 
308  ~DrawColorGuard() noexcept(false) {
309  if (SDL_SetRenderDrawColor(mContext.get(), mOldColor.r, mOldColor.g, mOldColor.b, mOldColor.a)) {
310  throw DrawColorGuardException(StringCompositor("Call to SDL_XxxRenderDrawColor failed:",
311  SDL_GetError()));
312  }
313  }
314 
320  DrawColorGuard(Context &context, SDL_Color color);
321 
327  DrawColorGuard(Context &context, color::RGBA color);
328 
333  explicit operator bool() const noexcept { return mStatus == 0; }
334 
340  int setDrawColor(SDL_Color color);
341 
348  return setDrawColor(color.toSdlColor());
349  }
350  };
351 
358  protected:
360  SDL_Rect mOldClip{};
361  int mStatus{0};
362 
363  public:
364  ClipRectangleGuard() = delete;
365  ClipRectangleGuard(const ClipRectangleGuard &) = delete;
366 
367  explicit operator bool () const { return mStatus == 0; }
368 
373  if (mOldClip.w == 0 && mOldClip.y == 0)
374  mStatus = SDL_RenderSetClipRect(mContext.get(), nullptr);
375  else
376  mStatus = SDL_RenderSetClipRect(mContext.get(), &mOldClip);
377  }
378 
385  explicit ClipRectangleGuard(Context &context) : mContext(context) {
386  SDL_RenderGetClipRect(mContext.get(), &mOldClip);
387  }
388 
394  ClipRectangleGuard(Context &context, const SDL_Rect &clip) : mContext(context) {
395  SDL_RenderGetClipRect(mContext.get(), &mOldClip);
396  mStatus = SDL_RenderSetClipRect(mContext.get(), &clip);
397  }
398 
407  ClipRectangleGuard(Context &context, int x, int y, int w, int h)
408  : ClipRectangleGuard(context, SDL_Rect{x, y, w, h}) {}
409 
417  ClipRectangleGuard(Context &context, const Rectangle &clip) : mContext(context) {
418  SDL_RenderGetClipRect(mContext.get(), &mOldClip);
419  SDL_Rect rect{clip.x, clip.y, clip.w, clip.h};
420  mStatus = SDL_RenderSetClipRect(mContext.get(), &rect);
421  }
422 
428  ClipRectangleGuard &operator=(SDL_Rect &clip) {
429  mStatus = SDL_RenderSetClipRect(mContext.get(), &clip);
430  return *this;
431  }
432 
440  SDL_Rect rect{clip.x, clip.y, clip.w, clip.h};
441  mStatus = SDL_RenderSetClipRect(mContext.get(), &rect);
442  return *this;
443  }
444 
445  ClipRectangleGuard &intersection(Rectangle &clip) {
446  SDL_Rect current;
447  SDL_RenderGetClipRect(mContext.get(), &current);
448  if (SDL_RectEmpty(&current)) {
449  operator=(clip);
450  } else {
451  mOldClip = current;
452  Rectangle r{current.x, current.y, current.w, current.h};
453  r = r.intersection(clip);
454  current = SDL_Rect{r.x, r.y, r.w, r.h};
455  mStatus = SDL_RenderSetClipRect(mContext.get(), &current);
456  }
457  return *this;
458  }
459  };
460 
462  protected:
463  SdlWindow mSdlWindow{};
464 
465  Context mContext{};
466 
467  bool mRunEventLoop{true};
468 
469  bool mRedrawBackground{true};
470 
471  Texture mBackground{};
472 
473  uint32_t mFrame{};
474 
475  std::vector<Rectangle> mDisplayBounds{};
476 
477  public:
478  RoseErrorCode ErrorCode{RoseErrorCode::OK};
479 
480  bool initialize(const std::string &title, Size initialSize, const Position<int>& initialPosition, uint32_t extraFlags);
481 
482  void eventLoop(std::shared_ptr<Screen> &screen);
483 
495  void drawAll(std::shared_ptr<Screen> &screen);
496 
497  std::function<void(SDL_Event)> eventCallback{};
498 
499  Context& context() { return mContext; }
500 
501  [[nodiscard]] int currentDisplayIndex() const { return SDL_GetWindowDisplayIndex(mSdlWindow.get()); }
502 
503  Rectangle displayBounds(int displayIndex = -1) {
504  if (displayIndex < 0)
505  displayIndex = currentDisplayIndex();
506 
507  if (displayIndex < 0 || displayIndex >= mDisplayBounds.size())
508  displayIndex = 0;
509 
510  return mDisplayBounds.at(displayIndex);
511  }
512 
513  Rectangle screenRectangle() {
514  Rectangle screenRectangle{};
515  SDL_GetWindowSize(mSdlWindow.get(), &screenRectangle.w, &screenRectangle.h);
516  return screenRectangle;
517  }
518 
519  void redrawBackground() { mRedrawBackground = true; }
520 
521  [[nodiscard]] Padding windowBorders() const noexcept {
522  Padding p{};
523  SDL_GetWindowBordersSize(mSdlWindow.get(), &p.t, &p.l, &p.b, &p.r);
524  return p;
525  }
526 
527  SdlWindow& getSdlWindow() {
528  return mSdlWindow;
529  }
530  };
531 
538  uint32_t mapRGBA(SDL_PixelFormat *format, const color::RGBA &color);
539 
540  color::RGBA getRGBA(SDL_PixelFormat *format, uint32_t pixel);
541 }
542 
Definition: GraphicsModel.cpp:20
ClipRectangleGuard & operator=(Rectangle &clip)
Assign a new clip rectangle through the ClipRectangleGuard.
Definition: GraphicsModel.h:439
Context & mContext
The renderer to which the draw colors are set.
Definition: GraphicsModel.h:294
std::string StringCompositor(Arg &&arg, Args &&... args)
Composite a pack of arguments that are streamable to a string.
Definition: Utilities.h:114
ClipRectangleGuard(Context &context, const Rectangle &clip)
Conditional constructor.
Definition: GraphicsModel.h:417
std::unique_ptr< SDL_Renderer, RendererDestroy > RendererPtr
An SDL_Renderer unique pointer.
Definition: GraphicsModel.h:94
Red Green Blue Alpha representation of a color.
Definition: Color.h:64
Thrown by RenderTargetGuard on errors.
Definition: GraphicsModel.h:218
A functor to destroy an SDL_Renderer.
Definition: GraphicsModel.h:83
~ClipRectangleGuard()
Set the old clip rectangle back on the renderer when destroyed.
Definition: GraphicsModel.h:372
int renderClear()
Prepare for the start of a rendering iteration.
Definition: GraphicsModel.h:136
ClipRectangleGuard(Context &context, int x, int y, int w, int h)
Constructor.
Definition: GraphicsModel.h:407
A functor to destroy an SDL_Window in a std::unique_ptr (rose::sdl::Window).
Definition: GraphicsModel.h:33
Hue Saturation Value (or Brightness) representation of a color.
Definition: Color.h:184
Abstraction of space consumed around an object for space, borders, etc.
Definition: Types.h:454
Abstraction of SDL_Texture.
Definition: Texture.h:46
Context
Definition: GraphicsModel.h:76
Context & mContext
The renderer to which the clip rectangles are set.
Definition: GraphicsModel.h:359
int mStatus
The status of the last SDL operation.
Definition: GraphicsModel.h:296
void setDrawBlendMode(SDL_BlendMode blendMode)
Set the draw blend mode.
Definition: GraphicsModel.h:121
constexpr RenderFlip() noexcept
Default constructor – No flipping.
Definition: GraphicsModel.h:66
~DrawColorGuard() noexcept(false)
Set the old clip rectangle back on the renderer when destroyed.
Definition: GraphicsModel.h:308
Thrown by DrawColorGuard on errors.
Definition: GraphicsModel.h:233
RoseErrorCode
Rose object error codes.
Definition: GraphicsModel.h:49
int setDrawColor(color::HSVA color)
Set the drawing color used for drawing Rectangles, lines and clearing.
Definition: GraphicsModel.h:192
A composite of a Position and a Size.
Definition: Types.h:307
Store the current draw color replacing it with a new draw color.
Definition: GraphicsModel.h:292
Store the current render target replacing it with a new render target.
Definition: GraphicsModel.h:245
int setDrawColor(color::RGBA color)
Set the draw Color on the renderer without pushing the old color on the stack.
Definition: GraphicsModel.h:347
ClipRectangleGuard(Context &context)
Speculative constructor.
Definition: GraphicsModel.h:385
std::unique_ptr< SDL_Window, SdlWindowDestroy > SdlWindow
An SDL_Window unique pointer.
Definition: GraphicsModel.h:44
uint32_t mapRGBA(SDL_PixelFormat *format, const color::RGBA &color)
Map a color::RGBA to a uint32_t.
Definition: GraphicsModel.cpp:304
int pixel(SDL_Renderer *renderer, Sint16 x, Sint16 y)
Draw pixel in currently set color.
Definition: GfxPrimitives.cpp:20
void renderPresent()
Complete a rendering iteration.
Definition: GraphicsModel.h:139
void operator()(SDL_Renderer *sdlRenderer)
Call the SDL API to destroy the renderer.
Definition: GraphicsModel.h:89
A size in integer dimensions.
Definition: Types.h:230
constexpr RGBA toRGBA() const noexcept
Convert to RGBA in an array of floats.
Definition: Color.h:262
void operator()(SDL_Window *sdlWindow)
Call the SDL API to destroy an SDL_Window.
Definition: GraphicsModel.h:39
A Widget manipulator to indicate if and how rendering a texture should be flipped.
Definition: GraphicsModel.h:62
ToDo: There is an issue that the initial scroll interaction is lost if the click/press lands on a Wid...
Definition: CelestialOverlay.cpp:13
Store the current clip rectangle replacing it with a new clip rectangle.
Definition: GraphicsModel.h:357
constexpr RenderFlip(SDL_RendererFlip flip) noexcept
Constructor – user specified flipping.
Definition: GraphicsModel.h:69
ClipRectangleGuard & operator=(SDL_Rect &clip)
Assign a new clip rectangle through the ClipRectangleGuard.
Definition: GraphicsModel.h:428
ClipRectangleGuard(Context &context, const SDL_Rect &clip)
Constructor.
Definition: GraphicsModel.h:394
auto get() const
Get an opaque pointer for API calls.
Definition: GraphicsModel.h:118
Definition: GraphicsModel.h:461
RenderTargetGuardException(const std::string &what_arg)
Create a RenderTargetGuardException.
Definition: GraphicsModel.h:224
constexpr SDL_Color toSdlColor() const noexcept
Convert this colour to an SDL_Color.
Definition: Color.h:97
User Interface Visual types.
Context & mContext
The Context being guarded.
Definition: GraphicsModel.h:247