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