From 1bbb40c4f8ae0aa7f98bd7243b753f2a585afb8a Mon Sep 17 00:00:00 2001 From: namark <namark@disroot.org> Date: Fri, 25 Oct 2019 00:38:00 +0400 Subject: [PATCH] Basic wrappers for display API with an example. --- examples/14_display.cpp | 47 ++++++++ source/simple/graphical.hpp | 1 + source/simple/graphical/display.cpp | 145 +++++++++++++++++++++++ source/simple/graphical/display.h | 113 ++++++++++++++++++ source/simple/graphical/initializer.cpp | 8 ++ source/simple/graphical/initializer.h | 3 + source/simple/graphical/pixel_format.cpp | 6 + source/simple/graphical/pixel_format.h | 4 +- source/simple/graphical/window.cpp | 7 ++ source/simple/graphical/window.h | 3 + 10 files changed, 335 insertions(+), 2 deletions(-) create mode 100644 examples/14_display.cpp create mode 100644 source/simple/graphical/display.cpp create mode 100644 source/simple/graphical/display.h diff --git a/examples/14_display.cpp b/examples/14_display.cpp new file mode 100644 index 0000000..d6eacab --- /dev/null +++ b/examples/14_display.cpp @@ -0,0 +1,47 @@ +#include <cstdio> +#include <cerrno> + +#include <iostream> + +#include "simple/graphical/initializer.h" + +using namespace simple::graphical; + +std::ostream& operator<<(std::ostream& os, display::mode mode) +{ + os << to_string(mode.format) << ' ' + << mode.size.x() << 'x' << mode.size.y() << '@' + << mode.refresh_rate; + return os; +} + +int main() try +{ + initializer graphics; + + for(auto&& display : graphics.displays()) + { + std::cout << "---Didplay---"<< '\n'; + for(auto&& mode : display.modes()) + { + std::cout << mode; + if(mode == display.current_mode()) + std::cout << " <--"; + std::cout << '\n'; + } + std::cout << '\n'; + } + + return 0; +} +catch(...) +{ + if(errno) + std::perror("ERROR"); + + const char* sdl_error = SDL_GetError(); + if(*sdl_error) + std::puts(sdl_error); + + throw; +} diff --git a/source/simple/graphical.hpp b/source/simple/graphical.hpp index c6d2aa2..e98fd59 100644 --- a/source/simple/graphical.hpp +++ b/source/simple/graphical.hpp @@ -2,6 +2,7 @@ #include "graphical/color.h" #include "graphical/color_vector.hpp" #include "graphical/common_def.h" +#include "graphical/display.h" #include "graphical/gl_window.h" #include "graphical/initializer.h" #include "graphical/palette_view.h" diff --git a/source/simple/graphical/display.cpp b/source/simple/graphical/display.cpp new file mode 100644 index 0000000..02a8f9b --- /dev/null +++ b/source/simple/graphical/display.cpp @@ -0,0 +1,145 @@ +#include "display.h" + +namespace simple::graphical +{ + + namespace detail + { + + template <typename Derived, typename... Payload> + Derived& index_iterator<Derived,Payload...>::operator++() noexcept + { + ++index; + return static_cast<Derived&>(*this); + } + + template <typename Derived, typename... Payload> + Derived index_iterator<Derived,Payload...>::operator++(int) noexcept + { + Derived temp = static_cast<Derived&>(*this); + ++(*this); + return temp; + } + + template <typename Derived, typename... Payload> + bool index_iterator<Derived,Payload...>::operator==(const Derived& other) const noexcept + { + return index == other.index; + } + + template <typename Derived, typename... Payload> + bool index_iterator<Derived,Payload...>::operator!=(const Derived& other) const noexcept + { + return !(*this == other); + } + + template <typename Derived, typename... Payload> + int index_iterator<Derived,Payload...>::operator-(const Derived& other) const noexcept + { + return index - other.index; + } + + template <typename Derived, typename... Payload> + index_iterator<Derived,Payload...>::index_iterator(protector, int index, Payload... payload) noexcept + : index(index), payload{payload...} + { } + + template <typename Iterator, typename... Payload> + Iterator index_list<Iterator,Payload...>::make_iterator(int index) const noexcept + { + using protector = typename Iterator::protector; + return std::make_from_tuple<Iterator>( + std::tuple_cat( + std::tuple{protector{},index}, + payload + ) + ); + } + + template <typename Iterator, typename... Payload> + Iterator index_list<Iterator,Payload...>::begin() const noexcept + { + return make_iterator(0); + } + + template <typename Iterator, typename... Payload> + Iterator index_list<Iterator,Payload...>::end() const noexcept + { + return make_iterator(count); + } + + template <typename Iterator,typename... Payload> + index_list<Iterator,Payload...>::index_list(int count, Payload... payload) noexcept + : count(count), payload{payload...} + { } + + template class index_iterator<display::mode_iterator,int>; + template class index_list<display::mode_iterator, int>; + template class index_iterator<display_iterator>; + template class index_list<display_iterator>; + + } // namespace detail + + display::mode from_sdl_mode(const SDL_DisplayMode& mode) + { + return { + static_cast<pixel_format::type>(mode.format), + {mode.w, mode.h}, + mode.refresh_rate + }; + } + + bool display::mode::operator==(const mode& other) const noexcept + { + return other.format == format && + other.size == size && + other.refresh_rate == refresh_rate; + } + + bool display::mode::operator!=(const mode& other) const noexcept + { + return !operator==(other); + } + + auto display::mode_iterator::operator*() const -> mode + { + SDL_DisplayMode mode; + int display_index = std::get<0>(payload); + sdlcore::utils::throw_error( + SDL_GetDisplayMode(display_index, index, &mode)); + return from_sdl_mode(mode); + } + + auto display::current_mode() const -> mode + { + SDL_DisplayMode mode; + sdlcore::utils::throw_error( + SDL_GetCurrentDisplayMode(index, &mode)); + return from_sdl_mode(mode); + } + + auto display::initial_mode() const -> mode + { + SDL_DisplayMode mode; + sdlcore::utils::throw_error( + SDL_GetDesktopDisplayMode(index, &mode)); + return from_sdl_mode(mode); + } + + auto display::modes() const noexcept -> mode_list + { + auto count = SDL_GetNumDisplayModes(index); + if(count < 0) + count = 0; + return mode_list(count, index); + } + + display::display(int index) noexcept : index(index) + { } + + display display_iterator::operator*() const + { + return display(index); + } + +} // namespace simple::graphical diff --git a/source/simple/graphical/display.h b/source/simple/graphical/display.h new file mode 100644 index 0000000..d711494 --- /dev/null +++ b/source/simple/graphical/display.h @@ -0,0 +1,113 @@ +#ifndef SIMPLE_GRAPHICAL_DISPLAY_H +#define SIMPLE_GRAPHICAL_DISPLAY_H + +#include "common_def.h" +#include "pixel_format.h" + +namespace simple::graphical +{ + + namespace detail + { + + // there is probably some library that does this better... + // maybe boost/iterator?? + template <typename Derived, typename... Payload> + class index_iterator + { + protected: + + class protector {}; + + public: + Derived& operator++() noexcept; + Derived operator++(int) noexcept; + bool operator==(const Derived&) const noexcept; + bool operator!=(const Derived&) const noexcept; + int operator-(const Derived&) const noexcept; + + explicit index_iterator(protector, int, Payload...) noexcept; + + protected: + int index; + std::tuple<Payload...> payload; + }; + + template <typename Iterator, typename... Payload> + class index_list + { + public: + Iterator begin() const noexcept; + Iterator end() const noexcept; + + protected: + explicit index_list(int, Payload...) noexcept; + private: + Iterator make_iterator(int) const noexcept; + int count; + std::tuple<Payload...> payload; + }; + + } // namespace detail + + class display + { + public: + + struct mode + { + pixel_format::type format; + int2 size; + int refresh_rate; + bool operator==(const mode&) const noexcept; + bool operator!=(const mode&) const noexcept; + }; + + class mode_iterator : public detail::index_iterator<mode_iterator,int> + { + public: + using index_iterator<mode_iterator,int>::index_iterator; + mode operator*() const; + + friend class detail::index_list<mode_iterator, int>; + }; + + class mode_list : public detail::index_list<mode_iterator, int> + { + private: + using index_list<mode_iterator,int>::index_list; + friend display; + }; + + mode current_mode() const; + mode initial_mode() const; + mode_list modes() const noexcept; + // TODO: bounds, DPI + private: + explicit display(int) noexcept; + int index; + + friend class display_iterator; + friend class window; + }; + + class display_iterator : public detail::index_iterator<display_iterator> + { + public: + using index_iterator<display_iterator>::index_iterator; + display operator*() const; + + friend class detail::index_list<display_iterator>; + }; + + class display_list : public detail::index_list<display_iterator> + { + private: + using index_list<display_iterator>::index_list; + friend class initializer; + }; + + +} // namespace simple::graphical + +#endif /* end of include guard */ diff --git a/source/simple/graphical/initializer.cpp b/source/simple/graphical/initializer.cpp index e76fd76..eb3ce59 100644 --- a/source/simple/graphical/initializer.cpp +++ b/source/simple/graphical/initializer.cpp @@ -66,3 +66,11 @@ initializer::screensaver_control::~screensaver_control() noexcept initializer::initializer() : sdlcore::initializer(sdlcore::system_flag::video), screensaver() {} + +display_list initializer::displays() const noexcept +{ + auto count = SDL_GetNumVideoDisplays(); + if(count < 0) + count = 0; + return display_list(count); +} diff --git a/source/simple/graphical/initializer.h b/source/simple/graphical/initializer.h index 1f85198..f30cb14 100644 --- a/source/simple/graphical/initializer.h +++ b/source/simple/graphical/initializer.h @@ -2,6 +2,8 @@ #define SIMPLE_GRAPHICAL_INITIALIZER_H #include "simple/sdlcore/initializer.h" +#include "display.h" + namespace simple::graphical { @@ -27,6 +29,7 @@ namespace simple::graphical public: initializer(); screensaver_control screensaver; + display_list displays() const noexcept; }; } // namespace simple::graphical diff --git a/source/simple/graphical/pixel_format.cpp b/source/simple/graphical/pixel_format.cpp index 0d418a8..9602db6 100644 --- a/source/simple/graphical/pixel_format.cpp +++ b/source/simple/graphical/pixel_format.cpp @@ -1,4 +1,5 @@ #include <type_traits> +#include "simple/support/enum.hpp" #include "pixel_format.h" #include "palette_view.h" @@ -63,4 +64,9 @@ namespace simple::graphical return SDL_GetPixelFormatName(guts()->format); } + const char* to_string(pixel_format::type type) noexcept + { + return SDL_GetPixelFormatName(support::to_integer(type)); + } + } // namespace simple::graphical diff --git a/source/simple/graphical/pixel_format.h b/source/simple/graphical/pixel_format.h index 217cd74..dea460d 100644 --- a/source/simple/graphical/pixel_format.h +++ b/source/simple/graphical/pixel_format.h @@ -1,9 +1,7 @@ #ifndef SIMPLE_GRAPHICAL_PIXEL_FORMAT_H #define SIMPLE_GRAPHICAL_PIXEL_FORMAT_H -#include <memory> #include <optional> -#include <SDL2/SDL.h> #include "simple/sdlcore/utils.hpp" #include "color.h" #include "palette_view.h" @@ -96,6 +94,8 @@ namespace simple::graphical friend surface convert(const surface& source, const pixel_format& format); }; + const char* to_string(pixel_format::type) noexcept; + } // namespace simple::graphical #endif /* end of include guard */ diff --git a/source/simple/graphical/window.cpp b/source/simple/graphical/window.cpp index dcb58b8..3a0ac46 100644 --- a/source/simple/graphical/window.cpp +++ b/source/simple/graphical/window.cpp @@ -108,4 +108,11 @@ namespace simple::graphical return SDL_GetWindowID(guts().get()); } + display window::display() const + { + int index = SDL_GetWindowDisplayIndex(guts().get()); + sdlcore::utils::throw_error(index < 0); + return graphical::display(index); + } + } // namespace simple::graphical diff --git a/source/simple/graphical/window.h b/source/simple/graphical/window.h index a5b90ed..f74c78d 100644 --- a/source/simple/graphical/window.h +++ b/source/simple/graphical/window.h @@ -9,6 +9,7 @@ #include "simple/sdlcore/utils.hpp" #include "common_def.h" +#include "display.h" namespace simple::graphical { @@ -80,6 +81,8 @@ namespace simple::graphical uint32_t id() const noexcept; + graphical::display display() const; + protected: window -- GitLab