orca/src/graphics/wgl_surface.c

279 lines
7.3 KiB
C
Raw Normal View History

2023-03-05 15:05:43 +00:00
/************************************************************//**
*
* @file: wgl_surface.c
* @author: Martin Fouilleul
* @date: 01/08/2022
* @revision:
*
*****************************************************************/
This commit restructures the codebase to melt the milepost platform layer into the main orca codebase. Here's a list of commits squashed in this update: - move angle files to ext/ and pull includes/libs from there when needed - remove milepost/ext/angle_headers - Collapsed milepost/ext into ext - Collapse milepost/scripts into scripts/ - collapse milepost/resources into resources/. WARN: this temporarily breaks milepost's native examples - collapse milepost/test into test/ - renamed test/ to tests/ - build milepost directly into build/bin - remove unused GLES and KHR folders from sdk/ - reorganizing milepost directory tree into app, graphics, platfrom, ui, util - collapse milepost/src to src/ - Move all native examples to sketches/ and remove milepost repo - Moving sketches resources into their own shared folder separate from the runtime's resource folder - Moving all binding code to src/wasmbind - Moving all binding code to src/wasmbind - pong: fix typo in error log - fixing log parameter order - add error logs to mg_image_create_* - Fix build scripts on windows - fixed include mistake after rebase - collapsing milepost.{h|c|m} to orca.{h|c|m} and moving from sdk/ to src/ - rename orca_app.h/main.c to runtime.h/c - collapsed sdk/ to src/ - put old sdk files into their respective dirs - renamed canvas_api.json to surface_api.json - moved all stb headers in ext/stb/ - remove unused OpenSansLatinSubset.ttf font - moving cstdlib to src/wasmlibc and removing some duplicates with src/platform - move libc stdarg and string functions from platform/ to wasmlibc/ - rename wasmlibc to libc-shim to reflect non-completeness - Expose abort/assert variadic functions and macros to orca apps, and forward libc-shim abort/assert to these - move Orca API runtime implementations to runtime_xxx - fix missing math constants when including math.h with msvc in graphics_common.c - Change name of runtime to orca_runtime. When bundling on Windows, change name of runtime executable to the name of the app.
2023-08-09 11:06:32 +00:00
#include"app/win32_app.h"
#include"graphics_surface.h"
2023-03-05 15:05:43 +00:00
#include"gl_loader.h"
#include<GL/wglext.h>
#include"util/macros.h"
2023-03-05 15:05:43 +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
#define OC_WGL_PROC(type, name) OC_CAT3(PFN, type, PROC) name = 0;
OC_WGL_PROC_LIST
#undef OC_WGL_PROC
2023-03-05 15:05:43 +00:00
//NOTE: wgl loader
typedef struct oc_wgl_dummy_context
2023-03-05 15:05:43 +00:00
{
bool init;
HWND hWnd;
HDC hDC;
HGLRC glContext;
} oc_wgl_dummy_context;
2023-03-05 15:05:43 +00:00
static oc_wgl_dummy_context oc_wglDummyContext = {0};
2023-03-05 15:05:43 +00:00
static void oc_wgl_init()
2023-03-05 15:05:43 +00:00
{
if(!oc_wglDummyContext.init)
2023-03-05 15:05:43 +00:00
{
//NOTE: create a dummy window
WNDCLASS windowClass = {.style = CS_OWNDC,
.lpfnWndProc = DefWindowProc,
.hInstance = GetModuleHandleW(NULL),
.lpszClassName = "oc_wgl_helper_window_class",
2023-03-05 15:05:43 +00:00
.hCursor = LoadCursor(0, IDC_ARROW)};
if(!RegisterClass(&windowClass))
{
//TODO: error
goto quit;
}
oc_wglDummyContext.hWnd = CreateWindow("oc_wgl_helper_window_class",
2023-03-05 15:05:43 +00:00
"dummy",
WS_OVERLAPPEDWINDOW,
0, 0, 100, 100,
0, 0, windowClass.hInstance, 0);
if(!oc_wglDummyContext.hWnd)
2023-03-05 15:05:43 +00:00
{
//TODO: error
goto quit;
}
oc_wglDummyContext.hDC = GetDC(oc_wglDummyContext.hWnd);
2023-03-05 15:05:43 +00:00
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);
2023-03-05 15:05:43 +00:00
oc_wglDummyContext.glContext = wglCreateContext(oc_wglDummyContext.hDC);
wglMakeCurrent(oc_wglDummyContext.hDC, oc_wglDummyContext.glContext);
2023-03-05 15:05:43 +00:00
//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
2023-03-05 15:05:43 +00:00
oc_wglDummyContext.init = true;
2023-03-05 15:05:43 +00:00
}
else
{
wglMakeCurrent(oc_wglDummyContext.hDC, oc_wglDummyContext.glContext);
2023-03-05 15:05:43 +00:00
}
quit:;
}
#undef OC_WGL_PROC_LIST
2023-03-05 15:05:43 +00:00
typedef struct oc_wgl_surface
2023-03-05 15:05:43 +00:00
{
oc_surface_data interface;
2023-03-05 15:05:43 +00:00
HDC hDC;
HGLRC glContext;
//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;
} oc_wgl_surface;
2023-03-05 15:05:43 +00:00
void oc_wgl_surface_destroy(oc_surface_data* interface)
2023-03-05 15:05:43 +00:00
{
oc_wgl_surface* surface = (oc_wgl_surface*)interface;
2023-03-05 15:05:43 +00:00
if(surface->glContext == wglGetCurrentContext())
{
wglMakeCurrent(NULL, NULL);
}
wglDeleteContext(surface->glContext);
oc_surface_cleanup(interface);
2023-03-05 15:05:43 +00:00
free(surface);
}
void oc_wgl_surface_prepare(oc_surface_data* interface)
2023-03-05 15:05:43 +00:00
{
oc_wgl_surface* surface = (oc_wgl_surface*)interface;
2023-03-05 15:05:43 +00:00
wglMakeCurrent(surface->hDC, surface->glContext);
oc_gl_select_api(&surface->api);
2023-03-05 15:05:43 +00:00
}
void oc_wgl_surface_present(oc_surface_data* interface)
2023-03-05 15:05:43 +00:00
{
oc_wgl_surface* surface = (oc_wgl_surface*)interface;
2023-03-05 15:05:43 +00:00
SwapBuffers(surface->hDC);
}
void oc_wgl_surface_deselect(oc_surface_data* interface)
{
wglMakeCurrent(NULL, NULL);
oc_gl_deselect_api();
}
void oc_wgl_surface_swap_interval(oc_surface_data* interface, int swap)
2023-03-05 15:05:43 +00:00
{
oc_wgl_surface* surface = (oc_wgl_surface*)interface;
2023-03-05 15:05:43 +00:00
wglSwapIntervalEXT(swap);
}
void* oc_wgl_get_proc(const char* name)
2023-03-05 15:05:43 +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);
}
oc_surface_data* oc_wgl_surface_create_for_window(oc_window window)
2023-03-05 15:05:43 +00:00
{
oc_wgl_surface* surface = 0;
2023-03-05 15:05:43 +00:00
oc_window_data* windowData = oc_window_ptr_from_handle(window);
2023-03-05 15:05:43 +00:00
if(windowData)
{
oc_wgl_init();
2023-03-05 15:05:43 +00:00
//NOTE: fill surface data and load api
surface = oc_malloc_type(oc_wgl_surface);
2023-03-05 15:05:43 +00:00
if(surface)
{
memset(surface, 0, sizeof(oc_wgl_surface));
oc_surface_init_for_window((oc_surface_data*)surface, windowData);
2023-03-05 15:05:43 +00:00
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;
2023-03-05 15:05:43 +00:00
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,
2023-03-05 15:05:43 +00:00
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,
2023-03-05 15:05:43 +00:00
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,
2023-03-05 15:05:43 +00:00
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0};
surface->glContext = wglCreateContextAttribsARB(surface->hDC, oc_wglDummyContext.glContext, contextAttrs);
2023-03-05 15:05:43 +00:00
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);
2023-03-05 15:05:43 +00:00
}
}
return((oc_surface_data*)surface);
2023-03-05 15:05:43 +00:00
}