Add alt-enter fullscreen toggle
[theoddone33/hhexen.git] / sdl / i_sdlgl.c
1 //**************************************************************************
2 //**
3 //** $Id$
4 //**
5 //**************************************************************************
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdarg.h>
10 #include <unistd.h>
11 #include <sys/time.h>
12 #include <SDL/SDL.h> 
13 #include <GL/gl.h>
14 #include <GL/glu.h>
15 #include "h2def.h"
16 #include "r_local.h"
17 #include "p_local.h"    // for P_AproxDistance
18 #include "sounds.h"
19 #include "i_sound.h"
20 #include "soundst.h"
21 #include "st_start.h"
22
23 // Public Data
24
25 int screenWidth  = SCREENWIDTH*2;
26 int screenHeight = SCREENHEIGHT*2;
27 int maxTexSize = 256;
28 int ratioLimit = 0;             // Zero if none.
29 int test3dfx = 0;
30
31 int DisplayTicker = 0;
32
33
34 // Code
35 extern void OGL_InitData();
36 extern void OGL_InitRenderer();
37 extern void OGL_ResetData();
38 extern void OGL_ResetLumpTexData();
39
40 void I_StartupNet (void);
41 void I_ShutdownNet (void);
42 void I_ReadExternDriver(void);
43 void GrabScreen (void);
44
45 extern int usemouse, usejoystick;
46
47 extern void **lumpcache;
48
49 int i_Vector;
50 externdata_t *i_ExternData;
51 boolean useexterndriver;
52
53 boolean mousepresent;
54
55 int ticcount;
56
57 boolean novideo; // if true, stay in text mode for debugging
58
59 #define KEY_INS         0x52
60 #define KEY_DEL         0x53
61 #define KEY_PGUP        0x49
62 #define KEY_PGDN        0x51
63 #define KEY_HOME        0x47
64 #define KEY_END         0x4f
65
66 //--------------------------------------------------------------------------
67 //
68 // PROC I_WaitVBL
69 //
70 //--------------------------------------------------------------------------
71
72 void I_WaitVBL(int vbls)
73 {
74         if( novideo )
75         {
76                 return;
77         }
78         while( vbls-- )
79         {
80         SDL_Delay( 16667/1000 );
81         }
82 }
83
84 //--------------------------------------------------------------------------
85 //
86 // PROC I_SetPalette
87 //
88 // Palette source must use 8 bit RGB elements.
89 //
90 //--------------------------------------------------------------------------
91
92 void I_SetPalette(byte *palette)
93 {
94 /*
95     SDL_Color* c;
96     SDL_Color* cend;
97     SDL_Color cmap[ 256 ];
98
99         if(novideo)
100         {
101                 return;
102         }
103         I_WaitVBL(1);
104
105     c = cmap;
106     cend = c + 256;
107         for( ; c != cend; c++ )
108         {
109                 //_outbyte(PEL_DATA, (gammatable[usegamma][*palette++])>>2);
110
111         c->r = gammatable[usegamma][*palette++];
112         c->g = gammatable[usegamma][*palette++];
113         c->b = gammatable[usegamma][*palette++];
114         }
115     SDL_SetColors( sdl_screen, cmap, 0, 256 );
116 */
117 }
118
119 /*
120 ============================================================================
121
122                                                         GRAPHICS MODE
123
124 ============================================================================
125 */
126
127 byte *pcscreen, *destscreen, *destview;
128
129 /*
130 ==============
131 =
132 = I_Update
133 =
134 ==============
135 */
136
137 int UpdateState;
138 extern int screenblocks;
139
140 void I_Update (void)
141 {
142         if(UpdateState == I_NOUPDATE)
143                 return;
144
145         SDL_GL_SwapBuffers();
146         UpdateState = I_NOUPDATE;
147 }
148
149 //--------------------------------------------------------------------------
150 //
151 // PROC I_InitGraphics
152 //
153 //--------------------------------------------------------------------------
154
155 void I_InitGraphics(void)
156 {
157     int p;
158     char text[20];
159     Uint32 flags = SDL_OPENGL;
160
161     if( novideo )
162     {
163         return;
164     }
165
166     if (M_CheckParm("-f") || M_CheckParm("--fullscreen")) {
167         flags |= SDL_FULLSCREEN;
168         setenv ("MESA_GLX_FX","fullscreen", 1);
169     } else {
170         setenv ("MESA_GLX_FX","disable",1);
171     }   
172     p = M_CheckParm ("-height");
173     if (p && p < myargc - 1)
174     {
175         screenHeight = atoi (myargv[p+1]);
176     }
177     p = M_CheckParm ("-width");
178     if (p && p < myargc - 1) {
179         screenWidth = atoi(myargv[p+1]);
180     }
181     ST_Message("Screen size:  %dx%d\n",screenWidth, screenHeight);
182
183     if(SDL_SetVideoMode(screenWidth, screenHeight, 8, flags) == NULL)
184     {
185         fprintf( stderr, "Couldn't set video mode %dx%d: %s\n",
186                  screenWidth, screenHeight, SDL_GetError() );
187         exit( 3 );
188     }
189
190     OGL_InitRenderer ();
191
192     glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
193
194     // Print some OpenGL information.
195     ST_Message( "I_InitGraphics: OpenGL information:\n" );
196     ST_Message( "  Vendor: %s\n", glGetString(GL_VENDOR) );
197     ST_Message( "  Renderer: %s\n", glGetString(GL_RENDERER) );
198     ST_Message( "  Version: %s\n", glGetString(GL_VERSION) );
199     ST_Message( "  GLU Version: %s\n", gluGetString((GLenum)GLU_VERSION) );
200
201     // Check the maximum texture size.
202     glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTexSize );
203     ST_Message("  Maximum texture size: %d\n", maxTexSize);
204     if( maxTexSize == 256 )
205     {
206             //ST_Message("  Is this Voodoo? Using size ratio limit.\n");
207             ratioLimit = 8;
208     }
209
210     if( M_CheckParm("-3dfxtest") )
211     {
212             test3dfx = 1;
213             ST_Message("  3dfx test mode.\n");
214     }
215
216     // Only grab if we want to
217     if (!M_CheckParm ("--nograb") && !M_CheckParm ("-g")) {
218             SDL_WM_GrabInput (SDL_GRAB_ON);
219     }
220
221     SDL_ShowCursor( 0 );
222     snprintf (text, 20, "HHexen v%s", HHEXEN_VERSION);
223     SDL_WM_SetCaption( text, "HHEXEN" );
224
225
226     //I_SetPalette( W_CacheLumpName("PLAYPAL", PU_CACHE) );
227 }
228
229 //--------------------------------------------------------------------------
230 //
231 // PROC I_ShutdownGraphics
232 //
233 //--------------------------------------------------------------------------
234
235 void I_ShutdownGraphics(void)
236 {
237     OGL_ResetData ();
238     OGL_ResetLumpTexData ();
239     SDL_Quit ();
240 }
241
242 //===========================================================================
243
244 //
245 //  Translates the key 
246 //
247
248 int xlatekey(SDL_keysym *key)
249 {
250
251     int rc;
252
253     switch(key->sym)
254     {
255       case SDLK_LEFT:   rc = KEY_LEFTARROW;     break;
256       case SDLK_RIGHT:  rc = KEY_RIGHTARROW;    break;
257       case SDLK_DOWN:   rc = KEY_DOWNARROW;     break;
258       case SDLK_UP:     rc = KEY_UPARROW;       break;
259       case SDLK_ESCAPE: rc = KEY_ESCAPE;        break;
260       case SDLK_RETURN: rc = KEY_ENTER;         break;
261       case SDLK_F1:     rc = KEY_F1;            break;
262       case SDLK_F2:     rc = KEY_F2;            break;
263       case SDLK_F3:     rc = KEY_F3;            break;
264       case SDLK_F4:     rc = KEY_F4;            break;
265       case SDLK_F5:     rc = KEY_F5;            break;
266       case SDLK_F6:     rc = KEY_F6;            break;
267       case SDLK_F7:     rc = KEY_F7;            break;
268       case SDLK_F8:     rc = KEY_F8;            break;
269       case SDLK_F9:     rc = KEY_F9;            break;
270       case SDLK_F10:    rc = KEY_F10;           break;
271       case SDLK_F11:    rc = KEY_F11;           break;
272       case SDLK_F12:    rc = KEY_F12;           break;
273         
274       case SDLK_INSERT: rc = KEY_INS;           break;
275       case SDLK_DELETE: rc = KEY_DEL;           break;
276       case SDLK_PAGEUP: rc = KEY_PGUP;          break;
277       case SDLK_PAGEDOWN: rc = KEY_PGDN;        break;
278       case SDLK_HOME:   rc = KEY_HOME;          break;
279       case SDLK_END:    rc = KEY_END;           break;
280
281       case SDLK_BACKSPACE: rc = KEY_BACKSPACE;  break;
282
283       case SDLK_PAUSE:  rc = KEY_PAUSE;         break;
284
285       case SDLK_EQUALS: rc = KEY_EQUALS;        break;
286
287       case SDLK_KP_MINUS:
288       case SDLK_MINUS:  rc = KEY_MINUS;         break;
289
290       case SDLK_LSHIFT:
291       case SDLK_RSHIFT:
292         rc = KEY_RSHIFT;
293         break;
294         
295       case SDLK_LCTRL:
296       case SDLK_RCTRL:
297         rc = KEY_RCTRL;
298         break;
299         
300       case SDLK_LALT:
301       case SDLK_LMETA:
302       case SDLK_RALT:
303       case SDLK_RMETA:
304         rc = KEY_RALT;
305         break;
306         
307       default:
308         rc = key->sym;
309         break;
310     }
311
312     return rc;
313
314 }
315
316
317 /* This processes SDL events */
318 void I_GetEvent(SDL_Event *Event)
319 {
320     Uint8 buttonstate;
321     event_t event;
322     SDLMod mod;
323
324     switch (Event->type)
325     {
326       case SDL_KEYDOWN:
327         mod = SDL_GetModState ();
328         if (mod & KMOD_RCTRL || mod & KMOD_LCTRL) {
329                 if (Event->key.keysym.sym == 'g') {
330                         if (SDL_WM_GrabInput (SDL_GRAB_QUERY) == SDL_GRAB_OFF)
331                                 SDL_WM_GrabInput (SDL_GRAB_ON);
332                         else
333                                 SDL_WM_GrabInput (SDL_GRAB_OFF);
334                 }
335         } else if (mod & KMOD_RALT || mod & KMOD_LALT) {
336                 if (Event->key.keysym.sym == SDLK_RETURN) {
337                         SDL_WM_ToggleFullScreen(SDL_GetVideoSurface());
338                 }
339         } else { 
340                 event.type = ev_keydown;
341                 event.data1 = xlatekey(&Event->key.keysym);
342                 H2_PostEvent(&event);
343         }
344         break;
345
346       case SDL_KEYUP:
347         event.type = ev_keyup;
348         event.data1 = xlatekey(&Event->key.keysym);
349         H2_PostEvent(&event);
350         break;
351
352       case SDL_MOUSEBUTTONDOWN:
353       case SDL_MOUSEBUTTONUP:
354         buttonstate = SDL_GetMouseState(NULL, NULL);
355         event.type = ev_mouse;
356         event.data1 = 0
357             | (buttonstate & SDL_BUTTON(1) ? 1 : 0)
358             | (buttonstate & SDL_BUTTON(2) ? 2 : 0)
359             | (buttonstate & SDL_BUTTON(3) ? 4 : 0);
360         event.data2 = event.data3 = 0;
361         H2_PostEvent(&event);
362         break;
363
364       case SDL_MOUSEMOTION:
365         /* Ignore mouse warp events */
366         if ( (Event->motion.x != SCREENWIDTH/2) ||
367              (Event->motion.y != SCREENHEIGHT/2) )
368         {
369             /* Warp the mouse back to the center */
370             event.type = ev_mouse;
371             event.data1 = 0
372                 | (Event->motion.state & SDL_BUTTON(1) ? 1 : 0)
373                 | (Event->motion.state & SDL_BUTTON(2) ? 2 : 0)
374                 | (Event->motion.state & SDL_BUTTON(3) ? 4 : 0);
375             event.data2 = Event->motion.xrel << 3;
376             event.data3 = -Event->motion.yrel << 3;
377             H2_PostEvent(&event);
378         }
379         break;
380
381       case SDL_QUIT:
382         I_Quit();
383     }
384
385 }
386
387 //
388 // I_StartTic
389 //
390 void I_StartTic (void)
391 {
392     SDL_Event Event;
393
394     while ( SDL_PollEvent(&Event) )
395         I_GetEvent(&Event);
396 }
397
398
399 /*
400 ============================================================================
401
402                                         TIMER INTERRUPT
403
404 ============================================================================
405 */
406
407
408 /*
409 ================
410 =
411 = I_TimerISR
412 =
413 ================
414 */
415
416 int I_TimerISR (void)
417 {
418         ticcount++;
419         return 0;
420 }
421
422 /*
423 ============================================================================
424
425                                                         MOUSE
426
427 ============================================================================
428 */
429
430 /*
431 ================
432 =
433 = StartupMouse
434 =
435 ================
436 */
437
438 void I_StartupMouse (void)
439 {
440         mousepresent = 1;
441 }
442
443 static int makeUniqueFilename( char* filename )
444 {
445     int i;
446
447     for( i = 0; i < 100; i++ )
448     {
449         sprintf( filename, "hexen%02d.bmp", i );
450
451         if( access( filename, F_OK ) == -1 )
452         {
453             // It does not exist.
454             return 1;
455         }
456     }
457
458     return 0;
459 }
460
461 void GrabScreen ()
462 {
463     SDL_Surface *image;
464     SDL_Surface *temp;
465     int idx;
466     char filename[80];
467
468     if (makeUniqueFilename(filename)) {
469         image = SDL_CreateRGBSurface(SDL_SWSURFACE, screenWidth, screenHeight,
470                                     24, 0x0000FF, 0x00FF00, 0xFF0000,0xFFFFFF);
471         temp = SDL_CreateRGBSurface(SDL_SWSURFACE, screenWidth, screenHeight,
472                                     24, 0x0000FF, 0x00FF00, 0xFF0000, 0xFFFFFF);
473
474         glReadPixels(0, 0, screenWidth, screenHeight, GL_RGB,
475                      GL_UNSIGNED_BYTE, image->pixels);
476         for (idx = 0; idx < screenHeight; idx++)
477         {
478                memcpy(temp->pixels + 3 * screenWidth * idx,
479                         (char *)image->pixels + 3
480                         * screenWidth*(screenHeight - idx),
481                         3*screenWidth);
482         }
483         memcpy(image->pixels,temp->pixels,screenWidth * screenHeight * 3);
484         SDL_SaveBMP(image, filename);
485         SDL_FreeSurface(image);
486     }
487 }
488