소스 검색

Do not allow selecting resolution no supported by display

Ivan Savenko 2 년 전
부모
커밋
01322aa4c5
5개의 변경된 파일115개의 추가작업 그리고 32개의 파일을 삭제
  1. 1 0
      Mods/vcmi/config/vcmi/english.json
  2. 0 8
      client/renderSDL/SDL_Extensions.cpp
  3. 0 3
      client/renderSDL/SDL_Extensions.h
  4. 105 21
      client/windows/GUIClasses.cpp
  5. 9 0
      client/windows/GUIClasses.h

+ 1 - 0
Mods/vcmi/config/vcmi/english.json

@@ -31,6 +31,7 @@
 	"vcmi.systemOptions.resolutionButton.help"  : "{Select resolution}\n\n Change in-game screen resolution. Game restart required to apply new resolution.",
 	"vcmi.systemOptions.resolutionMenu.hover"   : "Select resolution",
 	"vcmi.systemOptions.resolutionMenu.help"    : "Change in-game screen resolution.",
+	"vcmi.systemOptions.fullscreenFailed"       : "{Fullscreen}\n\n Failed to switch to fullscreen mode! Current resolution is not supported by display!",
 
 	"vcmi.townHall.missingBase"             : "Base building %s must be built first",
 	"vcmi.townHall.noCreaturesToRecruit"    : "There are no creatures to recruit!",

+ 0 - 8
client/renderSDL/SDL_Extensions.cpp

@@ -66,14 +66,6 @@ SDL_Color CSDL_Ext::toSDL(const ColorRGBA & color)
 	return result;
 }
 
