From 0292a167c07113d2e26b45ccb97a696a1fd63d0b Mon Sep 17 00:00:00 2001 From: Robert Date: Wed, 20 May 2020 15:37:43 +0200 Subject: [PATCH] Extracted RenderTarget from RenderWindow --- SDLU/CMakeLists.txt | 2 +- SDLU/graphics/CMakeLists.txt | 2 + SDLU/graphics/RenderTarget.cpp | 79 ++++++++++ SDLU/graphics/RenderTarget.hpp | 73 +++++++++ SDLU/graphics/RenderWindow.cpp | 274 +-------------------------------- SDLU/graphics/RenderWindow.hpp | 268 +------------------------------- SDLU_Example/header.hpp | 9 +- 7 files changed, 170 insertions(+), 537 deletions(-) create mode 100644 SDLU/graphics/RenderTarget.cpp create mode 100644 SDLU/graphics/RenderTarget.hpp diff --git a/SDLU/CMakeLists.txt b/SDLU/CMakeLists.txt index e25dabd..1e4fe4d 100644 --- a/SDLU/CMakeLists.txt +++ b/SDLU/CMakeLists.txt @@ -2,7 +2,7 @@ set(PNAME SDLU) add_library(${PNAME} alibi.cpp SDLU.hpp Util.hpp - "structures/Color.cpp" "structures/Mouse.cpp" "structures/Window.cpp") + "structures/Color.cpp" "structures/Mouse.cpp" "structures/Window.cpp" "graphics/RenderTarget.cpp") set_property(TARGET ${PNAME} PROPERTY CXX_STANDARD 17) diff --git a/SDLU/graphics/CMakeLists.txt b/SDLU/graphics/CMakeLists.txt index 5f1338f..13a58eb 100644 --- a/SDLU/graphics/CMakeLists.txt +++ b/SDLU/graphics/CMakeLists.txt @@ -1,4 +1,6 @@ target_sources(${PNAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/RenderWindow.hpp ${CMAKE_CURRENT_SOURCE_DIR}/RenderWindow.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/RenderTarget.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/RenderTarget.cpp ) \ No newline at end of file diff --git a/SDLU/graphics/RenderTarget.cpp b/SDLU/graphics/RenderTarget.cpp new file mode 100644 index 0000000..f3e615c --- /dev/null +++ b/SDLU/graphics/RenderTarget.cpp @@ -0,0 +1,79 @@ +#include "RenderTarget.hpp" + +#include +#include + +namespace sdlu +{ + Uint32 RenderTarget::m_uRenderers = -1; + + RenderTarget::~RenderTarget() + { + RETURN_IF_NULLPTR(renderer); + + SDL_DestroyRenderer(renderer); + } + + void RenderTarget::Clear(const Color& color) + { + RETURN_IF_NULLPTR(renderer); + + SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a); + SDL_RenderClear(renderer); + } + + void RenderTarget::Display() + { + RETURN_IF_NULLPTR(renderer); + + SDL_RenderPresent(renderer); + + if (m_oFramerate != 0) + { + Uint64 diff = std::chrono::duration_cast( + std::chrono::steady_clock::now() - m_oTimeSinceLastDisplay).count(); + + if (diff < 1000 / m_oFramerate) + { + SDL_Delay(static_cast(1000 / m_oFramerate - diff)); + } + } + + m_oTimeSinceLastDisplay = std::chrono::steady_clock::now(); + } + + void RenderTarget::SetMaxFramerate(Uint32 max) + { + m_oFramerate = max; + } + + RenderTarget::RenderTarget(SDL_Window* target) : + renderer(nullptr), m_oFramerate(0) + { + RETURN_IF_NOT_NULLPTR(renderer); + renderer = SDL_CreateRenderer(target, m_uRenderers, SDL_RENDERER_ACCELERATED); + + THROW_IF(IS_NULLPTR(renderer), + sdlu::ObjectCreationException("Failed to create SDL_Renderer* from SDL_Window*: " + + std::string(SDL_GetError()))); + m_uRenderers++; + + m_oTimeSinceLastDisplay = std::chrono::steady_clock::now(); + } + + RenderTarget::RenderTarget(SDL_Surface* target) : + renderer(nullptr), m_oFramerate(0) + { + m_oFramerate = 0; + + RETURN_IF_NOT_NULLPTR(renderer); + renderer = SDL_CreateSoftwareRenderer(target); + + THROW_IF(IS_NULLPTR(renderer), + sdlu::ObjectCreationException("Failed to create SDL_Renderer* from SDL_Surface*: " + + std::string(SDL_GetError()))); + m_uRenderers++; + + m_oTimeSinceLastDisplay = std::chrono::steady_clock::now(); + } +} \ No newline at end of file diff --git a/SDLU/graphics/RenderTarget.hpp b/SDLU/graphics/RenderTarget.hpp new file mode 100644 index 0000000..30f03f2 --- /dev/null +++ b/SDLU/graphics/RenderTarget.hpp @@ -0,0 +1,73 @@ +/** + * @file RenderTarget + * @brief Contains rendering related objects + * @author Lauchmelder23 + * @date 20.05.2020 + */ +#pragma once +#include + +#include + +#include + +namespace sdlu +{ + /** + * @brief Acts as a wrapper for SDL_Renderer*. You can't (and shouldn't) + * instantiate this, but rather derive from it. + */ + class RenderTarget + { + public: + virtual ~RenderTarget(); + + /** + * @brief Clears the display + * + * @param[in] color The color to clear the display with + */ + void Clear(const Color& color = Color::Black); + + /** + * @brief Display the current state of the renderer to the screen + */ + void Display(); + + /** + * @brief Sets a maximum framerate on the display function + * + * If the maximum framerate is not 0, SDL_Delay() will be called + * after each Display() to ensure that the time between displays + * is not shorter than the framerate limit. + * + * @param[in] max The new maximum framerate + */ + void SetMaxFramerate(Uint32 max); + + protected: + /** + * @brief Create Renderer and bind it to a window + * + * @param[in] target The SDL_Window to bind to + */ + RenderTarget(SDL_Window* target); + + /** + * @brief Create Renderer and bind it to a texture + * + * @param[in] target The SDL_Surface to bind to + */ + RenderTarget(SDL_Surface* target); + + protected: + SDL_Renderer* renderer; ///< The renderer object + + private: + Uint32 m_oFramerate; ///< The current maximum framerate of the window (0 = unlimited) + + std::chrono::steady_clock::time_point m_oTimeSinceLastDisplay; ///< The timepoint at which Display() was last called + + static Uint32 m_uRenderers; ///< The number of renderers instantiated so far + }; +} \ No newline at end of file diff --git a/SDLU/graphics/RenderWindow.cpp b/SDLU/graphics/RenderWindow.cpp index bed4869..4f4972b 100644 --- a/SDLU/graphics/RenderWindow.cpp +++ b/SDLU/graphics/RenderWindow.cpp @@ -8,282 +8,20 @@ namespace sdlu { RenderWindow::RenderWindow() : - m_pWindow(nullptr), m_pRenderer(nullptr), - m_oFramerate(0), m_oTimeSinceLastDisplay(std::chrono::steady_clock::now()) + Window(), RenderTarget(window) { - + // Empty } RenderWindow::RenderWindow(Vector2u dimension, const std::string& title, - Uint32 windowFlags, Uint32 rendererFlags) : - RenderWindow() + Uint32 windowFlags) : + Window(dimension, title, windowFlags), RenderTarget(window) { - Create(dimension, title, windowFlags, rendererFlags); + // Empty } RenderWindow::~RenderWindow() { - Close(); - } - - void RenderWindow::Create(Vector2u dimension, const std::string& title, - Uint32 windowFlags, Uint32 rendererFlags) - { - // Don't create a window when it already exists - RETURN_IF_NOT_NULLPTR(m_pWindow); - - m_pWindow = SDL_CreateWindow(title.c_str(), - SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, - dimension.x, dimension.y, - windowFlags); - - THROW_IF(IS_NULLPTR(m_pWindow), - ObjectCreationException("Failed to create SDL_Window. \nSDL_GetError(): " + std::string(SDL_GetError()))); - - m_pRenderer = SDL_CreateRenderer(m_pWindow, -1, rendererFlags); - THROW_IF(IS_NULLPTR(m_pRenderer), - ObjectCreationException("Failed to create SDL_Renderer. \nSDL_GetError(): " + std::string(SDL_GetError()))); - - OnCreate(); - } - - void RenderWindow::Close() - { - // Don't destroy a window that doesn't exist - RETURN_IF_NULLPTR(m_pWindow); - - SDL_DestroyRenderer(m_pRenderer); - m_pRenderer = nullptr; - - SDL_DestroyWindow(m_pWindow); - m_pWindow = nullptr; - - OnClose(); - } - - bool RenderWindow::IsOpen() const - { - RETURN_IF_NULLPTR(m_pWindow, false); - return (!SDL_GetWindowID(m_pWindow) ? false : true); - } - - bool RenderWindow::PollEvent(SDL_Event* event) - { - RETURN_IF_NULLPTR(m_pWindow, false); - // Handle events before the user in case a derived - // class decides to block the event. - while (SDL_PollEvent(event)) - { - switch(event->window.event) - { - case SDL_WINDOWEVENT_RESIZED: if (!OnResize()) return true; break; - default: return true; - } - } - - event = NULL; - return false; - } - - bool RenderWindow::WaitEvent(SDL_Event* event) - { - while (!PollEvent(event)) continue; - return true; - } - - Vector2i RenderWindow::GetPosition() const - { - RETURN_IF_NULLPTR(m_pWindow, Vector2i()); - - int x = 0, y = 0; - SDL_GetWindowPosition(m_pWindow, &x, &y); - return Vector2i(x, y); - } - - void RenderWindow::SetPosition(Vector2i position) - { - RETURN_IF_NULLPTR(m_pWindow); - - SDL_SetWindowPosition(m_pWindow, position.x, position.y); - } - - void RenderWindow::SetPosition(int x, int y) - { - RETURN_IF_NULLPTR(m_pWindow); - - SDL_SetWindowPosition(m_pWindow, x, y); - } - - Vector2u RenderWindow::GetSize() const - { - RETURN_IF_NULLPTR(m_pWindow, Vector2u()); - - int x = 0, y = 0; - SDL_GetWindowSize(m_pWindow, &x, &y); - return Vector2u(x, y); - } - - void RenderWindow::SetSize(Vector2u size) - { - RETURN_IF_NULLPTR(m_pWindow); - - SDL_SetWindowSize(m_pWindow, size.x, size.y); - } - - void RenderWindow::SetSize(unsigned int width, unsigned int height) - { - RETURN_IF_NULLPTR(m_pWindow); - - SDL_SetWindowSize(m_pWindow, width, height); - } - - std::string RenderWindow::GetTitle() const - { - RETURN_IF_NULLPTR(m_pWindow, ""); - - return SDL_GetWindowTitle(m_pWindow); - } - - void RenderWindow::SetTitle(std::string title) - { - RETURN_IF_NULLPTR(m_pWindow); - - SDL_SetWindowTitle(m_pWindow, title.c_str()); - } - - SDL_Window* const RenderWindow::GetWindow() const - { - return m_pWindow; - } - - SDL_Renderer* const RenderWindow::GetRenderer() const - { - return m_pRenderer; - } - - void RenderWindow::Clear(const Color& color) - { - RETURN_IF_NULLPTR(m_pWindow); - - SDL_SetRenderDrawColor(m_pRenderer, color.r, color.g, color.b, color.a); - SDL_RenderClear(m_pRenderer); - } - - void RenderWindow::Display() - { - RETURN_IF_NULLPTR(m_pWindow); - - SDL_RenderPresent(m_pRenderer); - - if (m_oFramerate != 0) - { - Uint64 diff = std::chrono::duration_cast( - std::chrono::steady_clock::now() - m_oTimeSinceLastDisplay).count(); - - if (diff < 1000 / m_oFramerate) - { - SDL_Delay(static_cast(1000 / m_oFramerate - diff)); - } - } - - m_oTimeSinceLastDisplay = std::chrono::steady_clock::now(); - } - - void RenderWindow::SetVisible(bool visible) - { - RETURN_IF_NULLPTR(m_pWindow); - if (visible) - SDL_ShowWindow(m_pWindow); - else - SDL_HideWindow(m_pWindow); - } - - void RenderWindow::SetVsync(bool vsync) - { - // SDL actually doesn't allow you to change the VSync - // flag of a Renderer after it's been created. This - // Changes it globally for all other windows - SDL_GL_SetSwapInterval(vsync); - } - - void RenderWindow::SetMouseCursorVisible(bool visible) - { - SDL_ShowCursor(visible); - } - - void RenderWindow::SetMouseCursorGrabbed(bool grabbed) - { - SDL_SetWindowGrab(m_pWindow, grabbed ? SDL_TRUE : SDL_FALSE); - } - - void RenderWindow::SetIcon(Uint32 width, Uint32 height, const Uint8* pixels) - { - size_t size = static_cast(width) * static_cast(height) * 4; - void* _pixels = malloc(size); - memcpy(_pixels, pixels, size); - SDL_Surface* surface = SDL_CreateRGBSurfaceWithFormatFrom(_pixels, - width, height, 32, 32 * width, - SDL_PIXELFORMAT_RGBA8888); - - SDL_SetWindowIcon(m_pWindow, surface); - } - - void RenderWindow::SetIcon(Uint32 width, Uint32 height, const Uint32* pixels) - { - size_t size = static_cast(width) * static_cast(height) * 4; - void* _pixels = malloc(size); - memcpy(_pixels, pixels, size); - SDL_Surface* surface = SDL_CreateRGBSurfaceWithFormatFrom(_pixels, - width, height, 32, 4 * width, - SDL_PIXELFORMAT_RGBA8888); - - SDL_SetWindowIcon(m_pWindow, surface); - } - - void RenderWindow::SetIcon(SDL_Surface* icon) - { - SDL_SetWindowIcon(m_pWindow, icon); - } - - void RenderWindow::SetMaxFramerate(Uint32 max) - { - m_oFramerate = max; - } - - void RenderWindow::SetMouseCursor(SDL_Cursor* cursor) - { - SDL_SetCursor(cursor); - } - - void RenderWindow::SetMouseCursor(SDL_SystemCursor cursor) - { - SDL_Cursor* _cursor = SDL_CreateSystemCursor(cursor); - SDL_SetCursor(_cursor); - } - - void RenderWindow::SetMouseCursor(SDL_Surface* surface, Vector2u clickspot) - { - SDL_Cursor* _cursor = SDL_CreateColorCursor(surface, clickspot.x, clickspot.y); - SDL_SetCursor(_cursor); - } - - void RenderWindow::SetMouseCursor(const Uint8* pixels, Vector2u size, Vector2u clickspot) - { - size_t _size = static_cast(size.x) * static_cast(size.y) * 4; - void* _pixels = malloc(_size); - memcpy(_pixels, pixels, _size); - SDL_Surface* surface = SDL_CreateRGBSurfaceWithFormatFrom(_pixels, - size.x, size.y, 32, 8 * size.x, SDL_PIXELFORMAT_RGBA8888); - this->SetMouseCursor(surface, clickspot); - } - - void RenderWindow::SetMouseCursor(const Uint32* pixels, Vector2u size, Vector2u clickspot) - { - size_t _size = static_cast(size.x) * static_cast(size.y) * 4; - void* _pixels = malloc(_size); - memcpy(_pixels, pixels, _size); - SDL_Surface* surface = SDL_CreateRGBSurfaceWithFormatFrom(_pixels, - size.x, size.y, 32, 8 * size.x, SDL_PIXELFORMAT_RGBA32); - this->SetMouseCursor(surface, clickspot); + // Empty } } \ No newline at end of file diff --git a/SDLU/graphics/RenderWindow.hpp b/SDLU/graphics/RenderWindow.hpp index b2189d9..a7dc99b 100644 --- a/SDLU/graphics/RenderWindow.hpp +++ b/SDLU/graphics/RenderWindow.hpp @@ -7,10 +7,13 @@ #pragma once #include #include + #include #include #include +#include +#include namespace sdlu { @@ -25,7 +28,7 @@ namespace sdlu * behaves similar to the sf::RenderWindow from SFML. It provides * utility and wrappers for common operations on those objects. */ - class RenderWindow + class RenderWindow : public Window, public RenderTarget { public: /** @@ -40,272 +43,11 @@ namespace sdlu * @param[in] title The title of the create window */ RenderWindow(Vector2u dimension, const std::string& title, - Uint32 windowFlags, Uint32 rendererFlags); + Uint32 windowFlags); RenderWindow(const RenderWindow& other) = delete; RenderWindow(const RenderWindow&& other) = delete; virtual ~RenderWindow(); - - /** - * @brief Creates the window and renderer. - * - * This function creates the SDL_Window and SDL_Renderer objects. If - * they were already created the function does nothing and returns. - * If it fails to create either, an ObjectCreationException is thrown. - * - * @param[in] dimension A vector containing the width and height - * @param[in] title The title of the create window - */ - void Create(Vector2u dimension, const std::string& title, - Uint32 windowFlags, Uint32 rendererFlags); - - /** - * @brief Destroys the window and renderer. - */ - void Close(); - - /** - * @brief Wether or not the window object is created - * - * @return True if the window is open, False if not - */ - bool IsOpen() const; - - /** - * @brief A non-blocking event polling function - * - * @param[out] event An object to write the latest event to - * @return True if there was an event, False if there wasn't - */ - bool PollEvent(SDL_Event* event); - - /** - * @brief A blocking event polling function - * - * @param[out] event An object to write the latest event to - * @return True if an event was polled - */ - bool WaitEvent(SDL_Event* event); - - - /** - * @brief Returns the current position of the window - * - * @return A vector with the current position relative to the top left corner of the display - */ - Vector2i GetPosition() const; - - /** - * @brief Sets a new window position - * - * @param[in] position A vector with the new position - */ - void SetPosition(Vector2i position); - - /** - * @brief Sets a new window position - * - * @param[in] x The new x position - * @param[in] y The new y position - */ - void SetPosition(int x, int y); - - - /** - * @brief Gets the current window size - * - * @return A vector with the windows size - */ - Vector2u GetSize() const; - - /** - * @brief Sets a new window size - * - * @param[in] size A vector with the new size - */ - void SetSize(Vector2u size); - - /** - * @brief Sets a new window size - * - * @param[in] width The new width of the window - * @param[in] height The new height of the window - */ - void SetSize(unsigned int width, unsigned int height); - - - /** - * @brief Gets the current window title - * - * @return The title of the widnow - */ - std::string GetTitle() const; - - /** - * @brief Sets a new window title - * - * @param[in] title The new window title - */ - void SetTitle(std::string title); - - /** - * @brief Returns a constant pointer to the SDL_Window - * - * @return A constant pointer to SDL_Window - */ - SDL_Window* const GetWindow() const; - - /** - * @brief Returns a constant pointer to the SDL_Renderer - * - * @return A constant pointer to SDL_Renderer - */ - SDL_Renderer* const GetRenderer() const; - - /** - * @brief Clears the display - * - * @param[in] color The color to clear the display with - */ - void Clear(const Color& color = Color::Black); - - /** - * @brief Display the current state of the renderer to the screen - */ - void Display(); - - /** - * @brief Set the windows visibility - * - * @param[in] visible The new visibility setting - */ - void SetVisible(bool visible); - - /** - * @brief (De)activates VSync !globally! - * - * @param[in] vsync Wether to enable or disable vsync - */ - void SetVsync(bool vsync); - - /** - * @brief Hides/Shows the mouse cursor inside the windos - * - * @param[in] visible The new visibility of the cursor - */ - void SetMouseCursorVisible(bool visible); - - /** - * @brief Traps the mouse cursor inside the window - * - * @param[in] grabbed Wether to (un)trap the cursor - */ - void SetMouseCursorGrabbed(bool grabbed); - - /** - * @brief Sets the window icon to an array of RGBA values - * - * @param[in] width Width of the icon (in px) - * @param[in] height Height of the icon (in px) - * @param[in] pixels Array of color data (RGBA as seperate 8-Bit integer values) - */ - void SetIcon(Uint32 width, Uint32 height, const Uint8* pixels); - - /** - * @brief Sets the window icon to an array of RGBA values - * - * @param[in] width Width of the icon (in px) - * @param[in] height Height of the icon (in px) - * @param[in] pixels Array of color data (RGBA as one 32-Bit integer value) - */ - void SetIcon(Uint32 width, Uint32 height, const Uint32* pixels); - - /** - * @brief Sets the window icon to a SDL_Surface - * - * @param[in] icon A SDL_Surface* holding the icon data - */ - void SetIcon(SDL_Surface* icon); - - /** - * @brief Sets a maximum framerate on the display function - * - * If the maximum framerate is not 0, SDL_Delay() will be called - * after each Display() to ensure that the time between displays - * is not shorter than the framerate limit. - * - * @param[in] max The new maximum framerate - */ - void SetMaxFramerate(Uint32 max); - - /** - * @brief Changes the mouse cursor - * - * @param[in] cursor A pointer to a SDL_Cursor containing cursor data - */ - void SetMouseCursor(SDL_Cursor* cursor); - - /** - * @brief Changes the mouse cursor - * - * @param[in] cursor An enum for a system cursor - */ - void SetMouseCursor(SDL_SystemCursor cursor); - - /** - * @brief Changes the mouse cursor - * - * @param[in] surface A pointer to a SDL_Surface containing sprite data - * @param[in] clickspot The effective position of the cursor relative to the top left of the sprite - */ - void SetMouseCursor(SDL_Surface* surface, Vector2u clickspot); - - /** - * @brief Changes the mouse cursor - * - * @param[in] pixels An array of color data (RGBA as seperate 8-bit values) - * @param[in] size Size of the cursor - * @param[in] clickspot The effective position of the cursor relative to the top left of the sprite - */ - void SetMouseCursor(const Uint8* pixels, Vector2u size, Vector2u clickspot); - - /** - * @brief Changes the mouse cursor - * - * @param[in] pixels An array of color data (RGBA as one 32-bit value) - * @param[in] size Size of the cursor - * @param[in] clickspot The effective position of the cursor relative to the top left of the sprite - */ - void SetMouseCursor(const Uint32* pixels, Vector2u size, Vector2u clickspot); - - protected: - SDL_Window* m_pWindow; ///< A pointer to the window object - SDL_Renderer* m_pRenderer; ///< A pointer to the renderer object - - protected: - /** - * @brief This function is called after Create() finishes - */ - virtual void OnCreate(); - - /** - * @brief This function is called after a SDL_WINDOWEVENT_RESIZED is polled. - * (PollEvent() must be called for this to work) - * - * @return True if the resize event should be popped from the event queue before - returning the polled event to the user - */ - virtual bool OnResize(); - - /** - * @brief This function is called after Close() finishes. - */ - virtual void OnClose(); - - private: - Uint32 m_oFramerate; - - std::chrono::steady_clock::time_point m_oTimeSinceLastDisplay; }; } \ No newline at end of file diff --git a/SDLU_Example/header.hpp b/SDLU_Example/header.hpp index aa993f3..a640b05 100644 --- a/SDLU_Example/header.hpp +++ b/SDLU_Example/header.hpp @@ -9,25 +9,24 @@ class MyWindow : public: MyWindow(Uint32 width, Uint32 height, const char* title) : RenderWindow(sdlu::Vector2u(width, height), title, - SDL_WINDOW_RESIZABLE, - NULL) + SDL_WINDOW_RESIZABLE) { // Empty } }; -void sdlu::RenderWindow::OnCreate() +void sdlu::Window::OnCreate() { std::cout << "Window was Created!" << std::endl; } -bool sdlu::RenderWindow::OnResize() +bool sdlu::Window::OnResize() { std::cout << "Window was Resized!" << std::endl; return true; } -void sdlu::RenderWindow::OnClose() +void sdlu::Window::OnClose() { std::cout << "Window was Closed!" << std::endl; } \ No newline at end of file