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