]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/grgl1.cpp
safer strings using SDL string functions
[taylor/freespace2.git] / src / graphics / grgl1.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 #include "gropengl.h"
10 #include "grgl1.h"
11 #include "gropenglinternal.h"
12 #include "2d.h"
13 #include "mouse.h"
14 #include "pstypes.h"
15 #include "cfile.h"
16 #include "bmpman.h"
17 #include "grinternal.h"
18
19
20 int OGL_fog_mode = 0;
21
22 int GL_one_inited = 0;
23
24
25 volatile int GL_activate = 0;
26 volatile int GL_deactivate = 0;
27
28 static GLuint Gr_saved_screen_tex = 0;
29
30 static int Gr_opengl_mouse_saved = 0;
31 static int Gr_opengl_mouse_saved_x = 0;
32 static int Gr_opengl_mouse_saved_y = 0;
33 static int Gr_opengl_mouse_saved_w = 0;
34 static int Gr_opengl_mouse_saved_h = 0;
35 static ubyte *Gr_opengl_mouse_saved_data = NULL;
36
37
38 PFNGLSECONDARYCOLORPOINTERPROC vglSecondaryColorPointer = NULL;
39
40
41 static gr_alpha_blend GL_current_alpha_blend = (gr_alpha_blend) -1;
42 static gr_zbuffer_type GL_current_zbuffer_type = (gr_zbuffer_type) -1;
43
44 void opengl1_set_state(gr_texture_source ts, gr_alpha_blend ab, gr_zbuffer_type zt)
45 {
46         opengl1_set_texture_state(ts);
47
48         if (ab != GL_current_alpha_blend) {
49                 switch (ab) {
50                         case ALPHA_BLEND_NONE:                  // 1*SrcPixel + 0*DestPixel
51                                 glBlendFunc(GL_ONE, GL_ZERO);
52                                 break;
53                         case ALPHA_BLEND_ADDITIVE:              // 1*SrcPixel + 1*DestPixel
54                                 glBlendFunc(GL_ONE, GL_ONE);
55                                 break;
56                         case ALPHA_BLEND_ALPHA_ADDITIVE:        // Alpha*SrcPixel + 1*DestPixel
57                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
58                                 break;
59                         case ALPHA_BLEND_ALPHA_BLEND_ALPHA:     // Alpha*SrcPixel + (1-Alpha)*DestPixel
60                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
61                                 break;
62                         case ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR: // Alpha*SrcPixel + (1-SrcPixel)*DestPixel
63                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
64                                 break;
65                         default:
66                                 break;
67                 }
68
69                 GL_current_alpha_blend = ab;
70         }
71
72         if (zt != GL_current_zbuffer_type) {
73                 switch (zt) {
74                         case ZBUFFER_TYPE_NONE:
75                                 glDepthFunc(GL_ALWAYS);
76                                 glDepthMask(GL_FALSE);
77                                 break;
78                         case ZBUFFER_TYPE_READ:
79                                 glDepthFunc(GL_LESS);
80                                 glDepthMask(GL_FALSE);
81                                 break;
82                         case ZBUFFER_TYPE_WRITE:
83                                 glDepthFunc(GL_ALWAYS);
84                                 glDepthMask(GL_TRUE);
85                                 break;
86                         case ZBUFFER_TYPE_FULL:
87                                 glDepthFunc(GL_LESS);
88                                 glDepthMask(GL_TRUE);
89                                 break;
90                         default:
91                                 break;
92                 }
93
94                 GL_current_zbuffer_type = zt;
95         }
96 }
97
98 void opengl1_cleanup()
99 {
100         if ( !GL_one_inited ) {
101                 return;
102         }
103
104         gr_opengl1_reset_clip();
105         gr_opengl1_clear();
106         gr_opengl1_flip();
107
108         opengl1_tcache_cleanup();
109
110         GL_one_inited = 0;
111 }
112
113 static void opengl1_init_func_pointers()
114 {
115         gr_screen.gf_flip = gr_opengl1_flip;
116         gr_screen.gf_set_clip = gr_opengl1_set_clip;
117         gr_screen.gf_reset_clip = gr_opengl1_reset_clip;
118
119         gr_screen.gf_clear = gr_opengl1_clear;
120
121         gr_screen.gf_aabitmap = gr_opengl1_aabitmap;
122         gr_screen.gf_aabitmap_ex = gr_opengl1_aabitmap_ex;
123
124         gr_screen.gf_rect = gr_opengl1_rect;
125         gr_screen.gf_shade = gr_opengl1_shade;
126         gr_screen.gf_string = gr_opengl1_string;
127         gr_screen.gf_circle = gr_opengl1_circle;
128
129         gr_screen.gf_line = gr_opengl1_line;
130         gr_screen.gf_aaline = gr_opengl1_aaline;
131         gr_screen.gf_pixel = gr_opengl1_pixel;
132         gr_screen.gf_scaler = gr_opengl1_scaler;
133         gr_screen.gf_tmapper = gr_opengl1_tmapper;
134
135         gr_screen.gf_gradient = gr_opengl1_gradient;
136
137         gr_screen.gf_print_screen = gr_opengl1_print_screen;
138
139         gr_screen.gf_fade_in = gr_opengl1_fade_in;
140         gr_screen.gf_fade_out = gr_opengl1_fade_out;
141         gr_screen.gf_flash = gr_opengl1_flash;
142
143         gr_screen.gf_zbuffer_clear = gr_opengl1_zbuffer_clear;
144
145         gr_screen.gf_save_screen = gr_opengl1_save_screen;
146         gr_screen.gf_restore_screen = gr_opengl1_restore_screen;
147         gr_screen.gf_free_screen = gr_opengl1_free_screen;
148
149         gr_screen.gf_dump_frame_start = gr_opengl1_dump_frame_start;
150         gr_screen.gf_dump_frame_stop = gr_opengl1_dump_frame_stop;
151         gr_screen.gf_dump_frame = gr_opengl1_dump_frame;
152
153         gr_screen.gf_set_gamma = gr_opengl1_set_gamma;
154
155         gr_screen.gf_lock = gr_opengl1_lock;
156         gr_screen.gf_unlock = gr_opengl1_unlock;
157
158         gr_screen.gf_fog_set = gr_opengl1_fog_set;
159
160         gr_screen.gf_get_region = gr_opengl1_get_region;
161
162         gr_screen.gf_set_cull = gr_opengl1_set_cull;
163
164         gr_screen.gf_cross_fade = gr_opengl1_cross_fade;
165
166         gr_screen.gf_preload_init = gr_opengl1_preload_init;
167         gr_screen.gf_preload = gr_opengl1_preload;
168
169         gr_screen.gf_zbias = gr_opengl1_zbias;
170
171         gr_screen.gf_force_windowed = gr_opengl_force_windowed;
172         gr_screen.gf_force_fullscreen = gr_opengl_force_fullscreen;
173         gr_screen.gf_toggle_fullscreen = gr_opengl_toggle_fullscreen;
174
175         gr_screen.gf_set_viewport = gr_opengl1_set_viewport;
176
177         gr_screen.gf_activate = gr_opengl1_activate;
178 }
179
180 void opengl1_init()
181 {
182         if (GL_one_inited) {
183                 return;
184         }
185
186         /*
187           1 = use secondary color ext
188           2 = use opengl linear fog
189          */
190         OGL_fog_mode = 2;
191
192         // only available with OpenGL 1.2+, must get ptr for Windows
193         vglSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)SDL_GL_GetProcAddress("glSecondaryColorPointer");
194
195         if (vglSecondaryColorPointer) {
196                 OGL_fog_mode = 1;
197         }
198
199         mprintf(("  Fog mode: %s\n", (OGL_fog_mode == 1) ? "secondary color" : "linear"));
200
201         glShadeModel(GL_SMOOTH);
202         glEnable(GL_DITHER);
203         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
204         glHint(GL_FOG_HINT, GL_NICEST);
205
206         glEnable(GL_DEPTH_TEST);
207         glEnable(GL_BLEND);
208
209         glEnable(GL_TEXTURE_2D);
210
211         glDepthRange(0.0, 1.0);
212
213         glPixelStorei(GL_PACK_ALIGNMENT, 1);
214         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
215
216         glFlush();
217
218         opengl1_init_func_pointers();
219         opengl1_tcache_init();
220
221         gr_opengl1_clear();
222
223         GL_one_inited = 1;
224 }
225
226 void gr_opengl1_activate(int active)
227 {
228         if (active) {
229                 GL_activate++;
230
231                 // don't grab key/mouse if cmdline says so or if we're fullscreen
232         //      if(!Cmdline_no_grab && !(SDL_GetVideoSurface()->flags & SDL_FULLSCREEN)) {
233         //              SDL_WM_GrabInput(SDL_GRAB_ON);
234         //      }
235         } else {
236                 GL_deactivate++;
237
238                 // let go of mouse/keyboard
239         //      SDL_WM_GrabInput(SDL_GRAB_OFF);
240         }
241 }
242
243 void gr_opengl1_clear()
244 {
245         glClearColor(gr_screen.current_clear_color.red / 255.0,
246                 gr_screen.current_clear_color.green / 255.0,
247                 gr_screen.current_clear_color.blue / 255.0, 1.0);
248
249         glClear( GL_COLOR_BUFFER_BIT );
250 }
251
252 void gr_opengl1_flip()
253 {
254         if ( !GL_one_inited ) {
255                 return;
256         }
257
258         gr_reset_clip();
259
260         mouse_eval_deltas();
261
262         Gr_opengl_mouse_saved = 0;
263
264         if ( mouse_is_visible() )       {
265                 int mx, my;
266
267                 gr_reset_clip();
268                 mouse_get_pos( &mx, &my );
269
270                 gr_opengl1_save_mouse_area(mx,my,32,32);
271
272                 if (Gr_cursor == -1) {
273 #ifndef NDEBUG
274                         gr_set_color(255,255,255);
275                         gr_line(mx, my, mx+7, my + 7);
276                         gr_line(mx, my, mx+5, my );
277                         gr_line(mx, my, mx, my+5);
278 #endif
279                 } else {
280                         gr_set_bitmap(Gr_cursor);
281                         gr_bitmap(mx, my);
282                 }
283          }
284
285 #ifndef NDEBUG
286         GLenum error = GL_NO_ERROR;
287
288         do {
289                 error = glGetError();
290
291                 if (error != GL_NO_ERROR) {
292                         nprintf(("Warning", "!!DEBUG!! OpenGL Error: %d\n", error));
293                 }
294         } while (error != GL_NO_ERROR);
295 #endif
296
297         SDL_GL_SwapWindow(GL_window);
298
299         opengl1_tcache_frame();
300
301         int cnt = GL_activate;
302         if ( cnt )      {
303                 GL_activate-=cnt;
304                 opengl1_tcache_flush();
305                 // gr_opengl_clip_cursor(1); /* mouse grab, see opengl_activate */
306         }
307
308         cnt = GL_deactivate;
309         if ( cnt )      {
310                 GL_deactivate-=cnt;
311                 // gr_opengl_clip_cursor(0);  /* mouse grab, see opengl_activate */
312         }
313 }
314
315 void gr_opengl1_set_clip(int x,int y,int w,int h)
316 {
317         // check for sanity of parameters
318         if (x < 0)
319                 x = 0;
320         if (y < 0)
321                 y = 0;
322
323         if (x >= gr_screen.max_w)
324                 x = gr_screen.max_w - 1;
325         if (y >= gr_screen.max_h)
326                 y = gr_screen.max_h - 1;
327
328         if (x + w > gr_screen.max_w)
329                 w = gr_screen.max_w - x;
330         if (y + h > gr_screen.max_h)
331                 h = gr_screen.max_h - y;
332
333         if (w > gr_screen.max_w)
334                 w = gr_screen.max_w;
335         if (h > gr_screen.max_h)
336                 h = gr_screen.max_h;
337
338         gr_screen.offset_x = x;
339         gr_screen.offset_y = y;
340         gr_screen.clip_left = 0;
341         gr_screen.clip_right = w-1;
342         gr_screen.clip_top = 0;
343         gr_screen.clip_bottom = h-1;
344         gr_screen.clip_width = w;
345         gr_screen.clip_height = h;
346
347         x = fl2i((x * GL_viewport_scale_w) + 0.5f) + GL_viewport_x;
348         y = fl2i((y * GL_viewport_scale_h) + 0.5f) + GL_viewport_y;
349         w = fl2i((w * GL_viewport_scale_w) + 0.5f);
350         h = fl2i((h * GL_viewport_scale_h) + 0.5f);
351
352         glEnable(GL_SCISSOR_TEST);
353         glScissor(x, GL_viewport_h-y-h, w, h);
354 }
355
356 void gr_opengl1_reset_clip()
357 {
358         gr_screen.offset_x = 0;
359         gr_screen.offset_y = 0;
360         gr_screen.clip_left = 0;
361         gr_screen.clip_top = 0;
362         gr_screen.clip_right = gr_screen.max_w - 1;
363         gr_screen.clip_bottom = gr_screen.max_h - 1;
364         gr_screen.clip_width = gr_screen.max_w;
365         gr_screen.clip_height = gr_screen.max_h;
366
367         glDisable(GL_SCISSOR_TEST);
368 }
369
370 void gr_opengl1_print_screen(const char *filename)
371 {
372         char tmp[MAX_FILENAME_LEN];
373         ubyte *buf = NULL;
374
375         SDL_strlcpy( tmp, filename, sizeof(tmp) );
376         SDL_strlcat( tmp, NOX(".tga"), sizeof(tmp) );
377
378         buf = (ubyte*)malloc(GL_viewport_w * GL_viewport_h * 3);
379
380         if (buf == NULL) {
381                 return;
382         }
383
384         CFILE *f = cfopen(tmp, "wb", CFILE_NORMAL, CF_TYPE_ROOT);
385
386         if (f == NULL) {
387                 free(buf);
388                 return;
389         }
390
391         // Write the TGA header
392         cfwrite_ubyte( 0, f );  //      IDLength;
393         cfwrite_ubyte( 0, f );  //      ColorMapType;
394         cfwrite_ubyte( 2, f );  //      ImageType;              // 2 = 24bpp, uncompressed, 10=24bpp rle compressed
395         cfwrite_ushort( 0, f ); // CMapStart;
396         cfwrite_ushort( 0, f ); //      CMapLength;
397         cfwrite_ubyte( 0, f );  // CMapDepth;
398         cfwrite_ushort( 0, f ); //      XOffset;
399         cfwrite_ushort( 0, f ); //      YOffset;
400         cfwrite_ushort( (ushort)GL_viewport_w, f );     //      Width;
401         cfwrite_ushort( (ushort)GL_viewport_h, f );     //      Height;
402         cfwrite_ubyte( 24, f ); //PixelDepth;
403         cfwrite_ubyte( 0, f );  //ImageDesc;
404
405         memset(buf, 0, GL_viewport_w * GL_viewport_h * 3);
406
407         glReadPixels(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h, GL_BGR, GL_UNSIGNED_BYTE, buf);
408
409         cfwrite(buf, GL_viewport_w * GL_viewport_h * 3, 1, f);
410
411         cfclose(f);
412
413         free(buf);
414 }
415
416 void gr_opengl1_fog_set(int fog_mode, int r, int g, int b, float fog_near, float fog_far)
417 {
418         SDL_assert((r >= 0) && (r < 256));
419         SDL_assert((g >= 0) && (g < 256));
420         SDL_assert((b >= 0) && (b < 256));
421
422         if (fog_mode == GR_FOGMODE_NONE) {
423                 if (gr_screen.current_fog_mode != fog_mode) {
424                         glDisable(GL_FOG);
425
426                         if (OGL_fog_mode == 1) {
427                                 glDisable(GL_COLOR_SUM);
428                         }
429                 }
430
431                 gr_screen.current_fog_mode = fog_mode;
432
433                 return;
434         }
435
436         if (gr_screen.current_fog_mode != fog_mode) {
437                 glEnable(GL_FOG);
438
439                 if (OGL_fog_mode == 1) {
440                         glEnable(GL_COLOR_SUM);
441                 } else if (OGL_fog_mode == 2) {
442                         glFogi(GL_FOG_MODE, GL_LINEAR);
443                 }
444
445                 gr_screen.current_fog_mode = fog_mode;
446         }
447
448         if ( (gr_screen.current_fog_color.red != r) ||
449                         (gr_screen.current_fog_color.green != g) ||
450                         (gr_screen.current_fog_color.blue != b) ) {
451                 GLfloat fc[4];
452
453                 gr_init_color( &gr_screen.current_fog_color, r, g, b );
454
455                 fc[0] = (float)r/255.0;
456                 fc[1] = (float)g/255.0;
457                 fc[2] = (float)b/255.0;
458                 fc[3] = 1.0;
459
460                 glFogfv(GL_FOG_COLOR, fc);
461         }
462
463         if( (fog_near >= 0.0f) && (fog_far >= 0.0f) &&
464                         ((fog_near != gr_screen.fog_near) ||
465                         (fog_far != gr_screen.fog_far)) ) {
466                 gr_screen.fog_near = fog_near;
467                 gr_screen.fog_far = fog_far;
468
469                 if (OGL_fog_mode == 2) {
470                         glFogf(GL_FOG_START, fog_near);
471                         glFogf(GL_FOG_END, fog_far);
472                 }
473         }
474 }
475
476 void gr_opengl1_set_cull(int cull)
477 {
478         if (cull) {
479                 glEnable (GL_CULL_FACE);
480                 glFrontFace (GL_CCW);
481         } else {
482                 glDisable (GL_CULL_FACE);
483         }
484 }
485
486 void gr_opengl1_zbuffer_clear(int mode)
487 {
488         if (mode) {
489                 Gr_zbuffering = 1;
490                 Gr_zbuffering_mode = GR_ZBUFF_FULL;
491                 Gr_global_zbuffering = 1;
492
493                 opengl1_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_FULL );
494                 glClear ( GL_DEPTH_BUFFER_BIT );
495         } else {
496                 Gr_zbuffering = 0;
497                 Gr_zbuffering_mode = GR_ZBUFF_NONE;
498                 Gr_global_zbuffering = 0;
499         }
500 }
501
502 void gr_opengl1_fade_in(int instantaneous)
503 {
504         // Empty - DDOI
505 }
506
507 void gr_opengl1_fade_out(int instantaneous)
508 {
509         // Empty - DDOI
510 }
511
512 void gr_opengl1_get_region(int front, int w, int h, ubyte *data)
513 {
514         if (front) {
515                 glReadBuffer(GL_FRONT);
516         } else {
517                 glReadBuffer(GL_BACK);
518         }
519
520         opengl1_set_state(TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE);
521
522         glPixelStorei(GL_UNPACK_ROW_LENGTH, GL_viewport_w);
523
524         int x = GL_viewport_x;
525         int y = (GL_viewport_y+GL_viewport_h)-h-1;
526
527         GLenum pxtype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
528
529         if (gr_screen.bytes_per_pixel == 4) {
530                 pxtype = GL_UNSIGNED_BYTE;
531         }
532
533         glReadPixels(x, y, w, h, GL_BGRA, pxtype, data);
534
535         glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
536 }
537
538 void gr_opengl1_save_mouse_area(int x, int y, int w, int h)
539 {
540         int x1, y1, x2, y2;
541
542         w = fl2i((w * GL_viewport_scale_w) + 0.5f);
543         h = fl2i((h * GL_viewport_scale_h) + 0.5f);
544
545         x1 = x;
546         y1 = y;
547         x2 = x+w-1;
548         y2 = y+h-1;
549
550         CAP(x1, 0, GL_viewport_w);
551         CAP(x2, 0, GL_viewport_w);
552         CAP(y1, 0, GL_viewport_h);
553         CAP(y2, 0, GL_viewport_h);
554
555         Gr_opengl_mouse_saved_x = x1;
556         Gr_opengl_mouse_saved_y = y1;
557         Gr_opengl_mouse_saved_w = x2 - x1 + 1;
558         Gr_opengl_mouse_saved_h = y2 - y1 + 1;
559
560         if ( (Gr_opengl_mouse_saved_w < 1) || (Gr_opengl_mouse_saved_h < 1) ) {
561                 return;
562         }
563
564         if (Gr_opengl_mouse_saved_data == NULL) {
565                 Gr_opengl_mouse_saved_data = (ubyte*)malloc(w * h * gr_screen.bytes_per_pixel);
566
567                 if ( !Gr_opengl_mouse_saved_data ) {
568                         return;
569                 }
570         }
571
572         opengl1_set_state(TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE);
573
574         x1 = GL_viewport_x+Gr_opengl_mouse_saved_x;
575         y1 = (GL_viewport_y+GL_viewport_h)-Gr_opengl_mouse_saved_y-Gr_opengl_mouse_saved_h;
576
577         GLenum pxtype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
578
579         if (gr_screen.bytes_per_pixel == 4) {
580                 pxtype = GL_UNSIGNED_BYTE;
581         }
582
583         glReadBuffer(GL_BACK);
584         glReadPixels(x1, y1, Gr_opengl_mouse_saved_w, Gr_opengl_mouse_saved_h,
585                         GL_BGRA, pxtype, Gr_opengl_mouse_saved_data);
586
587         Gr_opengl_mouse_saved = 1;
588 }
589
590 int gr_opengl1_save_screen()
591 {
592         gr_reset_clip();
593
594         if (Gr_saved_screen_tex) {
595                 mprintf(( "Screen already saved!\n" ));
596                 return -1;
597         }
598
599         glGenTextures(1, &Gr_saved_screen_tex);
600
601         if ( !Gr_saved_screen_tex ) {
602                 mprintf(( "Couldn't create texture for saved screen!\n" ));
603                 return -1;
604         }
605
606         opengl1_set_state(TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE);
607
608         glBindTexture(GL_TEXTURE_2D, Gr_saved_screen_tex);
609
610         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
611         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
612         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
613         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
614         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
615
616         glReadBuffer(GL_FRONT);
617         glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GL_viewport_x, GL_viewport_y,
618                         GL_viewport_w, GL_viewport_h, 0);
619
620         if (Gr_opengl_mouse_saved) {
621                 int x = Gr_opengl_mouse_saved_x;
622                 int y = GL_viewport_h-Gr_opengl_mouse_saved_y-Gr_opengl_mouse_saved_h;
623
624                 GLenum pxtype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
625
626                 if (gr_screen.bytes_per_pixel == 4) {
627                         pxtype = GL_UNSIGNED_BYTE;
628                 }
629
630                 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, Gr_opengl_mouse_saved_w,
631                                 Gr_opengl_mouse_saved_h, GL_BGRA, pxtype,
632                                 Gr_opengl_mouse_saved_data);
633         }
634
635         glBindTexture(GL_TEXTURE_2D, 0);
636
637         return 0;
638 }
639
640 void gr_opengl1_restore_screen(int id)
641 {
642         gr_reset_clip();
643
644         if ( !Gr_saved_screen_tex ) {
645                 gr_clear();
646                 return;
647         }
648
649         glBindTexture(GL_TEXTURE_2D, Gr_saved_screen_tex);
650
651         if (Gr_opengl_mouse_saved) {
652                 int x = Gr_opengl_mouse_saved_x;
653                 int y = GL_viewport_h-Gr_opengl_mouse_saved_y-Gr_opengl_mouse_saved_h;
654
655                 GLenum pxtype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
656
657                 if (gr_screen.bytes_per_pixel == 4) {
658                         pxtype = GL_UNSIGNED_BYTE;
659                 }
660
661                 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, Gr_opengl_mouse_saved_w,
662                                 Gr_opengl_mouse_saved_h, GL_BGRA, pxtype,
663                                 Gr_opengl_mouse_saved_data);
664         }
665
666         glMatrixMode(GL_MODELVIEW);
667         glPushMatrix();
668         glLoadIdentity();
669         glScalef(1.0f, -1.0f, 1.0f);
670
671         int tex_coord[] = { 0, 0, 0, 1, 1, 0, 1, 1 };
672         int ver_coord[] = { GL_viewport_x, GL_viewport_y, GL_viewport_x,
673                         GL_viewport_h, GL_viewport_w, GL_viewport_y, GL_viewport_w,
674                         GL_viewport_h
675         };
676
677         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
678         glEnableClientState(GL_VERTEX_ARRAY);
679
680         glTexCoordPointer(2, GL_INT, 0, &tex_coord);
681         glVertexPointer(2, GL_INT, 0, &ver_coord);
682
683         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
684
685         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
686         glDisableClientState(GL_VERTEX_ARRAY);
687
688         glPopMatrix();
689
690         glBindTexture(GL_TEXTURE_2D, 0);
691 }
692
693 void gr_opengl1_free_screen(int id)
694 {
695         if (Gr_saved_screen_tex) {
696                 glDeleteTextures(1, &Gr_saved_screen_tex);
697                 Gr_saved_screen_tex = 0;
698         }
699 }
700
701 void gr_opengl1_dump_frame_start(int first_frame, int frames_between_dumps)
702 {
703         STUB_FUNCTION;
704 }
705
706 void gr_opengl1_dump_frame_stop()
707 {
708         STUB_FUNCTION;
709 }
710
711 void gr_opengl1_dump_frame()
712 {
713         STUB_FUNCTION;
714 }
715
716 uint gr_opengl1_lock()
717 {
718         return 1;
719 }
720
721 void gr_opengl1_unlock()
722 {
723 }
724
725 void gr_opengl1_zbias(int bias)
726 {
727         if (bias) {
728                 glEnable(GL_POLYGON_OFFSET_FILL);
729                 glPolygonOffset(0.0, -bias);
730         } else {
731                 glDisable(GL_POLYGON_OFFSET_FILL);
732         }
733 }
734
735 void gr_opengl1_set_viewport(int width, int height)
736 {
737         int w, h, x, y;
738
739         float ratio = gr_screen.max_w / i2fl(gr_screen.max_h);
740
741         w = width;
742         h = i2fl((width / ratio) + 0.5f);
743
744         if (h > height) {
745                 h = height;
746                 w = i2fl((height * ratio) + 0.5f);
747         }
748
749         x = (width - w) / 2;
750         y = (height - h) / 2;
751
752         GL_viewport_x = x;
753         GL_viewport_y = y;
754         GL_viewport_w = w;
755         GL_viewport_h = h;
756         GL_viewport_scale_w = w / i2fl(gr_screen.max_w);
757         GL_viewport_scale_h = h / i2fl(gr_screen.max_h);
758
759         glViewport(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h);
760
761         glMatrixMode(GL_PROJECTION);
762         glLoadIdentity();
763         glOrtho(0, GL_viewport_w, GL_viewport_h, 0, 0.0, 1.0);
764         glMatrixMode(GL_MODELVIEW);
765         glLoadIdentity();
766         glScalef(GL_viewport_scale_w, GL_viewport_scale_h, 1.0f);
767 }