oops, can't get rid of main INCLUDE yet...
[btb/d2x.git] / arch / ogl / wgl.c
1 /* $Id: wgl.c,v 1.3 2003-01-15 02:40:54 btb Exp $ */
2 /*
3  *
4  * opengl platform specific functions for WGL - added by Peter Hawkins
5  * fullscreen example code courtesy of Jeff Slutter
6  * everything merged together and cleaned up by Matt Mueller
7  *         (with some win32 help from Nirvana)
8  *
9  *
10  */
11
12 #ifdef HAVE_CONFIG_H
13 #include <conf.h>
14 #endif
15
16 #include <windows.h>
17 #include <mmsystem.h>
18
19 #include "ogl_init.h"
20 #include "vers_id.h"
21 #include "error.h"
22 #include "key.h"
23 #include "joy.h"
24 #include "mouse.h"
25 #include "digi.h"
26 #include "args.h"
27 #include "resource.h"
28 /*#include "event.h"*/
29 #include <stdio.h>
30
31 //not defined in cygwin, needed to keep windows from resizing everything to fit the fullscreen res.
32 #ifndef CDS_FULLSCREEN
33 #define CDS_FULLSCREEN 0x4
34 #endif
35
36 DEVMODE devmode;//global so the activate proc can reset the screen mode.
37 HINSTANCE hInst=NULL;
38 HWND g_hWnd=NULL;
39
40 extern int Inferno_verbose;
41
42 static int mouse_hidden=0;
43
44
45 //extern unsigned int key_wparam, key_lparam, key_msg;
46 void keyboard_handler();
47 extern int WMKey_Handler_Ready;
48
49 HDC hDC;
50
51 static int GLPREF_width,GLPREF_height;
52 static int GLSTATE_width,GLSTATE_height;
53 static bool GLPREF_windowed;
54
55 static HGLRC GL_ResourceContext=NULL;
56 //static WORD Saved_gamma_values[256*3];
57 bool OpenGL_Initialize(void);
58 void OpenGL_Shutdown(void);
59
60
61 void PumpMessages(void)
62 {
63   MSG msg;
64
65   while (PeekMessage(&msg,NULL,0,0,PM_REMOVE|PM_NOYIELD))
66   {
67         TranslateMessage(&msg);
68         DispatchMessage(&msg);
69   }
70 }
71 static void finiObjects()
72 {
73 //      ogl_close();
74 //   if(mouse_hidden){
75 //    ShowCursor(TRUE);
76 //      mouse_hidden=0;
77 //   }
78
79  //  DisableOpenGL( g_hWnd, hDC, hRC );
80
81
82
83 int vid_susp=0;
84 int wgl_game_activate(int active,int min){
85         int i=0;//do_game_activate(active,min);
86         if (!gl_initialized) return -1;
87         //      printf("****** wgl_game_activate: %i %i,%i %i *******\n",GLPREF_windowed,active,min,vid_susp);
88         if (!active){
89                 mouse_close();
90                 if (!GLPREF_windowed)
91                         if (!vid_susp){
92                                 ChangeDisplaySettings(NULL,0);
93                                 vid_susp=1;
94                         }
95         }else{
96                 mouse_init(0);
97                 if (!GLPREF_windowed)
98                         if (vid_susp){
99                                 ChangeDisplaySettings(&devmode,CDS_FULLSCREEN);
100                                 ShowWindow(g_hWnd,SW_SHOWNORMAL);
101                                 SetWindowPos(g_hWnd,HWND_TOPMOST,0,0,GLPREF_width,GLPREF_height,SWP_FRAMECHANGED);//if you don't set the pos, it comes up half off the screen, or just shows the desktop
102                                 UpdateWindow(g_hWnd);
103                                 wglMakeCurrent(NULL, NULL);
104                                 wglMakeCurrent(hDC,GL_ResourceContext);//this seems to fix some glitches that appear when you alt-tab back in.
105                                 vid_susp=0;
106                         }
107         }
108         //      printf("****** -----------------: %i %i,%i %i *******\n",GLPREF_windowed,active,min,vid_susp);
109         return i;
110 }
111 long PASCAL DescentWndProc(HWND hWnd,UINT message,
112                                                    WPARAM wParam,LPARAM lParam )
113 {
114   switch(message)
115   {
116
117    case WM_KEYDOWN:
118    case WM_KEYUP:
119         if (WMKey_Handler_Ready) {
120 //      key_wparam=wParam; key_lparam=lParam; key_msg=message;
121           keyboard_handler();
122         }
123         break;
124    case WM_MOUSEMOVE:
125    case WM_LBUTTONDOWN:
126    case WM_LBUTTONUP:
127    case WM_RBUTTONDOWN:
128    case WM_RBUTTONUP:
129    case WM_NCMOUSEMOVE:
130    case WM_NCLBUTTONDOWN:
131    case WM_NCLBUTTONUP:
132    case WM_NCRBUTTONDOWN:
133    case WM_NCRBUTTONUP:
134          break;
135    case WM_PALETTECHANGED:
136    case WM_PALETTEISCHANGING:
137          return 0;
138    case WM_KILLFOCUS:
139          if (!GLPREF_windowed)
140                  ShowWindow(g_hWnd, SW_SHOWMINNOACTIVE);//this minimizes the game after you alt-tab out.
141          break;
142    case WM_ACTIVATE:
143          wgl_game_activate((!(LOWORD(wParam) == WA_INACTIVE)),(BOOL) HIWORD(wParam));
144          break;
145    case WM_ACTIVATEAPP:
146 //     Win32_Key_Hook(wParam);
147 // DPH: This doesn't work... no idea why not...
148          break;
149    case WM_DESTROY:
150          finiObjects();
151          PostQuitMessage(0);
152          break;
153    default:
154          return DefWindowProc(hWnd,message,wParam,lParam);
155   }
156   return 1;
157 }
158
159
160
161 void ogl_swap_buffers_internal(void){
162         SwapBuffers( hDC );
163 }
164
165 int get_win_x_bs(void){
166 //      return GetSystemMetrics(SM_CXBORDER)*2
167         return GetSystemMetrics(SM_CXFIXEDFRAME)*2;
168 }
169 int get_win_y_bs(void){
170 //      return GetSystemMetrics(SM_CYBORDER)*2+GetSystemMetrics(SM_CYCAPTION);
171         return GetSystemMetrics(SM_CYFIXEDFRAME)*2+GetSystemMetrics(SM_CYCAPTION);
172 }
173 void win32_create_window(int x,int y)
174 {
175         int flags;
176
177         WNDCLASS wcDescentClass;
178
179         if (!hInst)
180                 Error("hInst=NULL\n");
181
182
183         wcDescentClass.lpszClassName = "WinD1X";
184         wcDescentClass.hInstance     = hInst;
185         wcDescentClass.lpfnWndProc   = DescentWndProc;
186         wcDescentClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
187         //wcDescentClass.hIcon         = LoadIcon(NULL, IDI_WINLOGO);
188         wcDescentClass.hIcon         = LoadIcon(hInst, MAKEINTRESOURCE(IDI_MAIN_ICON));
189         wcDescentClass.lpszMenuName  = NULL;
190         wcDescentClass.hbrBackground = NULL;
191         wcDescentClass.style         = CS_OWNDC;
192         wcDescentClass.cbClsExtra    = 0;
193         wcDescentClass.cbWndExtra    = 0;
194                 
195         // Register the class
196         if (!RegisterClass(&wcDescentClass)){
197 //              printf("RegisterClass==0?\n");
198                 //always seems to return 0 after the first time, yet if you remove the call, it crashes. Heh.
199         }
200
201         if (ogl_fullscreen)
202                 flags=WS_POPUP;//uh.. don't remember if removing sysmenu did anything or not.. but it works.
203                 //flags=WS_POPUP | WS_SYSMENU;
204         else
205                 flags=WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;//let us minimize it.
206                 //flags=WS_OVERLAPPED | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
207
208         if (!ogl_fullscreen){
209                 x+=get_win_x_bs();y+=get_win_y_bs();
210         }else{
211                 if (FindArg("-gl_test2")){
212                         x=GetSystemMetrics(SM_CXSCREEN);
213                         y=GetSystemMetrics(SM_CYSCREEN);
214                 }
215         }
216         g_hWnd = CreateWindowEx(0,
217                         "WinD1X",
218                         "Descent",
219                         flags,
220                         0, 0,
221                         x,y,
222                         NULL,
223                         NULL,
224                         hInst,
225                         NULL
226                                                    );
227
228         if (!g_hWnd) Error("no window?\n");
229         ShowWindow(g_hWnd,SW_SHOWNORMAL);
230         UpdateWindow(g_hWnd);
231
232         OpenGL_Initialize();
233
234         if (ogl_fullscreen){
235         ShowCursor(FALSE);
236         mouse_hidden = 1;
237         }
238
239         key_init();
240         mouse_init(0);
241         joy_init(JOYSTICKID1);
242         if (!FindArg( "-nosound" ))
243                 digi_init();
244 //      printf("arch_init successfully completed\n");
245
246         gl_initialized=1;
247 }
248 void ogl_destroy_window(void){
249         if (gl_initialized){
250                 ogl_smash_texture_list_internal();
251                 if (mouse_hidden){
252                         ShowCursor(TRUE);
253                         mouse_hidden = 0;
254                 }
255                 if (g_hWnd){
256                         key_close();
257                         mouse_close();
258                         joy_close();
259                         if (!FindArg( "-nosound" ))
260                                 digi_close();
261                         OpenGL_Shutdown();
262                         DestroyWindow(g_hWnd);
263                 }else
264                         Error("ogl_destroy_window: no g_hWnd?\n");
265                 gl_initialized=0;
266         }
267         return;
268 }
269
270 void ogl_do_fullscreen_internal(void){
271         if (GLPREF_windowed==ogl_fullscreen){
272                 ogl_destroy_window();
273                 win32_create_window(GLPREF_width,GLPREF_height);
274                 ogl_vivify_texture_list_internal();
275         }
276 }
277
278
279 int ogl_init_window(int x, int y){
280         GLPREF_width=x;
281         GLPREF_height=y;
282         if (gl_initialized){
283                 if (GLSTATE_width==GLPREF_width && GLSTATE_height==GLPREF_height && GLPREF_windowed!=ogl_fullscreen)
284                         return 0;//we are already in the right mode, don't do anything.
285                 if (!ogl_fullscreen && GLPREF_windowed){
286                         SetWindowPos(g_hWnd,0,0,0,x+get_win_x_bs(),y+get_win_y_bs(),SWP_NOMOVE);
287                 }else{
288                         ogl_destroy_window();
289                         win32_create_window(x,y);
290                         ogl_vivify_texture_list_internal();
291                 }
292         }else {
293                 win32_create_window(x,y);
294         }
295         return 0;
296 }
297 void ogl_init(void){
298         hInst=GetModuleHandle (NULL);
299 }
300 void ogl_close(void){
301         ogl_destroy_window();
302 }
303
304
305 //windows opengl fullscreen changing - courtesy of Jeff Slutter
306
307 /*
308
309   Windows Full Screen Setup
310
311   ===========================================================================
312 */
313
314
315 // Entering this function, the following values must be valid
316 //              GLPREF_width,GLPREF_height: preferred width and height
317 //              GLPREF_windowed: do we want windowed or full screen mode
318 //              g_hWnd: handle to the window created for OpenGL
319 //      On exit from this function (if returned true) the following values will be set
320 //              GLSTATE_width,GLSTATE_height: real width and height of screen
321 //              hDC: device context of the window
322 //              GL_ResourceContext: OpenGL resource context
323 //              Saved_gamma_values: Initial gamma values
324 bool OpenGL_Initialize(void)
325 {
326         char *errstr="";
327         int width,height;
328         int pf;
329         PIXELFORMATDESCRIPTOR pfd;//, pfd_copy;
330
331         GLPREF_windowed=!ogl_fullscreen;
332         
333         if (FindArg("-gl_test1")){
334                 GLSTATE_width = GLPREF_width;
335                 GLSTATE_height = GLPREF_height;
336         }else{
337                 if(!GLPREF_windowed)
338                 {
339                         // First set our display mode
340                         // Create direct draw surface
341                         int retval;
342
343                         devmode.dmSize=sizeof(devmode);
344                         devmode.dmBitsPerPel=16;
345                         devmode.dmPelsWidth=GLPREF_width;
346                         devmode.dmPelsHeight=GLPREF_height;
347                         devmode.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
348                         if ((retval=FindArg("-gl_refresh"))){
349                                 devmode.dmDisplayFrequency=atoi(Args[retval+1]);
350                                 if (devmode.dmDisplayFrequency>=60)//uhh, I hope no one actually wants a refresh lower than 60.. gag.
351                                         devmode.dmFields|=DM_DISPLAYFREQUENCY;
352                                 printf("trying refresh %i hz\n",devmode.dmDisplayFrequency);
353                         }
354
355                         retval=ChangeDisplaySettings(&devmode,CDS_FULLSCREEN);
356
357                         if (retval!=DISP_CHANGE_SUCCESSFUL)
358                         {
359                                 // we couldn't switch to the desired screen mode
360                                 // fall back to 640x480
361                                 retval=-1;
362                                 devmode.dmBitsPerPel=16;
363                                 devmode.dmPelsWidth=640;
364                                 devmode.dmPelsHeight=480;
365                                 devmode.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
366
367                                 retval=ChangeDisplaySettings(&devmode,CDS_FULLSCREEN);
368                                 if (retval!=DISP_CHANGE_SUCCESSFUL)
369                                 {
370                                         errstr="ChangeDisplaySettings";
371                                         // we couldn't even switch to 640x480, we're out of here
372                                         // restore screen mode to default
373                                         ChangeDisplaySettings(NULL,0);
374                                         goto OpenGLError;
375                                 }else
376                                 {
377                                         // successful, change our global settings to reflect what 
378                                         // mode we are at
379                                         GLPREF_width=640;
380                                         GLPREF_height=480;
381                                 }
382                         }else
383                         {
384                                 // success at changing the video mode
385                         }
386                 }
387
388
389                 if(GLPREF_windowed)
390                 {
391                         // we want windowed mode, figure out how big the window is
392                         RECT rect;
393                         GetWindowRect(g_hWnd,&rect);
394                         width=abs(rect.right-rect.left);
395                         height=abs(rect.bottom-rect.top);
396                 }else
397                 {
398                         RECT rect;
399                         // full screen mode, we want the window to be on top of everything
400                         SetWindowPos(g_hWnd,HWND_TOPMOST,0,0,GLPREF_width,GLPREF_height,SWP_FRAMECHANGED);
401                         width=GLPREF_width;
402                         height=GLPREF_height;
403                         GetWindowRect(g_hWnd,&rect);
404                 }
405
406                 GLSTATE_width = width;
407                 GLSTATE_height = height;
408
409         }
410         
411         hDC = GetDC(g_hWnd);
412         
413         // Now we finally setup OpenGL
414         // If OpenGL is to be dynamically loaded, do this now (if the DLL isn't already
415         // loaded)
416         // remove the following error when you figure out what you want to do
417         // it's put here to make sure you notice this
418 #ifdef OGL_RUNTIME_LOAD
419         ogl_init_load_library();
420 #endif
421
422         // Setup our pixel format
423
424         memset(&pfd,0,sizeof(pfd));
425         pfd.nSize        = sizeof(pfd);
426         pfd.nVersion     = 1;
427         pfd.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
428 //      pfd.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_GENERIC_ACCELERATED;
429         pfd.iPixelType   = PFD_TYPE_RGBA;
430         //let the ogl driver decide. (fixes no hw accel in 16bit mode in w2k with tnt2)
431 //      pfd.cColorBits = 16;
432 //      pfd.cAlphaBits = 8;
433 //      pfd.cDepthBits = 0;
434 //      pfd.cAccumBits = 0;
435 //      pfd.cStencilBits = 0;
436         pfd.iLayerType = PFD_MAIN_PLANE;
437         pfd.dwLayerMask = PFD_MAIN_PLANE;
438
439
440         // Find the user's "best match" PFD 
441         pf = ChoosePixelFormat(hDC,&pfd);
442         if(pf == 0) 
443         {
444                 errstr="ChoosePixelFormat";
445                 // no pixel format closely matches      
446                 goto OpenGLError;
447         } 
448
449         // Set the new PFD
450         if(SetPixelFormat(hDC,pf,&pfd)==FALSE) 
451         {
452                 errstr="SetPixelFormat";
453                 // unable to set the pixel format
454                 goto OpenGLError;
455         }
456
457         // Now retrieve the PFD, we need to check some things
458 /*      if(DescribePixelFormat(hDC,pf,sizeof(PIXELFORMATDESCRIPTOR),&pfd_copy)==0)
459         {
460                 errstr="DescribePixelFormat";
461                 // unable to get the PFD
462                 goto OpenGLError;
463         }
464
465         // Make sure we are hardware accelerated
466         if((pfd_copy.dwFlags&PFD_GENERIC_ACCELERATED)==0&&(pfd_copy.dwFlags&PFD_GENERIC_FORMAT)!=0)
467         {
468                 // we are not hardware accelerated!
469                 goto OpenGLError;
470         }*/
471
472         // Finally, create our OpenGL context and make it current
473         GL_ResourceContext = wglCreateContext(hDC);
474         if(GL_ResourceContext==NULL)
475         {
476                 errstr="wglCreateContext";
477                 // we couldn't create a context!
478                 goto OpenGLError;
479         }
480
481         // Make the context current
482         wglMakeCurrent(hDC,GL_ResourceContext);
483
484         // Save our gamma values because we'll probably be changing them,
485         // this way we can restore them on exit
486
487 //      GetDeviceGammaRamp(hDC,(LPVOID)Saved_gamma_values);
488
489         return true;
490
491 OpenGLError:
492         // Shutdown OpenGL
493         OpenGL_Shutdown();
494         Error("opengl init error: %s\n",errstr);
495         return false;
496 }
497
498 void OpenGL_Shutdown(void)
499 {
500         // Do any needed OpenGL shutdown here
501
502
503         // Now do Window specific shutdown
504         if(wglMakeCurrent)//check to make sure the function is valid (dyanmic loaded OpenGL)
505                 wglMakeCurrent(NULL, NULL);
506
507         if(wglDeleteContext)//check to make sure the function is valid (dyanmic loaded OpenGL)
508                 wglDeleteContext(GL_ResourceContext);
509         
510         // Restore back to user screen settings
511         if(!GLPREF_windowed)
512                 ChangeDisplaySettings(NULL,0);
513
514         // Restore gamma values
515
516 //      SetDeviceGammaRamp(hDC,(LPVOID)Saved_gamma_values);
517         
518         ReleaseDC(g_hWnd,hDC);
519 }