FreeBASIC  0.91.0
gfx_driver_gdi.c
Go to the documentation of this file.
1 /* GDI gfx driver */
2 
3 #include "../fb_gfx.h"
4 #include "fb_gfx_win32.h"
5 
6 #define SCREENLIST(w, h) ((h) | (w) << 16)
7 #ifndef LWA_COLORKEY
8 #define LWA_COLORKEY 0x00000001
9 #endif
10 
11 static int driver_init(char *title, int w, int h, int depth, int refresh_rate, int flags);
12 static int *driver_fetch_modes(int depth, int *size);
13 
15 {
16  "GDI", /* char *name; */
17  driver_init, /* int (*init)(int w, int h, char *title, int fullscreen); */
18  fb_hWin32Exit, /* void (*exit)(void); */
19  fb_hWin32Lock, /* void (*lock)(void); */
20  fb_hWin32Unlock, /* void (*unlock)(void); */
21  fb_hWin32SetPalette, /* void (*set_palette)(int index, int r, int g, int b); */
22  fb_hWin32WaitVSync, /* void (*wait_vsync)(void); */
23  fb_hWin32GetMouse, /* int (*get_mouse)(int *x, int *y, int *z, int *buttons, int *clip); */
24  fb_hWin32SetMouse, /* void (*set_mouse)(int x, int y, int cursor, int clip); */
25  fb_hWin32SetWindowTitle,/* void (*set_window_title)(char *title); */
26  fb_hWin32SetWindowPos, /* int (*set_window_pos)(int x, int y); */
27  driver_fetch_modes, /* int *(*fetch_modes)(int depth, int *size); */
28  NULL, /* void (*flip)(void); */
29  NULL /* void (*poll_events)(void); */
30 };
31 
32 static BITMAPINFO *bitmap_info;
33 static HPALETTE palette;
34 static unsigned char *buffer;
35 
36 static void alpha_remover_blitter(unsigned char *dest, int pitch)
37 {
38  unsigned int *d, *s;
39  unsigned char *src = __fb_gfx->framebuffer;
40  unsigned int c;
41  char *dirty = __fb_gfx->dirty;
42  int x, y;
43 
44  for (y = __fb_gfx->h * __fb_gfx->scanline_size; y; y--) {
45  if (*dirty) {
46  s = (unsigned int *)src;
47  d = (unsigned int *)dest;
48  for (x = __fb_gfx->w; x; x--) {
49  c = *s++;
50  *d++ = c & ~MASK_A_32;
51  }
52  }
53  src += __fb_gfx->pitch;
54  dest += pitch;
55  }
56 }
57 
58 static void gdi_paint(void)
59 {
60  unsigned char *source;
61  HDC hdc;
62 
63  if (fb_win32.blitter)
64  source = buffer;
65  else
66  source = __fb_gfx->framebuffer;
67 
68  hdc = GetDC(fb_win32.wnd);
69  SelectPalette(hdc, palette, FALSE);
70  RealizePalette(hdc);
71  SetDIBitsToDevice(hdc, 0, 0, fb_win32.w, fb_win32.h, 0, 0, 0, fb_win32.h, source, bitmap_info, DIB_RGB_COLORS);
72  InvalidateRect(fb_win32.wnd, NULL, FALSE);
73  ReleaseDC(fb_win32.wnd, hdc);
74 }
75 
76 static int gdi_init(void)
77 {
78  DEVMODE mode;
79  DWORD style, ex_style = 0;
80  HDC hdc;
81  RECT rect;
82  LOGPALETTE *lp;
83  int x, y;
84  MONITORINFOEX monitor_info;
85  const char *devname = NULL;
86 
87  bitmap_info = NULL;
88  buffer = NULL;
89  palette = NULL;
90 
91  monitor_info.cbSize = sizeof(MONITORINFOEX);
92  monitor_info.szDevice[0] = '\0';
93 
94  if (fb_win32.GetMonitorInfo && fb_win32.monitor && fb_win32.GetMonitorInfo(fb_win32.monitor, (LPMONITORINFO)&monitor_info)) {
95  devname = monitor_info.szDevice;
96  }
97 
99  fb_hMemSet(&mode, 0, sizeof(mode));
100  mode.dmSize = sizeof(mode);
101  mode.dmPelsWidth = fb_win32.w;
102  mode.dmPelsHeight = fb_win32.h;
103  mode.dmBitsPerPel = fb_win32.depth;
104  mode.dmDisplayFrequency = fb_win32.refresh_rate;
105  mode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
106 
108  if (fb_win32.ChangeDisplaySettingsEx(devname, &mode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL)
109  return -1;
110  } else if (ChangeDisplaySettings(&mode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) {
111  return -1;
112  }
113 
114  style = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
115  } else {
116  style = WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME;
118  style &= ~WS_MAXIMIZEBOX;
120  style = WS_POPUP;
122  if (fb_win32.version < 0x500)
123  return -1;
124  ex_style = WS_EX_LAYERED;
125  }
126  }
127 
128  rect.left = rect.top = x = y = 0;
129  rect.right = fb_win32.w;
130  rect.bottom = fb_win32.h;
131  if (!(fb_win32.flags & DRIVER_FULLSCREEN)) {
132  /* windowed mode: center window on monitor */
133  AdjustWindowRect(&rect, style, 0);
134  rect.right -= rect.left;
135  rect.bottom -= rect.top;
136  if (monitor_info.szDevice[0]) {
137  x = monitor_info.rcMonitor.left + ((monitor_info.rcMonitor.right - monitor_info.rcMonitor.left - rect.right) >> 1);
138  y = monitor_info.rcMonitor.top + ((monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top - rect.bottom) >> 1);
139  } else {
140  x = (GetSystemMetrics(SM_CXSCREEN) - rect.right) >> 1;
141  y = (GetSystemMetrics(SM_CYSCREEN) - rect.bottom) >> 1;
142  }
143  } else if (monitor_info.szDevice[0]) {
144  /* fullscreen with valid monitor_info: place window on proper monitor */
145  x = monitor_info.rcMonitor.left;
146  y = monitor_info.rcMonitor.top;
147  }
148 
149  if (fb_hInitWindow(style | WS_VISIBLE, ex_style, x, y, rect.right, rect.bottom))
150  return -1;
153  return -1;
154  fb_win32.SetLayeredWindowAttributes(fb_win32.wnd, (fb_win32.depth > 8) ? RGB(255, 0, 255) : 0, 0, LWA_COLORKEY);
155  }
156 
157  bitmap_info = (BITMAPINFO *)calloc(1, sizeof(BITMAPINFO) + (sizeof(RGBQUAD) * 256));
158  if (!bitmap_info)
159  return -1;
160  bitmap_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
161  bitmap_info->bmiHeader.biBitCount = fb_win32.depth;
162  bitmap_info->bmiHeader.biPlanes = 1;
163  bitmap_info->bmiHeader.biWidth = fb_win32.w;
164  bitmap_info->bmiHeader.biHeight = -fb_win32.h;
165  bitmap_info->bmiHeader.biClrUsed = 256;
166  bitmap_info->bmiHeader.biCompression = BI_RGB;
167 
168  if ((fb_win32.depth >= 16) || (fb_win32.w & 0x3)) {
169  if (fb_win32.depth == 16) {
171  if (!fb_win32.blitter)
172  return -1;
173  }
174  else if (fb_win32.w & 0x3) {
176  if (!fb_win32.blitter)
177  return -1;
178  }
180  {
181  if( fb_win32.depth == 32 )
183  }
184  buffer = malloc(((fb_win32.w + 3) & ~3) * fb_win32.h * __fb_gfx->bpp);
185  if (!buffer)
186  return -1;
187  }
188 
189  hdc = GetDC(fb_win32.wnd);
190  __fb_gfx->refresh_rate = GetDeviceCaps(hdc, VREFRESH);
191 
192  lp = (LOGPALETTE *)malloc(sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256));
193  lp->palNumEntries = 256;
194  lp->palVersion = 0x300;
195  fb_hMemCpy(lp->palPalEntry, fb_win32.palette, sizeof(PALETTEENTRY) * 256);
196  palette = CreatePalette(lp);
197  free(lp);
198 
199  ReleaseDC(fb_win32.wnd, hdc);
200 
201  return 0;
202 }
203 
204 static void gdi_exit(void)
205 {
206  if (buffer)
207  free(buffer);
208  if (bitmap_info)
209  free(bitmap_info);
210  if (fb_win32.wnd) {
212  ChangeDisplaySettings(NULL, 0);
213  DestroyWindow(fb_win32.wnd);
214  }
215  if (palette)
216  DeleteObject(palette);
217 }
218 
219 #ifdef HOST_MINGW
220 static unsigned int WINAPI gdi_thread( void *param )
221 #else
222 static DWORD WINAPI gdi_thread( LPVOID param )
223 #endif
224 {
225  HANDLE running_event = param;
226  int i, y1, y2, h;
227  unsigned char *source, keystate[256];
228  HDC hdc;
229  RECT rect;
230 
231  if (gdi_init()) return 1;
232 
233  SetEvent(running_event);
235 
236  rect.left = 0;
237  rect.right = fb_win32.w;
238 
239  while (fb_win32.is_running)
240  {
241  fb_hWin32Lock();
242 
243  hdc = GetDC(fb_win32.wnd);
245  /* Can't use fb_hMemCpy as structure layout is different :( */
246  for (i = 0; i < 256; i++) {
247  bitmap_info->bmiColors[i].rgbRed = fb_win32.palette[i].peRed;
248  bitmap_info->bmiColors[i].rgbGreen = fb_win32.palette[i].peGreen;
249  bitmap_info->bmiColors[i].rgbBlue = fb_win32.palette[i].peBlue;
250  }
251  /* Update logical palette */
252  SetPaletteEntries(palette, 0, 256, fb_win32.palette);
253  SelectPalette(hdc, palette, FALSE);
254  RealizePalette(hdc);
256  }
257  /* Only do a single SetDIBitsToDevice call per frame */
258  for (y1 = 0; y1 < fb_win32.h; y1++) {
259  if (__fb_gfx->dirty[y1]) {
260  for (y2 = fb_win32.h - 1; !__fb_gfx->dirty[y2]; y2--)
261  ;
262  h = y2 - y1 + 1;
263  if (fb_win32.blitter) {
264  fb_win32.blitter(buffer, (__fb_gfx->pitch + 3) & ~3);
265  source = buffer + (y1 * ((__fb_gfx->pitch + 3) & ~0x3));
266  }
267  else
268  {
269  source = __fb_gfx->framebuffer + (y1 * __fb_gfx->pitch);
270  }
271 
272  SetDIBitsToDevice(hdc, 0, y1, fb_win32.w, h, 0, 0, 0, h, source, bitmap_info, DIB_RGB_COLORS);
273 
274  if (fb_win32.version < 0x500) {
275  rect.top = y1;
276  rect.bottom = h;
277  InvalidateRect(fb_win32.wnd, &rect, FALSE);
278  }
279 
280  break;
281  }
282  }
283  ReleaseDC(fb_win32.wnd, hdc);
284 
286 
287  if( fb_win32.is_active ) {
288  GetKeyboardState(keystate);
289  for (i = 0; __fb_keytable[i][0]; i++) {
290  if (__fb_keytable[i][2])
291  __fb_gfx->key[__fb_keytable[i][0]] = ((keystate[__fb_keytable[i][1]] & 0x80) |
292  (keystate[__fb_keytable[i][2]] & 0x80)) ? TRUE : FALSE;
293  else
294  __fb_gfx->key[__fb_keytable[i][0]] = (keystate[__fb_keytable[i][1]] & 0x80) ? TRUE : FALSE;
295  }
296  }
297 
299 
300  fb_hWin32Unlock();
301 
302  Sleep(10);
303  }
304 
305  return 1;
306 }
307 
308 static int driver_init(char *title, int w, int h, int depth, int refresh_rate, int flags)
309 {
310  fb_hMemSet(&fb_win32, 0, sizeof(fb_win32));
311 
312  if (flags & DRIVER_OPENGL)
313  return -1;
318 
319  return fb_hWin32Init(title, w, h, MAX(8, depth), refresh_rate, flags);
320 }
321 
322 static int *driver_fetch_modes(int depth, int *size)
323 {
324  int *data = NULL, *newdata;
325  int mode = 0;
326  int count = 0;
327  DEVMODE dm;
328 
329  while (EnumDisplaySettings(NULL, mode, &dm)) {
330  if ((dm.dmBitsPerPel == depth) ||
331  (dm.dmBitsPerPel == 15 && depth == 16) ||
332  (dm.dmBitsPerPel == 16 && depth == 15) ||
333  (dm.dmBitsPerPel == 24 && depth == 32) ||
334  (dm.dmBitsPerPel == 32 && depth == 24)) {
335  ++count;
336  newdata = realloc(data, count * sizeof(int));
337  if (!newdata) {
338  *size = count - 1;
339  return data;
340  }
341  data = newdata;
342  data[count - 1] = SCREENLIST(dm.dmPelsWidth, dm.dmPelsHeight);
343  }
344  ++mode;
345  }
346 
347  *size = count;
348  return data;
349 }