win32 support for multisampling and sRGB
authorJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 30 May 2020 12:19:55 +0000 (15:19 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Sat, 30 May 2020 12:19:55 +0000 (15:19 +0300)
miniglut.c

index 32b3d12..cffa432 100644 (file)
@@ -1219,51 +1219,158 @@ void glutSetCursor(int cidx)
        }
 }
 
+#define WGL_DRAW_TO_WINDOW     0x2001
+#define WGL_SUPPORT_OPENGL     0x2010
+#define WGL_DOUBLE_BUFFER      0x2011
+#define WGL_STEREO                     0x2012
+#define WGL_PIXEL_TYPE         0x2013
+#define WGL_COLOR_BITS         0x2014
+#define WGL_RED_BITS           0x2015
+#define WGL_GREEN_BITS         0x2017
+#define WGL_BLUE_BITS          0x2019
+#define WGL_ALPHA_BITS         0x201b
+#define WGL_ACCUM_BITS         0x201d
+#define WGL_DEPTH_BITS         0x2022
+#define WGL_STENCIL_BITS       0x2023
+
+#define WGL_TYPE_RGBA          0x202b
+#define WGL_TYPE_COLORINDEX    0x202c
+
+#define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB       0x20a9
+#define WGL_SAMPLE_BUFFERS_ARB                         0x2041
+#define WGL_SAMPLES_ARB                                                0x2042
+
+static PROC wglChoosePixelFormat;
+static PROC wglGetPixelFormatAttribiv;
+
+#define ATTR(a, v) \
+       do { *aptr++ = (a); *aptr++ = (v); } while(0)
+
+static unsigned int choose_pixfmt(unsigned int mode)
+{
+       unsigned int num_pixfmt, pixfmt = 0;
+       int attr[32] = { WGL_DRAW_TO_WINDOW, 1, WGL_SUPPORT_OPENGL, 1 };
 
-static void create_window(const char *title)
-{
-       int pixfmt;
-       PIXELFORMATDESCRIPTOR pfd = {0};
-       RECT rect;
+       int *aptr = attr;
+       int *samples = 0;
 
-       rect.left = init_x;
-       rect.top = init_y;
-       rect.right = init_x + init_width;
-       rect.bottom = init_y + init_height;
-       AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, 0);
+       if(mode & GLUT_DOUBLE) {
+               ATTR(WGL_DOUBLE_BUFFER, 1);
+       }
 
-       if(!(win = CreateWindow("MiniGLUT", title, WS_OVERLAPPEDWINDOW, rect.left, rect.top,
-                               rect.right - rect.left, rect.bottom - rect.top, 0, 0, hinst, 0))) {
-               panic("Failed to create window\n");
+       ATTR(WGL_PIXEL_TYPE, mode & GLUT_INDEX ? WGL_TYPE_COLORINDEX : WGL_TYPE_RGBA);
+       ATTR(WGL_COLOR_BITS, 8);
+       if(mode & GLUT_ALPHA) {
+               ATTR(WGL_ALPHA_BITS, 4);
        }
-       dc = GetDC(win);
+       if(mode & GLUT_DEPTH) {
+               ATTR(WGL_DEPTH_BITS, 16);
+       }
+       if(mode & GLUT_STENCIL) {
+               ATTR(WGL_STENCIL_BITS, 1);
+       }
+       if(mode & GLUT_ACCUM) {
+               ATTR(WGL_ACCUM_BITS, 1);
+       }
+       if(mode & GLUT_STEREO) {
+               ATTR(WGL_STEREO, 1);
+       }
+       if(mode & GLUT_SRGB) {
+               ATTR(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, 1);
+       }
+       if(mode & GLUT_MULTISAMPLE) {
+               ATTR(WGL_SAMPLE_BUFFERS_ARB, 1);
+               *aptr++ = WGL_SAMPLES_ARB;
+               samples = aptr;
+               *aptr++ = 32;
+       }
+       *aptr++ = 0;
 
-       pfd.nSize = sizeof pfd;
-       pfd.nVersion = 1;
-       pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
-       if(init_mode & GLUT_STEREO) {
-               pfd.dwFlags |= PFD_STEREO;
+       while(!wglChoosePixelFormat(dc, attr, 0, 1, &pixfmt, &num_pixfmt) && samples && *samples) {
+               *samples >>= 1;
+               if(!*samples) {
+                       aptr[-3] = 0;
+               }
        }
-       pfd.iPixelType = init_mode & GLUT_INDEX ? PFD_TYPE_COLORINDEX : PFD_TYPE_RGBA;
-       pfd.cColorBits = 24;
-       if(init_mode & GLUT_ALPHA) {
-               pfd.cAlphaBits = 8;
+       return pixfmt;
+}
+
+static PIXELFORMATDESCRIPTOR tmppfd = {
+       sizeof tmppfd, 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
+       PFD_TYPE_RGBA, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24, 8, 0,
+       PFD_MAIN_PLANE, 0, 0, 0, 0
+};
+#define TMPCLASS       "TempMiniGLUT"
+
+#define GETATTR(attr, vptr) \
+       do { \
+               int gattr = attr; \
+               wglGetPixelFormatAttribiv(dc, pixfmt, 0, 1, &gattr, vptr); \
+       } while(0)
+
+static int create_window_wglext(const char *title, int width, int height)
+{
+       WNDCLASSEX wc = {0};
+       HWND tmpwin = 0;
+       HDC tmpdc = 0;
+       HGLRC tmpctx = 0;
+       int pixfmt;
+
+       /* create a temporary window and GL context, just to query and retrieve
+        * the wglChoosePixelFormatEXT function
+        */
+       wc.cbSize = sizeof wc;
+       wc.hbrBackground = GetStockObject(BLACK_BRUSH);
+       wc.hCursor = LoadCursor(0, IDC_ARROW);
+       wc.hIcon = wc.hIconSm = LoadIcon(0, IDI_APPLICATION);
+       wc.hInstance = hinst;
+       wc.lpfnWndProc = DefWindowProc;
+       wc.lpszClassName = TMPCLASS;
+       wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+       if(!RegisterClassEx(&wc)) {
+               return 0;
+       }
+       if(!(tmpwin = CreateWindow(TMPCLASS, "temp", WS_OVERLAPPEDWINDOW, 0, 0,
+                                       width, height, 0, 0, hinst, 0))) {
+               goto fail;
        }
-       if(init_mode & GLUT_ACCUM) {
-               pfd.cAccumBits = 24;
+       tmpdc = GetDC(tmpwin);
+
+       if(!(pixfmt = ChoosePixelFormat(dc, &tmppfd)) ||
+                       !SetPixelFormat(dc, pixfmt, &tmppfd) ||
+                       !(tmpctx = wglCreateContext(tmpdc))) {
+               goto fail;
        }
-       if(init_mode & GLUT_DEPTH) {
-               pfd.cDepthBits = 24;
+       wglMakeCurrent(tmpdc, tmpctx);
+
+       if(!(wglChoosePixelFormat = wglGetProcAddress("wglChoosePixelFormatARB"))) {
+               if(!(wglChoosePixelFormat = wglGetProcAddress("wglChoosePixelFormatEXT"))) {
+                       goto fail;
+               }
+               if(!(wglGetPixelFormatAttribiv = wglGetProcAddress("wglGetPixelFormatAttribivEXT"))) {
+                       goto fail;
+               }
+       } else {
+               if(!(wglGetPixelFormatAttribiv = wglGetProcAddress("wglGetPixelFormatAttribivARB"))) {
+                       goto fail;
+               }
        }
-       if(init_mode & GLUT_STENCIL) {
-               pfd.cStencilBits = 8;
+       wglMakeCurrent(0, 0);
+       wglDeleteContext(tmpctx);
+       DestroyWindow(tmpwin);
+       UnregisterClass(TMPCLASS, hinst);
+
+       /* create the real window and context */
+       if(!(win = CreateWindow("MiniGLUT", title, WS_OVERLAPPEDWINDOW, init_x,
+                                       init_y, width, height, 0, 0, hinst, 0))) {
+               panic("Failed to create window\n");
        }
-       pfd.iLayerType = PFD_MAIN_PLANE;
+       dc = GetDC(win);
 
-       if(!(pixfmt = ChoosePixelFormat(dc, &pfd))) {
+       if(!(pixfmt = choose_pixfmt(init_mode))) {
                panic("Failed to find suitable pixel format\n");
        }
-       if(!SetPixelFormat(dc, pixfmt, &pfd)) {
+       if(!SetPixelFormat(dc, pixfmt, &tmppfd)) {
                panic("Failed to set the selected pixel format\n");
        }
        if(!(ctx = wglCreateContext(dc))) {
@@ -1271,16 +1378,97 @@ static void create_window(const char *title)
        }
        wglMakeCurrent(dc, ctx);
 
-       DescribePixelFormat(dc, pixfmt, sizeof pfd, &pfd);
-       ctx_info.rsize = pfd.cRedBits;
-       ctx_info.gsize = pfd.cGreenBits;
-       ctx_info.bsize = pfd.cBlueBits;
-       ctx_info.asize = pfd.cAlphaBits;
-       ctx_info.zsize = pfd.cDepthBits;
-       ctx_info.ssize = pfd.cStencilBits;
-       ctx_info.dblbuf = pfd.dwFlags & PFD_DOUBLEBUFFER ? 1 : 0;
-       ctx_info.samples = 1;   /* TODO */
-       ctx_info.srgb = 0;              /* TODO */
+       GETATTR(WGL_RED_BITS, &ctx_info.rsize);
+       GETATTR(WGL_GREEN_BITS, &ctx_info.gsize);
+       GETATTR(WGL_BLUE_BITS, &ctx_info.bsize);
+       GETATTR(WGL_ALPHA_BITS, &ctx_info.asize);
+       GETATTR(WGL_DEPTH_BITS, &ctx_info.zsize);
+       GETATTR(WGL_STENCIL_BITS, &ctx_info.ssize);
+       GETATTR(WGL_DOUBLE_BUFFER, &ctx_info.dblbuf);
+       GETATTR(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, &ctx_info.srgb);
+       GETATTR(WGL_SAMPLES_ARB, &ctx_info.samples);
+       return 0;
+
+fail:
+       if(tmpctx) {
+               wglMakeCurrent(0, 0);
+               wglDeleteContext(tmpctx);
+       }
+       if(tmpwin) {
+               DestroyWindow(tmpwin);
+       }
+       UnregisterClass(TMPCLASS, hinst);
+       return -1;
+}
+
+
+static void create_window(const char *title)
+{
+       int pixfmt;
+       PIXELFORMATDESCRIPTOR pfd = {0};
+       RECT rect;
+       int width, height;
+
+       rect.left = init_x;
+       rect.top = init_y;
+       rect.right = init_x + init_width;
+       rect.bottom = init_y + init_height;
+       AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, 0);
+       width = rect.right - rect.left;
+       height = rect.bottom - rect.top;
+
+       if(create_window_wglext(title, width, height) == -1) {
+
+               if(!(win = CreateWindow("MiniGLUT", title, WS_OVERLAPPEDWINDOW,
+                                       rect.left, rect.top, width, height, 0, 0, hinst, 0))) {
+                       panic("Failed to create window\n");
+               }
+               dc = GetDC(win);
+
+               pfd.nSize = sizeof pfd;
+               pfd.nVersion = 1;
+               pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
+               if(init_mode & GLUT_STEREO) {
+                       pfd.dwFlags |= PFD_STEREO;
+               }
+               pfd.iPixelType = init_mode & GLUT_INDEX ? PFD_TYPE_COLORINDEX : PFD_TYPE_RGBA;
+               pfd.cColorBits = 24;
+               if(init_mode & GLUT_ALPHA) {
+                       pfd.cAlphaBits = 8;
+               }
+               if(init_mode & GLUT_ACCUM) {
+                       pfd.cAccumBits = 24;
+               }
+               if(init_mode & GLUT_DEPTH) {
+                       pfd.cDepthBits = 24;
+               }
+               if(init_mode & GLUT_STENCIL) {
+                       pfd.cStencilBits = 8;
+               }
+               pfd.iLayerType = PFD_MAIN_PLANE;
+
+               if(!(pixfmt = ChoosePixelFormat(dc, &pfd))) {
+                       panic("Failed to find suitable pixel format\n");
+               }
+               if(!SetPixelFormat(dc, pixfmt, &pfd)) {
+                       panic("Failed to set the selected pixel format\n");
+               }
+               if(!(ctx = wglCreateContext(dc))) {
+                       panic("Failed to create the OpenGL context\n");
+               }
+               wglMakeCurrent(dc, ctx);
+
+               DescribePixelFormat(dc, pixfmt, sizeof pfd, &pfd);
+               ctx_info.rsize = pfd.cRedBits;
+               ctx_info.gsize = pfd.cGreenBits;
+               ctx_info.bsize = pfd.cBlueBits;
+               ctx_info.asize = pfd.cAlphaBits;
+               ctx_info.zsize = pfd.cDepthBits;
+               ctx_info.ssize = pfd.cStencilBits;
+               ctx_info.dblbuf = pfd.dwFlags & PFD_DOUBLEBUFFER ? 1 : 0;
+               ctx_info.samples = 0;
+               ctx_info.srgb = 0;
+       }
 
        ShowWindow(win, 1);
        SetForegroundWindow(win);