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