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