mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-15 02:25:32 -04:00
Combine window with opengl context code
There's no point making them separate since each windowing backend only works with one particular opengl context backend anyways
This commit is contained in:
parent
98f3b73c0a
commit
6f2c597b84
@ -31,21 +31,13 @@ Create a window, show a dialog window, set window contents, keyboard/mouse input
|
||||
Also monitor size, clipboard, cursor, raw relative mouse movement (optional)
|
||||
|
||||
Define:
|
||||
- ```CC_BUILD_WINGUI``` - Use Win32 API (Windows)
|
||||
- ```CC_BUILD_CARBON``` - Use Carbon (OSX)
|
||||
- ```CC_BUILD_X11``` - Use X11/XLib
|
||||
- ```CC_BUILD_SDL``` - Use SDL library
|
||||
- ```CC_BUILD_WEBCANVAS``` - Use emscripten canvas
|
||||
- ```CC_BUILD_WINGUI``` - Use Win32 API (Windows) (WGL)
|
||||
- ```CC_BUILD_CARBON``` - Use Carbon (Mac OSX) (AGL)
|
||||
- ```CC_BUILD_X11``` - Use X11/XLib (unix-ish) (glX)
|
||||
- ```CC_BUILD_SDL``` - Use SDL library (SDL)
|
||||
- ```CC_BUILD_WEBCANVAS``` - Use emscripten canvas (WebGL)
|
||||
|
||||
If using OpenGL, also OpenGL context creation
|
||||
|
||||
Define:
|
||||
- ```CC_BUILD_WGL``` - Use WGL (Windows OpenGL)
|
||||
- ```CC_BUILD_AGL``` - Use AGL (Apple OpenGL)
|
||||
- ```CC_BUILD_GLX``` - Use glX (X11/XLib)
|
||||
- ```CC_BUILD_EGL``` - Use EGL (mainly for GLES)
|
||||
- ```CC_BUILD_SDL``` - Use SDL library
|
||||
- ```CC_BUILD_WEBGL``` - Use emscripten WebGL
|
||||
If using OpenGL, also OpenGL context management
|
||||
|
||||
### Logger
|
||||
Dump registers and backtrace, log unhandled errors (e.g. invalid memory read)
|
||||
|
@ -136,14 +136,12 @@ typedef struct TextureRec_ { float U1, V1, U2, V2; } TextureRec;
|
||||
#define CC_BUILD_GL
|
||||
#define CC_BUILD_GLMODERN
|
||||
#define CC_BUILD_GLES
|
||||
#define CC_BUILD_EGL
|
||||
#define CC_BUILD_TOUCH
|
||||
#elif defined __linux__
|
||||
#define CC_BUILD_LINUX
|
||||
#define CC_BUILD_POSIX
|
||||
#define CC_BUILD_GL
|
||||
#define CC_BUILD_X11
|
||||
#define CC_BUILD_GLX
|
||||
#define CC_BUILD_CURL
|
||||
#define CC_BUILD_OPENAL
|
||||
#elif defined __APPLE__
|
||||
@ -151,7 +149,6 @@ typedef struct TextureRec_ { float U1, V1, U2, V2; } TextureRec;
|
||||
#define CC_BUILD_POSIX
|
||||
#define CC_BUILD_GL
|
||||
#define CC_BUILD_CARBON
|
||||
#define CC_BUILD_AGL
|
||||
#define CC_BUILD_CURL
|
||||
#define CC_BUILD_OPENAL
|
||||
#elif defined __sun__
|
||||
@ -159,7 +156,6 @@ typedef struct TextureRec_ { float U1, V1, U2, V2; } TextureRec;
|
||||
#define CC_BUILD_POSIX
|
||||
#define CC_BUILD_GL
|
||||
#define CC_BUILD_X11
|
||||
#define CC_BUILD_GLX
|
||||
#define CC_BUILD_CURL
|
||||
#define CC_BUILD_OPENAL
|
||||
#elif defined __FreeBSD__
|
||||
@ -167,7 +163,6 @@ typedef struct TextureRec_ { float U1, V1, U2, V2; } TextureRec;
|
||||
#define CC_BUILD_POSIX
|
||||
#define CC_BUILD_GL
|
||||
#define CC_BUILD_X11
|
||||
#define CC_BUILD_GLX
|
||||
#define CC_BUILD_CURL
|
||||
#define CC_BUILD_OPENAL
|
||||
#elif defined __OpenBSD__
|
||||
@ -175,7 +170,6 @@ typedef struct TextureRec_ { float U1, V1, U2, V2; } TextureRec;
|
||||
#define CC_BUILD_POSIX
|
||||
#define CC_BUILD_GL
|
||||
#define CC_BUILD_X11
|
||||
#define CC_BUILD_GLX
|
||||
#define CC_BUILD_CURL
|
||||
#define CC_BUILD_OPENAL
|
||||
#elif defined __NetBSD__
|
||||
@ -183,7 +177,6 @@ typedef struct TextureRec_ { float U1, V1, U2, V2; } TextureRec;
|
||||
#define CC_BUILD_POSIX
|
||||
#define CC_BUILD_GL
|
||||
#define CC_BUILD_X11
|
||||
#define CC_BUILD_GLX
|
||||
#define CC_BUILD_CURL
|
||||
#define CC_BUILD_OPENAL
|
||||
#elif defined __EMSCRIPTEN__
|
||||
@ -193,7 +186,6 @@ typedef struct TextureRec_ { float U1, V1, U2, V2; } TextureRec;
|
||||
#define CC_BUILD_GLMODERN
|
||||
#define CC_BUILD_GLES
|
||||
#define CC_BUILD_WEBCANVAS
|
||||
#define CC_BUILD_WEBGL
|
||||
#define CC_BUILD_TOUCH
|
||||
#endif
|
||||
#endif
|
||||
|
944
src/Window.c
944
src/Window.c
@ -621,6 +621,87 @@ void Window_UpdateRawMouse(void) {
|
||||
}
|
||||
|
||||
void Window_DisableRawMouse(void) { Window_DefaultDisableRawMouse(); }
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------WGL OpenGL--------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#ifdef CC_BUILD_GL
|
||||
static HGLRC ctx_handle;
|
||||
static HDC ctx_DC;
|
||||
typedef BOOL (WINAPI *FN_WGLSWAPINTERVAL)(int interval);
|
||||
static FN_WGLSWAPINTERVAL wglSwapIntervalEXT;
|
||||
static bool ctx_supports_vSync;
|
||||
|
||||
static void GLContext_SelectGraphicsMode(struct GraphicsMode* mode) {
|
||||
PIXELFORMATDESCRIPTOR pfd = { 0 };
|
||||
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
|
||||
/* TODO: PFD_SUPPORT_COMPOSITION FLAG? CHECK IF IT WORKS ON XP */
|
||||
pfd.cColorBits = mode->R + mode->G + mode->B;
|
||||
pfd.cDepthBits = GLCONTEXT_DEFAULT_DEPTH;
|
||||
|
||||
pfd.iPixelType = mode->IsIndexed ? PFD_TYPE_COLORINDEX : PFD_TYPE_RGBA;
|
||||
pfd.cRedBits = mode->R;
|
||||
pfd.cGreenBits = mode->G;
|
||||
pfd.cBlueBits = mode->B;
|
||||
pfd.cAlphaBits = mode->A;
|
||||
|
||||
int modeIndex = ChoosePixelFormat(win_DC, &pfd);
|
||||
if (modeIndex == 0) { Logger_Abort("Requested graphics mode not available"); }
|
||||
|
||||
Mem_Set(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
|
||||
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
pfd.nVersion = 1;
|
||||
|
||||
DescribePixelFormat(win_DC, modeIndex, pfd.nSize, &pfd);
|
||||
if (!SetPixelFormat(win_DC, modeIndex, &pfd)) {
|
||||
Logger_Abort2(GetLastError(), "SetPixelFormat failed");
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext_Init(struct GraphicsMode* mode) {
|
||||
GLContext_SelectGraphicsMode(mode);
|
||||
ctx_handle = wglCreateContext(win_DC);
|
||||
if (!ctx_handle) {
|
||||
ctx_handle = wglCreateContext(win_DC);
|
||||
}
|
||||
if (!ctx_handle) {
|
||||
Logger_Abort2(GetLastError(), "Failed to create OpenGL context");
|
||||
}
|
||||
|
||||
if (!wglMakeCurrent(win_DC, ctx_handle)) {
|
||||
Logger_Abort2(GetLastError(), "Failed to make OpenGL context current");
|
||||
}
|
||||
|
||||
ctx_DC = wglGetCurrentDC();
|
||||
wglSwapIntervalEXT = (FN_WGLSWAPINTERVAL)GLContext_GetAddress("wglSwapIntervalEXT");
|
||||
ctx_supports_vSync = wglSwapIntervalEXT != NULL;
|
||||
}
|
||||
|
||||
void GLContext_Update(void) { }
|
||||
bool GLContext_TryRestore(void) { return true; }
|
||||
void GLContext_Free(void) {
|
||||
if (!ctx_handle) return;
|
||||
wglDeleteContext(ctx_handle);
|
||||
ctx_handle = NULL;
|
||||
}
|
||||
|
||||
void* GLContext_GetAddress(const char* function) {
|
||||
void* address = wglGetProcAddress(function);
|
||||
return GLContext_IsInvalidAddress(address) ? NULL : address;
|
||||
}
|
||||
|
||||
bool GLContext_SwapBuffers(void) {
|
||||
if (!SwapBuffers(ctx_DC)) Logger_Abort2(GetLastError(), "Failed to swap buffers");
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLContext_SetFpsLimit(bool vsync, float minFrameMs) {
|
||||
if (ctx_supports_vSync) wglSwapIntervalEXT(vsync);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@ -1428,6 +1509,138 @@ void Window_CloseKeyboard(void) { }
|
||||
void Window_EnableRawMouse(void) { Window_DefaultEnableRawMouse(); }
|
||||
void Window_UpdateRawMouse(void) { Window_DefaultUpdateRawMouse(); }
|
||||
void Window_DisableRawMouse(void) { Window_DefaultDisableRawMouse(); }
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------glX OpenGL--------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#ifdef CC_BUILD_GL
|
||||
#include <GL/glx.h>
|
||||
static GLXContext ctx_handle;
|
||||
typedef int (*FN_GLXSWAPINTERVAL)(int interval);
|
||||
static FN_GLXSWAPINTERVAL swapIntervalMESA, swapIntervalSGI;
|
||||
static bool ctx_supports_vSync;
|
||||
|
||||
void GLContext_Init(struct GraphicsMode* mode) {
|
||||
static const String ext_mesa = String_FromConst("GLX_MESA_swap_control");
|
||||
static const String ext_sgi = String_FromConst("GLX_SGI_swap_control");
|
||||
|
||||
const char* raw_exts;
|
||||
String exts;
|
||||
ctx_handle = glXCreateContext(win_display, &win_visual, NULL, true);
|
||||
|
||||
if (!ctx_handle) {
|
||||
Platform_LogConst("Context create failed. Trying indirect...");
|
||||
ctx_handle = glXCreateContext(win_display, &win_visual, NULL, false);
|
||||
}
|
||||
if (!ctx_handle) Logger_Abort("Failed to create OpenGL context");
|
||||
|
||||
if (!glXIsDirect(win_display, ctx_handle)) {
|
||||
Platform_LogConst("== WARNING: Context is not direct ==");
|
||||
}
|
||||
if (!glXMakeCurrent(win_display, win_handle, ctx_handle)) {
|
||||
Logger_Abort("Failed to make OpenGL context current.");
|
||||
}
|
||||
|
||||
/* GLX may return non-null function pointers that don't actually work */
|
||||
/* So we need to manually check the extensions string for support */
|
||||
raw_exts = glXQueryExtensionsString(win_display, win_screen);
|
||||
exts = String_FromReadonly(raw_exts);
|
||||
|
||||
if (String_CaselessContains(&exts, &ext_mesa)) {
|
||||
swapIntervalMESA = (FN_GLXSWAPINTERVAL)GLContext_GetAddress("glXSwapIntervalMESA");
|
||||
}
|
||||
if (String_CaselessContains(&exts, &ext_sgi)) {
|
||||
swapIntervalSGI = (FN_GLXSWAPINTERVAL)GLContext_GetAddress("glXSwapIntervalSGI");
|
||||
}
|
||||
ctx_supports_vSync = swapIntervalMESA || swapIntervalSGI;
|
||||
}
|
||||
|
||||
void GLContext_Update(void) { }
|
||||
bool GLContext_TryRestore(void) { return true; }
|
||||
void GLContext_Free(void) {
|
||||
if (!ctx_handle) return;
|
||||
glXMakeCurrent(win_display, None, NULL);
|
||||
glXDestroyContext(win_display, ctx_handle);
|
||||
ctx_handle = NULL;
|
||||
}
|
||||
|
||||
void* GLContext_GetAddress(const char* function) {
|
||||
void* address = glXGetProcAddress((const GLubyte*)function);
|
||||
return GLContext_IsInvalidAddress(address) ? NULL : address;
|
||||
}
|
||||
|
||||
bool GLContext_SwapBuffers(void) {
|
||||
glXSwapBuffers(win_display, win_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLContext_SetFpsLimit(bool vsync, float minFrameMs) {
|
||||
int res;
|
||||
if (!ctx_supports_vSync) return;
|
||||
|
||||
if (swapIntervalMESA) {
|
||||
res = swapIntervalMESA(vsync);
|
||||
} else {
|
||||
res = swapIntervalSGI(vsync);
|
||||
}
|
||||
if (res) Platform_Log1("Set VSync failed, error: %i", &res);
|
||||
}
|
||||
|
||||
static void GLContext_GetAttribs(struct GraphicsMode* mode, int* attribs) {
|
||||
int i = 0;
|
||||
/* See http://www-01.ibm.com/support/knowledgecenter/ssw_aix_61/com.ibm.aix.opengl/doc/openglrf/glXChooseFBConfig.htm%23glxchoosefbconfig */
|
||||
/* See http://www-01.ibm.com/support/knowledgecenter/ssw_aix_71/com.ibm.aix.opengl/doc/openglrf/glXChooseVisual.htm%23b5c84be452rree */
|
||||
/* for the attribute declarations. Note that the attributes are different than those used in glxChooseVisual */
|
||||
|
||||
if (!mode->IsIndexed) { attribs[i++] = GLX_RGBA; }
|
||||
attribs[i++] = GLX_RED_SIZE; attribs[i++] = mode->R;
|
||||
attribs[i++] = GLX_GREEN_SIZE; attribs[i++] = mode->G;
|
||||
attribs[i++] = GLX_BLUE_SIZE; attribs[i++] = mode->B;
|
||||
attribs[i++] = GLX_ALPHA_SIZE; attribs[i++] = mode->A;
|
||||
attribs[i++] = GLX_DEPTH_SIZE; attribs[i++] = GLCONTEXT_DEFAULT_DEPTH;
|
||||
|
||||
attribs[i++] = GLX_DOUBLEBUFFER;
|
||||
attribs[i++] = 0;
|
||||
}
|
||||
|
||||
static XVisualInfo GLContext_SelectVisual(struct GraphicsMode* mode) {
|
||||
int attribs[20];
|
||||
int major, minor;
|
||||
XVisualInfo* visual = NULL;
|
||||
|
||||
int fbcount;
|
||||
GLXFBConfig* fbconfigs;
|
||||
XVisualInfo info;
|
||||
|
||||
GLContext_GetAttribs(mode, attribs);
|
||||
if (!glXQueryVersion(win_display, &major, &minor)) {
|
||||
Logger_Abort("glXQueryVersion failed");
|
||||
}
|
||||
|
||||
if (major >= 1 && minor >= 3) {
|
||||
/* ChooseFBConfig returns an array of GLXFBConfig opaque structures */
|
||||
fbconfigs = glXChooseFBConfig(win_display, win_screen, attribs, &fbcount);
|
||||
if (fbconfigs && fbcount) {
|
||||
/* Use the first GLXFBConfig from the fbconfigs array (best match) */
|
||||
visual = glXGetVisualFromFBConfig(win_display, *fbconfigs);
|
||||
XFree(fbconfigs);
|
||||
}
|
||||
}
|
||||
|
||||
if (!visual) {
|
||||
Platform_LogConst("Falling back to glXChooseVisual.");
|
||||
visual = glXChooseVisual(win_display, win_screen, attribs);
|
||||
}
|
||||
if (!visual) {
|
||||
Logger_Abort("Requested GraphicsMode not available.");
|
||||
}
|
||||
|
||||
info = *visual;
|
||||
XFree(visual);
|
||||
return info;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@ -2024,7 +2237,165 @@ void Window_UpdateRawMouse(void) { Window_CentreMousePosition(); }
|
||||
void Window_DisableRawMouse(void) {
|
||||
CGAssociateMouseAndMouseCursorPosition(1);
|
||||
Window_DefaultDisableRawMouse();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------AGL OpenGL--------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#ifdef CC_BUILD_GL
|
||||
#include <AGL/agl.h>
|
||||
|
||||
static AGLContext ctx_handle;
|
||||
static bool ctx_firstFullscreen;
|
||||
static int ctx_windowWidth, ctx_windowHeight;
|
||||
|
||||
static void GLContext_Check(int code, const char* place) {
|
||||
ReturnCode res;
|
||||
if (code) return;
|
||||
|
||||
res = aglGetError();
|
||||
if (res) Logger_Abort2(res, place);
|
||||
}
|
||||
|
||||
static void GLContext_MakeCurrent(void) {
|
||||
int code = aglSetCurrentContext(ctx_handle);
|
||||
GLContext_Check(code, "Setting GL context");
|
||||
}
|
||||
|
||||
static void GLContext_SetDrawable(void) {
|
||||
CGrafPtr windowPort = GetWindowPort(win_handle);
|
||||
int code = aglSetDrawable(ctx_handle, windowPort);
|
||||
GLContext_Check(code, "Attaching GL context");
|
||||
}
|
||||
|
||||
static void GLContext_GetAttribs(struct GraphicsMode* mode, GLint* attribs, bool fullscreen) {
|
||||
int i = 0;
|
||||
|
||||
if (!mode->IsIndexed) { attribs[i++] = AGL_RGBA; }
|
||||
attribs[i++] = AGL_RED_SIZE; attribs[i++] = mode->R;
|
||||
attribs[i++] = AGL_GREEN_SIZE; attribs[i++] = mode->G;
|
||||
attribs[i++] = AGL_BLUE_SIZE; attribs[i++] = mode->B;
|
||||
attribs[i++] = AGL_ALPHA_SIZE; attribs[i++] = mode->A;
|
||||
attribs[i++] = AGL_DEPTH_SIZE; attribs[i++] = GLCONTEXT_DEFAULT_DEPTH;
|
||||
|
||||
attribs[i++] = AGL_DOUBLEBUFFER;
|
||||
if (fullscreen) { attribs[i++] = AGL_FULLSCREEN; }
|
||||
attribs[i++] = 0;
|
||||
}
|
||||
|
||||
static void GLContext_UnsetFullscreen(void) {
|
||||
int code;
|
||||
Platform_LogConst("Unsetting AGL fullscreen.");
|
||||
|
||||
code = aglSetDrawable(ctx_handle, NULL);
|
||||
GLContext_Check(code, "Unattaching GL context");
|
||||
code = aglUpdateContext(ctx_handle);
|
||||
GLContext_Check(code, "Updating GL context (from Fullscreen)");
|
||||
|
||||
CGDisplayRelease(CGMainDisplayID());
|
||||
GLContext_SetDrawable();
|
||||
|
||||
win_fullscreen = false;
|
||||
Window_SetSize(ctx_windowWidth, ctx_windowHeight);
|
||||
}
|
||||
|
||||
static void GLContext_SetFullscreen(void) {
|
||||
int displayWidth = Display_Bounds.Width;
|
||||
int displayHeight = Display_Bounds.Height;
|
||||
int code;
|
||||
|
||||
Platform_LogConst("Switching to AGL fullscreen");
|
||||
CGDisplayCapture(CGMainDisplayID());
|
||||
|
||||
code = aglSetFullScreen(ctx_handle, displayWidth, displayHeight, 0, 0);
|
||||
GLContext_Check(code, "aglSetFullScreen");
|
||||
GLContext_MakeCurrent();
|
||||
|
||||
/* This is a weird hack to workaround a bug where the first time a context */
|
||||
/* is made fullscreen, we just end up with a blank screen. So we undo it as fullscreen */
|
||||
/* and redo it as fullscreen. */
|
||||
if (!ctx_firstFullscreen) {
|
||||
ctx_firstFullscreen = true;
|
||||
GLContext_UnsetFullscreen();
|
||||
GLContext_SetFullscreen();
|
||||
return;
|
||||
}
|
||||
|
||||
win_fullscreen = true;
|
||||
ctx_windowWidth = Window_Width;
|
||||
ctx_windowHeight = Window_Height;
|
||||
|
||||
windowX = Display_Bounds.X; Window_Width = Display_Bounds.Width;
|
||||
windowY = Display_Bounds.Y; Window_Height = Display_Bounds.Height;
|
||||
}
|
||||
|
||||
void GLContext_Init(struct GraphicsMode* mode) {
|
||||
GLint attribs[20];
|
||||
AGLPixelFormat fmt;
|
||||
GDHandle gdevice;
|
||||
OSStatus res;
|
||||
|
||||
/* Initially try creating fullscreen compatible context */
|
||||
res = DMGetGDeviceByDisplayID(CGMainDisplayID(), &gdevice, false);
|
||||
if (res) Logger_Abort2(res, "Getting display device failed");
|
||||
|
||||
GLContext_GetAttribs(mode, attribs, true);
|
||||
fmt = aglChoosePixelFormat(&gdevice, 1, attribs);
|
||||
res = aglGetError();
|
||||
|
||||
/* Try again with non-compatible context if that fails */
|
||||
if (!fmt || res == AGL_BAD_PIXELFMT) {
|
||||
Platform_LogConst("Failed to create full screen pixel format.");
|
||||
Platform_LogConst("Trying again to create a non-fullscreen pixel format.");
|
||||
|
||||
GLContext_GetAttribs(mode, attribs, false);
|
||||
fmt = aglChoosePixelFormat(NULL, 0, attribs);
|
||||
res = aglGetError();
|
||||
}
|
||||
if (res) Logger_Abort2(res, "Choosing pixel format");
|
||||
|
||||
ctx_handle = aglCreateContext(fmt, NULL);
|
||||
GLContext_Check(0, "Creating GL context");
|
||||
|
||||
aglDestroyPixelFormat(fmt);
|
||||
GLContext_Check(0, "Destroying pixel format");
|
||||
|
||||
GLContext_SetDrawable();
|
||||
GLContext_Update();
|
||||
GLContext_MakeCurrent();
|
||||
}
|
||||
|
||||
void GLContext_Update(void) {
|
||||
if (win_fullscreen) return;
|
||||
GLContext_SetDrawable();
|
||||
aglUpdateContext(ctx_handle);
|
||||
}
|
||||
bool GLContext_TryRestore(void) { return true; }
|
||||
|
||||
void GLContext_Free(void) {
|
||||
if (!ctx_handle) return;
|
||||
aglSetCurrentContext(NULL);
|
||||
aglDestroyContext(ctx_handle);
|
||||
ctx_handle = NULL;
|
||||
}
|
||||
|
||||
void* GLContext_GetAddress(const char* function) {
|
||||
void* address = DynamicLib_GetFrom("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", function);
|
||||
return GLContext_IsInvalidAddress(address) ? NULL : address;
|
||||
}
|
||||
|
||||
bool GLContext_SwapBuffers(void) {
|
||||
aglSwapBuffers(ctx_handle);
|
||||
GLContext_Check(0, "Swapping buffers");
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLContext_SetFpsLimit(bool vsync, float minFrameMs) {
|
||||
int value = vsync ? 1 : 0;
|
||||
aglSetInteger(ctx_handle, AGL_SWAP_INTERVAL, &value);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@ -2337,6 +2708,48 @@ void Window_DisableRawMouse(void) {
|
||||
SDL_SetRelativeMouseMode(false);
|
||||
Input_RawMode = false;
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------SDL OpenGL--------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#ifdef CC_BUILD_GL
|
||||
static SDL_GLContext win_ctx;
|
||||
|
||||
void GLContext_Init(struct GraphicsMode* mode) {
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, mode->R);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, mode->G);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, mode->B);
|
||||
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, mode->A);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, GLCONTEXT_DEFAULT_DEPTH);
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, true);
|
||||
|
||||
win_ctx = SDL_GL_CreateContext(win_handle);
|
||||
if (!win_ctx) Window_SDLFail("creating OpenGL context");
|
||||
}
|
||||
|
||||
void GLContext_Update(void) { }
|
||||
bool GLContext_TryRestore(void) { return true; }
|
||||
void GLContext_Free(void) {
|
||||
SDL_GL_DeleteContext(win_ctx);
|
||||
win_ctx = NULL;
|
||||
}
|
||||
|
||||
void* GLContext_GetAddress(const char* function) {
|
||||
return SDL_GL_GetProcAddress(function);
|
||||
}
|
||||
|
||||
bool GLContext_SwapBuffers(void) {
|
||||
SDL_GL_SwapWindow(win_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLContext_SetFpsLimit(bool vsync, float minFrameMs) {
|
||||
SDL_GL_SetSwapInterval(vsync);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@ -2733,6 +3146,56 @@ void Window_DisableRawMouse(void) {
|
||||
emscripten_exit_pointerlock();
|
||||
Input_RawMode = false;
|
||||
}
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*------------------------------------------------Emscripten WebGL context-------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#ifdef CC_BUILD_BGL
|
||||
#include "Graphics.h"
|
||||
static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx_handle;
|
||||
|
||||
static EM_BOOL GLContext_OnLost(int eventType, const void *reserved, void *userData) {
|
||||
Gfx_LoseContext("WebGL context lost");
|
||||
return 1;
|
||||
}
|
||||
|
||||
void GLContext_Init(struct GraphicsMode* mode) {
|
||||
EmscriptenWebGLContextAttributes attribs;
|
||||
emscripten_webgl_init_context_attributes(&attribs);
|
||||
attribs.alpha = false;
|
||||
attribs.depth = true;
|
||||
attribs.stencil = false;
|
||||
attribs.antialias = false;
|
||||
|
||||
ctx_handle = emscripten_webgl_create_context(NULL, &attribs);
|
||||
emscripten_webgl_make_context_current(ctx_handle);
|
||||
emscripten_set_webglcontextlost_callback("#canvas", NULL, 0, GLContext_OnLost);
|
||||
}
|
||||
|
||||
void GLContext_Update(void) {
|
||||
/* TODO: do we need to do something here.... ? */
|
||||
}
|
||||
bool GLContext_TryRestore(void) {
|
||||
return !emscripten_is_webgl_context_lost(ctx_handle);
|
||||
}
|
||||
|
||||
void GLContext_Free(void) {
|
||||
emscripten_webgl_destroy_context(ctx_handle);
|
||||
emscripten_set_webglcontextlost_callback("#canvas", NULL, 0, NULL);
|
||||
}
|
||||
|
||||
void* GLContext_GetAddress(const char* function) { return NULL; }
|
||||
bool GLContext_SwapBuffers(void) { return true; /* Browser implicitly does this */ }
|
||||
|
||||
void GLContext_SetFpsLimit(bool vsync, float minFrameMs) {
|
||||
if (vsync) {
|
||||
emscripten_set_main_loop_timing(EM_TIMING_RAF, 1);
|
||||
} else {
|
||||
emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, (int)minFrameMs);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*########################################################################################################################*
|
||||
@ -3078,428 +3541,12 @@ void Window_CloseKeyboard(void) {
|
||||
void Window_EnableRawMouse(void) { Window_DefaultEnableRawMouse(); }
|
||||
void Window_UpdateRawMouse(void) { }
|
||||
void Window_DisableRawMouse(void) { Window_DefaultDisableRawMouse(); }
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CC_BUILD_GL
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------WGL OpenGL--------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#ifdef CC_BUILD_WGL
|
||||
static HGLRC ctx_handle;
|
||||
static HDC ctx_DC;
|
||||
typedef BOOL (WINAPI *FN_WGLSWAPINTERVAL)(int interval);
|
||||
static FN_WGLSWAPINTERVAL wglSwapIntervalEXT;
|
||||
static bool ctx_supports_vSync;
|
||||
|
||||
static void GLContext_SelectGraphicsMode(struct GraphicsMode* mode) {
|
||||
PIXELFORMATDESCRIPTOR pfd = { 0 };
|
||||
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
pfd.nVersion = 1;
|
||||
pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
|
||||
/* TODO: PFD_SUPPORT_COMPOSITION FLAG? CHECK IF IT WORKS ON XP */
|
||||
pfd.cColorBits = mode->R + mode->G + mode->B;
|
||||
pfd.cDepthBits = GLCONTEXT_DEFAULT_DEPTH;
|
||||
|
||||
pfd.iPixelType = mode->IsIndexed ? PFD_TYPE_COLORINDEX : PFD_TYPE_RGBA;
|
||||
pfd.cRedBits = mode->R;
|
||||
pfd.cGreenBits = mode->G;
|
||||
pfd.cBlueBits = mode->B;
|
||||
pfd.cAlphaBits = mode->A;
|
||||
|
||||
int modeIndex = ChoosePixelFormat(win_DC, &pfd);
|
||||
if (modeIndex == 0) { Logger_Abort("Requested graphics mode not available"); }
|
||||
|
||||
Mem_Set(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
|
||||
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
|
||||
pfd.nVersion = 1;
|
||||
|
||||
DescribePixelFormat(win_DC, modeIndex, pfd.nSize, &pfd);
|
||||
if (!SetPixelFormat(win_DC, modeIndex, &pfd)) {
|
||||
Logger_Abort2(GetLastError(), "SetPixelFormat failed");
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext_Init(struct GraphicsMode* mode) {
|
||||
GLContext_SelectGraphicsMode(mode);
|
||||
ctx_handle = wglCreateContext(win_DC);
|
||||
if (!ctx_handle) {
|
||||
ctx_handle = wglCreateContext(win_DC);
|
||||
}
|
||||
if (!ctx_handle) {
|
||||
Logger_Abort2(GetLastError(), "Failed to create OpenGL context");
|
||||
}
|
||||
|
||||
if (!wglMakeCurrent(win_DC, ctx_handle)) {
|
||||
Logger_Abort2(GetLastError(), "Failed to make OpenGL context current");
|
||||
}
|
||||
|
||||
ctx_DC = wglGetCurrentDC();
|
||||
wglSwapIntervalEXT = (FN_WGLSWAPINTERVAL)GLContext_GetAddress("wglSwapIntervalEXT");
|
||||
ctx_supports_vSync = wglSwapIntervalEXT != NULL;
|
||||
}
|
||||
|
||||
void GLContext_Update(void) { }
|
||||
bool GLContext_TryRestore(void) { return true; }
|
||||
void GLContext_Free(void) {
|
||||
if (!ctx_handle) return;
|
||||
wglDeleteContext(ctx_handle);
|
||||
ctx_handle = NULL;
|
||||
}
|
||||
|
||||
void* GLContext_GetAddress(const char* function) {
|
||||
void* address = wglGetProcAddress(function);
|
||||
return GLContext_IsInvalidAddress(address) ? NULL : address;
|
||||
}
|
||||
|
||||
bool GLContext_SwapBuffers(void) {
|
||||
if (!SwapBuffers(ctx_DC)) Logger_Abort2(GetLastError(), "Failed to swap buffers");
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLContext_SetFpsLimit(bool vsync, float minFrameMs) {
|
||||
if (ctx_supports_vSync) wglSwapIntervalEXT(vsync);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------glX OpenGL--------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#ifdef CC_BUILD_GLX
|
||||
#include <GL/glx.h>
|
||||
static GLXContext ctx_handle;
|
||||
typedef int (*FN_GLXSWAPINTERVAL)(int interval);
|
||||
static FN_GLXSWAPINTERVAL swapIntervalMESA, swapIntervalSGI;
|
||||
static bool ctx_supports_vSync;
|
||||
|
||||
void GLContext_Init(struct GraphicsMode* mode) {
|
||||
static const String ext_mesa = String_FromConst("GLX_MESA_swap_control");
|
||||
static const String ext_sgi = String_FromConst("GLX_SGI_swap_control");
|
||||
|
||||
const char* raw_exts;
|
||||
String exts;
|
||||
ctx_handle = glXCreateContext(win_display, &win_visual, NULL, true);
|
||||
|
||||
if (!ctx_handle) {
|
||||
Platform_LogConst("Context create failed. Trying indirect...");
|
||||
ctx_handle = glXCreateContext(win_display, &win_visual, NULL, false);
|
||||
}
|
||||
if (!ctx_handle) Logger_Abort("Failed to create OpenGL context");
|
||||
|
||||
if (!glXIsDirect(win_display, ctx_handle)) {
|
||||
Platform_LogConst("== WARNING: Context is not direct ==");
|
||||
}
|
||||
if (!glXMakeCurrent(win_display, win_handle, ctx_handle)) {
|
||||
Logger_Abort("Failed to make OpenGL context current.");
|
||||
}
|
||||
|
||||
/* GLX may return non-null function pointers that don't actually work */
|
||||
/* So we need to manually check the extensions string for support */
|
||||
raw_exts = glXQueryExtensionsString(win_display, win_screen);
|
||||
exts = String_FromReadonly(raw_exts);
|
||||
|
||||
if (String_CaselessContains(&exts, &ext_mesa)) {
|
||||
swapIntervalMESA = (FN_GLXSWAPINTERVAL)GLContext_GetAddress("glXSwapIntervalMESA");
|
||||
}
|
||||
if (String_CaselessContains(&exts, &ext_sgi)) {
|
||||
swapIntervalSGI = (FN_GLXSWAPINTERVAL)GLContext_GetAddress("glXSwapIntervalSGI");
|
||||
}
|
||||
ctx_supports_vSync = swapIntervalMESA || swapIntervalSGI;
|
||||
}
|
||||
|
||||
void GLContext_Update(void) { }
|
||||
bool GLContext_TryRestore(void) { return true; }
|
||||
void GLContext_Free(void) {
|
||||
if (!ctx_handle) return;
|
||||
glXMakeCurrent(win_display, None, NULL);
|
||||
glXDestroyContext(win_display, ctx_handle);
|
||||
ctx_handle = NULL;
|
||||
}
|
||||
|
||||
void* GLContext_GetAddress(const char* function) {
|
||||
void* address = glXGetProcAddress((const GLubyte*)function);
|
||||
return GLContext_IsInvalidAddress(address) ? NULL : address;
|
||||
}
|
||||
|
||||
bool GLContext_SwapBuffers(void) {
|
||||
glXSwapBuffers(win_display, win_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLContext_SetFpsLimit(bool vsync, float minFrameMs) {
|
||||
int res;
|
||||
if (!ctx_supports_vSync) return;
|
||||
|
||||
if (swapIntervalMESA) {
|
||||
res = swapIntervalMESA(vsync);
|
||||
} else {
|
||||
res = swapIntervalSGI(vsync);
|
||||
}
|
||||
if (res) Platform_Log1("Set VSync failed, error: %i", &res);
|
||||
}
|
||||
|
||||
static void GLContext_GetAttribs(struct GraphicsMode* mode, int* attribs) {
|
||||
int i = 0;
|
||||
/* See http://www-01.ibm.com/support/knowledgecenter/ssw_aix_61/com.ibm.aix.opengl/doc/openglrf/glXChooseFBConfig.htm%23glxchoosefbconfig */
|
||||
/* See http://www-01.ibm.com/support/knowledgecenter/ssw_aix_71/com.ibm.aix.opengl/doc/openglrf/glXChooseVisual.htm%23b5c84be452rree */
|
||||
/* for the attribute declarations. Note that the attributes are different than those used in glxChooseVisual */
|
||||
|
||||
if (!mode->IsIndexed) { attribs[i++] = GLX_RGBA; }
|
||||
attribs[i++] = GLX_RED_SIZE; attribs[i++] = mode->R;
|
||||
attribs[i++] = GLX_GREEN_SIZE; attribs[i++] = mode->G;
|
||||
attribs[i++] = GLX_BLUE_SIZE; attribs[i++] = mode->B;
|
||||
attribs[i++] = GLX_ALPHA_SIZE; attribs[i++] = mode->A;
|
||||
attribs[i++] = GLX_DEPTH_SIZE; attribs[i++] = GLCONTEXT_DEFAULT_DEPTH;
|
||||
|
||||
attribs[i++] = GLX_DOUBLEBUFFER;
|
||||
attribs[i++] = 0;
|
||||
}
|
||||
|
||||
static XVisualInfo GLContext_SelectVisual(struct GraphicsMode* mode) {
|
||||
int attribs[20];
|
||||
int major, minor;
|
||||
XVisualInfo* visual = NULL;
|
||||
|
||||
int fbcount;
|
||||
GLXFBConfig* fbconfigs;
|
||||
XVisualInfo info;
|
||||
|
||||
GLContext_GetAttribs(mode, attribs);
|
||||
if (!glXQueryVersion(win_display, &major, &minor)) {
|
||||
Logger_Abort("glXQueryVersion failed");
|
||||
}
|
||||
|
||||
if (major >= 1 && minor >= 3) {
|
||||
/* ChooseFBConfig returns an array of GLXFBConfig opaque structures */
|
||||
fbconfigs = glXChooseFBConfig(win_display, win_screen, attribs, &fbcount);
|
||||
if (fbconfigs && fbcount) {
|
||||
/* Use the first GLXFBConfig from the fbconfigs array (best match) */
|
||||
visual = glXGetVisualFromFBConfig(win_display, *fbconfigs);
|
||||
XFree(fbconfigs);
|
||||
}
|
||||
}
|
||||
|
||||
if (!visual) {
|
||||
Platform_LogConst("Falling back to glXChooseVisual.");
|
||||
visual = glXChooseVisual(win_display, win_screen, attribs);
|
||||
}
|
||||
if (!visual) {
|
||||
Logger_Abort("Requested GraphicsMode not available.");
|
||||
}
|
||||
|
||||
info = *visual;
|
||||
XFree(visual);
|
||||
return info;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------AGL OpenGL--------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#ifdef CC_BUILD_AGL
|
||||
#include <AGL/agl.h>
|
||||
|
||||
static AGLContext ctx_handle;
|
||||
static bool ctx_firstFullscreen;
|
||||
static int ctx_windowWidth, ctx_windowHeight;
|
||||
|
||||
static void GLContext_Check(int code, const char* place) {
|
||||
ReturnCode res;
|
||||
if (code) return;
|
||||
|
||||
res = aglGetError();
|
||||
if (res) Logger_Abort2(res, place);
|
||||
}
|
||||
|
||||
static void GLContext_MakeCurrent(void) {
|
||||
int code = aglSetCurrentContext(ctx_handle);
|
||||
GLContext_Check(code, "Setting GL context");
|
||||
}
|
||||
|
||||
static void GLContext_SetDrawable(void) {
|
||||
CGrafPtr windowPort = GetWindowPort(win_handle);
|
||||
int code = aglSetDrawable(ctx_handle, windowPort);
|
||||
GLContext_Check(code, "Attaching GL context");
|
||||
}
|
||||
|
||||
static void GLContext_GetAttribs(struct GraphicsMode* mode, GLint* attribs, bool fullscreen) {
|
||||
int i = 0;
|
||||
|
||||
if (!mode->IsIndexed) { attribs[i++] = AGL_RGBA; }
|
||||
attribs[i++] = AGL_RED_SIZE; attribs[i++] = mode->R;
|
||||
attribs[i++] = AGL_GREEN_SIZE; attribs[i++] = mode->G;
|
||||
attribs[i++] = AGL_BLUE_SIZE; attribs[i++] = mode->B;
|
||||
attribs[i++] = AGL_ALPHA_SIZE; attribs[i++] = mode->A;
|
||||
attribs[i++] = AGL_DEPTH_SIZE; attribs[i++] = GLCONTEXT_DEFAULT_DEPTH;
|
||||
|
||||
attribs[i++] = AGL_DOUBLEBUFFER;
|
||||
if (fullscreen) { attribs[i++] = AGL_FULLSCREEN; }
|
||||
attribs[i++] = 0;
|
||||
}
|
||||
|
||||
static void GLContext_UnsetFullscreen(void) {
|
||||
int code;
|
||||
Platform_LogConst("Unsetting AGL fullscreen.");
|
||||
|
||||
code = aglSetDrawable(ctx_handle, NULL);
|
||||
GLContext_Check(code, "Unattaching GL context");
|
||||
code = aglUpdateContext(ctx_handle);
|
||||
GLContext_Check(code, "Updating GL context (from Fullscreen)");
|
||||
|
||||
CGDisplayRelease(CGMainDisplayID());
|
||||
GLContext_SetDrawable();
|
||||
|
||||
win_fullscreen = false;
|
||||
Window_SetSize(ctx_windowWidth, ctx_windowHeight);
|
||||
}
|
||||
|
||||
static void GLContext_SetFullscreen(void) {
|
||||
int displayWidth = Display_Bounds.Width;
|
||||
int displayHeight = Display_Bounds.Height;
|
||||
int code;
|
||||
|
||||
Platform_LogConst("Switching to AGL fullscreen");
|
||||
CGDisplayCapture(CGMainDisplayID());
|
||||
|
||||
code = aglSetFullScreen(ctx_handle, displayWidth, displayHeight, 0, 0);
|
||||
GLContext_Check(code, "aglSetFullScreen");
|
||||
GLContext_MakeCurrent();
|
||||
|
||||
/* This is a weird hack to workaround a bug where the first time a context */
|
||||
/* is made fullscreen, we just end up with a blank screen. So we undo it as fullscreen */
|
||||
/* and redo it as fullscreen. */
|
||||
if (!ctx_firstFullscreen) {
|
||||
ctx_firstFullscreen = true;
|
||||
GLContext_UnsetFullscreen();
|
||||
GLContext_SetFullscreen();
|
||||
return;
|
||||
}
|
||||
|
||||
win_fullscreen = true;
|
||||
ctx_windowWidth = Window_Width;
|
||||
ctx_windowHeight = Window_Height;
|
||||
|
||||
windowX = Display_Bounds.X; Window_Width = Display_Bounds.Width;
|
||||
windowY = Display_Bounds.Y; Window_Height = Display_Bounds.Height;
|
||||
}
|
||||
|
||||
void GLContext_Init(struct GraphicsMode* mode) {
|
||||
GLint attribs[20];
|
||||
AGLPixelFormat fmt;
|
||||
GDHandle gdevice;
|
||||
OSStatus res;
|
||||
|
||||
/* Initially try creating fullscreen compatible context */
|
||||
res = DMGetGDeviceByDisplayID(CGMainDisplayID(), &gdevice, false);
|
||||
if (res) Logger_Abort2(res, "Getting display device failed");
|
||||
|
||||
GLContext_GetAttribs(mode, attribs, true);
|
||||
fmt = aglChoosePixelFormat(&gdevice, 1, attribs);
|
||||
res = aglGetError();
|
||||
|
||||
/* Try again with non-compatible context if that fails */
|
||||
if (!fmt || res == AGL_BAD_PIXELFMT) {
|
||||
Platform_LogConst("Failed to create full screen pixel format.");
|
||||
Platform_LogConst("Trying again to create a non-fullscreen pixel format.");
|
||||
|
||||
GLContext_GetAttribs(mode, attribs, false);
|
||||
fmt = aglChoosePixelFormat(NULL, 0, attribs);
|
||||
res = aglGetError();
|
||||
}
|
||||
if (res) Logger_Abort2(res, "Choosing pixel format");
|
||||
|
||||
ctx_handle = aglCreateContext(fmt, NULL);
|
||||
GLContext_Check(0, "Creating GL context");
|
||||
|
||||
aglDestroyPixelFormat(fmt);
|
||||
GLContext_Check(0, "Destroying pixel format");
|
||||
|
||||
GLContext_SetDrawable();
|
||||
GLContext_Update();
|
||||
GLContext_MakeCurrent();
|
||||
}
|
||||
|
||||
void GLContext_Update(void) {
|
||||
if (win_fullscreen) return;
|
||||
GLContext_SetDrawable();
|
||||
aglUpdateContext(ctx_handle);
|
||||
}
|
||||
bool GLContext_TryRestore(void) { return true; }
|
||||
|
||||
void GLContext_Free(void) {
|
||||
if (!ctx_handle) return;
|
||||
aglSetCurrentContext(NULL);
|
||||
aglDestroyContext(ctx_handle);
|
||||
ctx_handle = NULL;
|
||||
}
|
||||
|
||||
void* GLContext_GetAddress(const char* function) {
|
||||
void* address = DynamicLib_GetFrom("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", function);
|
||||
return GLContext_IsInvalidAddress(address) ? NULL : address;
|
||||
}
|
||||
|
||||
bool GLContext_SwapBuffers(void) {
|
||||
aglSwapBuffers(ctx_handle);
|
||||
GLContext_Check(0, "Swapping buffers");
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLContext_SetFpsLimit(bool vsync, float minFrameMs) {
|
||||
int value = vsync ? 1 : 0;
|
||||
aglSetInteger(ctx_handle, AGL_SWAP_INTERVAL, &value);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------SDL OpenGL--------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#ifdef CC_BUILD_SDL
|
||||
#include <SDL2/SDL.h>
|
||||
static SDL_GLContext win_ctx;
|
||||
|
||||
void GLContext_Init(struct GraphicsMode* mode) {
|
||||
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, mode->R);
|
||||
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, mode->G);
|
||||
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, mode->B);
|
||||
SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, mode->A);
|
||||
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, GLCONTEXT_DEFAULT_DEPTH);
|
||||
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 0);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, true);
|
||||
|
||||
win_ctx = SDL_GL_CreateContext(win_handle);
|
||||
if (!win_ctx) Window_SDLFail("creating OpenGL context");
|
||||
}
|
||||
|
||||
void GLContext_Update(void) { }
|
||||
bool GLContext_TryRestore(void) { return true; }
|
||||
void GLContext_Free(void) {
|
||||
SDL_GL_DeleteContext(win_ctx);
|
||||
win_ctx = NULL;
|
||||
}
|
||||
|
||||
void* GLContext_GetAddress(const char* function) {
|
||||
return SDL_GL_GetProcAddress(function);
|
||||
}
|
||||
|
||||
bool GLContext_SwapBuffers(void) {
|
||||
SDL_GL_SwapWindow(win_handle);
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLContext_SetFpsLimit(bool vsync, float minFrameMs) {
|
||||
SDL_GL_SetSwapInterval(vsync);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*-------------------------------------------------------EGL OpenGL--------------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#ifdef CC_BUILD_EGL
|
||||
#ifdef CC_BUILD_GL
|
||||
#include <EGL/egl.h>
|
||||
static EGLDisplay ctx_display;
|
||||
static EGLContext ctx_context;
|
||||
@ -3507,14 +3554,6 @@ static EGLSurface ctx_surface;
|
||||
static EGLConfig ctx_config;
|
||||
static EGLint ctx_numConfig;
|
||||
|
||||
/*static XVisualInfo GLContext_SelectVisual(struct GraphicsMode* mode) {
|
||||
XVisualInfo info = { 0 };
|
||||
info.depth = 24;
|
||||
info.visual = CopyFromParent;
|
||||
info.visualid = CopyFromParent;
|
||||
return info;
|
||||
}*/
|
||||
|
||||
static void GLContext_InitSurface(void) {
|
||||
if (!win_handle) return; /* window not created or lost */
|
||||
ctx_surface = eglCreateWindowSurface(ctx_display, ctx_config, win_handle, NULL);
|
||||
@ -3591,60 +3630,7 @@ void GLContext_SetFpsLimit(bool vsync, float minFrameMs) {
|
||||
eglSwapInterval(ctx_display, vsync);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*########################################################################################################################*
|
||||
*------------------------------------------------Emscripten WebGL context-------------------------------------------------*
|
||||
*#########################################################################################################################*/
|
||||
#ifdef CC_BUILD_WEBGL
|
||||
#include "Graphics.h"
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <emscripten/html5.h>
|
||||
static EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx_handle;
|
||||
|
||||
static EM_BOOL GLContext_OnLost(int eventType, const void *reserved, void *userData) {
|
||||
Gfx_LoseContext("WebGL context lost");
|
||||
return 1;
|
||||
}
|
||||
|
||||
void GLContext_Init(struct GraphicsMode* mode) {
|
||||
EmscriptenWebGLContextAttributes attribs;
|
||||
emscripten_webgl_init_context_attributes(&attribs);
|
||||
attribs.alpha = false;
|
||||
attribs.depth = true;
|
||||
attribs.stencil = false;
|
||||
attribs.antialias = false;
|
||||
|
||||
ctx_handle = emscripten_webgl_create_context(NULL, &attribs);
|
||||
emscripten_webgl_make_context_current(ctx_handle);
|
||||
emscripten_set_webglcontextlost_callback("#canvas", NULL, 0, GLContext_OnLost);
|
||||
}
|
||||
|
||||
void GLContext_Update(void) {
|
||||
/* TODO: do we need to do something here.... ? */
|
||||
}
|
||||
bool GLContext_TryRestore(void) {
|
||||
return !emscripten_is_webgl_context_lost(ctx_handle);
|
||||
}
|
||||
|
||||
void GLContext_Free(void) {
|
||||
emscripten_webgl_destroy_context(ctx_handle);
|
||||
emscripten_set_webglcontextlost_callback("#canvas", NULL, 0, NULL);
|
||||
}
|
||||
|
||||
void* GLContext_GetAddress(const char* function) { return NULL; }
|
||||
bool GLContext_SwapBuffers(void) { return true; /* Browser implicitly does this */ }
|
||||
|
||||
void GLContext_SetFpsLimit(bool vsync, float minFrameMs) {
|
||||
if (vsync) {
|
||||
emscripten_set_main_loop_timing(EM_TIMING_RAF, 1);
|
||||
} else {
|
||||
emscripten_set_main_loop_timing(EM_TIMING_SETTIMEOUT, (int)minFrameMs);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef CC_BUILD_COCOA
|
||||
|
Loading…
x
Reference in New Issue
Block a user