source: Daodan/src/Daodan_GL.c@ 992

Last change on this file since 992 was 992, checked in by alloc, 11 years ago

Daodan: Removed unused MSVC tree, build folders; reorganized source layout; removed Flatline from current Daodan

File size: 11.6 KB
Line 
1#include <windows.h>
2#include <math.h>
3#include <GL/gl.h>
4#include <GL/glu.h>
5
6#include "Oni/Oni.h"
7
8#include "Daodan_Config.h"
9#include "Daodan_Utility.h"
10#include "Daodan_Win32.h"
11#include "Daodan_GL.h"
12
13static const M3tDisplayMode daodan_reslist[] =
14{
15 { 640, 480, 0, 0 },
16 { 720, 480, 0, 0 },
17 { 720, 576, 0, 0 },
18 { 768, 480, 0, 0 },
19 { 800, 480, 0, 0 },
20 { 800, 600, 0, 0 },
21 { 852, 480, 0, 0 },
22 { 856, 480, 0, 0 },
23 { 960, 540, 0, 0 },
24 { 960, 720, 0, 0 },
25 { 1024, 576, 0, 0 },
26 { 1024, 600, 0, 0 },
27 { 1024, 640, 0, 0 },
28 { 1024, 768, 0, 0 },
29 { 1152, 768, 0, 0 },
30 { 1152, 864, 0, 0 },
31 { 1280, 720, 0, 0 },
32 { 1280, 768, 0, 0 },
33 { 1280, 800, 0, 0 },
34 { 1280, 960, 0, 0 },
35 { 1280, 1024, 0, 0 },
36 { 1366, 768, 0, 0 },
37 { 1400, 1050, 0, 0 },
38 { 1440, 900, 0, 0 },
39 { 1600, 900, 0, 0 },
40 { 1600, 1200, 0, 0 },
41 { 1920, 1080, 0, 0 },
42 { 1920, 1200, 0, 0 },
43 { 1920, 1440, 0, 0 },
44};
45
46static DWORD window_style, window_exstyle;
47
48// HACK: use additional device entries to store display modes. It would give us
49// 67 mode slots total (far more than enough). I absolutely have no idea where
50// Rossy got his 104 (it would take up to 0x660 bytes while the whole GL state
51// is only 0x63c bytes). Maybe it was just octal (67 + 1).
52// This hack would break (crash!) "m3_display_list" script command.
53#define DD_MAX_MODES ((offsetof(M3tDrawEngineCaps,__unknown) - \
54 offsetof(M3tDrawEngineCaps,DisplayDevices) - \
55 offsetof(M3tDisplayDevice,Modes)) / sizeof(M3tDisplayMode))
56
57// Former daodan_resdepths.
58#define DD_MIN_DEPTH 16
59
60unsigned short ONICALL DD_GLrEnumerateDisplayModes(M3tDisplayMode* modes)
61{
62 unsigned int vmodes = 0;
63 unsigned int screen_x = GetSystemMetrics(SM_CXSCREEN);
64 unsigned int screen_y = GetSystemMetrics(SM_CYSCREEN);
65
66 unsigned int i;
67 signed int j;
68
69 DDrStartupMessage("Daodan: Listing display modes");
70
71 memset(modes, 0, sizeof(M3tDisplayMode) * DD_MAX_MODES);
72
73 if (M3gResolutionSwitch)
74 {
75 // Enumerate in -switch mode. "67 slots ought to be enough for anybody".
76
77 DEVMODE dm;
78
79 dm.dmSize = sizeof(dm);
80 dm.dmDriverExtra = 0;
81
82 for (i = 0; EnumDisplaySettings(NULL, i, &dm); ++i)
83 {
84 if (dm.dmBitsPerPel < DD_MIN_DEPTH || dm.dmPelsWidth < 640 || dm.dmPelsHeight < 480)
85 continue;
86 if (dm.dmPelsWidth < dm.dmPelsHeight)
87 continue;
88
89 // Already exists? Search backwards as modes are sorted most of the times
90 for (j = vmodes - 1; j >= 0; --j)
91 if (modes[j].Width == dm.dmPelsWidth && modes[j].Height == dm.dmPelsHeight &&
92 modes[j].Depth == dm.dmBitsPerPel)
93 break;
94
95 if (j >= 0)
96 continue; // We've found a match.
97
98 modes[vmodes].Width = dm.dmPelsWidth;
99 modes[vmodes].Height = dm.dmPelsHeight;
100 modes[vmodes].Depth = dm.dmBitsPerPel;
101
102 if (++vmodes >= DD_MAX_MODES)
103 break;
104 }
105 }
106 else
107 {
108 // In -noswitch we put predefined window sizes which don't overlap
109 // deskbar(s) plus one "native" fullscreen mode.
110
111 unsigned int workarea_width, workarea_height, frame_width, frame_height;
112 DWORD style, exstyle;
113 RECT rc;
114
115 if (SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0))
116 {
117 workarea_width = rc.right - rc.left;
118 workarea_height = rc.bottom - rc.top;
119 }
120 else
121 {
122 workarea_width = screen_x;
123 workarea_height = screen_y;
124 }
125
126 style = (DWORD) GetWindowLongPtr(ONgPlatformData.Window, GWL_STYLE);
127 exstyle = (DWORD) GetWindowLongPtr(ONgPlatformData.Window, GWL_EXSTYLE);
128
129 // Calculate additional width and height for window borders. Don't
130 // bother with system metrics. Let Windows calculate this.
131 rc.left = rc.top = 0;
132 rc.right = rc.bottom = 300;
133
134 if (AdjustWindowRectEx(&rc, style, FALSE, exstyle))
135 {
136 frame_width = rc.right - rc.left - 300;
137 frame_height = rc.bottom - rc.top - 300;
138 }
139 else
140 {
141 frame_width = 0;
142 frame_height = 0;
143 }
144
145 for (i = 0; i < sizeof(daodan_reslist) / sizeof(daodan_reslist[0]); ++i)
146 {
147 // Don't check the mode which has the same rect as screen. We would
148 // add it later as a special case.
149 if (daodan_reslist[i].Width == screen_x && daodan_reslist[i].Height == screen_y)
150 continue;
151
152 if (daodan_reslist[i].Width + frame_width <= workarea_width &&
153 daodan_reslist[i].Height + frame_height <= workarea_height)
154 {
155 modes[vmodes] = daodan_reslist[i];
156 modes[vmodes].Depth = GLgInitialMode.dmBitsPerPel;
157
158 if (++vmodes >= DD_MAX_MODES)
159 {
160 --vmodes; // Remove the last mode to make room for "fullscreen" mode.
161 break;
162 }
163 }
164 }
165
166 modes[vmodes].Width = GLgInitialMode.dmPelsWidth;
167 modes[vmodes].Height = GLgInitialMode.dmPelsHeight;
168 modes[vmodes].Depth = GLgInitialMode.dmBitsPerPel;
169 ++vmodes;
170 }
171
172 DDrStartupMessage("Daodan: %u modes available:", vmodes);
173 for (i = 0; i < vmodes; ++i)
174 DDrStartupMessage("Daodan: %ux%ux%u", modes[i].Width, modes[i].Height, modes[i].Depth);
175
176 return vmodes;
177}
178
179// Sets a new display mode (if it is somehow different from a current mode).
180// NOTE: signature for this function was changed to simplify code.
181UUtBool DD_GLrPlatform_SetDisplayMode(M3tDisplayMode* mode)
182{
183 if (mode->Height < 480)
184 return UUcFalse;
185
186 if (M3gResolutionSwitch)
187 {
188 DEVMODE new_mode, cur_mode;
189
190 cur_mode.dmSize = sizeof(cur_mode);
191 cur_mode.dmDriverExtra = 0;
192
193 // We don't need this check. Windows does this too (see CDS_RESET).
194 if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &cur_mode) ||
195 cur_mode.dmPelsWidth != mode->Width || cur_mode.dmPelsHeight != mode->Height ||
196 cur_mode.dmBitsPerPel != mode->Depth)
197 {
198 new_mode.dmSize = sizeof(new_mode);
199 new_mode.dmFields = DM_BITSPERPEL | DM_PELSHEIGHT | DM_PELSWIDTH;
200 new_mode.dmPelsWidth = mode->Width;
201 new_mode.dmPelsHeight = mode->Height;
202 new_mode.dmBitsPerPel = mode->Depth;
203
204 if (ChangeDisplaySettings(&new_mode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
205 return UUcFalse;
206 }
207
208 // We didn't change window size in DD_GLrPlatform_Initialize so we need
209 // to change it here.
210 SetWindowPos(ONgPlatformData.Window, NULL, 0, 0, mode->Width, mode->Height,
211 SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_NOZORDER);
212
213 return UUcTrue;
214 }
215 else
216 {
217 unsigned screen_x, screen_y;
218 DWORD style, exstyle, new_style, new_exstyle;
219 DWORD flags;
220 RECT rc, workarea_rc;
221 POINT pt;
222
223 screen_x = GetSystemMetrics(SM_CXSCREEN);
224 screen_y = GetSystemMetrics(SM_CYSCREEN);
225
226 GetClientRect(ONgPlatformData.Window, &rc);
227
228 // Don't do anything if the mode was not changed.
229 if (rc.right == mode->Width && rc.bottom == mode->Height)
230 return UUcTrue;
231
232 style = (DWORD) GetWindowLongPtr(ONgPlatformData.Window, GWL_STYLE);
233 exstyle = (DWORD) GetWindowLongPtr(ONgPlatformData.Window, GWL_EXSTYLE);
234 flags = SWP_NOACTIVATE | SWP_NOZORDER;
235
236 // Remember initial window style to correctly restore from fullscreen.
237 if (window_style == 0)
238 {
239 window_style = style;
240 window_exstyle = exstyle;
241 }
242
243 if (mode->Width == screen_x && mode->Height == screen_y)
244 {
245 // "Fullscreen" mode.
246 new_exstyle = exstyle & ~(WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME | WS_EX_STATICEDGE | WS_EX_WINDOWEDGE);
247 new_style = style & ~(WS_CAPTION | WS_BORDER | WS_THICKFRAME | WS_DLGFRAME);
248 new_style = new_style | WS_POPUP;
249 rc.left = 0;
250 rc.top = 0;
251 rc.right = mode->Width;
252 rc.bottom = mode->Height;
253 }
254 else
255 {
256 if (opt_border)
257 {
258 pt.x = rc.left;
259 pt.y = rc.top;
260 ClientToScreen(ONgPlatformData.Window, &pt);
261 }
262 else
263 {
264 pt.x = screen_x / 2 - mode->Width / 2;
265 pt.y = screen_y / 2 - mode->Height / 2;
266 }
267
268 new_exstyle = window_exstyle;
269 new_style = window_style;
270 rc.left = pt.x;
271 rc.top = pt.y;
272 rc.right = rc.left + mode->Width;
273 rc.bottom = rc.top + mode->Height;
274
275 AdjustWindowRectEx(&rc, new_style, FALSE, new_exstyle);
276
277 // Convert to width and height.
278 rc.right -= rc.left;
279 rc.bottom -= rc.top;
280
281 if (SystemParametersInfo(SPI_GETWORKAREA, 0, &workarea_rc, 0))
282 {
283 // We try to keep window position, but we should prevent window
284 // from going off screen.
285
286 if (rc.left + rc.right > workarea_rc.right)
287 rc.left = workarea_rc.right - rc.right;
288 if (rc.top + rc.bottom > workarea_rc.bottom)
289 rc.top = workarea_rc.bottom - rc.bottom;
290
291 // Titlebar should always be visible.
292
293 if (rc.left < workarea_rc.left)
294 rc.left = workarea_rc.left;
295 if (rc.top < workarea_rc.top)
296 rc.top = workarea_rc.top;
297 }
298 }
299
300 if (new_style != style)
301 {
302 SetWindowLongPtr(ONgPlatformData.Window, GWL_STYLE, (LONG_PTR) new_style);
303 flags |= SWP_FRAMECHANGED | SWP_DRAWFRAME;
304 }
305
306 if (new_exstyle != exstyle)
307 {
308 SetWindowLongPtr(ONgPlatformData.Window, GWL_EXSTYLE, (LONG_PTR) new_exstyle);
309 flags |= SWP_FRAMECHANGED | SWP_DRAWFRAME;
310 }
311
312 SetWindowPos(ONgPlatformData.Window, NULL, rc.left, rc.top, rc.right, rc.bottom, flags);
313 return UUcTrue;
314 }
315}
316
317static void ONICALL DD_GLiGamma_Restore(void)
318{
319 if (opt_gamma)
320 {
321 if (gl_api->wglSetDeviceGammaRamp3DFX)
322 gl_api->wglSetDeviceGammaRamp3DFX(gl->hDC, GLgInitialGammaRamp);
323 else
324 SetDeviceGammaRamp(gl->hDC, GLgInitialGammaRamp);
325 }
326}
327
328static void ONICALL DD_GLiGamma_Initialize(void)
329{
330 if (opt_gamma)
331 {
332 if (gl_api->wglSetDeviceGammaRamp3DFX)
333 {
334 UUrStartupMessage("Daodan: Using 3dfx gamma adjustment");
335 GLgGammaRampValid = gl_api->wglGetDeviceGammaRamp3DFX(gl->hDC, GLgInitialGammaRamp);
336 }
337 else
338 {
339 UUrStartupMessage("Daodan: Using Windows gamma adjustment");
340 GLgGammaRampValid = GetDeviceGammaRamp(gl->hDC, GLgInitialGammaRamp);
341 }
342
343 M3rSetGamma(ONrPersist_GetGamma());
344 }
345 else
346 {
347 GLgGammaRampValid = FALSE;
348 }
349}
350
351// Disposes OpenGL engine. Called once.
352void ONICALL DD_GLrPlatform_Dispose(void)
353{
354 DEVMODE dm;
355
356 DD_GLiGamma_Restore();
357
358 gl_api->wglMakeCurrent(NULL, NULL);
359 gl_api->wglDeleteContext(gl->hGLRC);
360 ReleaseDC(ONgPlatformData.Window, gl->hDC);
361
362 // Restore initial display mode if it does not match current mode.
363
364 dm.dmSize = sizeof(dm);
365 dm.dmDriverExtra = 0;
366
367 if (!EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &dm) ||
368 dm.dmPelsWidth != GLgInitialMode.dmPelsWidth ||
369 dm.dmPelsHeight != GLgInitialMode.dmPelsHeight ||
370 dm.dmBitsPerPel != GLgInitialMode.dmBitsPerPel)
371 {
372 ChangeDisplaySettings(&GLgInitialMode, 0);
373 }
374
375 // (skipping SetWindowPos as it only adds flickering)
376 gl_unload_library();
377}
378
379// Initializes (and re-initializes) OpenGL.
380UUtBool ONICALL DD_GLrPlatform_Initialize(void)
381{
382 static const M3tDisplayMode FallbackMode = { 640, 480, 16, 0 };
383
384 if (!DD_GLrPlatform_SetDisplayMode(&gl->DisplayMode))
385 {
386 gl->DisplayMode = FallbackMode;
387
388 if (!DD_GLrPlatform_SetDisplayMode(&gl->DisplayMode))
389 {
390 goto exit_err;
391 }
392 }
393
394 // (DD_GLrPlatform_SetDisplayMode updates a window rectangle for us)
395
396 if (!gl->hDC && !(gl->hDC = GetDC(ONgPlatformData.Window)))
397 {
398 goto exit_err;
399 }
400
401 if (!M3gResolutionSwitch && opt_gamma)
402 {
403 UUrStartupMessage("Daodan: Ignoring gamma setting due to windowed mode");
404 opt_gamma = false;
405 }
406
407 DD_GLiGamma_Initialize();
408
409 // This creates a rendering context too.
410 if (!gl_platform_set_pixel_format(gl->hDC))
411 {
412 if (gl->DisplayMode.Depth != 16)
413 {
414 gl->DisplayMode.Depth = 16;
415 if (!DD_GLrPlatform_SetDisplayMode(&gl->DisplayMode))
416 goto exit_err;
417
418 if (!gl_platform_set_pixel_format(gl->hDC))
419 goto exit_err;
420 }
421 }
422
423 return UUcTrue;
424
425exit_err:
426 AUrMessageBox(1, "Daodan: Failed to initialize OpenGL contexts; Oni will now exit.");
427 exit(0);
428 return 0;
429}
Note: See TracBrowser for help on using the repository browser.