From 146e0294b47281e2b0d1fe7ee7302d35c0989def Mon Sep 17 00:00:00 2001
From: Jonas Kulla <Nyocurio@gmail.com>
Date: Sat, 3 Jan 2015 18:48:09 +0100
Subject: [PATCH] Add option to fix the framerate to the native screen refresh
 rate

Useful on mobile devices where using non-standard framerates
looks absolutely horrible and screen refresh rates vary highly.
---
 mkxp.conf.sample  | 11 +++++++++++
 src/config.cpp    |  2 ++
 src/config.h      |  1 +
 src/eventthread.h |  3 +++
 src/graphics.cpp  | 18 +++++++++++++++---
 src/main.cpp      | 15 ++++++++++++---
 6 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/mkxp.conf.sample b/mkxp.conf.sample
index 589ae1e..31f2aae 100644
--- a/mkxp.conf.sample
+++ b/mkxp.conf.sample
@@ -88,6 +88,17 @@
 # frameSkip=true
 
 
+# Use a fixed framerate that is approx. equal to the
+# native screen refresh rate. This is different from
+# "fixedFramerate" because the actual frame rate is
+# reported back to the game, ensuring correct timers.
+# If the screen refresh rate cannot be determined,
+# this option is force-disabled
+# (default: disabled)
+#
+# syncToRefreshrate=false
+
+
 # Don't use alpha blending when rendering text
 # (default: disabled)
 #
diff --git a/src/config.cpp b/src/config.cpp
index fb2e676..091ea92 100644
--- a/src/config.cpp
+++ b/src/config.cpp
@@ -152,6 +152,7 @@ Config::Config()
       defScreenH(0),
       fixedFramerate(0),
       frameSkip(true),
+      syncToRefreshrate(false),
       solidFonts(false),
       subImageFix(false),
       gameFolder("."),
@@ -181,6 +182,7 @@ void Config::read(int argc, char *argv[])
 	PO_DESC(defScreenH, int) \
 	PO_DESC(fixedFramerate, int) \
 	PO_DESC(frameSkip, bool) \
+	PO_DESC(syncToRefreshrate, bool) \
 	PO_DESC(solidFonts, bool) \
 	PO_DESC(subImageFix, bool) \
 	PO_DESC(gameFolder, std::string) \
diff --git a/src/config.h b/src/config.h
index 71cfb42..9117fc0 100644
--- a/src/config.h
+++ b/src/config.h
@@ -86,6 +86,7 @@ struct Config
 
 	int fixedFramerate;
 	bool frameSkip;
+	bool syncToRefreshrate;
 
 	bool solidFonts;
 
diff --git a/src/eventthread.h b/src/eventthread.h
index 164148e..1414f37 100644
--- a/src/eventthread.h
+++ b/src/eventthread.h
@@ -187,6 +187,7 @@ struct RGSSThreadData
 
 	Vec2 sizeResoRatio;
 	Vec2i screenOffset;
+	const int refreshRate;
 
 	Config config;
 
@@ -196,12 +197,14 @@ struct RGSSThreadData
 	               const char *argv0,
 	               SDL_Window *window,
 	               ALCdevice *alcDev,
+	               int refreshRate,
 	               const Config& newconf)
 	    : ethread(ethread),
 	      argv0(argv0),
 	      window(window),
 	      alcDev(alcDev),
 	      sizeResoRatio(1, 1),
+	      refreshRate(refreshRate),
 	      config(newconf)
 	{}
 };
diff --git a/src/graphics.cpp b/src/graphics.cpp
index 76fb02c..2f31077 100644
--- a/src/graphics.cpp
+++ b/src/graphics.cpp
@@ -628,10 +628,19 @@ Graphics::Graphics(RGSSThreadData *data)
 {
 	p = new GraphicsPrivate(data);
 
-	if (data->config.fixedFramerate > 0)
-		p->fpsLimiter.setDesiredFPS(data->config.fixedFramerate);
-	else if (data->config.fixedFramerate < 0)
+	if (data->config.syncToRefreshrate)
+	{
+		p->frameRate = data->refreshRate;
 		p->fpsLimiter.disabled = true;
+	}
+	else if (data->config.fixedFramerate > 0)
+	{
+		p->fpsLimiter.setDesiredFPS(data->config.fixedFramerate);
+	}
+	else if (data->config.fixedFramerate < 0)
+	{
+		p->fpsLimiter.disabled = true;
+	}
 }
 
 Graphics::~Graphics()
@@ -798,6 +807,9 @@ void Graphics::setFrameRate(int value)
 {
 	p->frameRate = clamp(value, 10, 120);
 
+	if (p->threadData->config.syncToRefreshrate)
+		return;
+
 	if (p->threadData->config.fixedFramerate > 0)
 		return;
 
diff --git a/src/main.cpp b/src/main.cpp
index 4a87c28..890d7e6 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -68,13 +68,14 @@ printGLInfo()
 int rgssThreadFun(void *userdata)
 {
 	RGSSThreadData *threadData = static_cast<RGSSThreadData*>(userdata);
+	const Config &conf = threadData->config;
 	SDL_Window *win = threadData->window;
 	SDL_GLContext glCtx;
 
 	/* Setup GL context */
 	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
 
-	if (threadData->config.debugMode)
+	if (conf.debugMode)
 		SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
 
 	glCtx = SDL_GL_CreateContext(win);
@@ -103,7 +104,8 @@ int rgssThreadFun(void *userdata)
 
 	printGLInfo();
 
-	SDL_GL_SetSwapInterval(threadData->config.vsync ? 1 : 0);
+	bool vsync = conf.vsync || conf.syncToRefreshrate;
+	SDL_GL_SetSwapInterval(vsync ? 1 : 0);
 
 	GLDebugLogger dLogger;
 
@@ -283,9 +285,16 @@ int main(int argc, char *argv[])
 		return 0;
 	}
 
+	SDL_DisplayMode mode;
+	SDL_GetDisplayMode(0, 0, &mode);
+
+	/* Can't sync to display refresh rate if its value is unknown */
+	if (!mode.refresh_rate)
+		conf.syncToRefreshrate = false;
+
 	EventThread eventThread;
 	RGSSThreadData rtData(&eventThread, argv[0], win,
-	                      alcDev, conf);
+	                      alcDev, mode.refresh_rate, conf);
 
 	int winW, winH;
 	SDL_GetWindowSize(win, &winW, &winH);