From c7c552e27f77422ca143efa79e318fc51f093a83 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 19 Mar 2019 18:28:40 +1100 Subject: [PATCH] Decouple window system from OpenGL context system --- src/Core.h | 46 +-- src/Graphics.c | 2 +- src/Window.c | 841 +++++++++++++++++++++++++------------------------ 3 files changed, 452 insertions(+), 437 deletions(-) diff --git a/src/Core.h b/src/Core.h index 3122bfc1e..d0990b4eb 100644 --- a/src/Core.h +++ b/src/Core.h @@ -80,43 +80,45 @@ typedef struct TextureRec_ { float U1, V1, U2, V2; } TextureRec; /*#define CC_BUILD_GL11*/ #ifndef CC_BUILD_MANUAL -#ifdef _WIN32 -#define CC_BUILD_D3D9 +#if defined _WIN32 #define CC_BUILD_WIN -#endif -#ifdef __linux__ +#define CC_BUILD_D3D9 +#define CC_BUILD_WINGUI +#define CC_BUILD_WGL +#elif defined __linux__ #define CC_BUILD_LINUX -#define CC_BUILD_X11 #define CC_BUILD_POSIX -#endif -#ifdef __APPLE__ +#define CC_BUILD_X11 +#define CC_BUILD_GLX +#elif defined __APPLE__ #define CC_BUILD_OSX #define CC_BUILD_POSIX -#endif -#ifdef __sun__ +#define CC_BUILD_CARBON +#define CC_BUILD_AGL +#elif defined __sun__ #define CC_BUILD_SOLARIS -#define CC_BUILD_X11 #define CC_BUILD_POSIX -#endif -#ifdef __FreeBSD__ +#define CC_BUILD_X11 +#define CC_BUILD_GLX +#elif defined __FreeBSD__ #define CC_BUILD_FREEBSD -#define CC_BUILD_X11 #define CC_BUILD_POSIX -#endif -#ifdef __OpenBSD__ +#define CC_BUILD_X11 +#define CC_BUILD_GLX +#elif defined __OpenBSD__ #define CC_BUILD_OPENBSD -#define CC_BUILD_X11 #define CC_BUILD_POSIX -#endif -#ifdef __NetBSD__ +#define CC_BUILD_X11 +#define CC_BUILD_GLX +#elif defined __NetBSD__ #define CC_BUILD_NETBSD +#define CC_BUILD_POSIX #define CC_BUILD_X11 -#define CC_BUILD_POSIX -#endif -#ifdef __EMSCRIPTEN__ +#define CC_BUILD_GLX +#elif defined __EMSCRIPTEN__ #define CC_BUILD_WEB -#define CC_BUILD_SDL #define CC_BUILD_POSIX +#define CC_BUILD_SDL #define CC_BUILD_GLMODERN #error "Web backend is still a WIP. Please do not publicly mention it, thanks." #endif diff --git a/src/Graphics.c b/src/Graphics.c index b34db2c56..7e6836917 100644 --- a/src/Graphics.c +++ b/src/Graphics.c @@ -1225,7 +1225,7 @@ void Gfx_DeleteIb(GfxResourceID* ib) { void Gfx_SetDynamicVbData(GfxResourceID vb, void* vertices, int vCount) { uint32_t size = vCount * gfx_batchStride; - _glBindBuffer(GL_ARRAY_BUFFER, vb); + _glBindBuffer(GL_ARRAY_BUFFER, (GLuint)vb); _glBufferSubData(GL_ARRAY_BUFFER, 0, size, vertices); } #endif diff --git a/src/Window.c b/src/Window.c index 7ffdadcec..7b18bb7ad 100644 --- a/src/Window.c +++ b/src/Window.c @@ -95,7 +95,7 @@ void GraphicsMode_MakeDefault(struct GraphicsMode* m) { /*########################################################################################################################* *------------------------------------------------------Win32 window-------------------------------------------------------* *#########################################################################################################################*/ -#ifdef CC_BUILD_WIN +#ifdef CC_BUILD_WINGUI #define WIN32_LEAN_AND_MEAN #define NOSERVICE #define NOMCX @@ -655,90 +655,6 @@ void Window_DrawRaw(Rect2D r) { BOOL success = BitBlt(win_DC, r.X, r.Y, r.Width, r.Height, draw_DC, r.X, r.Y, SRCCOPY); SelectObject(draw_DC, oldSrc); } - - -/*########################################################################################################################* -*-----------------------------------------------------OpenGL context------------------------------------------------------* -*#########################################################################################################################*/ -#ifndef CC_BUILD_D3D9 -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.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; - - pfd.cDepthBits = mode->DepthBits; - pfd.cStencilBits = mode->StencilBits; - - 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"); - } -} - -static HGLRC ctx_Handle; -static HDC ctx_DC; -typedef BOOL (WINAPI *FN_WGLSWAPINTERVAL)(int interval); -static FN_WGLSWAPINTERVAL wglSwapIntervalEXT; -static bool ctx_supports_vSync; - -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) { } -void GLContext_Free(void) { - if (!wglDeleteContext(ctx_Handle)) { - Logger_Abort2(GetLastError(), "Failed to destroy OpenGL context"); - } - ctx_Handle = NULL; -} - -void* GLContext_GetAddress(const char* function) { - void* address = wglGetProcAddress(function); - return GLContext_IsInvalidAddress(address) ? NULL : address; -} - -void GLContext_SwapBuffers(void) { - if (!SwapBuffers(ctx_DC)) { - Logger_Abort2(GetLastError(), "Failed to swap buffers"); - } -} - -void GLContext_SetVSync(bool enabled) { - if (ctx_supports_vSync) wglSwapIntervalEXT(enabled); -} -#endif #endif @@ -747,7 +663,6 @@ void GLContext_SetVSync(bool enabled) { *#########################################################################################################################*/ #ifdef CC_BUILD_X11 #include -#include #define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_ADD 1 @@ -1635,150 +1550,13 @@ void Window_DrawRaw(Rect2D r) { XPutImage(win_display, win_handle, win_gc, win_image, r.X, r.Y, r.X, r.Y, r.Width, r.Height); } - - -/*########################################################################################################################* -*-----------------------------------------------------OpenGL context------------------------------------------------------* -*#########################################################################################################################*/ -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) { - const static String ext_mesa = String_FromConst("GLX_MESA_swap_control"); - const static 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) { } -void GLContext_Free(void) { - if (!ctx_Handle) return; - - if (glXGetCurrentContext() == ctx_Handle) { - glXMakeCurrent(win_display, None, NULL); - } - glXDestroyContext(win_display, ctx_Handle); - ctx_Handle = NULL; -} - -void* GLContext_GetAddress(const char* function) { - void* address = glXGetProcAddress(function); - return GLContext_IsInvalidAddress(address) ? NULL : address; -} - -void GLContext_SwapBuffers(void) { - glXSwapBuffers(win_display, win_handle); -} - -void GLContext_SetVSync(bool enabled) { - int res; - if (!ctx_supports_vSync) return; - - if (swapIntervalMESA) { - res = swapIntervalMESA(enabled); - } else { - res = swapIntervalSGI(enabled); - } - 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; - - if (mode->DepthBits) { - attribs[i++] = GLX_DEPTH_SIZE; attribs[i++] = mode->DepthBits; - } - if (mode->StencilBits) { - attribs[i++] = GLX_STENCIL_SIZE; attribs[i++] = mode->StencilBits; - } - - 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 /*########################################################################################################################* *------------------------------------------------------Carbon window------------------------------------------------------* *#########################################################################################################################*/ -#ifdef CC_BUILD_OSX -#include +#ifdef CC_BUILD_CARBON #include static WindowRef win_handle; @@ -2402,179 +2180,6 @@ void Window_DrawRaw(Rect2D r) { CGImageRelease(win_image); CGDataProviderRelease(provider); } - - -/*########################################################################################################################* -*-----------------------------------------------------OpenGL context------------------------------------------------------* -*#########################################################################################################################*/ -static AGLContext ctx_handle; -static bool ctx_fullscreen, ctx_firstFullscreen; -static Rect2D ctx_windowedBounds; - -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, int* 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; - - if (mode->DepthBits) { - attribs[i++] = AGL_DEPTH_SIZE; attribs[i++] = mode->DepthBits; - } - if (mode->StencilBits) { - attribs[i++] = AGL_STENCIL_SIZE; attribs[i++] = mode->StencilBits; - } - - 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(); - - ctx_fullscreen = false; - Window_UpdateWindowState(); - Window_SetSize(ctx_windowedBounds.Width, ctx_windowedBounds.Height); -} - -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; - } - - ctx_fullscreen = true; - ctx_windowedBounds = Window_ClientBounds; - - Window_ClientBounds = Display_Bounds; - Window_Bounds = Display_Bounds; - win_state = WINDOW_STATE_FULLSCREEN; -} - -void GLContext_Init(struct GraphicsMode* mode) { - int 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 (ctx_pendingFullscreen) { - ctx_pendingFullscreen = false; - GLContext_SetFullscreen(); - return; - } else if (ctx_pendingWindowed) { - ctx_pendingWindowed = false; - GLContext_UnsetFullscreen(); - } - - if (ctx_fullscreen) return; - GLContext_SetDrawable(); - aglUpdateContext(ctx_handle); -} - -void GLContext_Free(void) { - int code; - if (!ctx_handle) return; - - code = aglSetCurrentContext(NULL); - GLContext_Check(code, "Unsetting GL context"); - - code = aglDestroyContext(ctx_handle); - GLContext_Check(code, "Destroying GL context"); - 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; -} - -void GLContext_SwapBuffers(void) { - aglSwapBuffers(ctx_handle); - GLContext_Check(0, "Swapping buffers"); -} - -void GLContext_SetVSync(bool enabled) { - int value = enabled ? 1 : 0; - aglSetInteger(ctx_handle, AGL_SWAP_INTERVAL, &value); -} #endif @@ -2910,8 +2515,432 @@ void Window_DrawRaw(Rect2D r) { SDL_UpdateWindowSurfaceRects(win_handle, &rect, 1); } +void Window_EnableRawMouse(void) { + Window_RegrabMouse(); + SDL_SetRelativeMouseMode(true); + win_rawMouse = true; +} + +void Window_UpdateRawMouse(void) { + Window_CentreMousePosition(); +} + +void Window_DisableRawMouse(void) { + Window_RegrabMouse(); + SDL_SetRelativeMouseMode(false); + win_rawMouse = false; +} +#endif + + #ifndef CC_BUILD_D3D9 +/*########################################################################################################################* +*-------------------------------------------------------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.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; + + pfd.cDepthBits = mode->DepthBits; + pfd.cStencilBits = mode->StencilBits; + + 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) { } +void GLContext_Free(void) { + if (!wglDeleteContext(ctx_Handle)) { + Logger_Abort2(GetLastError(), "Failed to destroy OpenGL context"); + } + ctx_Handle = NULL; +} + +void* GLContext_GetAddress(const char* function) { + void* address = wglGetProcAddress(function); + return GLContext_IsInvalidAddress(address) ? NULL : address; +} + +void GLContext_SwapBuffers(void) { + if (!SwapBuffers(ctx_DC)) { + Logger_Abort2(GetLastError(), "Failed to swap buffers"); + } +} + +void GLContext_SetVSync(bool enabled) { + if (ctx_supports_vSync) wglSwapIntervalEXT(enabled); +} +#endif + + +/*########################################################################################################################* +*-------------------------------------------------------glX OpenGL--------------------------------------------------------* +*#########################################################################################################################*/ +#ifdef CC_BUILD_GLX +#include +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) { + const static String ext_mesa = String_FromConst("GLX_MESA_swap_control"); + const static 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) { } +void GLContext_Free(void) { + if (!ctx_Handle) return; + + if (glXGetCurrentContext() == ctx_Handle) { + glXMakeCurrent(win_display, None, NULL); + } + glXDestroyContext(win_display, ctx_Handle); + ctx_Handle = NULL; +} + +void* GLContext_GetAddress(const char* function) { + void* address = glXGetProcAddress(function); + return GLContext_IsInvalidAddress(address) ? NULL : address; +} + +void GLContext_SwapBuffers(void) { + glXSwapBuffers(win_display, win_handle); +} + +void GLContext_SetVSync(bool enabled) { + int res; + if (!ctx_supports_vSync) return; + + if (swapIntervalMESA) { + res = swapIntervalMESA(enabled); + } else { + res = swapIntervalSGI(enabled); + } + 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; + + if (mode->DepthBits) { + attribs[i++] = GLX_DEPTH_SIZE; attribs[i++] = mode->DepthBits; + } + if (mode->StencilBits) { + attribs[i++] = GLX_STENCIL_SIZE; attribs[i++] = mode->StencilBits; + } + + 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 + +static AGLContext ctx_handle; +static bool ctx_fullscreen, ctx_firstFullscreen; +static Rect2D ctx_windowedBounds; + +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, int* 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; + + if (mode->DepthBits) { + attribs[i++] = AGL_DEPTH_SIZE; attribs[i++] = mode->DepthBits; + } + if (mode->StencilBits) { + attribs[i++] = AGL_STENCIL_SIZE; attribs[i++] = mode->StencilBits; + } + + 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(); + + ctx_fullscreen = false; + Window_UpdateWindowState(); + Window_SetSize(ctx_windowedBounds.Width, ctx_windowedBounds.Height); +} + +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; + } + + ctx_fullscreen = true; + ctx_windowedBounds = Window_ClientBounds; + + Window_ClientBounds = Display_Bounds; + Window_Bounds = Display_Bounds; + win_state = WINDOW_STATE_FULLSCREEN; +} + +void GLContext_Init(struct GraphicsMode* mode) { + int 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 (ctx_pendingFullscreen) { + ctx_pendingFullscreen = false; + GLContext_SetFullscreen(); + return; + } else if (ctx_pendingWindowed) { + ctx_pendingWindowed = false; + GLContext_UnsetFullscreen(); + } + + if (ctx_fullscreen) return; + GLContext_SetDrawable(); + aglUpdateContext(ctx_handle); +} + +void GLContext_Free(void) { + int code; + if (!ctx_handle) return; + + code = aglSetCurrentContext(NULL); + GLContext_Check(code, "Unsetting GL context"); + + code = aglDestroyContext(ctx_handle); + GLContext_Check(code, "Destroying GL context"); + 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; +} + +void GLContext_SwapBuffers(void) { + aglSwapBuffers(ctx_handle); + GLContext_Check(0, "Swapping buffers"); +} + +void GLContext_SetVSync(bool enabled) { + int value = enabled ? 1 : 0; + aglSetInteger(ctx_handle, AGL_SWAP_INTERVAL, &value); +} +#endif + + +/*########################################################################################################################* +*-------------------------------------------------------SDL OpenGL--------------------------------------------------------* +*#########################################################################################################################*/ +#ifdef CC_BUILD_SDL +#include 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); @@ -2944,20 +2973,4 @@ void GLContext_SetVSync(bool enabled) { SDL_GL_SetSwapInterval(enabled); } #endif - -void Window_EnableRawMouse(void) { - Window_RegrabMouse(); - SDL_SetRelativeMouseMode(true); - win_rawMouse = true; -} - -void Window_UpdateRawMouse(void) { - Window_CentreMousePosition(); -} - -void Window_DisableRawMouse(void) { - Window_RegrabMouse(); - SDL_SetRelativeMouseMode(false); - win_rawMouse = false; -} -#endif +#endif \ No newline at end of file