implement brightness/palette effects in OGL using SetGammaRamp, much faster than...
[btb/d2x.git] / arch / ogl / wgl.c
1 /* $Id: wgl.c,v 1.6 2004-05-20 02:04:29 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 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 int ogl_setbrightness_internal(void)
161 {
162         return -1; // TODO: not yet implemented
163 }
164
165 void ogl_swap_buffers_internal(void){
166         SwapBuffers( hDC );
167 }
168
169 int get_win_x_bs(void){
170 //      return GetSystemMetrics(SM_CXBORDER)*2
171         return GetSystemMetrics(SM_CXFIXEDFRAME)*2;
172 }
173 int get_win_y_bs(void){
174 //      return GetSystemMetrics(SM_CYBORDER)*2+GetSystemMetrics(SM_CYCAPTION);
175         return GetSystemMetrics(SM_CYFIXEDFRAME)*2+GetSystemMetrics(SM_CYCAPTION);
176 }
177 void win32_create_window(int x,int y)
178 {
179         int flags;
180
181         WNDCLASS wcDescentClass;
182
183         if (!hInst)
184                 Error("hInst=NULL\n");
185
186
187         wcDescentClass.lpszClassName = "WinD1X";
188         wcDescentClass.hInstance     = hInst;
189         wcDescentClass.lpfnWndProc   = DescentWndProc;
190         wcDescentClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
191         //wcDescentClass.hIcon         = LoadIcon(NULL, IDI_WINLOGO);
192         wcDescentClass.hIcon         = LoadIcon(hInst, MAKEINTRESOURCE(IDI_MAIN_ICON));
193         wcDescentClass.lpszMenuName  = NULL;
194         wcDescentClass.hbrBackground = NULL;
195         wcDescentClass.style         = CS_OWNDC;
196         wcDescentClass.cbClsExtra    = 0;
197         wcDescentClass.cbWndExtra    = 0;
198                 
199         // Register the class
200         if (!RegisterClass(&wcDescentClass)){
201 //              printf("RegisterClass==0?\n");
202                 //always seems to return 0 after the first time, yet if you remove the call, it crashes. Heh.
203         }
204
205         if (ogl_fullscreen)
206                 flags=WS_POPUP;//uh.. don't remember if removing sysmenu did anything or not.. but it works.
207                 //flags=WS_POPUP | WS_SYSMENU;
208         else
209                 flags=WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;//let us minimize it.
210                 //flags=WS_OVERLAPPED | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
211
212         if (!ogl_fullscreen){
213                 x+=get_win_x_bs();y+=get_win_y_bs();
214         }else{
215                 if (FindArg("-gl_test2")){
216                         x=GetSystemMetrics(SM_CXSCREEN);
217                         y=GetSystemMetrics(SM_CYSCREEN);
218                 }
219         }
220         g_hWnd = CreateWindowEx(0,
221                         "WinD1X",
222                         "Descent",
223                         flags,
224                         0, 0,
225                         x,y,
226                         NULL,
227                         NULL,
228                         hInst,
229                         NULL
230                                                    );
231
232         if (!g_hWnd) Error("no window?\n");
233         ShowWindow(g_hWnd,SW_SHOWNORMAL);
234         UpdateWindow(g_hWnd);
235
236         OpenGL_Initialize();
237
238         if (ogl_fullscreen){
239         ShowCursor(FALSE);
240         mouse_hidden = 1;
241         }
242
243         key_init();
244         mouse_init(0);
245         joy_init(JOYSTICKID1);
246         if (!FindArg( "-nosound" ))
247                 digi_init();
248 //      printf("arch_init successfully completed\n");
249
250         gl_initialized=1;
251 }
252 void ogl_destroy_window(void){
253         if (gl_initialized){
254                 ogl_smash_texture_list_internal();
255                 if (mouse_hidden){
256                         ShowCursor(TRUE);
257                         mouse_hidden = 0;
258                 }
259                 if (g_hWnd){
260                         key_close();
261                         mouse_close();
262                         joy_close();
263                         if (!FindArg( "-nosound" ))
264                                 digi_close();
265                         OpenGL_Shutdown();
266                         DestroyWindow(g_hWnd);
267                 }else
268                         Error("ogl_destroy_window: no g_hWnd?\n");
269                 gl_initialized=0;
270         }
271         return;
272 }
273
274 void ogl_do_fullscreen_internal(void){
275         if (GLPREF_windowed==ogl_fullscreen){
276                 ogl_destroy_window();
277                 win32_create_window(GLPREF_width,GLPREF_height);
278                 ogl_vivify_texture_list_internal();
279         }
280 }
281
282
283 int ogl_init_window(int x, int y){
284         GLPREF_width=x;
285         GLPREF_height=y;
286         if (gl_initialized){
287                 if (GLSTATE_width==GLPREF_width && GLSTATE_height==GLPREF_height && GLPREF_windowed!=ogl_fullscreen)
288                         return 0;//we are already in the right mode, don't do anything.
289                 if (!ogl_fullscreen && GLPREF_windowed){
290                         SetWindowPos(g_hWnd,0,0,0,x+get_win_x_bs(),y+get_win_y_bs(),SWP_NOMOVE);
291                 }else{
292                         ogl_destroy_window();
293                         win32_create_window(x,y);
294                         ogl_vivify_texture_list_internal();
295                 }
296         }else {
297                 win32_create_window(x,y);
298         }
299         return 0;
300 }
301 void ogl_init(void){
302         hInst=GetModuleHandle (NULL);
303 }
304 void ogl_close(void){
305         ogl_destroy_window();
306 }
307
308
309 //windows opengl fullscreen changing - courtesy of Jeff Slutter
310
311 /*
312
313   Windows Full Screen Setup
314
315   ===========================================================================
316 */
317
318
319 // Entering this function, the following values must be valid
320 //              GLPREF_width,GLPREF_height: preferred width and height
321 //              GLPREF_windowed: do we want windowed or full screen mode
322 //              g_hWnd: handle to the window created for OpenGL
323 //      On exit from this function (if returned true) the following values will be set
324 //              GLSTATE_width,GLSTATE_height: real width and height of screen
325 //              hDC: device context of the window
326 //              GL_ResourceContext: OpenGL resource context
327 //              Saved_gamma_values: Initial gamma values
328 bool OpenGL_Initialize(void)
329 {
330         char *errstr="";
331         int width,height;
332         int pf;
333         PIXELFORMATDESCRIPTOR pfd;//, pfd_copy;
334
335         GLPREF_windowed=!ogl_fullscreen;
336         
337         if (FindArg("-gl_test1")){
338                 GLSTATE_width = GLPREF_width;
339                 GLSTATE_height = GLPREF_height;
340         }else{
341                 if(!GLPREF_windowed)
342                 {
343                         // First set our display mode
344                         // Create direct draw surface
345                         int retval;
346
347                         devmode.dmSize=sizeof(devmode);
348                         devmode.dmBitsPerPel=16;
349                         devmode.dmPelsWidth=GLPREF_width;
350                         devmode.dmPelsHeight=GLPREF_height;
351                         devmode.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
352                         if ((retval=FindArg("-gl_refresh"))){
353                                 devmode.dmDisplayFrequency=atoi(Args[retval+1]);
354                                 if (devmode.dmDisplayFrequency>=60)//uhh, I hope no one actually wants a refresh lower than 60.. gag.
355                                         devmode.dmFields|=DM_DISPLAYFREQUENCY;
356                                 printf("trying refresh %li hz\n", devmode.dmDisplayFrequency);
357                         }
358
359                         retval=ChangeDisplaySettings(&devmode,CDS_FULLSCREEN);
360
361                         if (retval!=DISP_CHANGE_SUCCESSFUL)
362                         {
363                                 // we couldn't switch to the desired screen mode
364                                 // fall back to 640x480
365                                 retval=-1;
366                                 devmode.dmBitsPerPel=16;
367                                 devmode.dmPelsWidth=640;
368                                 devmode.dmPelsHeight=480;
369                                 devmode.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
370
371                                 retval=ChangeDisplaySettings(&devmode,CDS_FULLSCREEN);
372                                 if (retval!=DISP_CHANGE_SUCCESSFUL)
373                                 {
374                                         errstr="ChangeDisplaySettings";
375                                         // we couldn't even switch to 640x480, we're out of here
376                                         // restore screen mode to default
377                                         ChangeDisplaySettings(NULL,0);
378                                         goto OpenGLError;
379                                 }else
380                                 {
381                                         // successful, change our global settings to reflect what 
382                                         // mode we are at
383                                         GLPREF_width=640;
384                                         GLPREF_height=480;
385                                 }
386                         }else
387                         {
388                                 // success at changing the video mode
389                         }
390                 }
391
392
393                 if(GLPREF_windowed)
394                 {
395                         // we want windowed mode, figure out how big the window is
396                         RECT rect;
397                         GetWindowRect(g_hWnd,&rect);
398                         width=abs(rect.right-rect.left);
399                         height=abs(rect.bottom-rect.top);
400                 }else
401                 {
402                         RECT rect;
403                         // full screen mode, we want the window to be on top of everything
404                         SetWindowPos(g_hWnd,HWND_TOPMOST,0,0,GLPREF_width,GLPREF_height,SWP_FRAMECHANGED);
405                         width=GLPREF_width;
406                         height=GLPREF_height;
407                         GetWindowRect(g_hWnd,&rect);
408                 }
409
410                 GLSTATE_width = width;
411                 GLSTATE_height = height;
412
413         }
414         
415         hDC = GetDC(g_hWnd);
416         
417         // Now we finally setup OpenGL
418         // If OpenGL is to be dynamically loaded, do this now (if the DLL isn't already
419         // loaded)
420         // remove the following error when you figure out what you want to do
421         // it's put here to make sure you notice this
422 #ifdef OGL_RUNTIME_LOAD
423         ogl_init_load_library();
424 #endif
425
426         // Setup our pixel format
427
428         memset(&pfd,0,sizeof(pfd));
429         pfd.nSize        = sizeof(pfd);
430         pfd.nVersion     = 1;
431         pfd.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
432 //      pfd.dwFlags      = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_GENERIC_ACCELERATED;
433         pfd.iPixelType   = PFD_TYPE_RGBA;
434         //let the ogl driver decide. (fixes no hw accel in 16bit mode in w2k with tnt2)
435 //      pfd.cColorBits = 16;
436 //      pfd.cAlphaBits = 8;
437 //      pfd.cDepthBits = 0;
438 //      pfd.cAccumBits = 0;
439 //      pfd.cStencilBits = 0;
440         pfd.iLayerType = PFD_MAIN_PLANE;
441         pfd.dwLayerMask = PFD_MAIN_PLANE;
442
443
444         // Find the user's "best match" PFD 
445         pf = ChoosePixelFormat(hDC,&pfd);
446         if(pf == 0) 
447         {
448                 errstr="ChoosePixelFormat";
449                 // no pixel format closely matches      
450                 goto OpenGLError;
451         } 
452
453         // Set the new PFD
454         if(SetPixelFormat(hDC,pf,&pfd)==FALSE) 
455         {
456                 errstr="SetPixelFormat";
457                 // unable to set the pixel format
458                 goto OpenGLError;
459         }
460
461         // Now retrieve the PFD, we need to check some things
462 /*      if(DescribePixelFormat(hDC,pf,sizeof(PIXELFORMATDESCRIPTOR),&pfd_copy)==0)
463         {
464                 errstr="DescribePixelFormat";
465                 // unable to get the PFD
466                 goto OpenGLError;
467         }
468
469         // Make sure we are hardware accelerated
470         if((pfd_copy.dwFlags&PFD_GENERIC_ACCELERATED)==0&&(pfd_copy.dwFlags&PFD_GENERIC_FORMAT)!=0)
471         {
472                 // we are not hardware accelerated!
473                 goto OpenGLError;
474         }*/
475
476         // Finally, create our OpenGL context and make it current
477         GL_ResourceContext = wglCreateContext(hDC);
478         if(GL_ResourceContext==NULL)
479         {
480                 errstr="wglCreateContext";
481                 // we couldn't create a context!
482                 goto OpenGLError;
483         }
484
485         // Make the context current
486         wglMakeCurrent(hDC,GL_ResourceContext);
487
488         // Save our gamma values because we'll probably be changing them,
489         // this way we can restore them on exit
490
491 //      GetDeviceGammaRamp(hDC,(LPVOID)Saved_gamma_values);
492
493         return true;
494
495 OpenGLError:
496         // Shutdown OpenGL
497         OpenGL_Shutdown();
498         Error("opengl init error: %s\n",errstr);
499         return false;
500 }
501
502 void OpenGL_Shutdown(void)
503 {
504         // Do any needed OpenGL shutdown here
505
506
507         // Now do Window specific shutdown
508         if(wglMakeCurrent)//check to make sure the function is valid (dyanmic loaded OpenGL)
509                 wglMakeCurrent(NULL, NULL);
510
511         if(wglDeleteContext)//check to make sure the function is valid (dyanmic loaded OpenGL)
512                 wglDeleteContext(GL_ResourceContext);
513         
514         // Restore back to user screen settings
515         if(!GLPREF_windowed)
516                 ChangeDisplaySettings(NULL,0);
517
518         // Restore gamma values
519
520 //      SetDeviceGammaRamp(hDC,(LPVOID)Saved_gamma_values);
521         
522         ReleaseDC(g_hWnd,hDC);
523 }