소스 검색

Rename & cleanup of WindowHandler -> ScreenHandler

Ivan Savenko 2 년 전
부모
커밋
e26b18c139

+ 5 - 5
client/CMT.cpp

@@ -24,7 +24,7 @@
 #include "gui/NotificationHandler.h"
 #include "ClientCommandManager.h"
 #include "windows/CMessage.h"
-#include "render/IWindowHandler.h"
+#include "render/IScreenHandler.h"
 
 #include "../lib/filesystem/Filesystem.h"
 #include "../lib/CConsoleHandler.h"
@@ -348,7 +348,7 @@ int main(int argc, char * argv[])
 	{
 		if(!vm.count("battle") && !vm.count("nointro") && settings["video"]["showIntro"].Bool())
 			playIntro();
-		GH.windowHandler().clearScreen();
+		GH.screenHandler().clearScreen();
 	}
 
 
@@ -547,7 +547,7 @@ static void handleEvent(SDL_Event & ev)
 		case EUserEvent::FULLSCREEN_TOGGLED:
 			{
 				boost::unique_lock<boost::recursive_mutex> lock(*CPlayerInterface::pim);
-				GH.windowHandler().onScreenResize();
+				GH.screenHandler().onScreenResize();
 				break;
 			}
 		default:
@@ -564,7 +564,7 @@ static void handleEvent(SDL_Event & ev)
 #ifndef VCMI_IOS
 			{
 				boost::unique_lock<boost::recursive_mutex> lock(*CPlayerInterface::pim);
-				GH.windowHandler().onScreenResize();
+				GH.screenHandler().onScreenResize();
 			}
 #endif
 			break;
@@ -651,7 +651,7 @@ static void quitApplication()
 	boost::this_thread::sleep(boost::posix_time::milliseconds(750));//???
 
 	if(!settings["session"]["headless"].Bool())
