2023-09-07 12:51:48 +00:00
|
|
|
/*************************************************************************
|
2023-03-05 15:05:43 +00:00
|
|
|
*
|
2023-09-07 12:51:48 +00:00
|
|
|
* Orca
|
|
|
|
* Copyright 2023 Martin Fouilleul and the Orca project contributors
|
|
|
|
* See LICENSE.txt for licensing information
|
2023-03-05 15:05:43 +00:00
|
|
|
*
|
2023-09-07 12:51:48 +00:00
|
|
|
**************************************************************************/
|
2023-08-19 12:49:23 +00:00
|
|
|
#include "app/win32_app.h"
|
|
|
|
#include "gl_loader.h"
|
|
|
|
#include "graphics_surface.h"
|
2023-03-05 15:05:43 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
#include "util/macros.h"
|
|
|
|
#include <GL/wglext.h>
|
2023-03-05 15:05:43 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
#define OC_WGL_PROC_LIST \
|
|
|
|
OC_WGL_PROC(WGLCHOOSEPIXELFORMATARB, wglChoosePixelFormatARB) \
|
|
|
|
OC_WGL_PROC(WGLCREATECONTEXTATTRIBSARB, wglCreateContextAttribsARB) \
|
|
|
|
OC_WGL_PROC(WGLMAKECONTEXTCURRENTARB, wglMakeContextCurrentARB) \
|
|
|
|
OC_WGL_PROC(WGLSWAPINTERVALEXT, wglSwapIntervalEXT)
|
2023-03-05 15:05:43 +00:00
|
|
|
|
|
|
|
//NOTE: wgl function pointers declarations
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
#define OC_WGL_PROC(type, name) OC_CAT3(PFN, type, PROC) name = 0;
|
2023-08-19 12:49:23 +00:00
|
|
|
OC_WGL_PROC_LIST
|
2023-08-14 08:26:11 +00:00
|
|
|
#undef OC_WGL_PROC
|
2023-03-05 15:05:43 +00:00
|
|
|
|
|
|
|
//NOTE: wgl loader
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
typedef struct oc_wgl_dummy_context
|
2023-03-05 15:05:43 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
bool init;
|
|
|
|
HWND hWnd;
|
|
|
|
HDC hDC;
|
|
|
|
HGLRC glContext;
|
2023-03-05 15:05:43 +00:00
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
} oc_wgl_dummy_context;
|
2023-03-05 15:05:43 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
static oc_wgl_dummy_context oc_wglDummyContext = { 0 };
|
2023-03-05 15:05:43 +00:00
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
static void oc_wgl_init()
|
2023-03-05 15:05:43 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
if(!oc_wglDummyContext.init)
|
|
|
|
{
|
|
|
|
//NOTE: create a dummy window
|
|
|
|
WNDCLASS windowClass = { .style = CS_OWNDC,
|
|
|
|
.lpfnWndProc = DefWindowProc,
|
|
|
|
.hInstance = GetModuleHandleW(NULL),
|
|
|
|
.lpszClassName = "oc_wgl_helper_window_class",
|
|
|
|
.hCursor = LoadCursor(0, IDC_ARROW) };
|
|
|
|
|
|
|
|
if(!RegisterClass(&windowClass))
|
|
|
|
{
|
|
|
|
//TODO: error
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
oc_wglDummyContext.hWnd = CreateWindow("oc_wgl_helper_window_class",
|
|
|
|
"dummy",
|
|
|
|
WS_OVERLAPPEDWINDOW,
|
|
|
|
0, 0, 100, 100,
|
|
|
|
0, 0, windowClass.hInstance, 0);
|
|
|
|
|
|
|
|
if(!oc_wglDummyContext.hWnd)
|
|
|
|
{
|
|
|
|
//TODO: error
|
|
|
|
goto quit;
|
|
|
|
}
|
|
|
|
oc_wglDummyContext.hDC = GetDC(oc_wglDummyContext.hWnd);
|
|
|
|
|
|
|
|
PIXELFORMATDESCRIPTOR pixelFormatDesc = {
|
|
|
|
sizeof(PIXELFORMATDESCRIPTOR),
|
|
|
|
1,
|
|
|
|
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, // Flags
|
|
|
|
PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette.
|
|
|
|
32, // Colordepth of the framebuffer.
|
|
|
|
0, 0, 0, 0, 0, 0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0, 0, 0, 0,
|
|
|
|
24, // Number of bits for the depthbuffer
|
|
|
|
8, // Number of bits for the stencilbuffer
|
|
|
|
0, // Number of Aux buffers in the framebuffer.
|
|
|
|
PFD_MAIN_PLANE,
|
|
|
|
0,
|
|
|
|
0, 0, 0
|
|
|
|
};
|
|
|
|
|
|
|
|
int pixelFormat = ChoosePixelFormat(oc_wglDummyContext.hDC, &pixelFormatDesc);
|
|
|
|
SetPixelFormat(oc_wglDummyContext.hDC, pixelFormat, &pixelFormatDesc);
|
|
|
|
|
|
|
|
oc_wglDummyContext.glContext = wglCreateContext(oc_wglDummyContext.hDC);
|
|
|
|
wglMakeCurrent(oc_wglDummyContext.hDC, oc_wglDummyContext.glContext);
|
|
|
|
|
|
|
|
//NOTE(martin): now load WGL extension functions
|
|
|
|
#define OC_WGL_PROC(type, name) name = (OC_CAT3(PFN, type, PROC))wglGetProcAddress(#name);
|
|
|
|
OC_WGL_PROC_LIST
|
|
|
|
#undef OC_WGL_PROC
|
|
|
|
|
|
|
|
oc_wglDummyContext.init = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wglMakeCurrent(oc_wglDummyContext.hDC, oc_wglDummyContext.glContext);
|
|
|
|
}
|
|
|
|
quit:;
|
2023-03-05 15:05:43 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
#undef OC_WGL_PROC_LIST
|
2023-03-05 15:05:43 +00:00
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
typedef struct oc_wgl_surface
|
2023-03-05 15:05:43 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_surface_data interface;
|
2023-03-05 15:05:43 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
HDC hDC;
|
|
|
|
HGLRC glContext;
|
2023-03-05 15:05:43 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
//NOTE: this may be a bit wasteful to have one api struct per surface, but win32 docs says that loading procs
|
|
|
|
// from different contexts might select different implementations (eg. depending on context version/pixel format)
|
|
|
|
oc_gl_api api;
|
2023-08-14 08:26:11 +00:00
|
|
|
} oc_wgl_surface;
|
2023-03-05 15:05:43 +00:00
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
void oc_wgl_surface_destroy(oc_surface_data* interface)
|
2023-03-05 15:05:43 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_wgl_surface* surface = (oc_wgl_surface*)interface;
|
2023-03-05 15:05:43 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
if(surface->glContext == wglGetCurrentContext())
|
|
|
|
{
|
|
|
|
wglMakeCurrent(NULL, NULL);
|
|
|
|
}
|
|
|
|
wglDeleteContext(surface->glContext);
|
2023-03-05 15:05:43 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_surface_cleanup(interface);
|
2023-03-05 15:05:43 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
free(surface);
|
2023-03-05 15:05:43 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
void oc_wgl_surface_prepare(oc_surface_data* interface)
|
2023-03-05 15:05:43 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_wgl_surface* surface = (oc_wgl_surface*)interface;
|
2023-03-05 15:05:43 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
wglMakeCurrent(surface->hDC, surface->glContext);
|
|
|
|
oc_gl_select_api(&surface->api);
|
2023-03-05 15:05:43 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
void oc_wgl_surface_present(oc_surface_data* interface)
|
2023-03-05 15:05:43 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_wgl_surface* surface = (oc_wgl_surface*)interface;
|
2023-06-21 10:36:05 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
SwapBuffers(surface->hDC);
|
2023-03-05 15:05:43 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
void oc_wgl_surface_deselect(oc_surface_data* interface)
|
2023-06-23 13:32:32 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
wglMakeCurrent(NULL, NULL);
|
|
|
|
oc_gl_deselect_api();
|
2023-06-23 13:32:32 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
void oc_wgl_surface_swap_interval(oc_surface_data* interface, int swap)
|
2023-03-05 15:05:43 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_wgl_surface* surface = (oc_wgl_surface*)interface;
|
|
|
|
wglSwapIntervalEXT(swap);
|
2023-03-05 15:05:43 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
void* oc_wgl_get_proc(const char* name)
|
2023-03-05 15:05:43 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
void* p = wglGetProcAddress(name);
|
|
|
|
if(p == 0
|
|
|
|
|| p == (void*)0x01
|
|
|
|
|| p == (void*)0x02
|
|
|
|
|| p == (void*)0x03
|
|
|
|
|| p == (void*)(-1))
|
|
|
|
{
|
|
|
|
//TODO: should we avoid re-loading every time?
|
|
|
|
HMODULE module = LoadLibrary("opengl32.dll");
|
|
|
|
p = (void*)GetProcAddress(module, name);
|
|
|
|
}
|
|
|
|
return (p);
|
2023-03-05 15:05:43 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
oc_surface_data* oc_wgl_surface_create_for_window(oc_window window)
|
2023-03-05 15:05:43 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_wgl_surface* surface = 0;
|
|
|
|
|
|
|
|
oc_window_data* windowData = oc_window_ptr_from_handle(window);
|
|
|
|
if(windowData)
|
|
|
|
{
|
|
|
|
oc_wgl_init();
|
|
|
|
|
|
|
|
//NOTE: fill surface data and load api
|
|
|
|
surface = oc_malloc_type(oc_wgl_surface);
|
|
|
|
if(surface)
|
|
|
|
{
|
|
|
|
memset(surface, 0, sizeof(oc_wgl_surface));
|
|
|
|
oc_surface_init_for_window((oc_surface_data*)surface, windowData);
|
|
|
|
|
|
|
|
surface->interface.api = OC_GL;
|
|
|
|
surface->interface.destroy = oc_wgl_surface_destroy;
|
|
|
|
surface->interface.prepare = oc_wgl_surface_prepare;
|
|
|
|
surface->interface.present = oc_wgl_surface_present;
|
|
|
|
surface->interface.swapInterval = oc_wgl_surface_swap_interval;
|
|
|
|
surface->interface.deselect = oc_wgl_surface_deselect;
|
|
|
|
|
|
|
|
surface->hDC = GetDC(surface->interface.layer.hWnd);
|
|
|
|
|
|
|
|
//NOTE(martin): create the pixel format and gl context
|
|
|
|
PIXELFORMATDESCRIPTOR pixelFormatDesc = {
|
|
|
|
sizeof(PIXELFORMATDESCRIPTOR),
|
|
|
|
1,
|
|
|
|
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, // Flags
|
|
|
|
PFD_TYPE_RGBA, // The kind of framebuffer. RGBA or palette.
|
|
|
|
32, // Colordepth of the framebuffer.
|
|
|
|
0, 0, 0, 0, 0, 0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0, 0, 0, 0,
|
|
|
|
24, // Number of bits for the depthbuffer
|
|
|
|
8, // Number of bits for the stencilbuffer
|
|
|
|
0, // Number of Aux buffers in the framebuffer.
|
|
|
|
PFD_MAIN_PLANE,
|
|
|
|
0,
|
|
|
|
0, 0, 0
|
|
|
|
};
|
|
|
|
|
|
|
|
int pixelFormatAttrs[] = {
|
|
|
|
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
|
|
|
|
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
|
|
|
|
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
|
|
|
|
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
|
|
|
|
WGL_TRANSPARENT_ARB, TRUE,
|
|
|
|
WGL_COLOR_BITS_ARB, 32,
|
|
|
|
WGL_RED_BITS_ARB, 8,
|
|
|
|
WGL_GREEN_BITS_ARB, 8,
|
|
|
|
WGL_BLUE_BITS_ARB, 8,
|
|
|
|
WGL_ALPHA_BITS_ARB, 8,
|
|
|
|
WGL_DEPTH_BITS_ARB, 24,
|
|
|
|
WGL_STENCIL_BITS_ARB, 8,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
u32 numFormats = 0;
|
|
|
|
int pixelFormat = 0;
|
|
|
|
|
|
|
|
wglChoosePixelFormatARB(surface->hDC, pixelFormatAttrs, 0, 1, &pixelFormat, &numFormats);
|
|
|
|
|
|
|
|
if(!pixelFormat)
|
|
|
|
{
|
|
|
|
//TODO: error
|
|
|
|
}
|
|
|
|
SetPixelFormat(surface->hDC, pixelFormat, &pixelFormatDesc);
|
|
|
|
|
|
|
|
int contextAttrs[] = {
|
|
|
|
WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
|
|
|
|
WGL_CONTEXT_MINOR_VERSION_ARB, 4,
|
|
|
|
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
surface->glContext = wglCreateContextAttribsARB(surface->hDC, oc_wglDummyContext.glContext, contextAttrs);
|
|
|
|
|
|
|
|
if(!surface->glContext)
|
|
|
|
{
|
|
|
|
//TODO error
|
|
|
|
int error = GetLastError();
|
|
|
|
printf("error: %i\n", error);
|
|
|
|
}
|
|
|
|
|
|
|
|
//NOTE: make gl context current and load api
|
|
|
|
wglMakeCurrent(surface->hDC, surface->glContext);
|
|
|
|
wglSwapIntervalEXT(1);
|
|
|
|
oc_gl_load_gl44(&surface->api, oc_wgl_get_proc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ((oc_surface_data*)surface);
|
2023-03-05 15:05:43 +00:00
|
|
|
}
|