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