-		GH.windowHandler().close();
+		GH.screenHandler().close();
 
 	if(logConfig != nullptr)
 	{

+ 3 - 3
client/CMakeLists.txt

@@ -76,7 +76,7 @@ set(client_SRCS
 	renderSDL/SDLImage.cpp
 	renderSDL/SDLImageLoader.cpp
 	renderSDL/SDLRWwrapper.cpp
-	renderSDL/WindowHandler.cpp
+	renderSDL/ScreenHandler.cpp
 	renderSDL/SDL_Extensions.cpp
 
 	widgets/Buttons.cpp
@@ -206,7 +206,7 @@ set(client_HEADERS
 	render/IFont.h
 	render/IImage.h
 	render/IImageLoader.h
-	render/IWindowHandler.h
+	render/IScreenHandler.h
 
 	renderSDL/CBitmapFont.h
 	renderSDL/CBitmapHanFont.h
@@ -216,7 +216,7 @@ set(client_HEADERS
 	renderSDL/SDLImage.h
 	renderSDL/SDLImageLoader.h
 	renderSDL/SDLRWwrapper.h
-	renderSDL/WindowHandler.h
+	renderSDL/ScreenHandler.h
 	renderSDL/SDL_Extensions.h
 	renderSDL/SDL_PixelAccess.h
 

+ 4 - 4
client/gui/CGuiHandler.cpp

@@ -18,7 +18,7 @@
 #include "../CGameInfo.h"
 #include "../render/Colors.h"
 #include "../renderSDL/SDL_Extensions.h"
-#include "../renderSDL/WindowHandler.h"
+#include "../renderSDL/ScreenHandler.h"
 #include "../CMT.h"
 #include "../CPlayerInterface.h"
 #include "../battle/BattleInterface.h"
@@ -98,7 +98,7 @@ void CGuiHandler::processLists(const ui16 activityFlag, std::function<void (std:
 
 void CGuiHandler::init()
 {
-	windowHandlerInstance = std::make_unique<WindowHandler>();
+	screenHandlerInstance = std::make_unique<ScreenHandler>();
 	shortcutsHandlerInstance = std::make_unique<ShortcutHandler>();
 	mainFPSmng = new CFramerateManager(settings["video"]["targetfps"].Integer());
 
@@ -806,9 +806,9 @@ void CGuiHandler::pushUserEvent(EUserEvent usercode, void * userdata)
 	SDL_PushEvent(&event);
 }
 
-IWindowHandler & CGuiHandler::windowHandler()
+IScreenHandler & CGuiHandler::screenHandler()
 {
-	return *windowHandlerInstance;
+	return *screenHandlerInstance;
 }
 
 void CGuiHandler::onScreenResize()

+ 3 - 3
client/gui/CGuiHandler.h

@@ -29,7 +29,7 @@ class CIntObject;
 class IUpdateable;
 class IShowActivatable;
 class IShowable;
-class IWindowHandler;
+class IScreenHandler;
 
 // TODO: event handling need refactoring
 enum class EUserEvent
@@ -96,7 +96,7 @@ private:
 	CIntObjectList doubleClickInterested;
 	CIntObjectList textInterested;
 
-	std::unique_ptr<IWindowHandler> windowHandlerInstance;
+	std::unique_ptr<IScreenHandler> screenHandlerInstance;
 
 	void handleMouseButtonClick(CIntObjectList & interestedObjs, MouseButton btn, bool isPressed);
 	void processLists(const ui16 activityFlag, std::function<void (std::list<CIntObject*> *)> cb);
@@ -137,7 +137,7 @@ public:
 	/// moves mouse pointer into specified position inside vcmi window
 	void moveCursorToPosition(const Point & position);
 
-	IWindowHandler & windowHandler();
+	IScreenHandler & screenHandler();
 
 	IUpdateable *curInt;
 

+ 5 - 5
client/render/IWindowHandler.h → client/render/IScreenHandler.h

@@ -1,5 +1,5 @@
 /*
- * IWindowHandler.h, part of VCMI engine
+ * IScreenHandler.h, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *
@@ -14,10 +14,10 @@ VCMI_LIB_NAMESPACE_BEGIN
 class Point;
 VCMI_LIB_NAMESPACE_END
 
-class IWindowHandler
+class IScreenHandler
 {
 public:
-	virtual ~IWindowHandler() = default;
+	virtual ~IScreenHandler() = default;
 
 	/// Updates window state after fullscreen state has been changed in settings
 	virtual void onScreenResize() = 0;
@@ -31,6 +31,6 @@ public:
 	/// Returns list of resolutions supported by current screen
 	virtual std::vector<Point> getSupportedResolutions() const = 0;
 
-	/// Returns <min, max> range of possible values for screen scaling
-	virtual std::tuple<double, double> getSupportedScalingRange() const = 0;
+	/// Returns <min, max> range of possible values for screen scaling percentage
+	virtual std::tuple<int, int> getSupportedScalingRange() const = 0;
 };

+ 62 - 50
client/renderSDL/WindowHandler.cpp → client/renderSDL/ScreenHandler.cpp

@@ -1,5 +1,5 @@
 /*
- * WindowHandler.cpp, part of VCMI engine
+ * ScreenHandler.cpp, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *
@@ -9,7 +9,7 @@
  */
 
 #include "StdInc.h"
-#include "WindowHandler.h"
+#include "ScreenHandler.h"
 
 #include "../../lib/CConfigHandler.h"
 #include "../gui/CGuiHandler.h"
@@ -23,6 +23,7 @@
 
 #include <SDL.h>
 
+// TODO: should be made into a private members of ScreenHandler
 SDL_Window * mainWindow = nullptr;
 SDL_Renderer * mainRenderer = nullptr;
 SDL_Texture * screenTexture = nullptr;
@@ -33,7 +34,7 @@ SDL_Surface * screenBuf = screen; //points to screen (if only advmapint is prese
 static const std::string NAME_AFFIX = "client";
 static const std::string NAME = GameConstants::VCMI_VERSION + std::string(" (") + NAME_AFFIX + ')'; //application name
 
-std::tuple<double, double> WindowHandler::getSupportedScalingRange() const
+std::tuple<int, int> ScreenHandler::getSupportedScalingRange() const
 {
 	// H3 resolution, any resolution smaller than that is not correctly supported
 	static const Point minResolution = {800, 600};
@@ -48,22 +49,22 @@ std::tuple<double, double> WindowHandler::getSupportedScalingRange() const
 	return { minimalScaling, maximalScaling };
 }
 
-Point WindowHandler::getPreferredLogicalResolution() const
+Point ScreenHandler::getPreferredLogicalResolution() const
 {
 	Point renderResolution = getPreferredRenderingResolution();
 	auto [minimalScaling, maximalScaling] = getSupportedScalingRange();
 
-	double userScaling = settings["video"]["resolution"]["scaling"].Float();
-	double scaling = std::clamp(userScaling, minimalScaling, maximalScaling);
+	int userScaling = settings["video"]["resolution"]["scaling"].Integer();
+	int scaling = std::clamp(userScaling, minimalScaling, maximalScaling);
 
 	Point logicalResolution = renderResolution * 100.0 / scaling;
 
 	return logicalResolution;
 }
 
-Point WindowHandler::getPreferredRenderingResolution() const
+Point ScreenHandler::getPreferredRenderingResolution() const
 {
-	if (getPreferredWindowMode() == EWindowMode::FULLSCREEN_WINDOWED)
+	if (getPreferredWindowMode() == EWindowMode::FULLSCREEN_BORDERLESS_WINDOWED)
 	{
 		SDL_Rect bounds;
 		SDL_GetDisplayBounds(getPreferredDisplayIndex(), &bounds);
@@ -79,7 +80,7 @@ Point WindowHandler::getPreferredRenderingResolution() const
 	}
 }
 
-int WindowHandler::getPreferredDisplayIndex() const
+int ScreenHandler::getPreferredDisplayIndex() const
 {
 #ifdef VCMI_MOBILE
 	// Assuming no multiple screens on Android / ios?
@@ -92,11 +93,11 @@ int WindowHandler::getPreferredDisplayIndex() const
 #endif
 }
 
-EWindowMode WindowHandler::getPreferredWindowMode() const
+EWindowMode ScreenHandler::getPreferredWindowMode() const
 {
 #ifdef VCMI_MOBILE
 	// On Android / ios game will always render to screen size
-	return EWindowMode::FULLSCREEN_WINDOWED;
+	return EWindowMode::FULLSCREEN_BORDERLESS_WINDOWED;
 #else
 	const JsonNode & video = settings["video"];
 	bool fullscreen = video["fullscreen"].Bool();
@@ -106,13 +107,13 @@ EWindowMode WindowHandler::getPreferredWindowMode() const
 		return EWindowMode::WINDOWED;
 
 	if (realFullscreen)
-		return EWindowMode::FULLSCREEN_TRUE;
+		return EWindowMode::FULLSCREEN_EXCLUSIVE;
 	else
-		return EWindowMode::FULLSCREEN_WINDOWED;
+		return EWindowMode::FULLSCREEN_BORDERLESS_WINDOWED;
 #endif
 }
 
-WindowHandler::WindowHandler()
+ScreenHandler::ScreenHandler()
 {
 #ifdef VCMI_WINDOWS
 	// set VCMI as "per-monitor DPI awareness". This completely disables any DPI-scaling by system.
@@ -145,36 +146,34 @@ WindowHandler::WindowHandler()
 #endif // VCMI_ANDROID
 
 	validateSettings();
-	recreateWindow();
+	recreateWindowAndScreenBuffers();
 }
 
-bool WindowHandler::recreateWindow()
+void ScreenHandler::recreateWindowAndScreenBuffers()
 {
-	destroyScreen();
+	destroyScreenBuffers();
 
 	if(mainWindow == nullptr)
-		initializeRenderer();
+		initializeWindow();
 	else
-		updateFullscreenState();
+		updateWindowState();
 
-	initializeScreen();
+	initializeScreenBuffers();
 
 	if(!settings["session"]["headless"].Bool() && settings["general"]["notifications"].Bool())
 	{
 		NotificationHandler::init(mainWindow);
 	}
-
-	return true;
 }
 
-void WindowHandler::updateFullscreenState()
+void ScreenHandler::updateWindowState()
 {
 #if !defined(VCMI_MOBILE)
 	int displayIndex = getPreferredDisplayIndex();
 
 	switch(getPreferredWindowMode())
 	{
-		case EWindowMode::FULLSCREEN_TRUE:
+		case EWindowMode::FULLSCREEN_EXCLUSIVE:
 		{
 			SDL_SetWindowFullscreen(mainWindow, SDL_WINDOW_FULLSCREEN);
 
@@ -190,7 +189,7 @@ void WindowHandler::updateFullscreenState()
 
 			return;
 		}
-		case EWindowMode::FULLSCREEN_WINDOWED:
+		case EWindowMode::FULLSCREEN_BORDERLESS_WINDOWED:
 		{
 			SDL_SetWindowFullscreen(mainWindow, SDL_WINDOW_FULLSCREEN_DESKTOP);
 			SDL_SetWindowPosition(mainWindow, SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex), SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex));
@@ -208,7 +207,7 @@ void WindowHandler::updateFullscreenState()
 #endif
 }
 
-void WindowHandler::initializeRenderer()
+void ScreenHandler::initializeWindow()
 {
 	mainWindow = createWindow();
 
@@ -227,7 +226,7 @@ void WindowHandler::initializeRenderer()
 	logGlobal->info("Created renderer %s", info.name);
 }
 
-void WindowHandler::initializeScreen()
+void ScreenHandler::initializeScreenBuffers()
 {
 #ifdef VCMI_ENDIAN_BIG
 	int bmask = 0xff000000;
@@ -277,7 +276,7 @@ void WindowHandler::initializeScreen()
 	clearScreen();
 }
 
-SDL_Window * WindowHandler::createWindowImpl(Point dimensions, int flags, bool center)
+SDL_Window * ScreenHandler::createWindowImpl(Point dimensions, int flags, bool center)
 {
 	int displayIndex = getPreferredDisplayIndex();
 	int positionFlags = center ? SDL_WINDOWPOS_CENTERED_DISPLAY(displayIndex) : SDL_WINDOWPOS_UNDEFINED_DISPLAY(displayIndex);
@@ -285,17 +284,17 @@ SDL_Window * WindowHandler::createWindowImpl(Point dimensions, int flags, bool c
 	return SDL_CreateWindow(NAME.c_str(), positionFlags, positionFlags, dimensions.x, dimensions.y, flags);
 }
 
-SDL_Window * WindowHandler::createWindow()
+SDL_Window * ScreenHandler::createWindow()
 {
 #ifndef VCMI_MOBILE
 	Point dimensions = getPreferredRenderingResolution();
 
 	switch(getPreferredWindowMode())
 	{
-		case EWindowMode::FULLSCREEN_TRUE:
+		case EWindowMode::FULLSCREEN_EXCLUSIVE:
 			return createWindowImpl(dimensions, SDL_WINDOW_FULLSCREEN, false);
 
-		case EWindowMode::FULLSCREEN_WINDOWED:
+		case EWindowMode::FULLSCREEN_BORDERLESS_WINDOWED:
 			return createWindowImpl(Point(), SDL_WINDOW_FULLSCREEN_DESKTOP, false);
 
 		case EWindowMode::WINDOWED:
@@ -325,17 +324,13 @@ SDL_Window * WindowHandler::createWindow()
 #endif
 }
 
-void WindowHandler::onScreenResize()
+void ScreenHandler::onScreenResize()
 {
-	if(!recreateWindow())
-	{
-		//will return false and report error if video mode is not supported
-		return;
-	}
+	recreateWindowAndScreenBuffers();
 	GH.onScreenResize();
 }
 
-void WindowHandler::validateSettings()
+void ScreenHandler::validateSettings()
 {
 #if !defined(VCMI_MOBILE)
 	{
@@ -368,14 +363,29 @@ void WindowHandler::validateSettings()
 		}
 	}
 
-	if (getPreferredWindowMode() == EWindowMode::FULLSCREEN_TRUE)
+	if (getPreferredWindowMode() == EWindowMode::FULLSCREEN_EXCLUSIVE)
 	{
-		// TODO: check that display supports selected resolution
+		auto legalOptions = getSupportedResolutions();
+		Point selectedResolution = getPreferredRenderingResolution();
+
+		if(!vstd::contains(legalOptions, selectedResolution))
+		{
+			// resolution selected for fullscreen mode is not supported by display
+			// try to find current display resolution and use it instead as "reasonable default"
+			SDL_DisplayMode mode;
+
+			if (SDL_GetDesktopDisplayMode(getPreferredDisplayIndex(), &mode) == 0)
+			{
+				Settings writer = settings.write["video"]["resolution"];
+				writer["width"].Float() = mode.w;
+				writer["height"].Float() = mode.h;
+			}
+		}
 	}
 #endif
 }
 
-int WindowHandler::getPreferredRenderingDriver() const
+int ScreenHandler::getPreferredRenderingDriver() const
 {
 	int result = -1;
 	const JsonNode & video = settings["video"];
@@ -403,9 +413,10 @@ int WindowHandler::getPreferredRenderingDriver() const
 	return result;
 }
 
-void WindowHandler::destroyScreen()
+void ScreenHandler::destroyScreenBuffers()
 {
-	screenBuf = nullptr; //it`s a link - just nullify
+	// screenBuf is not a separate surface, but points to either screen or screen2 - just set to null
+	screenBuf = nullptr;
 
 	if(nullptr != screen2)
 	{
@@ -426,7 +437,7 @@ void WindowHandler::destroyScreen()
 	}
 }
 
-void WindowHandler::destroyWindow()
+void ScreenHandler::destroyWindow()
 {
 	if(nullptr != mainRenderer)
 	{
@@ -441,32 +452,32 @@ void WindowHandler::destroyWindow()
 	}
 }
 
-void WindowHandler::close()
+void ScreenHandler::close()
 {
 	if(settings["general"]["notifications"].Bool())
 		NotificationHandler::destroy();
 
-	destroyScreen();
+	destroyScreenBuffers();
 	destroyWindow();
 	SDL_Quit();
 }
 
-void WindowHandler::clearScreen()
+void ScreenHandler::clearScreen()
 {
 	SDL_SetRenderDrawColor(mainRenderer, 0, 0, 0, 255);
 	SDL_RenderClear(mainRenderer);
 	SDL_RenderPresent(mainRenderer);
 }
 
-std::vector<Point> WindowHandler::getSupportedResolutions() const
+std::vector<Point> ScreenHandler::getSupportedResolutions() const
 {
 	int displayID = SDL_GetWindowDisplayIndex(mainWindow);
 	return getSupportedResolutions(displayID);
 }
 
-std::vector<Point> WindowHandler::getSupportedResolutions( int displayIndex) const
+std::vector<Point> ScreenHandler::getSupportedResolutions( int displayIndex) const
 {
-	//TODO: check this method on iOS / Android
+	//NOTE: this method is never called on Android/iOS, only on desktop systems
 
 	std::vector<Point> result;
 
@@ -488,6 +499,7 @@ std::vector<Point> WindowHandler::getSupportedResolutions( int displayIndex) con
 		return left.x * left.y < right.x * right.y;
 	});
 
+	// erase potential duplicates, e.g. resolutions with different framerate / bits per pixel
 	result.erase(boost::unique(result).end(), result.end());
 
 	return result;

+ 20 - 13
client/renderSDL/WindowHandler.h → client/renderSDL/ScreenHandler.h

@@ -1,5 +1,5 @@
 /*
- * WindowHandler.h, part of VCMI engine
+ * ScreenHandler.h, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *
@@ -16,7 +16,7 @@ struct SDL_Renderer;
 struct SDL_Surface;
 
 #include "../../lib/Point.h"
-#include "../render/IWindowHandler.h"
+#include "../render/IScreenHandler.h"
 
 enum class EWindowMode
 {
@@ -24,13 +24,13 @@ enum class EWindowMode
 	WINDOWED,
 	// game runs in a 'window' that always covers entire screen and uses unmodified desktop resolution
 	// The only mode that is available on mobile devices
-	FULLSCREEN_WINDOWED,
+	FULLSCREEN_BORDERLESS_WINDOWED,
 	// game runs in a fullscreen mode with resolution selected by player
-	FULLSCREEN_TRUE
+	FULLSCREEN_EXCLUSIVE
 };
 
 /// This class is responsible for management of game window and its main rendering surface
-class WindowHandler : public IWindowHandler
+class ScreenHandler : public IScreenHandler
 {
 	/// Dimensions of target surfaces/textures, this value is what game logic views as screen size
 	Point getPreferredLogicalResolution() const;
@@ -53,19 +53,26 @@ class WindowHandler : public IWindowHandler
 	/// Creates SDL window using OS-specific settings & user-specific config
 	SDL_Window * createWindow();
 
-	void initializeRenderer();
-	void initializeScreen();
-	void updateFullscreenState();
-
-	bool recreateWindow();
-	void destroyScreen();
+	/// Manages window and SDL renderer
+	void initializeWindow();
 	void destroyWindow();
 
+	/// Manages surfaces & textures used for
+	void initializeScreenBuffers();
+	void destroyScreenBuffers();
+
+	/// Updates state (e.g. position) of game window after resolution/fullscreen change
+	void updateWindowState();
+
+	/// Initializes or reiniitalizes all screen state
+	void recreateWindowAndScreenBuffers();
+
+	/// Performs validation of settings and updates them to valid values if necessary
 	void validateSettings();
 public:
 
 	/// Creates and initializes screen, window and SDL state
-	WindowHandler();
+	ScreenHandler();
 
 	/// Updates and potentially recreates target screen to match selected fullscreen status
 	void onScreenResize() final;
@@ -78,5 +85,5 @@ public:
 
 	std::vector<Point> getSupportedResolutions() const final;
 	std::vector<Point> getSupportedResolutions(int displayIndex) const;
-	std::tuple<double, double> getSupportedScalingRange() const final;
+	std::tuple<int, int> getSupportedScalingRange() const final;
 };

+ 5 - 5
client/windows/settings/GeneralOptionsTab.cpp

@@ -22,7 +22,7 @@
 #include "CPlayerInterface.h"
 #include "windows/GUIClasses.h"
 #include "CServerHandler.h"
-#include "render/IWindowHandler.h"
+#include "render/IScreenHandler.h"
 
 
 static void setIntSetting(std::string group, std::string field, int value)
@@ -183,7 +183,7 @@ GeneralOptionsTab::GeneralOptionsTab()
 
 void GeneralOptionsTab::selectGameResolution()
 {
-	supportedResolutions = GH.windowHandler().getSupportedResolutions();
+	supportedResolutions = GH.screenHandler().getSupportedResolutions();
 
 	std::vector<std::string> items;
 	size_t currentResolutionIndex = 0;
@@ -232,10 +232,10 @@ void GeneralOptionsTab::selectGameScaling()
 {
 	supportedScaling.clear();
 
-	auto [minimalScaling, maximalScaling] = GH.windowHandler().getSupportedScalingRange();
-	for (int i = 0; i <= static_cast<int>(maximalScaling); i += 10)
+	auto [minimalScaling, maximalScaling] = GH.screenHandler().getSupportedScalingRange();
+	for (int i = 0; i <= maximalScaling; i += 10)
 	{
-		if (i >= static_cast<int>(minimalScaling))
+		if (i >= minimalScaling)
 			supportedScaling.push_back(i);
 	}