[win32 surfaces] Backing win32 surfaces with child window and implementing frame/hidding control
This commit is contained in:
parent
4306d0a01c
commit
2dccfa5547
|
@ -1,3 +1,3 @@
|
||||||
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext
|
set INCLUDES=/I ..\..\src /I ..\..\src\util /I ..\..\src\platform /I ../../ext
|
||||||
|
|
||||||
cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GL /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib user32.lib opengl32.lib gdi32.lib shcore.lib /out:../../bin/example_gl_triangle.exe
|
cl /we4013 /Zi /Zc:preprocessor /DMG_IMPLEMENTS_BACKEND_GL /std:c11 %INCLUDES% main.c /link /LIBPATH:../../bin milepost.lib user32.lib opengl32.lib gdi32.lib shcore.lib /LIBPATH:../../bin libEGL.dll.lib libGLESv2.dll.lib /out:../../bin/example_gl_triangle.exe
|
||||||
|
|
|
@ -1,140 +0,0 @@
|
||||||
/************************************************************//**
|
|
||||||
*
|
|
||||||
* @file: egl_surface.cpp
|
|
||||||
* @author: Martin Fouilleul
|
|
||||||
* @date: 17/02/2023
|
|
||||||
* @revision:
|
|
||||||
*
|
|
||||||
*****************************************************************/
|
|
||||||
|
|
||||||
#define EGL_EGLEXT_PROTOTYPES
|
|
||||||
#include<EGL/egl.h>
|
|
||||||
#include<EGL/eglext.h>
|
|
||||||
|
|
||||||
#include"mp_app_internal.h"
|
|
||||||
#include"graphics_internal.h"
|
|
||||||
#include"gl_loader.h"
|
|
||||||
|
|
||||||
typedef struct mg_egl_surface
|
|
||||||
{
|
|
||||||
mg_surface_data interface;
|
|
||||||
|
|
||||||
void* nativeSurface;
|
|
||||||
|
|
||||||
EGLDisplay eglDisplay;
|
|
||||||
EGLConfig eglConfig;
|
|
||||||
EGLContext eglContext;
|
|
||||||
EGLSurface eglSurface;
|
|
||||||
|
|
||||||
mg_gl_api api;
|
|
||||||
|
|
||||||
} mg_egl_surface;
|
|
||||||
|
|
||||||
void mg_egl_surface_destroy(mg_surface_data* interface)
|
|
||||||
{
|
|
||||||
//////////////////////////////////////////////////
|
|
||||||
//TODO
|
|
||||||
//////////////////////////////////////////////////
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_egl_surface_prepare(mg_surface_data* interface)
|
|
||||||
{
|
|
||||||
mg_egl_surface* surface = (mg_egl_surface*)interface;
|
|
||||||
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
|
|
||||||
mg_gl_select_api(&surface->api);
|
|
||||||
}
|
|
||||||
|
|
||||||
void mg_egl_surface_present(mg_surface_data* interface)
|
|
||||||
{
|
|
||||||
mg_egl_surface* surface = (mg_egl_surface*)interface;
|
|
||||||
eglSwapBuffers(surface->eglDisplay, surface->eglSurface);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
mp_rect mg_egl_surface_get_frame(mg_surface_data* interface);
|
|
||||||
void mg_egl_surface_set_frame(mg_surface_data* interface, mp_rect frame);
|
|
||||||
void mg_egl_surface_set_hidden(mg_surface_data* interface, bool hidden);
|
|
||||||
bool mg_egl_surface_get_hidden(mg_surface_data* interface);
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if OS_MACOS
|
|
||||||
//NOTE: on macOS we need to explicitly set EGL_PLATFORM_ANGLE_TYPE_ANGLE to EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE, because
|
|
||||||
// EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE defaults to using CGL, and eglSetSwapInterval is broken for this backend
|
|
||||||
#define MG_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE
|
|
||||||
#elif OS_WIN64
|
|
||||||
#define MG_EGL_PLATFORM_ANGLE_TYPE EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mg_surface mg_egl_surface_create_for_window(mp_window window)
|
|
||||||
{
|
|
||||||
mg_surface res = mg_surface_nil();
|
|
||||||
|
|
||||||
//TODO: just need to check that the handle is valid
|
|
||||||
// then get native pointer from window handle
|
|
||||||
void* nativeSurface = mg_egl_get_native_surface(window);
|
|
||||||
|
|
||||||
if(nativeSurface)
|
|
||||||
{
|
|
||||||
mg_egl_surface* surface = malloc_type(mg_egl_surface);
|
|
||||||
memset(surface, 0, sizeof(mg_egl_surface));
|
|
||||||
|
|
||||||
surface->interface.backend = MG_BACKEND_GLES;
|
|
||||||
surface->interface.destroy = mg_egl_surface_destroy;
|
|
||||||
surface->interface.prepare = mg_egl_surface_prepare;
|
|
||||||
surface->interface.present = mg_egl_surface_present;
|
|
||||||
/*TODO
|
|
||||||
surface->interface.getFrame = mg_egl_surface_get_frame;
|
|
||||||
surface->interface.setFrame = mg_egl_surface_set_frame;
|
|
||||||
surface->interface.getHidden = mg_egl_surface_get_hidden;
|
|
||||||
surface->interface.setHidden = mg_egl_surface_set_hidden;
|
|
||||||
*/
|
|
||||||
|
|
||||||
surface->nativeSurface = nativeSurface;
|
|
||||||
|
|
||||||
EGLAttrib displayAttribs[] = {
|
|
||||||
EGL_PLATFORM_ANGLE_TYPE_ANGLE, MG_EGL_PLATFORM_ANGLE_TYPE,
|
|
||||||
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE,
|
|
||||||
EGL_NONE};
|
|
||||||
|
|
||||||
surface->eglDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE, (void*)EGL_DEFAULT_DISPLAY, displayAttribs);
|
|
||||||
eglInitialize(surface->eglDisplay, NULL, NULL);
|
|
||||||
|
|
||||||
EGLint const configAttributes[] = {
|
|
||||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
|
||||||
EGL_RED_SIZE, 8,
|
|
||||||
EGL_GREEN_SIZE, 8,
|
|
||||||
EGL_BLUE_SIZE, 8,
|
|
||||||
EGL_ALPHA_SIZE, 8,
|
|
||||||
EGL_DEPTH_SIZE, 24,
|
|
||||||
EGL_STENCIL_SIZE, 8,
|
|
||||||
EGL_SAMPLE_BUFFERS, 0,
|
|
||||||
EGL_SAMPLES, EGL_DONT_CARE,
|
|
||||||
EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT,
|
|
||||||
EGL_NONE };
|
|
||||||
|
|
||||||
int numConfigs = 0;
|
|
||||||
eglChooseConfig(surface->eglDisplay, configAttributes, &surface->eglConfig, 1, &numConfigs);
|
|
||||||
|
|
||||||
EGLint const surfaceAttributes[] = {EGL_NONE};
|
|
||||||
surface->eglSurface = eglCreateWindowSurface(surface->eglDisplay, surface->eglConfig, surface->nativeSurface, surfaceAttributes);
|
|
||||||
|
|
||||||
eglBindAPI(EGL_OPENGL_ES_API);
|
|
||||||
EGLint contextAttributes[] = {
|
|
||||||
EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
|
|
||||||
EGL_CONTEXT_MINOR_VERSION_KHR, 0,
|
|
||||||
EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM, EGL_TRUE,
|
|
||||||
EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE, EGL_TRUE,
|
|
||||||
EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE, EGL_FALSE,
|
|
||||||
EGL_NONE};
|
|
||||||
|
|
||||||
surface->eglContext = eglCreateContext(surface->eglDisplay, surface->eglConfig, EGL_NO_CONTEXT, contextAttributes);
|
|
||||||
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
|
|
||||||
|
|
||||||
mg_gl_load_gles32(&surface->api, (mg_gl_load_proc)eglGetProcAddress);
|
|
||||||
|
|
||||||
eglSwapInterval(surface->eglDisplay, 1);
|
|
||||||
|
|
||||||
res = mg_surface_alloc_handle((mg_surface_data*)surface);
|
|
||||||
}
|
|
||||||
return(res);
|
|
||||||
}
|
|
|
@ -2,7 +2,7 @@
|
||||||
*
|
*
|
||||||
* file: glsl_shaders.h
|
* file: glsl_shaders.h
|
||||||
* note: string literals auto-generated by embed_text.py
|
* note: string literals auto-generated by embed_text.py
|
||||||
* date: 17/022023
|
* date: 20/022023
|
||||||
*
|
*
|
||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
#ifndef __GLSL_SHADERS_H__
|
#ifndef __GLSL_SHADERS_H__
|
||||||
|
|
|
@ -60,12 +60,12 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MG_COMPILE_BACKEND_GL
|
#if MG_COMPILE_BACKEND_GL
|
||||||
= #include"wgl_surface.c"
|
#include"wgl_surface.c"
|
||||||
#include"gl_canvas.c"
|
#include"gl_canvas.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if MG_COMPILE_BACKEND_GLES
|
#if MG_COMPILE_BACKEND_GLES
|
||||||
#include"egl_surface.c"
|
#include"win32_egl_surface.c"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#elif defined(OS_MACOS)
|
#elif defined(OS_MACOS)
|
||||||
|
|
|
@ -57,6 +57,9 @@ void mg_wgl_surface_destroy(mg_surface_data* interface)
|
||||||
wglMakeCurrent(NULL, NULL);
|
wglMakeCurrent(NULL, NULL);
|
||||||
}
|
}
|
||||||
wglDeleteContext(surface->glContext);
|
wglDeleteContext(surface->glContext);
|
||||||
|
|
||||||
|
DestroyWindow(surface->hWnd);
|
||||||
|
|
||||||
free(surface);
|
free(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +83,7 @@ void mg_wgl_surface_swap_interval(mg_surface_data* interface, int swap)
|
||||||
wglSwapIntervalEXT(swap);
|
wglSwapIntervalEXT(swap);
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2 mg_wgl_contents_scaling(mg_surface_data* interface)
|
vec2 mg_wgl_surface_contents_scaling(mg_surface_data* interface)
|
||||||
{
|
{
|
||||||
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
|
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
|
||||||
return(surface->contentsScaling);
|
return(surface->contentsScaling);
|
||||||
|
@ -88,19 +91,64 @@ vec2 mg_wgl_contents_scaling(mg_surface_data* interface)
|
||||||
|
|
||||||
mp_rect mg_wgl_surface_get_frame(mg_surface_data* interface)
|
mp_rect mg_wgl_surface_get_frame(mg_surface_data* interface)
|
||||||
{
|
{
|
||||||
|
mp_rect res = {0};
|
||||||
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
|
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
|
||||||
|
if(surface)
|
||||||
|
{
|
||||||
RECT rect = {0};
|
RECT rect = {0};
|
||||||
GetClientRect(surface->hWnd, &rect);
|
GetClientRect(surface->hWnd, &rect);
|
||||||
|
|
||||||
vec2 scale = surface->contentsScaling;
|
vec2 scale = surface->contentsScaling;
|
||||||
|
|
||||||
mp_rect res = {rect.left/scale.x,
|
res = (mp_rect){rect.left/scale.x,
|
||||||
rect.bottom/scale.y,
|
rect.bottom/scale.y,
|
||||||
(rect.right - rect.left)/scale.x,
|
(rect.right - rect.left)/scale.x,
|
||||||
(rect.bottom - rect.top)/scale.y};
|
(rect.bottom - rect.top)/scale.y};
|
||||||
|
}
|
||||||
return(res);
|
return(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mg_wgl_surface_set_frame(mg_surface_data* interface, mp_rect frame)
|
||||||
|
{
|
||||||
|
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
|
||||||
|
if(surface)
|
||||||
|
{
|
||||||
|
HWND parent = GetParent(surface->hWnd);
|
||||||
|
RECT parentContentRect;
|
||||||
|
GetClientRect(parent, &parentContentRect);
|
||||||
|
int parentHeight = parentContentRect.bottom - parentContentRect.top;
|
||||||
|
|
||||||
|
SetWindowPos(surface->hWnd,
|
||||||
|
HWND_TOP,
|
||||||
|
frame.x * surface->contentsScaling.x,
|
||||||
|
parentHeight - (frame.y + frame.h) * surface->contentsScaling.y,
|
||||||
|
frame.w * surface->contentsScaling.x,
|
||||||
|
frame.h * surface->contentsScaling.y,
|
||||||
|
SWP_NOACTIVATE | SWP_NOZORDER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_wgl_surface_set_hidden(mg_surface_data* interface, bool hidden)
|
||||||
|
{
|
||||||
|
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
|
||||||
|
if(surface)
|
||||||
|
{
|
||||||
|
ShowWindow(surface->hWnd, hidden ? SW_HIDE : SW_NORMAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_wgl_surface_get_hidden(mg_surface_data* interface)
|
||||||
|
{
|
||||||
|
bool hidden = false;
|
||||||
|
mg_wgl_surface* surface = (mg_wgl_surface*)interface;
|
||||||
|
if(surface)
|
||||||
|
{
|
||||||
|
hidden = !IsWindowVisible(surface->hWnd);
|
||||||
|
}
|
||||||
|
return(hidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void* mg_wgl_get_proc(const char* name)
|
void* mg_wgl_get_proc(const char* name)
|
||||||
{
|
{
|
||||||
void* p = wglGetProcAddress(name);
|
void* p = wglGetProcAddress(name);
|
||||||
|
@ -117,6 +165,11 @@ void* mg_wgl_get_proc(const char* name)
|
||||||
return(p);
|
return(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LRESULT mg_wgl_surface_window_proc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
return(DefWindowProc(windowHandle, message, wParam, lParam));
|
||||||
|
}
|
||||||
|
|
||||||
mg_surface mg_wgl_surface_create_for_window(mp_window window)
|
mg_surface mg_wgl_surface_create_for_window(mp_window window)
|
||||||
{
|
{
|
||||||
mg_surface surfaceHandle = mg_surface_nil();
|
mg_surface surfaceHandle = mg_surface_nil();
|
||||||
|
@ -180,6 +233,31 @@ mg_surface mg_wgl_surface_create_for_window(mp_window window)
|
||||||
//NOTE(martin): now load WGL extension functions
|
//NOTE(martin): now load WGL extension functions
|
||||||
wgl_load_procs();
|
wgl_load_procs();
|
||||||
|
|
||||||
|
//NOTE(martin): create a child window for the surface
|
||||||
|
WNDCLASS childWindowClass = {.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
||||||
|
.lpfnWndProc = mg_wgl_surface_window_proc,
|
||||||
|
.hInstance = GetModuleHandleW(NULL),
|
||||||
|
.lpszClassName = "wgl_surface_window_class",
|
||||||
|
.hCursor = LoadCursor(0, IDC_ARROW)};
|
||||||
|
|
||||||
|
if(!RegisterClass(&childWindowClass))
|
||||||
|
{
|
||||||
|
//TODO: error
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_rect frame = mp_window_get_content_rect(window);
|
||||||
|
|
||||||
|
u32 dpi = GetDpiForWindow(windowData->win32.hWnd);
|
||||||
|
vec2 contentsScaling = (vec2){(float)dpi/96., (float)dpi/96.};
|
||||||
|
|
||||||
|
HWND childWindow = CreateWindow("wgl_surface_window_class", "Test",
|
||||||
|
WS_CHILD|WS_VISIBLE,
|
||||||
|
0, 0, frame.w*contentsScaling.x, frame.h*contentsScaling.y,
|
||||||
|
windowData->win32.hWnd,
|
||||||
|
0,
|
||||||
|
childWindowClass.hInstance,
|
||||||
|
0);
|
||||||
|
|
||||||
//NOTE(martin): now create the true pixel format and gl context
|
//NOTE(martin): now create the true pixel format and gl context
|
||||||
int pixelFormatAttrs[] = {
|
int pixelFormatAttrs[] = {
|
||||||
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
|
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
|
||||||
|
@ -191,7 +269,7 @@ mg_surface mg_wgl_surface_create_for_window(mp_window window)
|
||||||
WGL_STENCIL_BITS_ARB, 8,
|
WGL_STENCIL_BITS_ARB, 8,
|
||||||
0};
|
0};
|
||||||
|
|
||||||
HDC hDC = GetDC(windowData->win32.hWnd);
|
HDC hDC = GetDC(childWindow);
|
||||||
u32 numFormats = 0;
|
u32 numFormats = 0;
|
||||||
|
|
||||||
wglChoosePixelFormatARB(hDC, pixelFormatAttrs, 0, 1, &pixelFormat, &numFormats);
|
wglChoosePixelFormatARB(hDC, pixelFormatAttrs, 0, 1, &pixelFormat, &numFormats);
|
||||||
|
@ -234,16 +312,18 @@ mg_surface mg_wgl_surface_create_for_window(mp_window window)
|
||||||
surface->interface.prepare = mg_wgl_surface_prepare;
|
surface->interface.prepare = mg_wgl_surface_prepare;
|
||||||
surface->interface.present = mg_wgl_surface_present;
|
surface->interface.present = mg_wgl_surface_present;
|
||||||
surface->interface.swapInterval = mg_wgl_surface_swap_interval;
|
surface->interface.swapInterval = mg_wgl_surface_swap_interval;
|
||||||
surface->interface.contentsScaling = mg_wgl_contents_scaling;
|
surface->interface.contentsScaling = mg_wgl_surface_contents_scaling;
|
||||||
surface->interface.getFrame = mg_wgl_surface_get_frame;
|
surface->interface.getFrame = mg_wgl_surface_get_frame;
|
||||||
|
surface->interface.setFrame = mg_wgl_surface_set_frame;
|
||||||
|
surface->interface.getHidden = mg_wgl_surface_get_hidden;
|
||||||
|
surface->interface.setHidden = mg_wgl_surface_set_hidden;
|
||||||
//TODO: get/set frame/hidden
|
//TODO: get/set frame/hidden
|
||||||
|
|
||||||
surface->hWnd = windowData->win32.hWnd;
|
surface->hWnd = childWindow;
|
||||||
surface->hDC = hDC;
|
surface->hDC = hDC;
|
||||||
surface->glContext = glContext;
|
surface->glContext = glContext;
|
||||||
|
|
||||||
u32 dpi = GetDpiForWindow(windowData->win32.hWnd);
|
surface->contentsScaling = contentsScaling;
|
||||||
surface->contentsScaling = (vec2){(float)dpi/96., (float)dpi/96.};
|
|
||||||
|
|
||||||
mg_gl_load_gl43(&surface->api, mg_wgl_get_proc);
|
mg_gl_load_gl43(&surface->api, mg_wgl_get_proc);
|
||||||
|
|
||||||
|
|
|
@ -822,15 +822,4 @@ str8 mp_app_get_resource_path(mem_arena* arena, const char* name)
|
||||||
}
|
}
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void* mg_egl_get_native_surface(mp_window_data* window)
|
|
||||||
{
|
|
||||||
void* res = 0;
|
|
||||||
mp_window_data* windowData = mp_window_ptr_from_handle(window);
|
|
||||||
if(windowData)
|
|
||||||
{
|
|
||||||
res = (void*)windowData->win32.hWnd;
|
|
||||||
}
|
|
||||||
return(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef LOG_SUBSYSTEM
|
#undef LOG_SUBSYSTEM
|
||||||
|
|
|
@ -0,0 +1,234 @@
|
||||||
|
/************************************************************//**
|
||||||
|
*
|
||||||
|
* @file: win32_egl_surface.cpp
|
||||||
|
* @author: Martin Fouilleul
|
||||||
|
* @date: 17/02/2023
|
||||||
|
* @revision:
|
||||||
|
*
|
||||||
|
*****************************************************************/
|
||||||
|
|
||||||
|
#define EGL_EGLEXT_PROTOTYPES
|
||||||
|
#include<EGL/egl.h>
|
||||||
|
#include<EGL/eglext.h>
|
||||||
|
|
||||||
|
#include"mp_app_internal.h"
|
||||||
|
#include"graphics_internal.h"
|
||||||
|
#include"gl_loader.h"
|
||||||
|
|
||||||
|
typedef struct mg_egl_surface
|
||||||
|
{
|
||||||
|
mg_surface_data interface;
|
||||||
|
|
||||||
|
HWND hWnd;
|
||||||
|
vec2 contentsScaling;
|
||||||
|
|
||||||
|
EGLDisplay eglDisplay;
|
||||||
|
EGLConfig eglConfig;
|
||||||
|
EGLContext eglContext;
|
||||||
|
EGLSurface eglSurface;
|
||||||
|
|
||||||
|
mg_gl_api api;
|
||||||
|
|
||||||
|
} mg_egl_surface;
|
||||||
|
|
||||||
|
void mg_egl_surface_destroy(mg_surface_data* interface)
|
||||||
|
{
|
||||||
|
mg_egl_surface* surface = (mg_egl_surface*)interface;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
//TODO
|
||||||
|
//////////////////////////////////////////////////
|
||||||
|
DestroyWindow(surface->hWnd);
|
||||||
|
free(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_egl_surface_prepare(mg_surface_data* interface)
|
||||||
|
{
|
||||||
|
mg_egl_surface* surface = (mg_egl_surface*)interface;
|
||||||
|
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
|
||||||
|
mg_gl_select_api(&surface->api);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_egl_surface_present(mg_surface_data* interface)
|
||||||
|
{
|
||||||
|
mg_egl_surface* surface = (mg_egl_surface*)interface;
|
||||||
|
eglSwapBuffers(surface->eglDisplay, surface->eglSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_egl_surface_swap_interval(mg_surface_data* interface, int swap)
|
||||||
|
{
|
||||||
|
mg_egl_surface* surface = (mg_egl_surface*)interface;
|
||||||
|
eglSwapInterval(surface->eglDisplay, swap);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 mg_egl_surface_contents_scaling(mg_surface_data* interface)
|
||||||
|
{
|
||||||
|
mg_egl_surface* surface = (mg_egl_surface*)interface;
|
||||||
|
return(surface->contentsScaling);
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_rect mg_egl_surface_get_frame(mg_surface_data* interface)
|
||||||
|
{
|
||||||
|
mp_rect res = {0};
|
||||||
|
mg_egl_surface* surface = (mg_egl_surface*)interface;
|
||||||
|
if(surface)
|
||||||
|
{
|
||||||
|
RECT rect = {0};
|
||||||
|
GetClientRect(surface->hWnd, &rect);
|
||||||
|
|
||||||
|
vec2 scale = surface->contentsScaling;
|
||||||
|
|
||||||
|
res = (mp_rect){rect.left/scale.x,
|
||||||
|
rect.bottom/scale.y,
|
||||||
|
(rect.right - rect.left)/scale.x,
|
||||||
|
(rect.bottom - rect.top)/scale.y};
|
||||||
|
}
|
||||||
|
return(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_egl_surface_set_frame(mg_surface_data* interface, mp_rect frame)
|
||||||
|
{
|
||||||
|
mg_egl_surface* surface = (mg_egl_surface*)interface;
|
||||||
|
if(surface)
|
||||||
|
{
|
||||||
|
HWND parent = GetParent(surface->hWnd);
|
||||||
|
RECT parentContentRect;
|
||||||
|
GetClientRect(parent, &parentContentRect);
|
||||||
|
int parentHeight = parentContentRect.bottom - parentContentRect.top;
|
||||||
|
|
||||||
|
SetWindowPos(surface->hWnd,
|
||||||
|
HWND_TOP,
|
||||||
|
frame.x * surface->contentsScaling.x,
|
||||||
|
parentHeight - (frame.y + frame.h) * surface->contentsScaling.y,
|
||||||
|
frame.w * surface->contentsScaling.x,
|
||||||
|
frame.h * surface->contentsScaling.y,
|
||||||
|
SWP_NOACTIVATE | SWP_NOZORDER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void mg_egl_surface_set_hidden(mg_surface_data* interface, bool hidden)
|
||||||
|
{
|
||||||
|
mg_egl_surface* surface = (mg_egl_surface*)interface;
|
||||||
|
if(surface)
|
||||||
|
{
|
||||||
|
ShowWindow(surface->hWnd, hidden ? SW_HIDE : SW_NORMAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mg_egl_surface_get_hidden(mg_surface_data* interface)
|
||||||
|
{
|
||||||
|
bool hidden = false;
|
||||||
|
mg_egl_surface* surface = (mg_egl_surface*)interface;
|
||||||
|
if(surface)
|
||||||
|
{
|
||||||
|
hidden = !IsWindowVisible(surface->hWnd);
|
||||||
|
}
|
||||||
|
return(hidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LRESULT mg_egl_surface_window_proc(HWND windowHandle, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
return(DefWindowProc(windowHandle, message, wParam, lParam));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mg_surface mg_egl_surface_create_for_window(mp_window window)
|
||||||
|
{
|
||||||
|
mg_surface res = mg_surface_nil();
|
||||||
|
|
||||||
|
mp_window_data* windowData = mp_window_ptr_from_handle(window);
|
||||||
|
if(windowData)
|
||||||
|
{
|
||||||
|
//NOTE(martin): create a child window for the surface
|
||||||
|
WNDCLASS childWindowClass = {.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
||||||
|
.lpfnWndProc = mg_egl_surface_window_proc,
|
||||||
|
.hInstance = GetModuleHandleW(NULL),
|
||||||
|
.lpszClassName = "egl_surface_window_class",
|
||||||
|
.hCursor = LoadCursor(0, IDC_ARROW)};
|
||||||
|
|
||||||
|
if(!RegisterClass(&childWindowClass))
|
||||||
|
{
|
||||||
|
//TODO: error
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_rect frame = mp_window_get_content_rect(window);
|
||||||
|
|
||||||
|
u32 dpi = GetDpiForWindow(windowData->win32.hWnd);
|
||||||
|
vec2 contentsScaling = (vec2){(float)dpi/96., (float)dpi/96.};
|
||||||
|
|
||||||
|
HWND childWindow = CreateWindow("egl_surface_window_class", "Test",
|
||||||
|
WS_CHILD|WS_VISIBLE,
|
||||||
|
0, 0, frame.w*contentsScaling.x, frame.h*contentsScaling.y,
|
||||||
|
windowData->win32.hWnd,
|
||||||
|
0,
|
||||||
|
childWindowClass.hInstance,
|
||||||
|
0);
|
||||||
|
|
||||||
|
mg_egl_surface* surface = malloc_type(mg_egl_surface);
|
||||||
|
memset(surface, 0, sizeof(mg_egl_surface));
|
||||||
|
|
||||||
|
surface->interface.backend = MG_BACKEND_GLES;
|
||||||
|
surface->interface.destroy = mg_egl_surface_destroy;
|
||||||
|
surface->interface.prepare = mg_egl_surface_prepare;
|
||||||
|
surface->interface.present = mg_egl_surface_present;
|
||||||
|
surface->interface.swapInterval = mg_egl_surface_swap_interval;
|
||||||
|
surface->interface.contentsScaling = mg_egl_surface_contents_scaling;
|
||||||
|
surface->interface.getFrame = mg_egl_surface_get_frame;
|
||||||
|
surface->interface.setFrame = mg_egl_surface_set_frame;
|
||||||
|
surface->interface.getHidden = mg_egl_surface_get_hidden;
|
||||||
|
surface->interface.setHidden = mg_egl_surface_set_hidden;
|
||||||
|
|
||||||
|
surface->hWnd = childWindow;
|
||||||
|
surface->contentsScaling = contentsScaling;
|
||||||
|
|
||||||
|
EGLAttrib displayAttribs[] = {
|
||||||
|
EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE,
|
||||||
|
EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE,
|
||||||
|
EGL_NONE};
|
||||||
|
|
||||||
|
surface->eglDisplay = eglGetPlatformDisplay(EGL_PLATFORM_ANGLE_ANGLE, (void*)EGL_DEFAULT_DISPLAY, displayAttribs);
|
||||||
|
eglInitialize(surface->eglDisplay, NULL, NULL);
|
||||||
|
|
||||||
|
EGLint const configAttributes[] = {
|
||||||
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||||
|
EGL_RED_SIZE, 8,
|
||||||
|
EGL_GREEN_SIZE, 8,
|
||||||
|
EGL_BLUE_SIZE, 8,
|
||||||
|
EGL_ALPHA_SIZE, 8,
|
||||||
|
EGL_DEPTH_SIZE, 24,
|
||||||
|
EGL_STENCIL_SIZE, 8,
|
||||||
|
EGL_SAMPLE_BUFFERS, 0,
|
||||||
|
EGL_SAMPLES, EGL_DONT_CARE,
|
||||||
|
EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT,
|
||||||
|
EGL_NONE };
|
||||||
|
|
||||||
|
int numConfigs = 0;
|
||||||
|
eglChooseConfig(surface->eglDisplay, configAttributes, &surface->eglConfig, 1, &numConfigs);
|
||||||
|
|
||||||
|
EGLint const surfaceAttributes[] = {EGL_NONE};
|
||||||
|
surface->eglSurface = eglCreateWindowSurface(surface->eglDisplay,
|
||||||
|
surface->eglConfig,
|
||||||
|
surface->hWnd,
|
||||||
|
surfaceAttributes);
|
||||||
|
|
||||||
|
eglBindAPI(EGL_OPENGL_ES_API);
|
||||||
|
EGLint contextAttributes[] = {
|
||||||
|
EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
|
||||||
|
EGL_CONTEXT_MINOR_VERSION_KHR, 1,
|
||||||
|
EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM, EGL_TRUE,
|
||||||
|
EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE, EGL_TRUE,
|
||||||
|
EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE, EGL_FALSE,
|
||||||
|
EGL_NONE};
|
||||||
|
|
||||||
|
surface->eglContext = eglCreateContext(surface->eglDisplay, surface->eglConfig, EGL_NO_CONTEXT, contextAttributes);
|
||||||
|
eglMakeCurrent(surface->eglDisplay, surface->eglSurface, surface->eglSurface, surface->eglContext);
|
||||||
|
|
||||||
|
mg_gl_load_gles32(&surface->api, (mg_gl_load_proc)eglGetProcAddress);
|
||||||
|
|
||||||
|
eglSwapInterval(surface->eglDisplay, 1);
|
||||||
|
|
||||||
|
res = mg_surface_alloc_handle((mg_surface_data*)surface);
|
||||||
|
}
|
||||||
|
return(res);
|
||||||
|
}
|
26
todo.txt
26
todo.txt
|
@ -15,27 +15,23 @@ Overview
|
||||||
[>] Allow selecting version of GL/GLES context when creating surface
|
[>] Allow selecting version of GL/GLES context when creating surface
|
||||||
- pass/set attributes when creating surface?
|
- pass/set attributes when creating surface?
|
||||||
|
|
||||||
|
[ ] Check that we can make GLES and GL surfaces co-exist in the app
|
||||||
|
[ ] Allow controlling surface overlaying
|
||||||
|
|
||||||
|
[/] could have an internal, per-platform mp_layer struct that handles resizing/hiding etc...
|
||||||
|
-> avoid duplication of frame/hiding and duplication of egl code.
|
||||||
|
[/] EGL surfaces: See how we can isolate platform-specific stuff and just deal with one egl impl...
|
||||||
|
[/] Automatic surface resizing
|
||||||
[/] Keep dummy window/dummy context around for gl context creation, and don't reload wgl functions every time
|
[/] Keep dummy window/dummy context around for gl context creation, and don't reload wgl functions every time
|
||||||
|
|
||||||
[.] Reintroduce GLES surface
|
[!] Sort out gles contents scaling for high dpi on osx
|
||||||
[?] See how we can isolate platform-specific stuff and just deal with egl there...
|
[!] Properly destroy egl surfaces
|
||||||
|
[!] win32 surfaces: only register surface child window once?
|
||||||
[.] Back surface by child windows and implement moving frame/hiding/overlay
|
|
||||||
[x] osx gles surface
|
|
||||||
[ ] Sort out gles contents scaling for high dpi
|
|
||||||
[ ] win32 opengl surfaces
|
|
||||||
[ ] win32 gles surface
|
|
||||||
|
|
||||||
[/] could have an internal, per-platform mp_layer struct that handles resizing/hiding etc...
|
|
||||||
-> avoid duplication of frame/hiding and duplication of egl code.
|
|
||||||
|
|
||||||
[ ] then check that we can make GLES and GL surfaces co-exist in the app
|
|
||||||
|
|
||||||
[!] Make linking with libEGL optional, even if EGL backend is compiled in milepost?
|
[!] Make linking with libEGL optional, even if EGL backend is compiled in milepost?
|
||||||
[!] Bundle examples with their own resources?? (e.g. avoiding clashes in metal libs files in bin directory)
|
[!] Bundle examples with their own resources?? (e.g. avoiding clashes in metal libs files in bin directory)
|
||||||
[!] Fix canvas shader precision issue on OSX
|
[!] Fix canvas shader precision issue on OSX
|
||||||
[!] Fix canvas perf issue on OSX
|
[!] Fix canvas perf issue on OSX
|
||||||
[!] osx: Remove need to include objc defs from osx_app.h in egl impl. Also properly guard angle backend attribute (must be metal on osx and default on win32)
|
|
||||||
|
|
||||||
[ ] Delegated drawing API+Impl
|
[ ] Delegated drawing API+Impl
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue