FreeBASIC  0.91.0
gfx_driver_opengl.c
Go to the documentation of this file.
1 /* OpenGL gfx driver */
2 
3 #include "../fb_gfx.h"
4 #include "fb_gfx_win32.h"
5 #include "../fb_gfx_gl.h"
6 
7 #ifndef DISABLE_OPENGL
8 
9 #ifndef WGL_ARB_pixel_format
10 #define WGL_ARB_pixel_format
11 
12 #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
13 #define WGL_DRAW_TO_WINDOW_ARB 0x2001
14 #define WGL_DRAW_TO_BITMAP_ARB 0x2002
15 #define WGL_ACCELERATION_ARB 0x2003
16 #define WGL_NEED_PALETTE_ARB 0x2004
17 #define WGL_NEED_SYSTEM_PALETTE_ARB 0x2005
18 #define WGL_SWAP_LAYER_BUFFERS_ARB 0x2006
19 #define WGL_SWAP_METHOD_ARB 0x2007
20 #define WGL_NUMBER_OVERLAYS_ARB 0x2008
21 #define WGL_NUMBER_UNDERLAYS_ARB 0x2009
22 #define WGL_TRANSPARENT_ARB 0x200A
23 #define WGL_TRANSPARENT_RED_VALUE_ARB 0x2037
24 #define WGL_TRANSPARENT_GREEN_VALUE_ARB 0x2038
25 #define WGL_TRANSPARENT_BLUE_VALUE_ARB 0x2039
26 #define WGL_TRANSPARENT_ALPHA_VALUE_ARB 0x203A
27 #define WGL_TRANSPARENT_INDEX_VALUE_ARB 0x203B
28 #define WGL_SHARE_DEPTH_ARB 0x200C
29 #define WGL_SHARE_STENCIL_ARB 0x200D
30 #define WGL_SHARE_ACCUM_ARB 0x200E
31 #define WGL_SUPPORT_GDI_ARB 0x200F
32 #define WGL_SUPPORT_OPENGL_ARB 0x2010
33 #define WGL_DOUBLE_BUFFER_ARB 0x2011
34 #define WGL_STEREO_ARB 0x2012
35 #define WGL_PIXEL_TYPE_ARB 0x2013
36 #define WGL_COLOR_BITS_ARB 0x2014
37 #define WGL_RED_BITS_ARB 0x2015
38 #define WGL_RED_SHIFT_ARB 0x2016
39 #define WGL_GREEN_BITS_ARB 0x2017
40 #define WGL_GREEN_SHIFT_ARB 0x2018
41 #define WGL_BLUE_BITS_ARB 0x2019
42 #define WGL_BLUE_SHIFT_ARB 0x201A
43 #define WGL_ALPHA_BITS_ARB 0x201B
44 #define WGL_ALPHA_SHIFT_ARB 0x201C
45 #define WGL_ACCUM_BITS_ARB 0x201D
46 #define WGL_ACCUM_RED_BITS_ARB 0x201E
47 #define WGL_ACCUM_GREEN_BITS_ARB 0x201F
48 #define WGL_ACCUM_BLUE_BITS_ARB 0x2020
49 #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
50 #define WGL_DEPTH_BITS_ARB 0x2022
51 #define WGL_STENCIL_BITS_ARB 0x2023
52 #define WGL_AUX_BUFFERS_ARB 0x2024
53 #define WGL_NO_ACCELERATION_ARB 0x2025
54 #define WGL_GENERIC_ACCELERATION_ARB 0x2026
55 #define WGL_FULL_ACCELERATION_ARB 0x2027
56 #define WGL_SWAP_EXCHANGE_ARB 0x2028
57 #define WGL_SWAP_COPY_ARB 0x2029
58 #define WGL_SWAP_UNDEFINED_ARB 0x202A
59 #define WGL_TYPE_RGBA_ARB 0x202B
60 #define WGL_TYPE_COLORINDEX_ARB 0x202C
61 #define WGL_SAMPLE_BUFFERS_ARB 0x2041
62 #define WGL_SAMPLES_ARB 0x2042
63 
64 #endif
65 
66 static int driver_init(char *title, int w, int h, int depth, int refresh_rate, int flags);
67 static void driver_exit(void);
68 static void driver_lock(void);
69 static void driver_unlock(void);
70 static void driver_flip(void);
71 static int *driver_fetch_modes(int depth, int *size);
72 static void driver_poll_events(void);
73 static int opengl_init(void);
74 static void opengl_exit(void);
75 
77 {
78  "OpenGL", /* char *name; */
79  driver_init, /* int (*init)(int w, int h, char *title, int fullscreen); */
80  driver_exit, /* void (*exit)(void); */
81  driver_lock, /* void (*lock)(void); */
82  driver_unlock, /* void (*unlock)(void); */
83  NULL, /* void (*set_palette)(int index, int r, int g, int b); */
84  fb_hWin32WaitVSync, /* void (*wait_vsync)(void); */
85  fb_hWin32GetMouse, /* int (*get_mouse)(int *x, int *y, int *z, int *buttons, int *clip); */
86  fb_hWin32SetMouse, /* void (*set_mouse)(int x, int y, int cursor, int clip); */
87  fb_hWin32SetWindowTitle,/* void (*set_window_title)(char *title); */
88  fb_hWin32SetWindowPos, /* int (*set_window_pos)(int x, int y); */
89  driver_fetch_modes, /* int *(*fetch_modes)(int depth, int *size); */
90  driver_flip, /* void (*flip)(void); */
91  driver_poll_events /* void (*poll_events)(void); */
92 };
93 
94 
95 typedef HGLRC (APIENTRY *WGLCREATECONTEXT)(HDC);
96 typedef BOOL (APIENTRY *WGLMAKECURRENT)(HDC, HGLRC);
97 typedef BOOL (APIENTRY *WGLDELETECONTEXT)(HGLRC);
98 typedef PROC (APIENTRY *WGLGETPROCADDRESS)(LPCSTR);
99 typedef PCHAR (APIENTRY *WGLGETEXTENSIONSTRINGARB)(HDC);
100 typedef BOOL (APIENTRY *WGLCHOOSEPIXELFORMATARB)(HDC, const int *, const FLOAT *, int, int *, int *);
101 
102 typedef struct FB_WGL {
109 } FB_WGL;
110 
112 static FB_WGL fb_wgl;
113 static HGLRC hglrc;
114 static HDC hdc;
115 
116 void *fb_hGL_GetProcAddress(const char *proc)
117 {
118  return (void *)fb_wgl.GetProcAddress(proc);
119 }
120 
121 static int GL_init(PIXELFORMATDESCRIPTOR *pfd)
122 {
123  HWND wnd;
124  HDC hdc;
125  HGLRC hglrc;
126  int pf, res = 0;
127  char *wgl_extensions = NULL;
128 
129  wnd = CreateWindow(fb_win32.window_class, "OpenGL setup", WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
130  0, 0, 8, 8, HWND_DESKTOP, NULL, fb_win32.hinstance, NULL);
131  if (!wnd)
132  return -1;
133 
134  hdc = GetDC(wnd);
135  pf = ChoosePixelFormat(hdc, pfd);
136  SetPixelFormat(hdc, pf, pfd);
137 
138  hglrc = fb_wgl.CreateContext(hdc);
139  fb_wgl.MakeCurrent(hdc, hglrc);
140 
141  fb_wgl.GetProcAddress = (WGLGETPROCADDRESS)GetProcAddress(library, "wglGetProcAddress");
142  fb_wgl.GetExtensionStringARB = (WGLGETEXTENSIONSTRINGARB)fb_wgl.GetProcAddress("wglGetExtensionsStringARB");
143  if (!fb_wgl.GetExtensionStringARB)
144  fb_wgl.GetExtensionStringARB = (WGLGETEXTENSIONSTRINGARB)fb_wgl.GetProcAddress("wglGetExtensionsStringEXT");
145  if (fb_wgl.GetExtensionStringARB)
146  wgl_extensions = fb_wgl.GetExtensionStringARB(hdc);
147 
148  res = fb_hGL_Init(library, wgl_extensions);
149  if (res == 0) {
150  if (fb_hGL_ExtensionSupported("WGL_ARB_pixel_format"))
151  fb_wgl.ChoosePixelFormatARB = (WGLCHOOSEPIXELFORMATARB)fb_wgl.GetProcAddress("wglChoosePixelFormatARB");
152  }
153 
154  fb_wgl.MakeCurrent(NULL, NULL);
155  fb_wgl.DeleteContext(hglrc);
156  ReleaseDC(wnd, hdc);
157 
158  DestroyWindow(wnd);
159 
160  return res;
161 }
162 
163 static void opengl_paint(void)
164 {
165 }
166 
167 static int opengl_init(void)
168 {
169  DEVMODE mode;
170  DWORD style;
171  RECT rect;
172  UINT flags;
173  int x, y;
174  MONITORINFOEX monitor_info;
175  const char *devname = NULL;
176 
177  monitor_info.cbSize = sizeof(MONITORINFOEX);
178  monitor_info.szDevice[0] = '\0';
179 
180  if (fb_win32.GetMonitorInfo && fb_win32.monitor && fb_win32.GetMonitorInfo(fb_win32.monitor, (LPMONITORINFO)&monitor_info)) {
181  devname = monitor_info.szDevice;
182  }
183 
184  style = GetWindowLong(fb_win32.wnd, GWL_STYLE);
185  flags = SWP_FRAMECHANGED;
187  fb_hMemSet(&mode, 0, sizeof(mode));
188  mode.dmSize = sizeof(mode);
189  mode.dmPelsWidth = fb_win32.w;
190  mode.dmPelsHeight = fb_win32.h;
191  mode.dmBitsPerPel = fb_win32.depth;
192  mode.dmDisplayFrequency = fb_win32.refresh_rate;
193  mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
195  if (fb_win32.ChangeDisplaySettingsEx(devname, &mode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
196  return -1;
197  } else if (ChangeDisplaySettings(&mode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
198  return -1;
199  }
200  style &= ~WS_OVERLAPPEDWINDOW;
201  style |= WS_POPUP;
202  }
203  else {
205  style &= ~WS_OVERLAPPEDWINDOW;
206  style |= WS_POPUP;
207  }
208  else {
209  style |= WS_OVERLAPPEDWINDOW;
210  style &= ~(WS_POPUP | WS_THICKFRAME);
212  style &= ~WS_MAXIMIZEBOX;
213  }
214  flags |= SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSENDCHANGING | SWP_NOZORDER;
215  }
216  SetWindowLong(fb_win32.wnd, GWL_STYLE, style);
217  rect.left = rect.top = x = y = 0;
218  rect.right = fb_win32.w;
219  rect.bottom = fb_win32.h;
220  if (!(fb_win32.flags & DRIVER_FULLSCREEN)) {
221  AdjustWindowRect(&rect, style, FALSE);
222  if (monitor_info.szDevice[0]) {
223  x = monitor_info.rcMonitor.left + ((monitor_info.rcMonitor.right - monitor_info.rcMonitor.left - rect.right) >> 1);
224  y = monitor_info.rcMonitor.top + ((monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top - rect.bottom) >> 1);
225  } else {
226  x = (GetSystemMetrics(SM_CXSCREEN) - rect.right) >> 1;
227  y = (GetSystemMetrics(SM_CYSCREEN) - rect.bottom) >> 1;
228  }
229  } else if (monitor_info.szDevice[0]) {
230  /* fullscreen with valid monitor_info: place window on proper monitor */
231  x = monitor_info.rcMonitor.left;
232  y = monitor_info.rcMonitor.top;
233  }
234  fb_win32.fullw = rect.right - rect.left;
235  fb_win32.fullh = rect.bottom - rect.top;
236  SetWindowPos(fb_win32.wnd, 0, x, y, fb_win32.fullw, fb_win32.fullh, flags);
237  ShowWindow(fb_win32.wnd, SW_SHOW);
238  SetForegroundWindow(fb_win32.wnd);
240  __fb_gfx->refresh_rate = GetDeviceCaps(hdc, VREFRESH);
241 
242  return 0;
243 }
244 
245 static void opengl_exit(void)
246 {
248  ChangeDisplaySettings(NULL, 0);
249  ShowWindow(fb_win32.wnd, SW_HIDE);
250 }
251 
252 static int driver_init(char *title, int w, int h, int depth_arg, int refresh_rate, int flags)
253 {
254  const char *wgl_funcs[] = { "wglCreateContext", "wglMakeCurrent", "wglDeleteContext", NULL };
255  PIXELFORMATDESCRIPTOR pfd = {
256  sizeof(PIXELFORMATDESCRIPTOR), 1,
257  PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
258  PFD_TYPE_RGBA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0,
259  PFD_MAIN_PLANE, 0, 0, 0, 0
260  };
261  int attribs[64] = {
262  WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
264  WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
265  0
266  }, *attrib = &attribs[6], *samples_attrib = NULL;
267  int depth = MAX(8, depth_arg);
268  int pf = 0, num_formats, format;
269 
270  fb_hMemSet(&fb_win32, 0, sizeof(fb_win32));
271 
272  library = NULL;
273  hglrc = NULL;
274  hdc = NULL;
275 
276  if (!(flags & DRIVER_OPENGL))
277  return -1;
278 
279  library = fb_hDynLoad("opengl32.dll", wgl_funcs, (void **)&fb_wgl);
280  if (!library)
281  return -1;
282 
286 
287  if (fb_hWin32Init(title, w, h, depth, refresh_rate, flags))
288  return -1;
289 
290  if (GL_init(&pfd))
291  return -1;
292 
293  if (fb_hInitWindow((WS_CLIPSIBLINGS | WS_CLIPCHILDREN) & ~WS_THICKFRAME, 0, 0, 0, w, h))
294  return -1;
295 
296  if (opengl_init())
297  return -1;
298 
299  /* setup pixel format */
301  *attrib++ = WGL_COLOR_BITS_ARB;
302  pfd.cColorBits = *attrib++ = __fb_gl_params.color_bits;
303  *attrib++ = WGL_RED_BITS_ARB;
304  pfd.cRedBits = *attrib++ = __fb_gl_params.color_red_bits;
305  *attrib++ = WGL_GREEN_BITS_ARB;
306  pfd.cGreenBits = *attrib++ = __fb_gl_params.color_green_bits;
307  *attrib++ = WGL_BLUE_BITS_ARB;
308  pfd.cBlueBits = *attrib++ = __fb_gl_params.color_blue_bits;
309  *attrib++ = WGL_ALPHA_BITS_ARB;
310  pfd.cAlphaBits = *attrib++ = __fb_gl_params.color_alpha_bits;
311  *attrib++ = WGL_DEPTH_BITS_ARB;
312  pfd.cDepthBits = *attrib++ = __fb_gl_params.depth_bits;
314  *attrib++ = WGL_ACCUM_BITS_ARB;
315  pfd.cAccumBits = *attrib++ = __fb_gl_params.accum_bits;
316  }
318  *attrib++ = WGL_ACCUM_RED_BITS_ARB;
319  pfd.cAccumRedBits = *attrib++ = __fb_gl_params.accum_red_bits;
320  }
322  *attrib++ = WGL_ACCUM_RED_BITS_ARB;
323  pfd.cAccumGreenBits = *attrib++ = __fb_gl_params.accum_green_bits;
324  }
326  *attrib++ = WGL_ACCUM_BLUE_BITS_ARB;
327  pfd.cAccumBlueBits = *attrib++ = __fb_gl_params.accum_blue_bits;
328  }
330  *attrib++ = WGL_ACCUM_ALPHA_BITS_ARB;
331  pfd.cAccumAlphaBits = *attrib++ = __fb_gl_params.accum_alpha_bits;
332  }
334  *attrib++ = WGL_STENCIL_BITS_ARB;
335  pfd.cStencilBits = *attrib++ = __fb_gl_params.stencil_bits;
336  }
338  *attrib++ = WGL_SAMPLE_BUFFERS_ARB;
339  *attrib++ = GL_TRUE;
340  *attrib++ = WGL_SAMPLES_ARB;
341  samples_attrib = attrib;
342  *attrib++ = __fb_gl_params.num_samples;
343  }
344  *attrib = 0;
345 
346  hdc = GetDC(fb_win32.wnd);
347  if (fb_wgl.ChoosePixelFormatARB) {
348  do {
349  if ((fb_wgl.ChoosePixelFormatARB(hdc, attribs, NULL, 1, &format, &num_formats)) && (num_formats > 0)) {
350  pf = format;
351  break;
352  }
353  } while ((samples_attrib) && ((*samples_attrib -= 2) >= 0));
354  }
355  if (!pf) {
356  flags &= ~HAS_MULTISAMPLE;
357  pf = ChoosePixelFormat(hdc, &pfd);
358  }
359 
360  if ((!pf) || (!SetPixelFormat(hdc, pf, &pfd)))
361  return -1;
362  hglrc = fb_wgl.CreateContext(hdc);
363  if (!hglrc)
364  return -1;
365  fb_wgl.MakeCurrent(hdc, hglrc);
366 
367  if ((samples_attrib) && (*samples_attrib > 0))
369 
370  return 0;
371 }
372 
373 static void driver_exit(void)
374 {
375  if (library) {
376  if (hglrc) {
377  fb_wgl.MakeCurrent(NULL, NULL);
378  fb_wgl.DeleteContext(hglrc);
379  }
380  if (hdc)
381  ReleaseDC(fb_win32.wnd, hdc);
383  ChangeDisplaySettings(NULL, 0);
384  if (fb_win32.wnd)
385  DestroyWindow(fb_win32.wnd);
387  }
388 
389  fb_hWin32Exit();
390 }
391 
392 static void driver_lock(void)
393 {
394 }
395 
396 static void driver_unlock(void)
397 {
398 }
399 
400 static void driver_flip(void)
401 {
402  SwapBuffers(hdc);
403 }
404 
405 static void driver_poll_events(void)
406 {
407  if( fb_win32.is_active ) {
408  int i;
409  unsigned char keystate[256];
410 
411  GetKeyboardState(keystate);
412  for (i = 0; __fb_keytable[i][0]; i++) {
413  if (__fb_keytable[i][2])
414  __fb_gfx->key[__fb_keytable[i][0]] = ((keystate[__fb_keytable[i][1]] & 0x80) |
415  (keystate[__fb_keytable[i][2]] & 0x80)) ? TRUE : FALSE;
416  else
417  __fb_gfx->key[__fb_keytable[i][0]] = (keystate[__fb_keytable[i][1]] & 0x80) ? TRUE : FALSE;
418  }
419  }
420 
422 }
423 
424 static int *driver_fetch_modes(int depth, int *size)
425 {
426  DEVMODE devmode;
427  int *modes = NULL, index = 0;
428 
429  *size = 0;
430 
431  for (;;) {
432  if (!EnumDisplaySettings(NULL, index, &devmode))
433  break;
434  index++;
435  if (devmode.dmBitsPerPel == depth) {
436  (*size)++;
437  modes = (int *)realloc(modes, *size * sizeof(int));
438  modes[(*size) - 1] = (devmode.dmPelsWidth << 16) | devmode.dmPelsHeight;
439  }
440  }
441 
442  return modes;
443 }
444 
445 #endif