]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/grgl1.cpp
just use linear fog in GL1; cleanup
[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 "SDL_opengl.h"
10
11 #include "gropengl.h"
12 #include "gropenglinternal.h"
13 #include "grgl1.h"
14 #include "2d.h"
15 #include "mouse.h"
16 #include "pstypes.h"
17 #include "cfile.h"
18 #include "bmpman.h"
19 #include "grinternal.h"
20 #include "osapi.h"
21 #include "osregistry.h"
22
23
24 int GL_one_inited = 0;
25
26
27 static GLuint GL_stream_tex = 0;
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_opengl_reset_clip();
105         gr_opengl_clear();
106         gr_opengl1_flip();
107
108         gr_opengl1_free_screen(0);
109
110         if (Gr_opengl_mouse_saved_data) {
111                 free(Gr_opengl_mouse_saved_data);
112                 Gr_opengl_mouse_saved_data = NULL;
113         }
114
115         opengl1_tcache_cleanup();
116
117         if (GL_context) {
118                 SDL_GL_DeleteContext(GL_context);
119                 GL_context = NULL;
120         }
121
122         GL_one_inited = 0;
123 }
124
125 static void opengl1_init_func_pointers()
126 {
127         gr_screen.gf_flip = gr_opengl1_flip;
128         gr_screen.gf_set_clip = gr_opengl1_set_clip;
129         gr_screen.gf_reset_clip = gr_opengl_reset_clip;
130
131         gr_screen.gf_clear = gr_opengl_clear;
132
133         gr_screen.gf_aabitmap = gr_opengl1_aabitmap;
134         gr_screen.gf_aabitmap_ex = gr_opengl1_aabitmap_ex;
135
136         gr_screen.gf_rect = gr_opengl1_rect;
137         gr_screen.gf_shade = gr_opengl1_shade;
138         gr_screen.gf_string = gr_opengl1_string;
139         gr_screen.gf_circle = gr_opengl1_circle;
140
141         gr_screen.gf_line = gr_opengl1_line;
142         gr_screen.gf_aaline = gr_opengl1_aaline;
143         gr_screen.gf_pixel = gr_opengl1_pixel;
144         gr_screen.gf_scaler = gr_opengl1_scaler;
145         gr_screen.gf_tmapper = gr_opengl1_tmapper;
146
147         gr_screen.gf_gradient = gr_opengl1_gradient;
148
149         gr_screen.gf_print_screen = gr_opengl_print_screen;
150
151         gr_screen.gf_fade_in = gr_opengl1_fade_in;
152         gr_screen.gf_fade_out = gr_opengl1_fade_out;
153         gr_screen.gf_flash = gr_opengl1_flash;
154
155         gr_screen.gf_zbuffer_clear = gr_opengl1_zbuffer_clear;
156
157         gr_screen.gf_save_screen = gr_opengl1_save_screen;
158         gr_screen.gf_restore_screen = gr_opengl1_restore_screen;
159         gr_screen.gf_free_screen = gr_opengl1_free_screen;
160
161         gr_screen.gf_dump_frame_start = gr_opengl1_dump_frame_start;
162         gr_screen.gf_dump_frame_stop = gr_opengl1_dump_frame_stop;
163         gr_screen.gf_dump_frame = gr_opengl1_dump_frame;
164
165         gr_screen.gf_stream_start = gr_opengl1_stream_start;
166         gr_screen.gf_stream_frame = gr_opengl1_stream_frame;
167         gr_screen.gf_stream_stop = gr_opengl1_stream_stop;
168
169         gr_screen.gf_set_gamma = gr_opengl1_set_gamma;
170
171         gr_screen.gf_lock = gr_opengl_lock;
172         gr_screen.gf_unlock = gr_opengl_unlock;
173
174         gr_screen.gf_fog_set = gr_opengl1_fog_set;
175
176         gr_screen.gf_get_region = gr_opengl1_get_region;
177
178         gr_screen.gf_set_cull = gr_opengl_set_cull;
179
180         gr_screen.gf_cross_fade = gr_opengl1_cross_fade;
181
182         gr_screen.gf_preload_init = gr_opengl1_preload_init;
183         gr_screen.gf_preload = gr_opengl1_preload;
184
185         gr_screen.gf_zbias = gr_opengl_zbias;
186
187         gr_screen.gf_force_windowed = gr_opengl_force_windowed;
188         gr_screen.gf_force_fullscreen = gr_opengl_force_fullscreen;
189         gr_screen.gf_toggle_fullscreen = gr_opengl_toggle_fullscreen;
190
191         gr_screen.gf_set_viewport = gr_opengl1_set_viewport;
192
193         gr_screen.gf_activate = gr_opengl_activate;
194
195         gr_screen.gf_release_texture = gr_opengl1_release_texture;
196 }
197
198 int opengl1_init()
199 {
200         if (GL_one_inited) {
201                 return 1;
202         }
203
204         GL_one_inited = 1;
205
206         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, 0);
207         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
208         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
209
210         GL_context = SDL_GL_CreateContext(GL_window);
211
212         if ( !GL_context ) {
213                 opengl1_cleanup();
214                 return 0;
215         }
216
217         mprintf(("  Vendor   : %s\n", glGetString(GL_VENDOR)));
218         mprintf(("  Renderer : %s\n", glGetString(GL_RENDERER)));
219         mprintf(("  Version  : %s\n", glGetString(GL_VERSION)));
220
221         // set up generic variables
222         opengl_set_variables();
223
224         opengl1_init_func_pointers();
225         opengl1_tcache_init();
226
227         // initial viewport setup
228         gr_opengl1_set_viewport(gr_screen.max_w, gr_screen.max_h);
229
230         glShadeModel(GL_SMOOTH);
231         glEnable(GL_DITHER);
232         glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
233         glHint(GL_FOG_HINT, GL_NICEST);
234
235         glEnable(GL_DEPTH_TEST);
236         glEnable(GL_BLEND);
237
238         glEnable(GL_TEXTURE_2D);
239
240         glDepthRange(0.0, 1.0);
241
242         glPixelStorei(GL_PACK_ALIGNMENT, 1);
243         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
244
245         glFlush();
246
247         gr_opengl_clear();
248         gr_opengl_set_cull(1);
249
250         return 1;
251 }
252
253 void gr_opengl1_flip()
254 {
255         if ( !GL_one_inited ) {
256                 return;
257         }
258
259         gr_reset_clip();
260
261         mouse_eval_deltas();
262
263         Gr_opengl_mouse_saved = 0;
264
265         if ( mouse_is_visible() )       {
266                 int mx, my;
267
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         CAP(x, 0, gr_screen.max_w - 1);
319         CAP(y, 0, gr_screen.max_h - 1);
320         CAP(w, 0, gr_screen.max_w - x);
321         CAP(h, 0, gr_screen.max_h - y);
322
323         gr_screen.offset_x = x;
324         gr_screen.offset_y = y;
325         gr_screen.clip_left = 0;
326         gr_screen.clip_right = w-1;
327         gr_screen.clip_top = 0;
328         gr_screen.clip_bottom = h-1;
329         gr_screen.clip_width = w;
330         gr_screen.clip_height = h;
331
332         x = fl2i((x * GL_viewport_scale_w) + 0.5f) + GL_viewport_x;
333         y = fl2i((y * GL_viewport_scale_h) + 0.5f) + GL_viewport_y;
334         w = fl2i((w * GL_viewport_scale_w) + 0.5f);
335         h = fl2i((h * GL_viewport_scale_h) + 0.5f);
336
337         glEnable(GL_SCISSOR_TEST);
338         glScissor(x, GL_viewport_h-y-h, w, h);
339 }
340
341 void gr_opengl1_fog_set(int fog_mode, int r, int g, int b, float fog_near, float fog_far)
342 {
343         SDL_assert((r >= 0) && (r < 256));
344         SDL_assert((g >= 0) && (g < 256));
345         SDL_assert((b >= 0) && (b < 256));
346
347         if (fog_mode == GR_FOGMODE_NONE) {
348                 if (gr_screen.current_fog_mode != fog_mode) {
349                         glDisable(GL_FOG);
350                 }
351
352                 gr_screen.current_fog_mode = fog_mode;
353
354                 return;
355         }
356
357         if (gr_screen.current_fog_mode != fog_mode) {
358                 glEnable(GL_FOG);
359                 glFogi(GL_FOG_MODE, GL_LINEAR);
360
361                 gr_screen.current_fog_mode = fog_mode;
362         }
363
364         if ( (gr_screen.current_fog_color.red != r) ||
365                         (gr_screen.current_fog_color.green != g) ||
366                         (gr_screen.current_fog_color.blue != b) ) {
367                 gr_init_color( &gr_screen.current_fog_color, r, g, b );
368
369                 GLfloat fc[4];
370
371                 fc[0] = r / 255.0f;
372                 fc[1] = g / 255.0f;
373                 fc[2] = b / 255.0f;
374                 fc[3] = 1.0f;
375
376                 glFogfv(GL_FOG_COLOR, fc);
377         }
378
379         if( (fog_near >= 0.0f) && (fog_far >= 0.0f) &&
380                         ((fog_near != gr_screen.fog_near) ||
381                         (fog_far != gr_screen.fog_far)) ) {
382                 gr_screen.fog_near = fog_near;
383                 gr_screen.fog_far = fog_far;
384
385                 glFogf(GL_FOG_START, fog_near);
386                 glFogf(GL_FOG_END, fog_far);
387         }
388 }
389
390 void gr_opengl1_zbuffer_clear(int mode)
391 {
392         if (mode) {
393                 Gr_zbuffering = 1;
394                 Gr_zbuffering_mode = GR_ZBUFF_FULL;
395                 Gr_global_zbuffering = 1;
396
397                 opengl1_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_FULL );
398                 glClear ( GL_DEPTH_BUFFER_BIT );
399         } else {
400                 Gr_zbuffering = 0;
401                 Gr_zbuffering_mode = GR_ZBUFF_NONE;
402                 Gr_global_zbuffering = 0;
403         }
404 }
405
406 void gr_opengl1_fade_in(int instantaneous)
407 {
408         // Empty - DDOI
409 }
410
411 void gr_opengl1_fade_out(int instantaneous)
412 {
413         // Empty - DDOI
414 }
415
416 void gr_opengl1_get_region(int front, int w, int h, ubyte *data)
417 {
418         if (front) {
419                 glReadBuffer(GL_FRONT);
420         } else {
421                 glReadBuffer(GL_BACK);
422         }
423
424         opengl1_set_state(TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE);
425
426         glPixelStorei(GL_UNPACK_ROW_LENGTH, GL_viewport_w);
427
428         int x = GL_viewport_x;
429         int y = (GL_viewport_y+GL_viewport_h)-h-1;
430
431         GLenum pxtype = GL_UNSIGNED_SHORT_5_5_5_1;
432
433         if (gr_screen.bytes_per_pixel == 4) {
434                 pxtype = GL_UNSIGNED_BYTE;
435         }
436
437         glReadPixels(x, y, w, h, GL_RGBA, pxtype, data);
438
439         glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
440 }
441
442 void gr_opengl1_save_mouse_area(int x, int y, int w, int h)
443 {
444         int x1, y1, x2, y2;
445
446         if (Gr_saved_screen_tex) {
447                 // already saved, don't need it again
448                 return;
449         }
450
451         w = fl2i((w * GL_viewport_scale_w) + 0.5f);
452         h = fl2i((h * GL_viewport_scale_h) + 0.5f);
453
454         x1 = x;
455         y1 = y;
456         x2 = x+w-1;
457         y2 = y+h-1;
458
459         CAP(x1, 0, GL_viewport_w);
460         CAP(x2, 0, GL_viewport_w);
461         CAP(y1, 0, GL_viewport_h);
462         CAP(y2, 0, GL_viewport_h);
463
464         Gr_opengl_mouse_saved_x = x1;
465         Gr_opengl_mouse_saved_y = y1;
466         Gr_opengl_mouse_saved_w = x2 - x1 + 1;
467         Gr_opengl_mouse_saved_h = y2 - y1 + 1;
468
469         if ( (Gr_opengl_mouse_saved_w < 1) || (Gr_opengl_mouse_saved_h < 1) ) {
470                 return;
471         }
472
473         if (Gr_opengl_mouse_saved_data == NULL) {
474                 Gr_opengl_mouse_saved_data = (ubyte*)malloc(w * h * 3);
475
476                 if ( !Gr_opengl_mouse_saved_data ) {
477                         return;
478                 }
479         }
480
481         x1 = GL_viewport_x+Gr_opengl_mouse_saved_x;
482         y1 = (GL_viewport_y+GL_viewport_h)-Gr_opengl_mouse_saved_y-Gr_opengl_mouse_saved_h;
483
484         glReadBuffer(GL_BACK);
485
486         glReadPixels(x1, y1, Gr_opengl_mouse_saved_w, Gr_opengl_mouse_saved_h,
487                         GL_RGB, GL_UNSIGNED_BYTE, Gr_opengl_mouse_saved_data);
488
489         Gr_opengl_mouse_saved = 1;
490 }
491
492 int gr_opengl1_save_screen()
493 {
494         gr_reset_clip();
495
496         if (Gr_saved_screen_tex) {
497                 mprintf(( "Screen already saved!\n" ));
498                 return -1;
499         }
500
501         glGenTextures(1, &Gr_saved_screen_tex);
502
503         if ( !Gr_saved_screen_tex ) {
504                 mprintf(( "Couldn't create texture for saved screen!\n" ));
505                 return -1;
506         }
507
508         glBindTexture(GL_TEXTURE_2D, Gr_saved_screen_tex);
509
510         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
511         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
512         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
513         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
514         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
515
516         glReadBuffer(GL_FRONT);
517
518         glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GL_viewport_x, GL_viewport_y,
519                         GL_viewport_w, GL_viewport_h, 0);
520
521         if (Gr_opengl_mouse_saved) {
522                 int x = Gr_opengl_mouse_saved_x;
523                 int y = GL_viewport_h-Gr_opengl_mouse_saved_y-Gr_opengl_mouse_saved_h;
524
525                 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, Gr_opengl_mouse_saved_w,
526                                 Gr_opengl_mouse_saved_h, GL_RGB, GL_UNSIGNED_BYTE,
527                                 Gr_opengl_mouse_saved_data);
528         }
529
530         glBindTexture(GL_TEXTURE_2D, 0);
531
532         return 0;
533 }
534
535 void gr_opengl1_restore_screen(int)
536 {
537         gr_reset_clip();
538
539         if ( !Gr_saved_screen_tex ) {
540                 gr_clear();
541                 return;
542         }
543
544         int x = 0;
545         int y = 0;
546         int w = fl2i(GL_viewport_w / GL_viewport_scale_w + 0.5f);
547         int h = fl2i(GL_viewport_h / GL_viewport_scale_h + 0.5f);
548
549         const int tex_coord[] = { 0, 1, 0, 0, 1, 1, 1, 0 };     // y-flipped
550         const int ver_coord[] = { x, y, x, h, w, y, w, h };
551
552         glColor4ub(255, 255, 255, 255);
553
554         glBindTexture(GL_TEXTURE_2D, Gr_saved_screen_tex);
555
556         opengl1_set_state(TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE);
557
558         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
559         glEnableClientState(GL_VERTEX_ARRAY);
560
561         glTexCoordPointer(2, GL_INT, 0, &tex_coord);
562         glVertexPointer(2, GL_INT, 0, &ver_coord);
563
564         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
565
566         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
567         glDisableClientState(GL_VERTEX_ARRAY);
568
569         glBindTexture(GL_TEXTURE_2D, 0);
570 }
571
572 void gr_opengl1_free_screen(int)
573 {
574         if (Gr_saved_screen_tex) {
575                 glDeleteTextures(1, &Gr_saved_screen_tex);
576                 Gr_saved_screen_tex = 0;
577         }
578 }
579
580 void gr_opengl1_dump_frame_start(int first_frame, int frames_between_dumps)
581 {
582         STUB_FUNCTION;
583 }
584
585 void gr_opengl1_dump_frame_stop()
586 {
587         STUB_FUNCTION;
588 }
589
590 void gr_opengl1_dump_frame()
591 {
592         STUB_FUNCTION;
593 }
594
595 static int GL_stream_w = 0;
596 static int GL_stream_h = 0;
597 static bool GL_stream_scale = false;
598 static float GL_stream_scale_by = 1.0f;
599
600 static rb_t GL_stream[4];
601
602 void gr_opengl1_stream_start(int x, int y, int w, int h)
603 {
604         if (GL_stream_tex) {
605                 return;
606         }
607
608         if (gr_screen.use_sections) {
609                 mprintf(("GR_STREAM: Bitmap sections not supported\n"));
610                 return;
611         }
612
613         int tex_w = next_pow2(w);
614         int tex_h = next_pow2(h);
615
616         glGenTextures(1, &GL_stream_tex);
617
618         glBindTexture(GL_TEXTURE_2D, GL_stream_tex);
619
620         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
621         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
622         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
623         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
624
625         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, NULL);
626
627         glBindTexture(GL_TEXTURE_2D, 0);
628
629         uint scale = os_config_read_uint("Video", "ScaleMovies", 1);
630
631         if (scale) {
632                 GL_stream_scale = true;
633
634                 GL_stream_scale_by = GL_viewport_w / i2fl(w);
635         } else {
636                 GL_stream_scale = false;
637         }
638
639         int sx, sy;
640
641         if (x < 0) {
642                 sx = scale ? 0 : ((gr_screen.max_w - w) / 2);
643         } else {
644                 sx = x;
645         }
646
647         if (y < 0) {
648                 sy = scale ? ((480 - h) / 2) : ((gr_screen.max_h - h) / 2);
649         } else {
650                 sy = y;
651         }
652
653         GL_stream_w = w;
654         GL_stream_h = h;
655
656         GL_stream[0].x = i2fl(sx);
657         GL_stream[0].y = i2fl(sy);
658         GL_stream[0].u = 0.0f;
659         GL_stream[0].v = 0.0f;
660
661         GL_stream[1].x = i2fl(sx);
662         GL_stream[1].y = i2fl(sy + h);
663         GL_stream[1].u = 0.0f;
664         GL_stream[1].v = i2fl(h) / i2fl(tex_h);
665
666         GL_stream[2].x = i2fl(sx + w);
667         GL_stream[2].y = i2fl(sy);
668         GL_stream[2].u = i2fl(w) / i2fl(tex_w);
669         GL_stream[2].v = 0.0f;
670
671         GL_stream[3].x = i2fl(sx + w);
672         GL_stream[3].y = i2fl(sy + h);
673         GL_stream[3].u = i2fl(w) / i2fl(tex_w);
674         GL_stream[3].v = i2fl(h) / i2fl(tex_h);
675
676         glDisable(GL_DEPTH_TEST);
677 }
678
679 void gr_opengl1_stream_frame(ubyte *frame)
680 {
681         if ( !GL_stream_tex ) {
682                 return;
683         }
684
685         glEnableClientState(GL_VERTEX_ARRAY);
686         glVertexPointer(2, GL_FLOAT, sizeof(rb_t), &GL_stream[0].x);
687
688         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
689         glTexCoordPointer(2, GL_FLOAT, sizeof(rb_t), &GL_stream[0].u);
690
691         glBindTexture(GL_TEXTURE_2D, GL_stream_tex);
692
693         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GL_stream_w, GL_stream_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, frame);
694
695         if (GL_stream_scale) {
696                 glPushMatrix();
697                 glLoadIdentity();
698                 glScalef(GL_stream_scale_by, GL_stream_scale_by, 1.0f);
699         }
700
701         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
702
703         if (GL_stream_scale) {
704                 glPopMatrix();
705         }
706
707         glBindTexture(GL_TEXTURE_2D, 0);
708
709         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
710         glDisableClientState(GL_VERTEX_ARRAY);
711 }
712
713 void gr_opengl1_stream_stop()
714 {
715         if (GL_stream_tex) {
716                 glBindTexture(GL_TEXTURE_2D, 0);
717                 glDeleteTextures(1, &GL_stream_tex);
718                 GL_stream_tex = 0;
719
720                 glEnable(GL_DEPTH_TEST);
721         }
722 }
723
724 void gr_opengl1_set_viewport(int width, int height)
725 {
726         int w, h, x, y;
727
728         float ratio = gr_screen.max_w / i2fl(gr_screen.max_h);
729
730         w = width;
731         h = fl2i((width / ratio) + 0.5f);
732
733         if (h > height) {
734                 h = height;
735                 w = fl2i((height * ratio) + 0.5f);
736         }
737
738         x = (width - w) / 2;
739         y = (height - h) / 2;
740
741         GL_viewport_x = x;
742         GL_viewport_y = y;
743         GL_viewport_w = w;
744         GL_viewport_h = h;
745         GL_viewport_scale_w = w / i2fl(gr_screen.max_w);
746         GL_viewport_scale_h = h / i2fl(gr_screen.max_h);
747
748         glViewport(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h);
749
750         glMatrixMode(GL_PROJECTION);
751         glLoadIdentity();
752         glOrtho(0, GL_viewport_w, GL_viewport_h, 0, 0.0, 1.0);
753         glMatrixMode(GL_MODELVIEW);
754         glLoadIdentity();
755         glScalef(GL_viewport_scale_w, GL_viewport_scale_h, 1.0f);
756
757         // free mouse cursor storage, since the size might have changed
758         if (Gr_opengl_mouse_saved_data) {
759                 free(Gr_opengl_mouse_saved_data);
760                 Gr_opengl_mouse_saved_data = NULL;
761         }
762
763         // clear screen once to fix issues with edges on non-4:3
764         gr_opengl_clear();
765 }