feat(launcher): Set CVARs from the command line
Some checks failed
Ubuntu Cross to Win64 / Cross Compile with ming64 (1.4.0, ubuntu-latest) (push) Failing after 1m39s
Some checks failed
Ubuntu Cross to Win64 / Cross Compile with ming64 (1.4.0, ubuntu-latest) (push) Failing after 1m39s
This commit is contained in:
parent
88fd8a3059
commit
50bd92dfcb
6
cfg/launcher.cfg
Normal file
6
cfg/launcher.cfg
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
rt_Renderer = vk
|
||||||
|
rt_WindowTitle = "rtengine"
|
||||||
|
rt_WindowWidth = 1024
|
||||||
|
rt_WindowHeight = 768
|
||||||
|
rt_WindowMode = 0
|
||||||
|
rt_GameLib = "(null)"
|
@ -2,15 +2,20 @@
|
|||||||
#define RT_LAUNCHER_GAME_API_H
|
#define RT_LAUNCHER_GAME_API_H
|
||||||
|
|
||||||
#include <runtime/runtime.h>
|
#include <runtime/runtime.h>
|
||||||
|
#include <runtime/timing.h>
|
||||||
|
|
||||||
typedef void rt_game_register_cvars_fn(void);
|
typedef void rt_game_register_cvars_fn(void);
|
||||||
typedef rt_result rt_game_initialize_fn(void);
|
typedef rt_result rt_game_initialize_fn(void);
|
||||||
typedef void rt_game_shutdown(void);
|
typedef void rt_game_shutdown_fn(void);
|
||||||
|
typedef void rt_game_update_fn(rt_time_delta delta);
|
||||||
|
typedef void rt_game_render_fn(void);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
rt_game_register_cvars_fn *RegisterCVARs;
|
rt_game_register_cvars_fn *RegisterCVARs;
|
||||||
rt_game_initialize_fn *Init;
|
rt_game_initialize_fn *Init;
|
||||||
rt_game_shutdown *Shutdown;
|
rt_game_shutdown_fn *Shutdown;
|
||||||
|
rt_game_update_fn *Update;
|
||||||
|
rt_game_render_fn *Render;
|
||||||
} rt_game_api;
|
} rt_game_api;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#include "runtime/aio.h"
|
|
||||||
#include "runtime/file_tab.h"
|
#include "runtime/file_tab.h"
|
||||||
#include "runtime/mem_arena.h"
|
#include "runtime/mem_arena.h"
|
||||||
|
#include "runtime/timing.h"
|
||||||
|
|
||||||
#ifdef __WIN32
|
#ifdef __WIN32
|
||||||
#define GLFW_EXPOSE_NATIVE_WIN32
|
#define GLFW_EXPOSE_NATIVE_WIN32
|
||||||
@ -29,6 +29,13 @@ RT_CVAR_I(rt_WindowMode, "The window mode. Available options: 0 (=Windowed), 1 (
|
|||||||
RT_CVAR_I(rt_FullscreenRefreshRate, "Requested refresh rate for exclusive fullscreen. Set to 0 to use the monitors current setting. (Default: 0)", 0);
|
RT_CVAR_I(rt_FullscreenRefreshRate, "Requested refresh rate for exclusive fullscreen. Set to 0 to use the monitors current setting. (Default: 0)", 0);
|
||||||
RT_CVAR_S(rt_Monitor, "Name of the monitor on which the window should be created. Leave empty to use the primary monitor. (Default: "")", "");
|
RT_CVAR_S(rt_Monitor, "Name of the monitor on which the window should be created. Leave empty to use the primary monitor. (Default: "")", "");
|
||||||
|
|
||||||
|
RT_CVAR_F(rt_Framerate, "Target framerate in FPS. (Default: 60.0)", 60.0);
|
||||||
|
|
||||||
|
/* These are for experiments and debugging */
|
||||||
|
RT_CVAR_I(rt_LauncherCreateGLContext, "Create an OpenGL context in the launcher. 1: on, 0: off. (Default: 0)", 0);
|
||||||
|
RT_CVAR_I(rt_LauncherGLContextMajor, "OpenGL Major version. (Default: 4)", 4);
|
||||||
|
RT_CVAR_I(rt_LauncherGLContextMinor, "OpenGL minor version. (Default: 5)", 5);
|
||||||
|
|
||||||
RT_CVAR_S(rt_GameLib, "Path to the game library. Only usable in internal builds. (Default: "")", "");
|
RT_CVAR_S(rt_GameLib, "Path to the game library. Only usable in internal builds. (Default: "")", "");
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -57,6 +64,12 @@ static void SetupConfig(void) {
|
|||||||
rtRegisterCVAR(&rt_WindowMode);
|
rtRegisterCVAR(&rt_WindowMode);
|
||||||
rtRegisterCVAR(&rt_Monitor);
|
rtRegisterCVAR(&rt_Monitor);
|
||||||
|
|
||||||
|
rtRegisterCVAR(&rt_Framerate);
|
||||||
|
|
||||||
|
rtRegisterCVAR(&rt_LauncherCreateGLContext);
|
||||||
|
rtRegisterCVAR(&rt_LauncherGLContextMajor);
|
||||||
|
rtRegisterCVAR(&rt_LauncherGLContextMinor);
|
||||||
|
|
||||||
rtRegisterCVAR(&rt_GameLib);
|
rtRegisterCVAR(&rt_GameLib);
|
||||||
|
|
||||||
rt_file_id config_fid = rtAddFile("cfg/launcher.cfg");
|
rt_file_id config_fid = rtAddFile("cfg/launcher.cfg");
|
||||||
@ -73,9 +86,46 @@ static void LoadGameAndRendererConfig() {
|
|||||||
rtProcessConfigFiles(RT_ARRAY_COUNT(fids), fids);
|
rtProcessConfigFiles(RT_ARRAY_COUNT(fids), fids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ParseCommandLineCVARs(int argc, char **argv) {
|
||||||
|
for (int i = 1; i < argc - 1; ++i) {
|
||||||
|
const char *name = argv[i];
|
||||||
|
if (name[0] != '-' || name[1] != '-')
|
||||||
|
continue;
|
||||||
|
name = &name[2];
|
||||||
|
rt_cvar *cvar = rtGetCVAR(name);
|
||||||
|
if (!cvar) {
|
||||||
|
++i; /* Skip value */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const char *value = argv[i + 1];
|
||||||
|
|
||||||
|
if (rtSetCVARFromString(cvar, value) != RT_SUCCESS) {
|
||||||
|
rtLog("LAUNCHER", "Failed to set %s to %s. Invalid value?", cvar->name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip value */
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *ParseCommandLineGameLib(int argc, char **argv) {
|
||||||
|
char *game_lib_cmdline = NULL;
|
||||||
|
#ifdef RT_DEBUG
|
||||||
|
for (int i = 1; i < argc - 1; ++i) {
|
||||||
|
if (strcmp(argv[i], "--game") == 0) {
|
||||||
|
game_lib_cmdline = argv[i + 1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return game_lib_cmdline;
|
||||||
|
}
|
||||||
|
|
||||||
static void __NullGame_RegisterCVARs(void) {}
|
static void __NullGame_RegisterCVARs(void) {}
|
||||||
static rt_result __NullGame_Init(void) { return RT_SUCCESS; }
|
static rt_result __NullGame_Init(void) { return RT_SUCCESS; }
|
||||||
static void __NullGame_Shutdown(void) {}
|
static void __NullGame_Shutdown(void) {}
|
||||||
|
static void __NullGame_Update(rt_time_delta delta) { RT_UNUSED(delta); }
|
||||||
|
static void __NullGame_Render(void) {}
|
||||||
|
|
||||||
|
|
||||||
static rt_game_api LoadGame(const char *cmdline_gamelib) {
|
static rt_game_api LoadGame(const char *cmdline_gamelib) {
|
||||||
@ -111,6 +161,8 @@ out:
|
|||||||
.RegisterCVARs = __NullGame_RegisterCVARs,
|
.RegisterCVARs = __NullGame_RegisterCVARs,
|
||||||
.Init = __NullGame_Init,
|
.Init = __NullGame_Init,
|
||||||
.Shutdown = __NullGame_Shutdown,
|
.Shutdown = __NullGame_Shutdown,
|
||||||
|
.Update = __NullGame_Update,
|
||||||
|
.Render = __NullGame_Render,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,25 +221,26 @@ static int Entry(int argc, char **argv) {
|
|||||||
g_renderer.RegisterCVARs();
|
g_renderer.RegisterCVARs();
|
||||||
|
|
||||||
/* Load the game */
|
/* Load the game */
|
||||||
const char *game_lib_cmdline = NULL;
|
const char *game_lib_cmdline = ParseCommandLineGameLib(argc, argv);
|
||||||
#ifdef RT_DEBUG
|
|
||||||
for (int i = 1; i < argc - 1; ++i) {
|
|
||||||
if (strcmp(argv[i], "--game") == 0) {
|
|
||||||
game_lib_cmdline = argv[i + 1];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
rt_game_api game = LoadGame(game_lib_cmdline);
|
rt_game_api game = LoadGame(game_lib_cmdline);
|
||||||
game.RegisterCVARs();
|
game.RegisterCVARs();
|
||||||
|
|
||||||
LoadGameAndRendererConfig();
|
LoadGameAndRendererConfig();
|
||||||
|
ParseCommandLineCVARs(argc, argv);
|
||||||
|
|
||||||
/* Create the window */
|
/* Create the window */
|
||||||
GLFWmonitor *monitor = ChooseMonitor();
|
GLFWmonitor *monitor = ChooseMonitor();
|
||||||
|
|
||||||
GLFWwindow *window = NULL;
|
GLFWwindow *window = NULL;
|
||||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
if (!rt_LauncherCreateGLContext.i) {
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||||
|
} else {
|
||||||
|
rtLog("LAUNCHER", "Creating an OpenGL %d.%d context", rt_LauncherGLContextMajor.i, rt_LauncherGLContextMinor.i);
|
||||||
|
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, rt_LauncherGLContextMajor.i);
|
||||||
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, rt_LauncherGLContextMinor.i);
|
||||||
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||||
|
}
|
||||||
glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE);
|
glfwWindowHint(GLFW_FOCUSED, GLFW_TRUE);
|
||||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||||
glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_TRUE);
|
glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_TRUE);
|
||||||
@ -239,6 +292,10 @@ static int Entry(int argc, char **argv) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rt_LauncherCreateGLContext.i) {
|
||||||
|
glfwMakeContextCurrent(window);
|
||||||
|
}
|
||||||
|
|
||||||
/* Initialize the renderer */
|
/* Initialize the renderer */
|
||||||
rt_renderer_init_info renderer_init_info;
|
rt_renderer_init_info renderer_init_info;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -268,8 +325,29 @@ static int Entry(int argc, char **argv) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rt_time_delta time_per_update = 1.0 / (double)rt_Framerate.f;
|
||||||
|
rt_timestamp previous = rtTimeNow();
|
||||||
|
rt_time_delta lag = time_per_update;
|
||||||
while (!glfwWindowShouldClose(window)) {
|
while (!glfwWindowShouldClose(window)) {
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
|
||||||
|
rt_timestamp current = rtTimeNow();
|
||||||
|
rt_time_delta elapsed = rtTimeBetween(previous, current);
|
||||||
|
previous = current;
|
||||||
|
lag += elapsed;
|
||||||
|
|
||||||
|
/* TODO: Process input */
|
||||||
|
|
||||||
|
while (lag >= time_per_update) {
|
||||||
|
game.Update(time_per_update);
|
||||||
|
lag -= time_per_update;
|
||||||
|
}
|
||||||
|
|
||||||
|
game.Render();
|
||||||
|
|
||||||
|
if (rt_LauncherCreateGLContext.i) {
|
||||||
|
glfwSwapBuffers(window);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
game.Shutdown();
|
game.Shutdown();
|
||||||
|
@ -143,38 +143,7 @@ static int Handler(void *user, const char *section, const char *name, const char
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_read = 0;
|
if (rtSetCVARFromString(cvar, value) != RT_SUCCESS) {
|
||||||
switch (cvar->type) {
|
|
||||||
case RT_CVAR_TYPE_INT:
|
|
||||||
num_read = sscanf(value, "%d", &cvar->i);
|
|
||||||
break;
|
|
||||||
case RT_CVAR_TYPE_FLOAT:
|
|
||||||
num_read = sscanf(value, "%f", &cvar->f);
|
|
||||||
break;
|
|
||||||
case RT_CVAR_TYPE_STRING: {
|
|
||||||
num_read = 1;
|
|
||||||
char *copy = rtStoreString(value);
|
|
||||||
if (!copy) {
|
|
||||||
rtReportError("CVAR",
|
|
||||||
"Failed to store string value of cvar %s in config file %s.",
|
|
||||||
name,
|
|
||||||
file_path);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
cvar->s = copy;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RT_CVAR_TYPE_SIZE:
|
|
||||||
num_read = sscanf(value, "%zu", &cvar->sz);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
rtReportError("CVAR", "CVar %s has an invalid type.", cvar->name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (num_read == 1) {
|
|
||||||
rtNotifyCVARChange(cvar);
|
|
||||||
} else {
|
|
||||||
rtLog("CVAR", "Failed to read value of CVar %s in config file %s.", cvar->name, file_path);
|
rtLog("CVAR", "Failed to read value of CVar %s in config file %s.", cvar->name, file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,4 +272,40 @@ void ProcessEarlyEngineConfigs(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RT_DLLEXPORT rt_result rtSetCVARFromString(rt_cvar *cvar, const char *value_str) {
|
||||||
|
|
||||||
|
int num_read = 0;
|
||||||
|
switch (cvar->type) {
|
||||||
|
case RT_CVAR_TYPE_INT:
|
||||||
|
num_read = sscanf(value_str, "%d", &cvar->i);
|
||||||
|
break;
|
||||||
|
case RT_CVAR_TYPE_FLOAT:
|
||||||
|
num_read = sscanf(value_str, "%f", &cvar->f);
|
||||||
|
break;
|
||||||
|
case RT_CVAR_TYPE_STRING: {
|
||||||
|
num_read = 1;
|
||||||
|
char *copy = rtStoreString(value_str);
|
||||||
|
if (!copy) {
|
||||||
|
rtReportError("CVAR",
|
||||||
|
"Failed to store string value of cvar %s.",
|
||||||
|
cvar->name);
|
||||||
|
return RT_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
cvar->s = copy;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case RT_CVAR_TYPE_SIZE:
|
||||||
|
num_read = sscanf(value_str, "%zu", &cvar->sz);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rtReportError("CVAR", "CVar %s has an invalid type.", cvar->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_read == 1) {
|
||||||
|
rtNotifyCVARChange(cvar);
|
||||||
|
}
|
||||||
|
return (num_read) ? RT_SUCCESS : RT_INVALID_VALUE;
|
||||||
|
}
|
||||||
|
@ -57,8 +57,10 @@ RT_DLLEXPORT void rtNotifyCVARChange(const rt_cvar *cvar);
|
|||||||
* They are processed in-order, meaning later files can overwrite earlier files. */
|
* They are processed in-order, meaning later files can overwrite earlier files. */
|
||||||
RT_DLLEXPORT rt_result rtProcessConfigFiles(unsigned int count, const rt_file_id *fids);
|
RT_DLLEXPORT rt_result rtProcessConfigFiles(unsigned int count, const rt_file_id *fids);
|
||||||
|
|
||||||
|
RT_DLLEXPORT rt_result rtSetCVARFromString(rt_cvar *cvar, const char *value_str);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -52,7 +52,7 @@ rt_result InitTiming(void) {
|
|||||||
rtReportError("TIMING", "Clock reports resolution greater than 1 second.");
|
rtReportError("TIMING", "Clock reports resolution greater than 1 second.");
|
||||||
return RT_INVALID_VALUE;
|
return RT_INVALID_VALUE;
|
||||||
}
|
}
|
||||||
_gettime_freq = res.tv_nsec * 1000000000;
|
_gettime_freq = 1000000000;
|
||||||
double us_res = (double)res.tv_nsec / 1e3;
|
double us_res = (double)res.tv_nsec / 1e3;
|
||||||
|
|
||||||
rtLog("TIMING", "clock_gettime resolution: %.3lf us.", us_res);
|
rtLog("TIMING", "clock_gettime resolution: %.3lf us.", us_res);
|
||||||
|
Loading…
Reference in New Issue
Block a user