-Rect CSDL_Ext::getDisplayBounds()
-{
-	SDL_Rect displayBounds;
-	SDL_GetDisplayBounds(std::max(0, SDL_GetWindowDisplayIndex(mainWindow)), &displayBounds);
-
-	return fromSDL(displayBounds);
-}
-
 void CSDL_Ext::setColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors)
 {
 	SDL_SetPaletteColors(surface->format->palette,colors,firstcolor,ncolors);

+ 0 - 3
client/renderSDL/SDL_Extensions.h

@@ -108,9 +108,6 @@ typedef void (*TColorPutterAlpha)(uint8_t *&ptr, const uint8_t & R, const uint8_
 	uint32_t colorTouint32_t(const SDL_Color * color); //little endian only
 	SDL_Color makeColor(ui8 r, ui8 g, ui8 b, ui8 a);
 
-	/// returns dimensions of display on which VCMI window is located
-	Rect getDisplayBounds();
-
 	void drawLine(SDL_Surface * sur, int x1, int y1, int x2, int y2, const SDL_Color & color1, const SDL_Color & color2);
 	void drawBorder(SDL_Surface * sur, int x, int y, int w, int h, const SDL_Color &color, int depth = 1);
 	void drawBorder(SDL_Surface * sur, const Rect &r, const SDL_Color &color, int depth = 1);

+ 105 - 21
client/windows/GUIClasses.cpp

@@ -540,7 +540,7 @@ CSystemOptionsWindow::CSystemOptionsWindow()
 
 	fullscreen = std::make_shared<CToggleButton>(Point(246, 215), "sysopchk.def", CButton::tooltipLocalized("vcmi.systemOptions.fullscreenButton"), [&](bool value)
 	{
-		setBoolSetting("video", "fullscreen", value);
+		setFullscreenMode(value);
 	});
 	fullscreen->setSelected(settings["video"]["fullscreen"].Bool());
 
@@ -552,27 +552,110 @@ CSystemOptionsWindow::CSystemOptionsWindow()
 	gameResLabel = std::make_shared<CLabel>(170, 292, FONT_MEDIUM, ETextAlignment::CENTER, Colors::YELLOW, resolutionToString(screenRes["width"].Integer(), screenRes["height"].Integer()));
 }
 
-void CSystemOptionsWindow::selectGameRes()
+void CSystemOptionsWindow::setFullscreenMode( bool on)
 {
-	std::vector<std::string> items;
+	fillSelectableResolutions();
 
-#ifndef VCMI_IOS
-	Rect displayBounds = CSDL_Ext::getDisplayBounds();
-#endif
+	const auto & screenRes = settings["video"]["screenRes"];
+	const Point desiredResolution(screenRes["width"].Integer(), screenRes["height"].Integer());
+	const Point currentResolution(screen->w, screen->h);
 
-	size_t currentResolutionIndex = 0;
-	size_t i = 0;
-	for(const auto & it : conf.guiOptions)
+	if (!isResolutionSupported(currentResolution, on))
 	{
-		const auto & resolution = it.first;
-#ifndef VCMI_IOS
-		if(displayBounds.w < resolution.first || displayBounds.h < resolution.second)
+		fullscreen->setSelected(!on);
+		LOCPLINT->showInfoDialog(CGI->generaltexth->translate("vcmi.systemOptions.fullscreenFailed"));
+		return;
+	}
+
+	setBoolSetting("video", "fullscreen", on);
+
+	if (!isResolutionSupported(desiredResolution, on))
+	{
+		// user changed his desired resolution and switched to fullscreen
+		// however resolution he selected before is not available in fullscreen
+		// so reset it back to currect resolution which is confirmed to be supported earlier
+		Settings gameRes = settings.write["video"]["screenRes"];
+		gameRes["width"].Float() = currentResolution.x;
+		gameRes["height"].Float() = currentResolution.y;
+
+		gameResLabel->setText(resolutionToString(currentResolution.x, currentResolution.y));
+	}
+}
+
+void CSystemOptionsWindow::fillSupportedResolutions()
+{
+	supportedResolutions.clear();
+
+	// in game we can only change resolution, display is fixed
+	int displayID = SDL_GetWindowDisplayIndex(mainWindow);
+
+	int modesCount = SDL_GetNumDisplayModes(displayID);
+
+	for (int i =0; i < modesCount; ++i)
+	{
+		SDL_DisplayMode mode;
+		if (SDL_GetDisplayMode(displayID, i, &mode) != 0)
 			continue;
+
+		Point resolution(mode.w, mode.h);
+
+		supportedResolutions.push_back(resolution);
+	}
+}
+
+void CSystemOptionsWindow::fillSelectableResolutions()
+{
+	fillSupportedResolutions();
+	selectableResolutions.clear();
+
+	for(const auto & it : conf.guiOptions)
+	{
+		const Point dimensions(it.first.first, it.first.second);
+
+		if(isResolutionSupported(dimensions))
+			selectableResolutions.push_back(dimensions);
+	}
+
+	boost::range::sort(selectableResolutions, [](const auto & left, const auto & right)
+	{
+		return left.x * left.y < right.x * right.y;
+	});
+}
+
+bool CSystemOptionsWindow::isResolutionSupported(const Point & resolution)
+{
+	return isResolutionSupported( resolution, settings["video"]["fullscreen"].Bool());
+}
+
+bool CSystemOptionsWindow::isResolutionSupported(const Point & resolution, bool fullscreen)
+{
+#ifdef VCMI_IOS
+	// ios can use any resolution
+	bool canUseAllResolutions = true;
+#else
+	// in fullscreen only resolutions supported by monitor can be used
+	bool canUseAllResolutions = (fullscreen == false);
 #endif
 
-		auto resolutionStr = resolutionToString(resolution.first, resolution.second);
+	if (canUseAllResolutions)
+		return true;
+
+	return vstd::contains(supportedResolutions, resolution);
+}
+
+void CSystemOptionsWindow::selectGameRes()
+{
+	fillSelectableResolutions();
+
+	std::vector<std::string> items;
+	size_t currentResolutionIndex = 0;
+	size_t i = 0;
+	for(const auto & it : selectableResolutions)
+	{
+		auto resolutionStr = resolutionToString(it.x, it.y);
 		if(gameResLabel->getText() == resolutionStr)
 			currentResolutionIndex = i;
+
 		items.push_back(std::move(resolutionStr));
 		++i;
 	}
@@ -586,20 +669,21 @@ void CSystemOptionsWindow::selectGameRes()
 
 void CSystemOptionsWindow::setGameRes(int index)
 {
-	auto iter = conf.guiOptions.begin();
-	std::advance(iter, index);
+	assert(index >= 0 && index < selectableResolutions.size());
+
+	if ( index < 0 || index >= selectableResolutions.size() )
+		return;
 
-	//do not set resolution to illegal one (0x0)
-	assert(iter!=conf.guiOptions.end() && iter->first.first > 0 && iter->first.second > 0);
+	Point resolution = selectableResolutions[index];
 
 	Settings gameRes = settings.write["video"]["screenRes"];
-	gameRes["width"].Float() = iter->first.first;
-	gameRes["height"].Float() = iter->first.second;
+	gameRes["width"].Float() = resolution.x;
+	gameRes["height"].Float() = resolution.y;
 
 	std::string resText;
-	resText += boost::lexical_cast<std::string>(iter->first.first);
+	resText += std::to_string(resolution.x);
 	resText += "x";
-	resText += boost::lexical_cast<std::string>(iter->first.second);
+	resText += std::to_string(resolution.y);
 	gameResLabel->setText(resText);
 }
 

+ 9 - 0
client/windows/GUIClasses.h

@@ -226,6 +226,9 @@ private:
 
 	SettingsListener onFullscreenChanged;
 
+	std::vector<Point> supportedResolutions;
+	std::vector<Point> selectableResolutions;
+
 	//functions bound to buttons
 	void bloadf(); //load game
 	void bsavef(); //save game
@@ -234,6 +237,12 @@ private:
 	void brestartf(); //restart game
 	void bmainmenuf(); //return to main menu
 
+	void setFullscreenMode( bool on);
+	void fillSupportedResolutions();
+	void fillSelectableResolutions();
+	bool isResolutionSupported(const Point & resolution);
+	bool isResolutionSupported(const Point & resolution, bool fullscreen);
+
 	void selectGameRes();
 	void setGameRes(int index);
 	void closeAndPushEvent(EUserEvent code);