source: Daodan/src/Daodan_GL.c@ 717

Last change on this file since 717 was 705, checked in by alloc, 12 years ago

Daodan: DaodanGL fixes, intro/outro fixes, chinese=true by default

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