Merge branch 'master' of https://github.com/86Box/86Box
This commit is contained in:
@@ -129,6 +129,9 @@ int video_fullscreen_scale = 0; /* (C) video */
|
||||
int video_fullscreen_first = 0; /* (C) video */
|
||||
int enable_overscan = 0; /* (C) video */
|
||||
int force_43 = 0; /* (C) video */
|
||||
int video_vsync = 0; /* (C) video */
|
||||
int video_framerate = -1; /* (C) video */
|
||||
char video_shader[512] = { '\0' }; /* (C) video */
|
||||
int serial_enabled[SERIAL_MAX] = {0,0}; /* (C) enable serial ports */
|
||||
int bugger_enabled = 0; /* (C) enable ISAbugger */
|
||||
int postcard_enabled = 0; /* (C) enable POST card */
|
||||
|
21
src/config.c
21
src/config.c
@@ -528,6 +528,12 @@ load_general(void)
|
||||
#if USE_DISCORD
|
||||
enable_discord = !!config_get_int(cat, "enable_discord", 0);
|
||||
#endif
|
||||
|
||||
#ifdef DEV_BRANCH /* feature-opengl */
|
||||
video_framerate = config_get_int(cat, "video_gl_framerate", -1);
|
||||
video_vsync = config_get_int(cat, "video_gl_vsync", 0);
|
||||
strcpy_s(video_shader, sizeof(video_shader), config_get_string(cat, "video_gl_shader", ""));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1968,6 +1974,21 @@ save_general(void)
|
||||
config_delete_var(cat, "enable_discord");
|
||||
#endif
|
||||
|
||||
#ifdef DEV_BRANCH /* feature-opengl */
|
||||
if (video_framerate != -1)
|
||||
config_set_int(cat, "video_gl_framerate", video_framerate);
|
||||
else
|
||||
config_delete_var(cat, "video_gl_framerate");
|
||||
if (video_vsync != 0)
|
||||
config_set_int(cat, "video_gl_vsync", video_vsync);
|
||||
else
|
||||
config_delete_var(cat, "video_gl_vsync");
|
||||
if (strlen(video_shader) > 0)
|
||||
config_set_string(cat, "video_gl_shader", video_shader);
|
||||
else
|
||||
config_delete_var(cat, "video_gl_shader");
|
||||
#endif
|
||||
|
||||
delete_section_if_empty(cat);
|
||||
}
|
||||
|
||||
|
@@ -90,7 +90,10 @@ extern int vid_cga_contrast, /* (C) video */
|
||||
video_fullscreen_scale, /* (C) video */
|
||||
enable_overscan, /* (C) video */
|
||||
force_43, /* (C) video */
|
||||
video_vsync, /* (C) video */
|
||||
video_framerate, /* (C) video */
|
||||
gfxcard; /* (C) graphics/video card */
|
||||
extern char video_shader[512]; /* (C) video */
|
||||
extern int serial_enabled[], /* (C) enable serial ports */
|
||||
bugger_enabled, /* (C) enable ISAbugger */
|
||||
postcard_enabled, /* (C) enable POST card */
|
||||
|
@@ -116,6 +116,8 @@
|
||||
#define IDS_2140 2140 // "CD-ROM images (*.ISO;*.CU.."
|
||||
#define IDS_2141 2141 // "%hs Device Configuration"
|
||||
#define IDS_2142 2142 // "Monitor in sleep mode"
|
||||
#define IDS_2143 2143 // "OpenGL Shaders (*.GLSL)..."
|
||||
#define IDS_2144 2144 // "OpenGL options"
|
||||
|
||||
#define IDS_4096 4096 // "Hard disk (%s)"
|
||||
#define IDS_4097 4097 // "%01i:%01i"
|
||||
@@ -223,7 +225,7 @@
|
||||
|
||||
#define IDS_LANG_ENUS IDS_7168
|
||||
|
||||
#define STR_NUM_2048 95
|
||||
#define STR_NUM_2048 97
|
||||
#define STR_NUM_3072 11
|
||||
#define STR_NUM_4096 39
|
||||
#define STR_NUM_4352 6
|
||||
|
@@ -101,6 +101,7 @@ extern int plat_dir_check(char *path);
|
||||
extern int plat_dir_create(char *path);
|
||||
extern uint64_t plat_timer_read(void);
|
||||
extern uint32_t plat_get_ticks(void);
|
||||
extern uint32_t plat_get_micro_ticks(void);
|
||||
extern void plat_delay_ms(uint32_t count);
|
||||
extern void plat_pause(int p);
|
||||
extern void plat_mouse_capture(int on);
|
||||
@@ -111,7 +112,7 @@ extern void plat_vidsize(int x, int y);
|
||||
extern void plat_setfullscreen(int on);
|
||||
extern void plat_resize(int x, int y);
|
||||
extern void plat_vidapi_enable(int enabled);
|
||||
|
||||
extern void plat_vid_reload_options(void);
|
||||
|
||||
/* Resource management. */
|
||||
extern void set_language(int id);
|
||||
|
@@ -341,6 +341,17 @@
|
||||
#define IDM_DISCORD 40090
|
||||
#endif
|
||||
|
||||
#ifdef DEV_BRANCH /* feature-opengl */
|
||||
#define IDM_VID_GL_FPS_BLITTER 40100
|
||||
#define IDM_VID_GL_FPS_25 40101
|
||||
#define IDM_VID_GL_FPS_30 40102
|
||||
#define IDM_VID_GL_FPS_50 40103
|
||||
#define IDM_VID_GL_FPS_60 40104
|
||||
#define IDM_VID_GL_FPS_75 40105
|
||||
#define IDM_VID_GL_VSYNC 40106
|
||||
#define IDM_VID_GL_SHADER 40107
|
||||
#endif
|
||||
|
||||
#define IDM_LOG_BREAKPOINT 51201
|
||||
#define IDM_DUMP_VRAM 51202 // should be an Action
|
||||
|
||||
|
@@ -63,6 +63,10 @@ DECLARE_HANDLE(DPI_AWARENESS_CONTEXT);
|
||||
#define ZIP_SUBMENU_NAME L"ZIPSubmenu"
|
||||
#define MO_SUBMENU_NAME L"MOSubmenu"
|
||||
|
||||
#ifdef DEV_BRANCH /* feature-opengl */
|
||||
#define VID_GL_SUBMENU L"VidGLSubMenu"
|
||||
#endif
|
||||
|
||||
/* Application-specific window messages.
|
||||
|
||||
A dialog sends 0x8895 with WPARAM = 1 followed by 0x8896 with WPARAM = 1 on open,
|
||||
|
@@ -23,5 +23,6 @@ extern int opengl_pause(void);
|
||||
extern void opengl_close(void);
|
||||
extern void opengl_set_fs(int fs);
|
||||
extern void opengl_resize(int w, int h);
|
||||
extern void opengl_reload(void);
|
||||
|
||||
#endif /*!WIN_OPENGL_H*/
|
@@ -17,7 +17,7 @@
|
||||
|
||||
#include <glad/glad.h>
|
||||
|
||||
GLuint load_custom_shaders();
|
||||
GLuint load_custom_shaders(const char* path);
|
||||
GLuint load_default_shaders();
|
||||
|
||||
#endif /*!WIN_OPENGL_GLSLP_H*/
|
@@ -66,7 +66,7 @@ BEGIN
|
||||
MENUITEM "&SDL (Software)", IDM_VID_SDL_SW
|
||||
MENUITEM "SDL (&Hardware)", IDM_VID_SDL_HW
|
||||
MENUITEM "SDL (&OpenGL)", IDM_VID_SDL_OPENGL
|
||||
#ifdef DEV_BRANCH
|
||||
#ifdef DEV_BRANCH /* feature-opengl */
|
||||
MENUITEM "Open&GL (3.3 Core)", IDM_VID_OPENGL_CORE
|
||||
#endif
|
||||
#ifdef USE_VNC
|
||||
@@ -237,6 +237,22 @@ BEGIN
|
||||
END
|
||||
END
|
||||
|
||||
#ifdef DEV_BRANCH /* feature-opengl */
|
||||
VidGLSubMenu MENU DISCARDABLE
|
||||
BEGIN
|
||||
POPUP "Target &framerate"
|
||||
BEGIN
|
||||
MENUITEM "&Sync with video", IDM_VID_GL_FPS_BLITTER
|
||||
MENUITEM "&25 fps", IDM_VID_GL_FPS_25
|
||||
MENUITEM "&30 fps", IDM_VID_GL_FPS_30
|
||||
MENUITEM "&50 fps", IDM_VID_GL_FPS_50
|
||||
MENUITEM "&60 fps", IDM_VID_GL_FPS_60
|
||||
MENUITEM "&75 fps", IDM_VID_GL_FPS_75
|
||||
END
|
||||
MENUITEM "&VSync", IDM_VID_GL_VSYNC
|
||||
MENUITEM "&Select shader...", IDM_VID_GL_SHADER
|
||||
END
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
@@ -1080,6 +1096,8 @@ BEGIN
|
||||
IDS_2140 "CD-ROM images (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0"
|
||||
IDS_2141 "%hs Device Configuration"
|
||||
IDS_2142 "Monitor in sleep mode"
|
||||
IDS_2143 "OpenGL Shaders (*.GLSL)\0*.GLSL\0All files (*.*)\0*.*\0"
|
||||
IDS_2144 "OpenGL options"
|
||||
END
|
||||
|
||||
STRINGTABLE DISCARDABLE
|
||||
|
@@ -99,17 +99,18 @@ static const struct {
|
||||
int (*pause)(void);
|
||||
void (*enable)(int enable);
|
||||
void (*set_fs)(int fs);
|
||||
void (*reload)(void);
|
||||
} vid_apis[RENDERERS_NUM] = {
|
||||
{ "SDL_Software", 1, (int(*)(void*))sdl_inits, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs },
|
||||
{ "SDL_Hardware", 1, (int(*)(void*))sdl_inith, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs },
|
||||
{ "SDL_OpenGL", 1, (int(*)(void*))sdl_initho, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs }
|
||||
#ifdef DEV_BRANCH
|
||||
,{ "OpenGL_Core", 1, (int(*)(void*))opengl_init, opengl_close, opengl_resize, opengl_pause, NULL, opengl_set_fs}
|
||||
{ "SDL_Software", 1, (int(*)(void*))sdl_inits, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs, NULL },
|
||||
{ "SDL_Hardware", 1, (int(*)(void*))sdl_inith, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs, NULL },
|
||||
{ "SDL_OpenGL", 1, (int(*)(void*))sdl_initho, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs, NULL }
|
||||
#ifdef DEV_BRANCH /* feature-opengl */
|
||||
,{ "OpenGL_Core", 1, (int(*)(void*))opengl_init, opengl_close, opengl_resize, opengl_pause, NULL, opengl_set_fs, opengl_reload}
|
||||
#else
|
||||
,{ "OpenGL_Core", 1, (int(*)(void*))sdl_initho, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs } /* fall back to SDL_OpenGL */
|
||||
,{ "OpenGL_Core", 1, (int(*)(void*))sdl_initho, sdl_close, NULL, sdl_pause, sdl_enable, sdl_set_fs, NULL } /* fall back to SDL_OpenGL */
|
||||
#endif
|
||||
#ifdef USE_VNC
|
||||
,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL, NULL }
|
||||
,{ "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause, NULL, NULL }
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -857,9 +858,8 @@ plat_timer_read(void)
|
||||
return(li.QuadPart);
|
||||
}
|
||||
|
||||
|
||||
uint32_t
|
||||
plat_get_ticks(void)
|
||||
static LARGE_INTEGER
|
||||
plat_get_ticks_common(void)
|
||||
{
|
||||
LARGE_INTEGER EndingTime, ElapsedMicroseconds;
|
||||
|
||||
@@ -880,9 +880,20 @@ plat_get_ticks(void)
|
||||
ElapsedMicroseconds.QuadPart *= 1000000;
|
||||
ElapsedMicroseconds.QuadPart /= Frequency.QuadPart;
|
||||
|
||||
return (uint32_t) (ElapsedMicroseconds.QuadPart / 1000);
|
||||
return ElapsedMicroseconds;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
plat_get_ticks(void)
|
||||
{
|
||||
return (uint32_t)(plat_get_ticks_common().QuadPart / 1000);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
plat_get_micro_ticks(void)
|
||||
{
|
||||
return (uint32_t)plat_get_ticks_common().QuadPart;
|
||||
}
|
||||
|
||||
void
|
||||
plat_delay_ms(uint32_t count)
|
||||
@@ -928,7 +939,7 @@ plat_vidapi_name(int api)
|
||||
case 2:
|
||||
name = "sdl_opengl";
|
||||
break;
|
||||
#ifdef DEV_BRANCH
|
||||
#ifdef DEV_BRANCH /* feature-opengl */
|
||||
case 3:
|
||||
name = "opengl_core";
|
||||
break;
|
||||
@@ -1104,6 +1115,15 @@ plat_setfullscreen(int on)
|
||||
plat_vidapi_enable(1);
|
||||
}
|
||||
|
||||
void
|
||||
plat_vid_reload_options(void)
|
||||
{
|
||||
if (!vid_api_inited || !vid_apis[vid_api].reload)
|
||||
return;
|
||||
|
||||
vid_apis[vid_api].reload();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
take_screenshot(void)
|
||||
|
@@ -35,12 +35,14 @@
|
||||
*/
|
||||
#define UNICODE
|
||||
#include <Windows.h>
|
||||
#include <process.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_syswm.h>
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <86box/86box.h>
|
||||
#include <86box/plat.h>
|
||||
@@ -52,13 +54,6 @@
|
||||
static const int INIT_WIDTH = 640;
|
||||
static const int INIT_HEIGHT = 400;
|
||||
|
||||
/* Option; Target framerate: Sync with emulation / 25 fps / 30 fps / 50 fps / 60 fps / 75 fps */
|
||||
static const int SYNC_WITH_BLITTER = 1;
|
||||
static const int TARGET_FRAMETIME = 13;
|
||||
|
||||
/* Option; Vsync: Off / On */
|
||||
static const int VSYNC = 0;
|
||||
|
||||
/**
|
||||
* @brief A dedicated OpenGL thread.
|
||||
* OpenGL context's don't handle multiple threads well.
|
||||
@@ -89,9 +84,10 @@ static union
|
||||
{
|
||||
HANDLE closing;
|
||||
HANDLE resize;
|
||||
HANDLE reload;
|
||||
HANDLE blit_waiting;
|
||||
};
|
||||
HANDLE asArray[3];
|
||||
HANDLE asArray[4];
|
||||
} sync_objects = { 0 };
|
||||
|
||||
/**
|
||||
@@ -110,11 +106,24 @@ static volatile struct
|
||||
/**
|
||||
* @brief Resize event parameters.
|
||||
*/
|
||||
static volatile struct
|
||||
static struct
|
||||
{
|
||||
int width, height, fullscreen, scaling_mode;
|
||||
mutex_t* mutex;
|
||||
} resize_info = { 0 };
|
||||
|
||||
/**
|
||||
* @brief Renderer options
|
||||
*/
|
||||
static struct
|
||||
{
|
||||
int vsync; /* Vertical sync; 0 = off, 1 = on */
|
||||
int frametime; /* Frametime in microseconds, or -1 to sync with blitter */
|
||||
char shaderfile[512]; /* Shader file path. Match the length of openfilestring in win_dialog.c */
|
||||
int shaderfile_changed; /* Has shader file path changed. To prevent unnecessary shader recompilation. */
|
||||
mutex_t* mutex;
|
||||
} options = { 0 };
|
||||
|
||||
/**
|
||||
* @brief Identifiers to OpenGL objects and uniforms.
|
||||
*/
|
||||
@@ -133,15 +142,6 @@ typedef struct
|
||||
GLint frame_count;
|
||||
} gl_identifiers;
|
||||
|
||||
/**
|
||||
* @brief Userdata to pass onto windows message hook
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
HWND window;
|
||||
int* fullscreen;
|
||||
} winmessage_data;
|
||||
|
||||
/**
|
||||
* @brief Set or unset OpenGL context window as a child window.
|
||||
*
|
||||
@@ -171,28 +171,21 @@ static void set_parent_binding(int enable)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Windows message handler for SDL Windows.
|
||||
* @param userdata winmessage_data
|
||||
* @param hWnd
|
||||
* @brief Windows message handler for our window.
|
||||
* @param message
|
||||
* @param wParam
|
||||
* @param lParam
|
||||
* @param fullscreen
|
||||
*/
|
||||
static void winmessage_hook(void* userdata, void* hWnd, unsigned int message, Uint64 wParam, Sint64 lParam)
|
||||
static void handle_window_messages(UINT message, WPARAM wParam, LPARAM lParam, int fullscreen)
|
||||
{
|
||||
winmessage_data* msg_data = (winmessage_data*)userdata;
|
||||
|
||||
/* Process only our window */
|
||||
if (msg_data->window != hWnd || parent == NULL)
|
||||
return;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_LBUTTONUP:
|
||||
case WM_LBUTTONDOWN:
|
||||
case WM_MBUTTONUP:
|
||||
case WM_MBUTTONDOWN:
|
||||
if (!*msg_data->fullscreen)
|
||||
if (!fullscreen)
|
||||
{
|
||||
/* Mouse events that enter and exit capture. */
|
||||
PostMessage(parent, message, wParam, lParam);
|
||||
@@ -202,13 +195,13 @@ static void winmessage_hook(void* userdata, void* hWnd, unsigned int message, Ui
|
||||
case WM_KEYUP:
|
||||
case WM_SYSKEYDOWN:
|
||||
case WM_SYSKEYUP:
|
||||
if (*msg_data->fullscreen)
|
||||
if (fullscreen)
|
||||
{
|
||||
PostMessage(parent, message, wParam, lParam);
|
||||
}
|
||||
break;
|
||||
case WM_INPUT:
|
||||
if (*msg_data->fullscreen)
|
||||
if (fullscreen)
|
||||
{
|
||||
/* Raw input handler from win_ui.c : input_proc */
|
||||
|
||||
@@ -238,6 +231,74 @@ static void winmessage_hook(void* userdata, void* hWnd, unsigned int message, Ui
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief (Re-)apply shaders to OpenGL context.
|
||||
* @param gl Identifiers from initialize
|
||||
*/
|
||||
static void apply_shaders(gl_identifiers* gl)
|
||||
{
|
||||
GLuint old_shader_ID = 0;
|
||||
|
||||
if (gl->shader_progID != 0)
|
||||
old_shader_ID = gl->shader_progID;
|
||||
|
||||
if (strlen(options.shaderfile) > 0)
|
||||
gl->shader_progID = load_custom_shaders(options.shaderfile);
|
||||
else
|
||||
gl->shader_progID = 0;
|
||||
|
||||
if (gl->shader_progID == 0)
|
||||
gl->shader_progID = load_default_shaders();
|
||||
|
||||
glUseProgram(gl->shader_progID);
|
||||
|
||||
/* Delete old shader if one exists (changing shader) */
|
||||
if (old_shader_ID != 0)
|
||||
glDeleteProgram(old_shader_ID);
|
||||
|
||||
GLint vertex_coord = glGetAttribLocation(gl->shader_progID, "VertexCoord");
|
||||
if (vertex_coord != -1)
|
||||
{
|
||||
glEnableVertexAttribArray(vertex_coord);
|
||||
glVertexAttribPointer(vertex_coord, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0);
|
||||
}
|
||||
|
||||
GLint tex_coord = glGetAttribLocation(gl->shader_progID, "TexCoord");
|
||||
if (tex_coord != -1)
|
||||
{
|
||||
glEnableVertexAttribArray(tex_coord);
|
||||
glVertexAttribPointer(tex_coord, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
|
||||
}
|
||||
|
||||
GLint color = glGetAttribLocation(gl->shader_progID, "Color");
|
||||
if (color != -1)
|
||||
{
|
||||
glEnableVertexAttribArray(color);
|
||||
glVertexAttribPointer(color, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(4 * sizeof(GLfloat)));
|
||||
}
|
||||
|
||||
GLint mvp_matrix = glGetUniformLocation(gl->shader_progID, "MVPMatrix");
|
||||
if (mvp_matrix != -1)
|
||||
{
|
||||
static const GLfloat mvp[] = {
|
||||
1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 1.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f
|
||||
};
|
||||
glUniformMatrix4fv(mvp_matrix, 1, GL_FALSE, mvp);
|
||||
}
|
||||
|
||||
GLint frame_direction = glGetUniformLocation(gl->shader_progID, "FrameDirection");
|
||||
if (frame_direction != -1)
|
||||
glUniform1i(frame_direction, 1); /* always forward */
|
||||
|
||||
gl->input_size = glGetUniformLocation(gl->shader_progID, "InputSize");
|
||||
gl->output_size = glGetUniformLocation(gl->shader_progID, "OutputSize");
|
||||
gl->texture_size = glGetUniformLocation(gl->shader_progID, "TextureSize");
|
||||
gl->frame_count = glGetUniformLocation(gl->shader_progID, "FrameCount");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialize OpenGL context
|
||||
* @return Identifiers
|
||||
@@ -265,7 +326,7 @@ static gl_identifiers initialize_glcontext()
|
||||
glGenTextures(1, &gl.textureID);
|
||||
glBindTexture(GL_TEXTURE_2D, gl.textureID);
|
||||
|
||||
GLfloat border_color[] = { 0.f, 0.f, 0.f, 1.f };
|
||||
static const GLfloat border_color[] = { 0.f, 0.f, 0.f, 1.f };
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
@@ -276,61 +337,14 @@ static gl_identifiers initialize_glcontext()
|
||||
|
||||
glClearColor(0.f, 0.f, 0.f, 1.f);
|
||||
|
||||
gl.shader_progID = load_custom_shaders();
|
||||
|
||||
if (gl.shader_progID == 0)
|
||||
gl.shader_progID = load_default_shaders();
|
||||
|
||||
glUseProgram(gl.shader_progID);
|
||||
|
||||
GLint vertex_coord = glGetAttribLocation(gl.shader_progID, "VertexCoord");
|
||||
if (vertex_coord != -1)
|
||||
{
|
||||
glEnableVertexAttribArray(vertex_coord);
|
||||
glVertexAttribPointer(vertex_coord, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), 0);
|
||||
}
|
||||
|
||||
GLint tex_coord = glGetAttribLocation(gl.shader_progID, "TexCoord");
|
||||
if (tex_coord != -1)
|
||||
{
|
||||
glEnableVertexAttribArray(tex_coord);
|
||||
glVertexAttribPointer(tex_coord, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
|
||||
}
|
||||
|
||||
GLint color = glGetAttribLocation(gl.shader_progID, "Color");
|
||||
if (color != -1)
|
||||
{
|
||||
glEnableVertexAttribArray(color);
|
||||
glVertexAttribPointer(color, 4, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (void*)(4 * sizeof(GLfloat)));
|
||||
}
|
||||
|
||||
GLint mvp_matrix = glGetUniformLocation(gl.shader_progID, "MVPMatrix");
|
||||
if (mvp_matrix != -1)
|
||||
{
|
||||
static const GLfloat mvp[] = {
|
||||
1.f, 0.f, 0.f, 0.f,
|
||||
0.f, 1.f, 0.f, 0.f,
|
||||
0.f, 0.f, 1.f, 0.f,
|
||||
0.f, 0.f, 0.f, 1.f
|
||||
};
|
||||
glUniformMatrix4fv(mvp_matrix, 1, GL_FALSE, mvp);
|
||||
}
|
||||
|
||||
GLint frame_direction = glGetUniformLocation(gl.shader_progID, "FrameDirection");
|
||||
if (frame_direction != -1)
|
||||
glUniform1i(frame_direction, 1); /* always forward */
|
||||
|
||||
gl.input_size = glGetUniformLocation(gl.shader_progID, "InputSize");
|
||||
gl.output_size = glGetUniformLocation(gl.shader_progID, "OutputSize");
|
||||
gl.texture_size = glGetUniformLocation(gl.shader_progID, "TextureSize");
|
||||
gl.frame_count = glGetUniformLocation(gl.shader_progID, "FrameCount");
|
||||
apply_shaders(&gl);
|
||||
|
||||
return gl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Clean up OpenGL context
|
||||
* @param Identifiers from initialize
|
||||
* @param gl Identifiers from initialize
|
||||
*/
|
||||
static void finalize_glcontext(gl_identifiers gl)
|
||||
{
|
||||
@@ -357,6 +371,34 @@ static void render_and_swap(gl_identifiers gl)
|
||||
glUniform1i(gl.frame_count, frame_counter = (frame_counter + 1) & 1023);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle failure in OpenGL thread.
|
||||
* Acts like a renderer until closing.
|
||||
*/
|
||||
static void opengl_fail()
|
||||
{
|
||||
if (window != NULL)
|
||||
{
|
||||
SDL_DestroyWindow(window);
|
||||
window = NULL;
|
||||
}
|
||||
|
||||
/* TODO: Notify user. */
|
||||
|
||||
HANDLE handles[] = { sync_objects.closing, sync_objects.blit_waiting };
|
||||
|
||||
while (1)
|
||||
{
|
||||
switch (WaitForMultipleObjects(2, handles, FALSE, INFINITE))
|
||||
{
|
||||
case WAIT_OBJECT_0: /* Close requested. End thread. */
|
||||
_endthread();
|
||||
case WAIT_OBJECT_0 + 1: /* Blitter is waiting, signal it to continue. */
|
||||
SetEvent(blit_done);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Main OpenGL thread proc.
|
||||
*
|
||||
@@ -369,22 +411,21 @@ static void opengl_main(void* param)
|
||||
|
||||
window = SDL_CreateWindow("86Box OpenGL Renderer", 0, 0, resize_info.width, resize_info.height, SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS);
|
||||
|
||||
SDL_GL_SetSwapInterval(VSYNC);
|
||||
if (window == NULL)
|
||||
opengl_fail();
|
||||
|
||||
/* Keep track of certain parameters, only changed in this thread to avoid race conditions */
|
||||
int fullscreen = resize_info.fullscreen, video_width = INIT_WIDTH, video_height = INIT_HEIGHT;
|
||||
int fullscreen = resize_info.fullscreen, video_width = INIT_WIDTH, video_height = INIT_HEIGHT,
|
||||
output_width = resize_info.width, output_height = resize_info.height, frametime = options.frametime;
|
||||
|
||||
SDL_SysWMinfo wmi = { 0 };
|
||||
SDL_VERSION(&wmi.version);
|
||||
SDL_GetWindowWMInfo(window, &wmi);
|
||||
|
||||
if (wmi.subsystem == SDL_SYSWM_WINDOWS)
|
||||
window_hwnd = wmi.info.win.window;
|
||||
|
||||
/* Pass window handle and full screen mode to windows message hook */
|
||||
winmessage_data msg_data = (winmessage_data){ window_hwnd, &fullscreen };
|
||||
if (wmi.subsystem != SDL_SYSWM_WINDOWS)
|
||||
opengl_fail();
|
||||
|
||||
SDL_SetWindowsMessageHook(winmessage_hook, &msg_data);
|
||||
window_hwnd = wmi.info.win.window;
|
||||
|
||||
if (!fullscreen)
|
||||
set_parent_binding(1);
|
||||
@@ -393,45 +434,69 @@ static void opengl_main(void* param)
|
||||
|
||||
SDL_GLContext context = SDL_GL_CreateContext(window);
|
||||
|
||||
gladLoadGLLoader(SDL_GL_GetProcAddress);
|
||||
if (context == NULL)
|
||||
opengl_fail();
|
||||
|
||||
SDL_GL_SetSwapInterval(options.vsync);
|
||||
|
||||
if (!gladLoadGLLoader(SDL_GL_GetProcAddress))
|
||||
{
|
||||
SDL_GL_DeleteContext(context);
|
||||
opengl_fail();
|
||||
}
|
||||
|
||||
gl_identifiers gl = initialize_glcontext();
|
||||
|
||||
if (gl.frame_count != -1)
|
||||
glUniform1i(gl.frame_count, 0);
|
||||
if (gl.output_size != -1)
|
||||
glUniform2f(gl.output_size, output_width, output_height);
|
||||
|
||||
uint32_t last_swap = -TARGET_FRAMETIME;
|
||||
uint32_t last_swap = plat_get_micro_ticks() - frametime;
|
||||
|
||||
/* Render loop */
|
||||
int closing = 0;
|
||||
while (!closing)
|
||||
{
|
||||
if (SYNC_WITH_BLITTER)
|
||||
/* Rendering is done right after handling an event. */
|
||||
if (frametime < 0)
|
||||
render_and_swap(gl);
|
||||
|
||||
DWORD wait_result = WAIT_TIMEOUT;
|
||||
|
||||
do
|
||||
{
|
||||
if (!SYNC_WITH_BLITTER)
|
||||
/* Rendering is timed by frame capping. */
|
||||
if (frametime >= 0)
|
||||
{
|
||||
uint32_t ticks = plat_get_ticks();
|
||||
if (ticks - last_swap > TARGET_FRAMETIME)
|
||||
uint32_t ticks = plat_get_micro_ticks();
|
||||
|
||||
uint32_t elapsed = ticks - last_swap;
|
||||
|
||||
if (elapsed + 1000 > frametime)
|
||||
{
|
||||
/* Spin the remaining time (< 1ms) to next frame */
|
||||
while (elapsed < frametime)
|
||||
{
|
||||
Sleep(0); /* Yield processor time */
|
||||
ticks = plat_get_micro_ticks();
|
||||
elapsed = ticks - last_swap;
|
||||
}
|
||||
|
||||
render_and_swap(gl);
|
||||
last_swap = ticks;
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Event event;
|
||||
|
||||
/* Handle SDL_Window events */
|
||||
while (SDL_PollEvent(&event)) { /* No need for actual handlers, but message queue must be processed. */ }
|
||||
|
||||
/* Keep cursor hidden in full screen and mouse capture */
|
||||
int show_cursor = !(fullscreen || !!mouse_capture);
|
||||
if (SDL_ShowCursor(-1) != show_cursor)
|
||||
SDL_ShowCursor(show_cursor);
|
||||
/* Handle window messages */
|
||||
MSG msg;
|
||||
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||||
{
|
||||
if (msg.hwnd == window_hwnd)
|
||||
handle_window_messages(msg.message, msg.wParam, msg.lParam, fullscreen);
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
/* Wait for synchronized events for 1ms before going back to window events */
|
||||
wait_result = WaitForMultipleObjects(sizeof(sync_objects) / sizeof(HANDLE), sync_objects.asArray, FALSE, 1);
|
||||
@@ -472,6 +537,8 @@ static void opengl_main(void* param)
|
||||
}
|
||||
else if (sync_event == sync_objects.resize)
|
||||
{
|
||||
thread_wait_mutex(resize_info.mutex);
|
||||
|
||||
if (fullscreen != resize_info.fullscreen)
|
||||
{
|
||||
fullscreen = resize_info.fullscreen;
|
||||
@@ -523,10 +590,13 @@ static void opengl_main(void* param)
|
||||
}
|
||||
}
|
||||
|
||||
glViewport(pad_x / 2, pad_y / 2, width - pad_x, height - pad_y);
|
||||
output_width = width - pad_x;
|
||||
output_height = height - pad_y;
|
||||
|
||||
glViewport(pad_x / 2, pad_y / 2, output_width, output_height);
|
||||
|
||||
if (gl.output_size != -1)
|
||||
glUniform2f(gl.output_size, width - pad_x, height - pad_y);
|
||||
glUniform2f(gl.output_size, output_width, output_height);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -535,12 +605,50 @@ static void opengl_main(void* param)
|
||||
/* SWP_NOZORDER is needed for child window and SDL doesn't enable it. */
|
||||
SetWindowPos(window_hwnd, parent, 0, 0, resize_info.width, resize_info.height, SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE);
|
||||
|
||||
output_width = resize_info.width;
|
||||
output_height = resize_info.height;
|
||||
|
||||
glViewport(0, 0, resize_info.width, resize_info.height);
|
||||
|
||||
if (gl.output_size != -1)
|
||||
glUniform2f(gl.output_size, resize_info.width, resize_info.height);
|
||||
}
|
||||
|
||||
thread_release_mutex(resize_info.mutex);
|
||||
}
|
||||
else if (sync_event == sync_objects.reload)
|
||||
{
|
||||
thread_wait_mutex(options.mutex);
|
||||
|
||||
frametime = options.frametime;
|
||||
|
||||
SDL_GL_SetSwapInterval(options.vsync);
|
||||
|
||||
if (options.shaderfile_changed)
|
||||
{
|
||||
/* Change shader program. */
|
||||
apply_shaders(&gl);
|
||||
|
||||
/* Uniforms need to be updated after proram change. */
|
||||
if (gl.input_size != -1)
|
||||
glUniform2f(gl.input_size, video_width, video_height);
|
||||
if (gl.output_size != -1)
|
||||
glUniform2f(gl.output_size, output_width, output_height);
|
||||
if (gl.texture_size != -1)
|
||||
glUniform2f(gl.texture_size, video_width, video_height);
|
||||
if (gl.frame_count != -1)
|
||||
glUniform1i(gl.frame_count, 0);
|
||||
|
||||
options.shaderfile_changed = 0;
|
||||
}
|
||||
|
||||
thread_release_mutex(options.mutex);
|
||||
}
|
||||
|
||||
/* Keep cursor hidden in full screen and mouse capture */
|
||||
int show_cursor = !(fullscreen || !!mouse_capture);
|
||||
if (SDL_ShowCursor(-1) != show_cursor)
|
||||
SDL_ShowCursor(show_cursor);
|
||||
}
|
||||
|
||||
finalize_glcontext(gl);
|
||||
@@ -549,8 +657,6 @@ static void opengl_main(void* param)
|
||||
|
||||
set_parent_binding(0);
|
||||
|
||||
SDL_SetWindowsMessageHook(NULL, NULL);
|
||||
|
||||
SDL_DestroyWindow(window);
|
||||
|
||||
window = NULL;
|
||||
@@ -577,8 +683,19 @@ static void opengl_blit(int x, int y, int y1, int y2, int w, int h)
|
||||
video_blit_complete();
|
||||
}
|
||||
|
||||
static int framerate_to_frametime(int framerate)
|
||||
{
|
||||
if (framerate < 0)
|
||||
return -1;
|
||||
|
||||
return (int)ceilf(1.e6f / (float)framerate);
|
||||
}
|
||||
|
||||
int opengl_init(HWND hwnd)
|
||||
{
|
||||
if (thread != NULL)
|
||||
return 0;
|
||||
|
||||
for (int i = 0; i < sizeof(sync_objects) / sizeof(HANDLE); i++)
|
||||
sync_objects.asArray[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
@@ -594,6 +711,12 @@ int opengl_init(HWND hwnd)
|
||||
resize_info.height = parent_size.bottom - parent_size.top;
|
||||
resize_info.fullscreen = video_fullscreen & 1;
|
||||
resize_info.scaling_mode = video_fullscreen_scale;
|
||||
resize_info.mutex = thread_create_mutex();
|
||||
|
||||
options.vsync = video_vsync;
|
||||
options.frametime = framerate_to_frametime(video_framerate);
|
||||
strcpy_s(options.shaderfile, sizeof(options.shaderfile), video_shader);
|
||||
options.mutex = thread_create_mutex();
|
||||
|
||||
thread = thread_create(opengl_main, (void*)NULL);
|
||||
|
||||
@@ -620,6 +743,9 @@ void opengl_close(void)
|
||||
|
||||
memset((void*)&blit_info, 0, sizeof(blit_info));
|
||||
|
||||
thread_close_mutex(resize_info.mutex);
|
||||
thread_close_mutex(options.mutex);
|
||||
|
||||
SetEvent(blit_done);
|
||||
|
||||
thread = NULL;
|
||||
@@ -640,9 +766,13 @@ void opengl_set_fs(int fs)
|
||||
if (thread == NULL)
|
||||
return;
|
||||
|
||||
thread_wait_mutex(resize_info.mutex);
|
||||
|
||||
resize_info.fullscreen = fs;
|
||||
resize_info.scaling_mode = video_fullscreen_scale;
|
||||
|
||||
thread_release_mutex(resize_info.mutex);
|
||||
|
||||
SetEvent(sync_objects.resize);
|
||||
}
|
||||
|
||||
@@ -651,9 +781,34 @@ void opengl_resize(int w, int h)
|
||||
if (thread == NULL)
|
||||
return;
|
||||
|
||||
thread_wait_mutex(resize_info.mutex);
|
||||
|
||||
resize_info.width = w;
|
||||
resize_info.height = h;
|
||||
resize_info.scaling_mode = video_fullscreen_scale;
|
||||
|
||||
thread_release_mutex(resize_info.mutex);
|
||||
|
||||
SetEvent(sync_objects.resize);
|
||||
}
|
||||
|
||||
void opengl_reload(void)
|
||||
{
|
||||
if (thread == NULL)
|
||||
return;
|
||||
|
||||
thread_wait_mutex(options.mutex);
|
||||
|
||||
options.vsync = video_vsync;
|
||||
options.frametime = framerate_to_frametime(video_framerate);
|
||||
|
||||
if (strcmp(video_shader, options.shaderfile) != 0)
|
||||
{
|
||||
strcpy_s(options.shaderfile, sizeof(options.shaderfile), video_shader);
|
||||
options.shaderfile_changed = 1;
|
||||
}
|
||||
|
||||
thread_release_mutex(options.mutex);
|
||||
|
||||
SetEvent(sync_objects.reload);
|
||||
}
|
@@ -69,13 +69,7 @@ void main() {\n\
|
||||
*/
|
||||
static char* read_file_to_string(const char* path)
|
||||
{
|
||||
char* full_path = (char*)malloc(sizeof(char) * (strlen(path) + strlen(exe_path) + 1));
|
||||
|
||||
plat_append_filename(full_path, exe_path, path);
|
||||
|
||||
FILE* file_handle = plat_fopen(full_path, "rb");
|
||||
|
||||
free(full_path);
|
||||
FILE* file_handle = plat_fopen(path, "rb");
|
||||
|
||||
if (file_handle != NULL)
|
||||
{
|
||||
@@ -107,13 +101,13 @@ static char* read_file_to_string(const char* path)
|
||||
* @brief Compile custom shaders into a program.
|
||||
* @return Shader program identifier.
|
||||
*/
|
||||
GLuint load_custom_shaders()
|
||||
GLuint load_custom_shaders(const char* path)
|
||||
{
|
||||
GLint status = GL_FALSE;
|
||||
int info_log_length;
|
||||
|
||||
/* TODO: get path from config */
|
||||
char* shader = read_file_to_string("shaders/shader.glsl");
|
||||
char* shader = read_file_to_string(path);
|
||||
|
||||
if (shader != NULL)
|
||||
{
|
||||
|
104
src/win/win_ui.c
104
src/win/win_ui.c
@@ -177,6 +177,71 @@ video_toggle_option(HMENU h, int *val, int id)
|
||||
device_force_redraw();
|
||||
}
|
||||
|
||||
/* Recursively finds and deletes target submenu */
|
||||
int delete_submenu(HMENU parent, HMENU target)
|
||||
{
|
||||
for (int i = 0; i < GetMenuItemCount(parent); i++)
|
||||
{
|
||||
MENUITEMINFO mii;
|
||||
mii.cbSize = sizeof(mii);
|
||||
mii.fMask = MIIM_SUBMENU;
|
||||
|
||||
if (GetMenuItemInfo(parent, i, TRUE, &mii) != 0)
|
||||
{
|
||||
if (mii.hSubMenu == target)
|
||||
{
|
||||
DeleteMenu(parent, i, MF_BYPOSITION);
|
||||
return 1;
|
||||
}
|
||||
else if (mii.hSubMenu != NULL)
|
||||
{
|
||||
if (delete_submenu(mii.hSubMenu, target))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
show_render_options_menu()
|
||||
{
|
||||
#ifdef DEV_BRANCH /* feature-opengl */
|
||||
static int menu_vidapi = -1;
|
||||
static HMENU cur_menu = NULL;
|
||||
|
||||
if (vid_api == menu_vidapi)
|
||||
return;
|
||||
|
||||
if (cur_menu != NULL)
|
||||
{
|
||||
if (delete_submenu(menuMain, cur_menu))
|
||||
cur_menu = NULL;
|
||||
}
|
||||
|
||||
if (cur_menu == NULL)
|
||||
{
|
||||
switch (IDM_VID_SDL_SW + vid_api)
|
||||
{
|
||||
case IDM_VID_OPENGL_CORE:
|
||||
cur_menu = LoadMenu(hinstance, VID_GL_SUBMENU);
|
||||
InsertMenu(GetSubMenu(menuMain, 1), 4, MF_BYPOSITION | MF_STRING | MF_POPUP, (UINT_PTR)cur_menu, plat_get_string(IDS_2144));
|
||||
CheckMenuItem(menuMain, IDM_VID_GL_FPS_BLITTER, video_framerate == -1 ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(menuMain, IDM_VID_GL_FPS_25, video_framerate == 25 ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(menuMain, IDM_VID_GL_FPS_30, video_framerate == 30 ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(menuMain, IDM_VID_GL_FPS_50, video_framerate == 50 ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(menuMain, IDM_VID_GL_FPS_60, video_framerate == 60 ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(menuMain, IDM_VID_GL_FPS_75, video_framerate == 75 ? MF_CHECKED : MF_UNCHECKED);
|
||||
CheckMenuItem(menuMain, IDM_VID_GL_VSYNC, video_vsync ? MF_CHECKED : MF_UNCHECKED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
menu_vidapi = vid_api;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ResetAllMenus(void)
|
||||
@@ -223,8 +288,9 @@ ResetAllMenus(void)
|
||||
CheckMenuItem(menuMain, IDM_VID_SDL_SW, MF_UNCHECKED);
|
||||
CheckMenuItem(menuMain, IDM_VID_SDL_HW, MF_UNCHECKED);
|
||||
CheckMenuItem(menuMain, IDM_VID_SDL_OPENGL, MF_UNCHECKED);
|
||||
#ifdef DEV_BRANCH
|
||||
#ifdef DEV_BRANCH /* feature-opengl */
|
||||
CheckMenuItem(menuMain, IDM_VID_OPENGL_CORE, MF_UNCHECKED);
|
||||
show_render_options_menu();
|
||||
#endif
|
||||
#ifdef USE_VNC
|
||||
CheckMenuItem(menuMain, IDM_VID_VNC, MF_UNCHECKED);
|
||||
@@ -672,7 +738,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
case IDM_VID_SDL_SW:
|
||||
case IDM_VID_SDL_HW:
|
||||
case IDM_VID_SDL_OPENGL:
|
||||
#ifdef DEV_BRANCH
|
||||
#ifdef DEV_BRANCH /* feature-opengl */
|
||||
case IDM_VID_OPENGL_CORE:
|
||||
#endif
|
||||
#ifdef USE_VNC
|
||||
@@ -682,8 +748,42 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
plat_setvid(LOWORD(wParam) - IDM_VID_SDL_SW);
|
||||
CheckMenuItem(hmenu, IDM_VID_SDL_SW + vid_api, MF_CHECKED);
|
||||
config_save();
|
||||
show_render_options_menu();
|
||||
break;
|
||||
|
||||
#ifdef DEV_BRANCH /* feature-opengl */
|
||||
case IDM_VID_GL_FPS_BLITTER:
|
||||
case IDM_VID_GL_FPS_25:
|
||||
case IDM_VID_GL_FPS_30:
|
||||
case IDM_VID_GL_FPS_50:
|
||||
case IDM_VID_GL_FPS_60:
|
||||
case IDM_VID_GL_FPS_75:
|
||||
{
|
||||
static const int fps[] = { -1, 25, 30, 50, 60, 75 };
|
||||
int idx = 0;
|
||||
for (; fps[idx] != video_framerate; idx++);
|
||||
CheckMenuItem(hmenu, IDM_VID_GL_FPS_BLITTER + idx, MF_UNCHECKED);
|
||||
video_framerate = fps[LOWORD(wParam) - IDM_VID_GL_FPS_BLITTER];
|
||||
CheckMenuItem(hmenu, LOWORD(wParam), MF_CHECKED);
|
||||
plat_vid_reload_options();
|
||||
config_save();
|
||||
break;
|
||||
}
|
||||
case IDM_VID_GL_VSYNC:
|
||||
video_vsync = !video_vsync;
|
||||
CheckMenuItem(hmenu, IDM_VID_GL_VSYNC, video_vsync ? MF_CHECKED : MF_UNCHECKED);
|
||||
plat_vid_reload_options();
|
||||
config_save();
|
||||
break;
|
||||
case IDM_VID_GL_SHADER:
|
||||
win_notify_dlg_open();
|
||||
if (file_dlg_st(hwnd, IDS_2143, video_shader, NULL, 0) == 0)
|
||||
strcpy_s(video_shader, sizeof(video_shader), openfilestring);
|
||||
win_notify_dlg_closed();
|
||||
plat_vid_reload_options();
|
||||
break;
|
||||
#endif
|
||||
|
||||
case IDM_VID_FULLSCREEN:
|
||||
plat_setfullscreen(1);
|
||||
config_save();
|
||||
|
Reference in New Issue
Block a user