2021-04-10 01:35:17 +03:00
|
|
|
/*
|
|
|
|
|
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
|
|
|
|
* running old operating systems and software designed for IBM
|
|
|
|
|
* PC systems and compatibles from 1981 through fairly recent
|
|
|
|
|
* system designs based on the PCI bus.
|
|
|
|
|
*
|
|
|
|
|
* This file is part of the 86Box distribution.
|
|
|
|
|
*
|
|
|
|
|
* Rendering module for OpenGL
|
|
|
|
|
*
|
|
|
|
|
* NOTE: This is very much still a work-in-progress.
|
|
|
|
|
* Expect missing functionality, hangs and bugs.
|
|
|
|
|
*
|
2021-04-12 17:01:58 +03:00
|
|
|
* TODO: Full screen stretch options
|
2021-04-10 17:41:51 +03:00
|
|
|
* Loader for glsl files.
|
|
|
|
|
* libretro has a sizeable library that could
|
|
|
|
|
* be a good target for compatibility.
|
|
|
|
|
* (UI) options
|
|
|
|
|
* ...
|
|
|
|
|
*
|
2021-04-10 01:35:17 +03:00
|
|
|
* Authors: Teemu Korhonen
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2021 Teemu Korhonen
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define UNICODE
|
|
|
|
|
#include <Windows.h>
|
|
|
|
|
#include <SDL2/SDL.h>
|
|
|
|
|
#include <SDL2/SDL_syswm.h>
|
|
|
|
|
#include <glad/glad.h>
|
|
|
|
|
|
|
|
|
|
#include <stdatomic.h>
|
|
|
|
|
|
|
|
|
|
#include <86box/plat.h>
|
|
|
|
|
#include <86box/video.h>
|
2021-04-12 17:01:58 +03:00
|
|
|
#include <86box/win.h>
|
2021-04-10 01:35:17 +03:00
|
|
|
#include <86box/win_opengl.h>
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/**
|
|
|
|
|
* @brief A dedicated OpenGL thread.
|
|
|
|
|
* OpenGL context's don't handle multiple threads well.
|
|
|
|
|
*/
|
2021-04-10 01:35:17 +03:00
|
|
|
static thread_t* thread = NULL;
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/**
|
|
|
|
|
* @brief A window usable with an OpenGL context
|
|
|
|
|
*/
|
2021-04-10 01:35:17 +03:00
|
|
|
static SDL_Window* window = NULL;
|
2021-04-10 17:41:51 +03:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Window info to modify window style.
|
|
|
|
|
*/
|
2021-04-10 01:35:17 +03:00
|
|
|
static SDL_SysWMinfo wmi = {};
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/**
|
|
|
|
|
* @brief Parent window (hwndRender from win_ui)
|
|
|
|
|
*/
|
2021-04-10 01:35:17 +03:00
|
|
|
static HWND parent = NULL;
|
2021-04-10 17:41:51 +03:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Events listened in OpenGL thread.
|
|
|
|
|
*/
|
2021-04-10 01:35:17 +03:00
|
|
|
static union
|
|
|
|
|
{
|
|
|
|
|
struct
|
|
|
|
|
{
|
|
|
|
|
HANDLE closing;
|
|
|
|
|
HANDLE resize;
|
|
|
|
|
HANDLE blit_waiting;
|
|
|
|
|
};
|
|
|
|
|
HANDLE asArray[3];
|
|
|
|
|
} sync_objects = {};
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/**
|
|
|
|
|
* @brief Signal from OpenGL thread that it's done with video buffer.
|
|
|
|
|
*/
|
2021-04-10 01:35:17 +03:00
|
|
|
static HANDLE blit_done = NULL;
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/**
|
|
|
|
|
* @brief Blit event parameters.
|
|
|
|
|
*/
|
2021-04-10 01:35:17 +03:00
|
|
|
static volatile struct
|
|
|
|
|
{
|
|
|
|
|
int x, y, y1, y2, w, h, resized;
|
|
|
|
|
} blit_info = {};
|
|
|
|
|
|
2021-04-11 22:29:00 +03:00
|
|
|
/**
|
|
|
|
|
* @brief Resize event parameters.
|
|
|
|
|
*/
|
|
|
|
|
static volatile struct
|
|
|
|
|
{
|
2021-04-12 17:01:58 +03:00
|
|
|
int width, height, fullscreen;
|
2021-04-11 22:29:00 +03:00
|
|
|
} resize_info = {};
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/**
|
|
|
|
|
* @brief Identifiers to OpenGL object used.
|
|
|
|
|
*/
|
2021-04-10 01:35:17 +03:00
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
GLuint vertexArrayID;
|
|
|
|
|
GLuint vertexBufferID;
|
|
|
|
|
GLuint textureID;
|
|
|
|
|
GLuint shader_progID;
|
|
|
|
|
} gl_objects;
|
|
|
|
|
|
2021-04-12 17:01:58 +03:00
|
|
|
/**
|
|
|
|
|
* @brief Userdata to pass onto windows message hook
|
|
|
|
|
*/
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
HWND window;
|
|
|
|
|
int* fullscreen;
|
|
|
|
|
} winmessage_data;
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/**
|
|
|
|
|
* @brief Default vertex shader.
|
|
|
|
|
*/
|
2021-04-10 01:35:17 +03:00
|
|
|
static const GLchar* v_shader = "#version 330 core\n\
|
|
|
|
|
layout(location = 0) in vec2 pos;\n\
|
|
|
|
|
layout(location = 1) in vec2 tex_in;\n\
|
|
|
|
|
out vec2 tex;\n\
|
|
|
|
|
void main(){\n\
|
|
|
|
|
gl_Position = vec4(pos, 0.0, 1.0);\n\
|
|
|
|
|
tex = tex_in;\n\
|
|
|
|
|
}\n";
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/**
|
|
|
|
|
* @brief Default fragment shader.
|
|
|
|
|
*
|
|
|
|
|
* Note: Last two lines in main make it a very simple 50% scanline filter.
|
|
|
|
|
*/
|
2021-04-10 01:35:17 +03:00
|
|
|
static const GLchar* f_shader = "#version 330 core\n\
|
|
|
|
|
in vec2 tex;\n\
|
|
|
|
|
out vec4 color;\n\
|
|
|
|
|
uniform sampler2D texs;\n\
|
|
|
|
|
void main() {\n\
|
|
|
|
|
color = texture(texs, tex);\n\
|
|
|
|
|
if (int(gl_FragCoord.y) % 2 == 0)\n\
|
|
|
|
|
color = color * vec4(0.5,0.5,0.5,1.0);\n\
|
|
|
|
|
}\n";
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/**
|
|
|
|
|
* @brief Load and compile default shaders into a program.
|
|
|
|
|
* @return Shader program identifier.
|
|
|
|
|
*/
|
2021-04-12 00:53:24 +03:00
|
|
|
static GLuint load_shaders()
|
2021-04-10 01:35:17 +03:00
|
|
|
{
|
|
|
|
|
GLuint vs_id = glCreateShader(GL_VERTEX_SHADER);
|
|
|
|
|
GLuint fs_id = glCreateShader(GL_FRAGMENT_SHADER);
|
|
|
|
|
|
|
|
|
|
GLint compile_status = GL_FALSE;
|
|
|
|
|
int info_log_length;
|
|
|
|
|
char info_log_text[200];
|
|
|
|
|
|
|
|
|
|
glShaderSource(vs_id, 1, &v_shader, NULL);
|
|
|
|
|
glCompileShader(vs_id);
|
|
|
|
|
|
|
|
|
|
glGetShaderiv(vs_id, GL_COMPILE_STATUS, &compile_status);
|
|
|
|
|
glGetShaderiv(vs_id, GL_INFO_LOG_LENGTH, &info_log_length);
|
|
|
|
|
|
|
|
|
|
glGetShaderInfoLog(vs_id, info_log_length, NULL, info_log_text);
|
|
|
|
|
|
|
|
|
|
glShaderSource(fs_id, 1, &f_shader, NULL);
|
|
|
|
|
glCompileShader(fs_id);
|
|
|
|
|
|
|
|
|
|
glGetShaderiv(fs_id, GL_COMPILE_STATUS, &compile_status);
|
|
|
|
|
glGetShaderiv(fs_id, GL_INFO_LOG_LENGTH, &info_log_length);
|
|
|
|
|
|
|
|
|
|
glGetShaderInfoLog(fs_id, info_log_length, NULL, info_log_text);
|
|
|
|
|
|
|
|
|
|
GLuint prog_id = glCreateProgram();
|
|
|
|
|
|
|
|
|
|
glAttachShader(prog_id, vs_id);
|
|
|
|
|
glAttachShader(prog_id, fs_id);
|
|
|
|
|
|
|
|
|
|
glLinkProgram(prog_id);
|
|
|
|
|
|
|
|
|
|
glDetachShader(prog_id, vs_id);
|
|
|
|
|
glDetachShader(prog_id, fs_id);
|
|
|
|
|
|
|
|
|
|
glDeleteShader(vs_id);
|
|
|
|
|
glDeleteShader(fs_id);
|
|
|
|
|
|
|
|
|
|
return prog_id;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/**
|
|
|
|
|
* @brief Set or unset OpenGL context window as a child window.
|
|
|
|
|
*
|
2021-04-11 22:29:00 +03:00
|
|
|
* Modifies the window style and sets the parent window.
|
|
|
|
|
* WS_EX_NOACTIVATE keeps the window from stealing input focus.
|
2021-04-10 17:41:51 +03:00
|
|
|
*/
|
2021-04-12 00:53:24 +03:00
|
|
|
static void set_parent_binding(int enable)
|
2021-04-10 01:35:17 +03:00
|
|
|
{
|
|
|
|
|
if (wmi.subsystem != SDL_SYSWM_WINDOWS)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
long style = GetWindowLong(wmi.info.win.window, GWL_STYLE);
|
2021-04-11 22:29:00 +03:00
|
|
|
long ex_style = GetWindowLong(wmi.info.win.window, GWL_EXSTYLE);
|
|
|
|
|
|
2021-04-10 01:35:17 +03:00
|
|
|
if (enable)
|
2021-04-11 22:29:00 +03:00
|
|
|
{
|
2021-04-10 01:35:17 +03:00
|
|
|
style |= WS_CHILD;
|
2021-04-11 22:29:00 +03:00
|
|
|
ex_style |= WS_EX_NOACTIVATE;
|
|
|
|
|
}
|
2021-04-10 01:35:17 +03:00
|
|
|
else
|
2021-04-11 22:29:00 +03:00
|
|
|
{
|
2021-04-10 01:35:17 +03:00
|
|
|
style &= ~WS_CHILD;
|
2021-04-11 22:29:00 +03:00
|
|
|
ex_style &= ~WS_EX_NOACTIVATE;
|
|
|
|
|
}
|
2021-04-10 01:35:17 +03:00
|
|
|
|
|
|
|
|
SetWindowLong(wmi.info.win.window, GWL_STYLE, style);
|
2021-04-11 22:29:00 +03:00
|
|
|
SetWindowLong(wmi.info.win.window, GWL_EXSTYLE, ex_style);
|
2021-04-10 01:35:17 +03:00
|
|
|
|
|
|
|
|
SetParent(wmi.info.win.window, enable ? parent : NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-12 00:53:24 +03:00
|
|
|
/**
|
|
|
|
|
* @brief Windows message handler for SDL Windows.
|
2021-04-12 17:01:58 +03:00
|
|
|
* @param userdata winmessage_data
|
2021-04-12 00:53:24 +03:00
|
|
|
* @param hWnd
|
|
|
|
|
* @param message
|
|
|
|
|
* @param wParam
|
|
|
|
|
* @param lParam
|
|
|
|
|
*/
|
|
|
|
|
static void winmessage_hook(void* userdata, void* hWnd, unsigned int message, Uint64 wParam, Sint64 lParam)
|
|
|
|
|
{
|
2021-04-12 17:01:58 +03:00
|
|
|
winmessage_data* msg_data = (winmessage_data*)userdata;
|
|
|
|
|
|
2021-04-12 00:53:24 +03:00
|
|
|
/* Process only our window */
|
2021-04-12 17:01:58 +03:00
|
|
|
if (msg_data->window != hWnd || parent == NULL)
|
2021-04-12 00:53:24 +03:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
switch (message)
|
|
|
|
|
{
|
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
|
case WM_MBUTTONUP:
|
|
|
|
|
/* Mouse events that enter and exit capture. */
|
|
|
|
|
PostMessage(parent, message, wParam, lParam);
|
|
|
|
|
break;
|
|
|
|
|
case WM_INPUT:
|
2021-04-12 17:01:58 +03:00
|
|
|
if (*msg_data->fullscreen)
|
|
|
|
|
{
|
|
|
|
|
/* Raw input handler from win_ui.c : input_proc */
|
|
|
|
|
|
|
|
|
|
UINT size = 0;
|
|
|
|
|
PRAWINPUT raw = NULL;
|
|
|
|
|
|
|
|
|
|
/* Here we read the raw input data */
|
|
|
|
|
GetRawInputData((HRAWINPUT)(LPARAM)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
|
|
|
|
|
raw = (PRAWINPUT)malloc(size);
|
|
|
|
|
if (GetRawInputData((HRAWINPUT)(LPARAM)lParam, RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)) == size) {
|
|
|
|
|
switch (raw->header.dwType)
|
|
|
|
|
{
|
|
|
|
|
case RIM_TYPEKEYBOARD:
|
|
|
|
|
keyboard_handle(raw);
|
|
|
|
|
break;
|
|
|
|
|
case RIM_TYPEMOUSE:
|
|
|
|
|
win_mouse_handle(raw);
|
|
|
|
|
break;
|
|
|
|
|
case RIM_TYPEHID:
|
|
|
|
|
win_joystick_handle(raw);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
free(raw);
|
|
|
|
|
}
|
2021-04-12 00:53:24 +03:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/**
|
|
|
|
|
* @brief Initialize OpenGL context
|
|
|
|
|
* @return Object identifiers
|
|
|
|
|
*/
|
2021-04-10 01:35:17 +03:00
|
|
|
static gl_objects initialize_glcontext()
|
|
|
|
|
{
|
2021-04-10 17:41:51 +03:00
|
|
|
/* Vertex and texture 2d coordinates making a quad as triangle strip */
|
2021-04-10 01:35:17 +03:00
|
|
|
static const GLfloat surface[] = {
|
|
|
|
|
-1.f, 1.f, 0.f, 0.f,
|
|
|
|
|
1.f, 1.f, 1.f, 0.f,
|
|
|
|
|
-1.f, -1.f, 0.f, 1.f,
|
|
|
|
|
1.f, -1.f, 1.f, 1.f
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
gl_objects obj = {};
|
|
|
|
|
|
|
|
|
|
glGenVertexArrays(1, &obj.vertexArrayID);
|
|
|
|
|
|
|
|
|
|
glBindVertexArray(obj.vertexArrayID);
|
|
|
|
|
|
|
|
|
|
glGenBuffers(1, &obj.vertexBufferID);
|
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, obj.vertexBufferID);
|
|
|
|
|
glBufferData(GL_ARRAY_BUFFER, sizeof(surface), surface, GL_STATIC_DRAW);
|
|
|
|
|
|
|
|
|
|
glGenTextures(1, &obj.textureID);
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, obj.textureID);
|
|
|
|
|
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
2021-04-10 17:41:51 +03:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
2021-04-10 01:35:17 +03:00
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
|
|
|
|
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 640, 400, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
|
|
|
|
|
|
|
|
|
|
glClearColor(0.f, 0.f, 0.f, 1.f);
|
|
|
|
|
|
2021-04-12 00:53:24 +03:00
|
|
|
obj.shader_progID = load_shaders();
|
2021-04-10 01:35:17 +03:00
|
|
|
|
|
|
|
|
glUseProgram(obj.shader_progID);
|
|
|
|
|
|
|
|
|
|
glEnableVertexAttribArray(0);
|
|
|
|
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), 0);
|
|
|
|
|
|
|
|
|
|
glEnableVertexAttribArray(1);
|
|
|
|
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (void*)(2 * sizeof(GLfloat)));
|
|
|
|
|
|
|
|
|
|
return obj;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/**
|
2021-04-12 17:01:58 +03:00
|
|
|
* @brief Clean up OpenGL context
|
2021-04-10 17:41:51 +03:00
|
|
|
* @param Object identifiers from initialize
|
|
|
|
|
*/
|
2021-04-10 01:35:17 +03:00
|
|
|
static void finalize_glcontext(gl_objects obj)
|
|
|
|
|
{
|
|
|
|
|
glDeleteProgram(obj.shader_progID);
|
|
|
|
|
glDeleteTextures(1, &obj.textureID);
|
|
|
|
|
glDeleteBuffers(1, &obj.vertexBufferID);
|
|
|
|
|
glDeleteVertexArrays(1, &obj.vertexArrayID);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/**
|
|
|
|
|
* @brief Main OpenGL thread proc.
|
|
|
|
|
*
|
|
|
|
|
* OpenGL context should be accessed only from this single thread.
|
|
|
|
|
* Events are used to synchronize communication.
|
|
|
|
|
*/
|
2021-04-10 01:35:17 +03:00
|
|
|
static void opengl_main()
|
|
|
|
|
{
|
2021-04-11 22:29:00 +03:00
|
|
|
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); /* Is this actually doing anything...? */
|
2021-04-10 01:35:17 +03:00
|
|
|
|
2021-04-11 22:29:00 +03:00
|
|
|
window = SDL_CreateWindow("86Box OpenGL Renderer", 0, 0, resize_info.width, resize_info.height, SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS);
|
2021-04-12 00:53:24 +03:00
|
|
|
|
2021-04-12 17:01:58 +03:00
|
|
|
/* Keeps track of full screen, but only changed in this thread. */
|
|
|
|
|
int fullscreen = resize_info.fullscreen;
|
|
|
|
|
|
2021-04-10 01:35:17 +03:00
|
|
|
SDL_VERSION(&wmi.version);
|
|
|
|
|
SDL_GetWindowWMInfo(window, &wmi);
|
|
|
|
|
|
2021-04-12 17:01:58 +03:00
|
|
|
/* Pass window handle and full screen mode to windows message hook */
|
|
|
|
|
winmessage_data msg_data = (winmessage_data){ wmi.info.win.window, &fullscreen };
|
|
|
|
|
|
2021-04-12 00:53:24 +03:00
|
|
|
if (wmi.subsystem == SDL_SYSWM_WINDOWS)
|
2021-04-12 17:01:58 +03:00
|
|
|
SDL_SetWindowsMessageHook(winmessage_hook, &msg_data);
|
2021-04-12 00:53:24 +03:00
|
|
|
|
2021-04-12 17:01:58 +03:00
|
|
|
if (!fullscreen)
|
|
|
|
|
set_parent_binding(1);
|
|
|
|
|
else
|
|
|
|
|
SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
|
2021-04-10 01:35:17 +03:00
|
|
|
|
|
|
|
|
SDL_GLContext context = SDL_GL_CreateContext(window);
|
|
|
|
|
|
|
|
|
|
gladLoadGLLoader(SDL_GL_GetProcAddress);
|
|
|
|
|
|
|
|
|
|
gl_objects obj = initialize_glcontext();
|
|
|
|
|
|
|
|
|
|
/* Render loop */
|
|
|
|
|
int closing = 0;
|
|
|
|
|
while (!closing)
|
|
|
|
|
{
|
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|
|
|
|
SDL_GL_SwapWindow(window);
|
|
|
|
|
|
|
|
|
|
DWORD wait_result = WAIT_TIMEOUT;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
SDL_Event event;
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/* Handle SDL_Window events */
|
2021-04-12 00:53:24 +03:00
|
|
|
while (SDL_PollEvent(&event)) { /* No need for actual handlers, but message queue must be processed. */ }
|
|
|
|
|
|
2021-04-12 17:01:58 +03:00
|
|
|
if (!fullscreen && SDL_ShowCursor(-1) == !!mouse_capture)
|
2021-04-12 00:53:24 +03:00
|
|
|
SDL_ShowCursor(!mouse_capture);
|
2021-04-10 01:35:17 +03:00
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/* Wait for synchronized events for 1ms before going back to window events */
|
2021-04-10 01:35:17 +03:00
|
|
|
wait_result = WaitForMultipleObjects(sizeof(sync_objects) / sizeof(HANDLE), sync_objects.asArray, FALSE, 1);
|
|
|
|
|
|
|
|
|
|
} while (wait_result == WAIT_TIMEOUT);
|
|
|
|
|
|
|
|
|
|
HANDLE sync_event = sync_objects.asArray[wait_result - WAIT_OBJECT_0];
|
|
|
|
|
|
|
|
|
|
if (sync_event == sync_objects.closing)
|
|
|
|
|
{
|
|
|
|
|
closing = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (sync_event == sync_objects.blit_waiting)
|
|
|
|
|
{
|
2021-04-10 17:41:51 +03:00
|
|
|
/* Resize the texture if */
|
2021-04-10 01:35:17 +03:00
|
|
|
if (blit_info.resized)
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, blit_info.w, blit_info.h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/* Transfer video buffer to texture */
|
2021-04-10 01:35:17 +03:00
|
|
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, blit_info.y1, blit_info.w, blit_info.y2 - blit_info.y1, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &(render_buffer->dat)[blit_info.y1 * blit_info.w]);
|
|
|
|
|
|
2021-04-10 17:41:51 +03:00
|
|
|
/* Signal that we're done with the video buffer */
|
2021-04-10 01:35:17 +03:00
|
|
|
SetEvent(blit_done);
|
|
|
|
|
}
|
|
|
|
|
else if (sync_event == sync_objects.resize)
|
|
|
|
|
{
|
2021-04-12 17:01:58 +03:00
|
|
|
if (fullscreen != resize_info.fullscreen)
|
|
|
|
|
{
|
|
|
|
|
fullscreen = resize_info.fullscreen;
|
|
|
|
|
|
|
|
|
|
set_parent_binding(!fullscreen);
|
|
|
|
|
|
|
|
|
|
SDL_SetWindowFullscreen(window, fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
|
|
|
|
|
|
|
|
|
if (fullscreen)
|
|
|
|
|
SDL_RaiseWindow(window);
|
|
|
|
|
|
|
|
|
|
SDL_ShowCursor(!fullscreen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fullscreen)
|
|
|
|
|
{
|
|
|
|
|
int width, height;
|
|
|
|
|
|
|
|
|
|
SDL_GetWindowSize(window, &width, &height);
|
|
|
|
|
|
|
|
|
|
glViewport(0, 0, width, height);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
SDL_SetWindowSize(window, resize_info.width, resize_info.height);
|
|
|
|
|
|
|
|
|
|
/* SWP_NOZORDER is needed for child window and SDL doesn't enable it. */
|
|
|
|
|
SetWindowPos(wmi.info.win.window, parent, 0, 0, resize_info.width, resize_info.height, SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOMOVE | SWP_NOACTIVATE);
|
|
|
|
|
|
|
|
|
|
glViewport(0, 0, resize_info.width, resize_info.height);
|
|
|
|
|
}
|
2021-04-10 01:35:17 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
finalize_glcontext(obj);
|
|
|
|
|
|
|
|
|
|
SDL_GL_DeleteContext(context);
|
|
|
|
|
|
2021-04-12 00:53:24 +03:00
|
|
|
set_parent_binding(0);
|
|
|
|
|
|
|
|
|
|
SDL_SetWindowsMessageHook(NULL, NULL);
|
2021-04-10 01:35:17 +03:00
|
|
|
|
|
|
|
|
SDL_DestroyWindow(window);
|
|
|
|
|
|
|
|
|
|
window = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-12 00:53:24 +03:00
|
|
|
static void opengl_blit(int x, int y, int y1, int y2, int w, int h)
|
2021-04-10 01:35:17 +03:00
|
|
|
{
|
|
|
|
|
if (y1 == y2 || h <= 0 || render_buffer == NULL)
|
|
|
|
|
{
|
|
|
|
|
video_blit_complete();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
blit_info.resized = (w != blit_info.w || h != blit_info.h);
|
|
|
|
|
blit_info.x = x;
|
|
|
|
|
blit_info.y = y;
|
|
|
|
|
blit_info.y1 = y1;
|
|
|
|
|
blit_info.y2 = y2;
|
|
|
|
|
blit_info.w = w;
|
|
|
|
|
blit_info.h = h;
|
|
|
|
|
|
|
|
|
|
SignalObjectAndWait(sync_objects.blit_waiting, blit_done, INFINITE, FALSE);
|
|
|
|
|
|
|
|
|
|
video_blit_complete();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int opengl_init(HWND hwnd)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < sizeof(sync_objects) / sizeof(HANDLE); i++)
|
|
|
|
|
sync_objects.asArray[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
|
|
|
|
|
|
blit_done = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
|
|
|
|
|
|
parent = hwnd;
|
2021-04-11 22:29:00 +03:00
|
|
|
|
|
|
|
|
RECT parent_size;
|
|
|
|
|
|
|
|
|
|
GetWindowRect(parent, &parent_size);
|
|
|
|
|
|
|
|
|
|
resize_info.width = parent_size.right - parent_size.left;
|
|
|
|
|
resize_info.height = parent_size.bottom - parent_size.top;
|
2021-04-12 17:01:58 +03:00
|
|
|
resize_info.fullscreen = video_fullscreen & 1;
|
2021-04-10 01:35:17 +03:00
|
|
|
|
|
|
|
|
thread = thread_create(opengl_main, (void*)NULL);
|
|
|
|
|
|
|
|
|
|
atexit(opengl_close);
|
|
|
|
|
|
|
|
|
|
video_setblit(opengl_blit);
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int opengl_pause()
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void opengl_close()
|
|
|
|
|
{
|
|
|
|
|
if (thread == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
SetEvent(sync_objects.closing);
|
|
|
|
|
|
|
|
|
|
thread_wait(thread, -1);
|
|
|
|
|
|
|
|
|
|
memset((void*)&blit_info, 0, sizeof(blit_info));
|
|
|
|
|
|
|
|
|
|
SetEvent(blit_done);
|
|
|
|
|
|
|
|
|
|
thread = NULL;
|
|
|
|
|
|
|
|
|
|
CloseHandle(blit_done);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < sizeof(sync_objects) / sizeof(HANDLE); i++)
|
|
|
|
|
{
|
|
|
|
|
CloseHandle(sync_objects.asArray[i]);
|
|
|
|
|
sync_objects.asArray[i] = (HANDLE)NULL;
|
|
|
|
|
}
|
2021-04-11 22:29:00 +03:00
|
|
|
|
|
|
|
|
parent = NULL;
|
2021-04-10 01:35:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void opengl_set_fs(int fs)
|
|
|
|
|
{
|
2021-04-12 17:01:58 +03:00
|
|
|
if (thread == NULL)
|
|
|
|
|
return;
|
2021-04-10 01:35:17 +03:00
|
|
|
|
2021-04-12 17:01:58 +03:00
|
|
|
resize_info.fullscreen = fs;
|
|
|
|
|
|
|
|
|
|
SetEvent(sync_objects.resize);
|
2021-04-10 01:35:17 +03:00
|
|
|
}
|
|
|
|
|
|
2021-04-11 22:29:00 +03:00
|
|
|
void opengl_resize(int w, int h)
|
2021-04-10 01:35:17 +03:00
|
|
|
{
|
2021-04-12 00:53:24 +03:00
|
|
|
if (thread == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
2021-04-11 22:29:00 +03:00
|
|
|
resize_info.width = w;
|
|
|
|
|
resize_info.height = h;
|
2021-04-10 01:35:17 +03:00
|
|
|
|
2021-04-11 22:29:00 +03:00
|
|
|
SetEvent(sync_objects.resize);
|
2021-04-10 01:35:17 +03:00
|
|
|
}
|