]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/grgl2.cpp
add debug spew for when GL2 falls back
[taylor/freespace2.git] / src / graphics / grgl2.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_opengles2.h"
10
11 #include "gropengl.h"
12 #include "gropenglinternal.h"
13 #include "grgl2.h"
14 #include "2d.h"
15 #include "mouse.h"
16 #include "pstypes.h"
17 #include "bmpman.h"
18 #include "grinternal.h"
19 #include "osregistry.h"
20 #include "cfile.h"
21
22
23 int GL_two_inited = 0;
24
25 bool Use_mipmaps = false;
26
27 static GLuint FB_texture = 0;
28 static GLuint FB_id = 0;
29 static GLuint FB_rb_id = 0;
30
31 static GLuint GL_saved_screen_tex = 0;
32 static GLuint GL_stream_tex = 0;
33
34
35 static gr_alpha_blend GL_current_alpha_blend = (gr_alpha_blend) -1;
36 static gr_zbuffer_type GL_current_zbuffer_type = (gr_zbuffer_type) -1;
37
38 void opengl2_set_state(gr_texture_source ts, gr_alpha_blend ab, gr_zbuffer_type zt)
39 {
40         opengl2_set_texture_state(ts);
41
42         if (ab != GL_current_alpha_blend) {
43                 switch (ab) {
44                         case ALPHA_BLEND_NONE:                  // 1*SrcPixel + 0*DestPixel
45                                 glBlendFunc(GL_ONE, GL_ZERO);
46                                 break;
47                         case ALPHA_BLEND_ADDITIVE:              // 1*SrcPixel + 1*DestPixel
48                                 glBlendFunc(GL_ONE, GL_ONE);
49                                 break;
50                         case ALPHA_BLEND_ALPHA_ADDITIVE:        // Alpha*SrcPixel + 1*DestPixel
51                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
52                                 break;
53                         case ALPHA_BLEND_ALPHA_BLEND_ALPHA:     // Alpha*SrcPixel + (1-Alpha)*DestPixel
54                                 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
55                                 break;
56                         case ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR: // Alpha*SrcPixel + (1-SrcPixel)*DestPixel
57                                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
58                                 break;
59                         default:
60                                 break;
61                 }
62
63                 GL_current_alpha_blend = ab;
64         }
65
66         if (zt != GL_current_zbuffer_type) {
67                 switch (zt) {
68                         case ZBUFFER_TYPE_NONE:
69                                 glDepthFunc(GL_ALWAYS);
70                                 glDepthMask(GL_FALSE);
71                                 break;
72                         case ZBUFFER_TYPE_READ:
73                                 glDepthFunc(GL_LESS);
74                                 glDepthMask(GL_FALSE);
75                                 break;
76                         case ZBUFFER_TYPE_WRITE:
77                                 glDepthFunc(GL_ALWAYS);
78                                 glDepthMask(GL_TRUE);
79                                 break;
80                         case ZBUFFER_TYPE_FULL:
81                                 glDepthFunc(GL_LESS);
82                                 glDepthMask(GL_TRUE);
83                                 break;
84                         default:
85                                 break;
86                 }
87
88                 GL_current_zbuffer_type = zt;
89         }
90 }
91
92 static void opengl2_init_func_pointers()
93 {
94         gr_screen.gf_flip = gr_opengl2_flip;
95         gr_screen.gf_set_clip = gr_opengl2_set_clip;
96         gr_screen.gf_reset_clip = gr_opengl_reset_clip;
97
98         gr_screen.gf_clear = gr_opengl_clear;
99
100         gr_screen.gf_aabitmap = gr_opengl2_aabitmap;
101         gr_screen.gf_aabitmap_ex = gr_opengl2_aabitmap_ex;
102
103         gr_screen.gf_rect = gr_opengl2_rect;
104         gr_screen.gf_shade = gr_opengl2_shade;
105         gr_screen.gf_string = gr_opengl2_string;
106         gr_screen.gf_circle = gr_opengl2_circle;
107
108         gr_screen.gf_line = gr_opengl2_line;
109         gr_screen.gf_aaline = gr_opengl2_aaline;
110         gr_screen.gf_pixel = gr_opengl2_pixel;
111         gr_screen.gf_scaler = gr_opengl2_scaler;
112         gr_screen.gf_tmapper = gr_opengl2_tmapper;
113
114         gr_screen.gf_gradient = gr_opengl2_gradient;
115
116         gr_screen.gf_print_screen = gr_opengl2_print_screen;
117
118         gr_screen.gf_fade_in = gr_opengl2_fade_in;
119         gr_screen.gf_fade_out = gr_opengl2_fade_out;
120         gr_screen.gf_flash = gr_opengl2_flash;
121
122         gr_screen.gf_zbuffer_clear = gr_opengl2_zbuffer_clear;
123
124         gr_screen.gf_save_screen = gr_opengl2_save_screen;
125         gr_screen.gf_restore_screen = gr_opengl2_restore_screen;
126         gr_screen.gf_free_screen = gr_opengl2_free_screen;
127
128         gr_screen.gf_dump_frame_start = gr_opengl2_dump_frame_start;
129         gr_screen.gf_dump_frame_stop = gr_opengl2_dump_frame_stop;
130         gr_screen.gf_dump_frame = gr_opengl2_dump_frame;
131
132         gr_screen.gf_stream_start = gr_opengl2_stream_start;
133         gr_screen.gf_stream_frame = gr_opengl2_stream_frame;
134         gr_screen.gf_stream_stop = gr_opengl2_stream_stop;
135
136         gr_screen.gf_set_gamma = gr_opengl2_set_gamma;
137
138         gr_screen.gf_lock = gr_opengl_lock;
139         gr_screen.gf_unlock = gr_opengl_unlock;
140
141         gr_screen.gf_fog_set = gr_opengl2_fog_set;
142
143         gr_screen.gf_get_region = gr_opengl2_get_region;
144
145         gr_screen.gf_set_cull = gr_opengl_set_cull;
146
147         gr_screen.gf_cross_fade = gr_opengl2_cross_fade;
148
149         gr_screen.gf_preload_init = gr_opengl2_preload_init;
150         gr_screen.gf_preload = gr_opengl2_preload;
151
152         gr_screen.gf_zbias = gr_opengl_zbias;
153
154         gr_screen.gf_set_viewport = gr_opengl2_set_viewport;
155
156         gr_screen.gf_activate = gr_opengl_activate;
157
158         gr_screen.gf_release_texture = gr_opengl2_release_texture;
159 }
160
161 static int opengl2_create_framebuffer()
162 {
163         // create texture
164         glGenTextures(1, &FB_texture);
165         glBindTexture(GL_TEXTURE_2D, FB_texture);
166
167         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
168         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
169         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
170         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
171
172         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gr_screen.max_w, gr_screen.max_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
173
174         glBindTexture(GL_TEXTURE_2D, 0);
175
176         // create renderbuffer
177         glGenRenderbuffers(1, &FB_rb_id);
178         glBindRenderbuffer(GL_RENDERBUFFER, FB_rb_id);
179
180         glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, gr_screen.max_w, gr_screen.max_h);
181
182         glBindRenderbuffer(GL_RENDERBUFFER, 0);
183
184         // create framebuffer
185         glGenFramebuffers(1, &FB_id);
186         glBindFramebuffer(GL_FRAMEBUFFER, FB_id);
187
188         // attach texture and renderbuffer
189         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, FB_texture, 0);
190         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, FB_rb_id);
191
192         GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
193
194         glBindFramebuffer(GL_FRAMEBUFFER, 0);
195
196         if (status != GL_FRAMEBUFFER_COMPLETE) {
197                 if (FB_texture) {
198                         glDeleteTextures(1, &FB_texture);
199                         FB_texture = 0;
200                 }
201
202                 if (FB_rb_id) {
203                         glDeleteRenderbuffers(1, &FB_rb_id);
204                         FB_rb_id = 0;
205                 }
206
207                 if (FB_id) {
208                         glDeleteFramebuffers(1, &FB_id);
209                         FB_id = 0;
210                 }
211
212                 return 0;
213         }
214
215         return 1;
216 }
217
218 void opengl2_cleanup()
219 {
220         if ( !GL_two_inited ) {
221                 return;
222         }
223
224         glBindFramebuffer(GL_FRAMEBUFFER, 0);
225
226         if (FB_texture) {
227                 glDeleteTextures(1, &FB_texture);
228                 FB_texture = 0;
229         }
230
231         if (FB_rb_id) {
232                 glDeleteRenderbuffers(1, &FB_rb_id);
233                 FB_rb_id = 0;
234         }
235
236         if (FB_id) {
237                 glDeleteFramebuffers(1, &FB_id);
238                 FB_id = 0;
239         }
240
241         opengl2_tcache_cleanup();
242         opengl2_shader_cleanup();
243
244         if (GL_context) {
245                 SDL_GL_DeleteContext(GL_context);
246                 GL_context = NULL;
247         }
248
249         GL_two_inited = 0;
250 }
251
252 int opengl2_init()
253 {
254         if (GL_two_inited) {
255                 return 1;
256         }
257
258         GL_two_inited = 1;
259
260         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
261         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
262         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
263
264         GL_context = SDL_GL_CreateContext(GL_window);
265
266         if ( !GL_context ) {
267                 opengl2_cleanup();
268                 return 0;
269         }
270
271         mprintf(("  Vendor   : %s\n", glGetString(GL_VENDOR)));
272         mprintf(("  Renderer : %s\n", glGetString(GL_RENDERER)));
273         mprintf(("  Version  : %s\n", glGetString(GL_VERSION)));
274
275         // initial viewport setup
276         gr_opengl2_set_viewport(gr_screen.max_w, gr_screen.max_h);
277
278         // set up generic variables
279         opengl_set_variables();
280
281         opengl2_init_func_pointers();
282         opengl2_tcache_init();
283
284         if ( !opengl2_shader_init() ) {
285                 mprintf(("  Fallback : shader init failure!\n"));
286                 opengl2_cleanup();
287                 return 0;
288         }
289
290         if ( !opengl2_create_framebuffer() ) {
291                 mprintf(("  Fallback : fbo init failure!\n"));
292                 opengl2_cleanup();
293                 return 0;
294         }
295
296         glEnable(GL_DITHER);
297         glEnable(GL_DEPTH_TEST);
298         glEnable(GL_BLEND);
299         glEnable(GL_TEXTURE_2D);
300
301         glDepthRangef(0.0f, 1.0f);
302
303         glPixelStorei(GL_PACK_ALIGNMENT, 1);
304         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
305
306         if ( SDL_GL_ExtensionSupported("GL_OES_texture_npot") ) {
307                 Use_mipmaps     = true;
308         }
309
310         mprintf(("  Mipmaps  : %s\n", Use_mipmaps ? "Enabled" : "Disabled"));
311
312         glFlush();
313
314         gr_opengl_clear();
315         gr_opengl_set_cull(1);
316
317         return 1;
318 }
319
320 void gr_opengl2_flip()
321 {
322         if ( !GL_two_inited ) {
323                 return;
324         }
325
326         glBindFramebuffer(GL_FRAMEBUFFER, 0);
327
328         gr_opengl_reset_clip();
329
330         // set viewport to window size
331         glViewport(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h);
332
333         glClear(GL_COLOR_BUFFER_BIT);
334
335         {
336                 float x = 0.0f;
337                 float y = 0.0f;
338                 float w = i2fl(GL_viewport_w);
339                 float h = i2fl(GL_viewport_h);
340
341                 const float tex_coord[] = { 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f };
342                 const float ver_coord[] = { x, y, x, h, w, y, w, h };
343
344                 opengl2_shader_use(PROG_WINDOW);
345
346                 glEnableVertexAttribArray(SDRI_POSITION);
347                 glVertexAttribPointer(SDRI_POSITION, 2, GL_FLOAT, GL_FALSE, 0, &ver_coord);
348
349                 glEnableVertexAttribArray(SDRI_TEXCOORD);
350                 glVertexAttribPointer(SDRI_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, &tex_coord);
351
352                 glBindTexture(GL_TEXTURE_2D, FB_texture);
353
354                 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
355
356                 glBindTexture(GL_TEXTURE_2D, 0);
357
358                 glDisableVertexAttribArray(SDRI_TEXCOORD);
359                 glDisableVertexAttribArray(SDRI_POSITION);
360         }
361
362         mouse_eval_deltas();
363
364         if ( mouse_is_visible() ) {
365                 int mx, my;
366
367                 mouse_get_pos(&mx, &my);
368
369                 if ( opengl2_tcache_set(Gr_cursor, TCACHE_TYPE_BITMAP_INTERFACE) ) {
370                         opengl2_set_state(TEXTURE_SOURCE_DECAL, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE);
371
372                         int bw, bh;
373                         bm_get_info(Gr_cursor, &bw, &bh);
374
375                         float x = i2fl(mx) * GL_viewport_scale_w;
376                         float y = i2fl(my) * GL_viewport_scale_h;
377                         float w = x + (bw * GL_viewport_scale_w);
378                         float h = y + (bh * GL_viewport_scale_h);
379
380                         const float tex_coord[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f };
381                         const float ver_coord[] = { x, y, x, h, w, y, w, h };
382
383                         opengl2_shader_use(PROG_WINDOW);
384
385                         glEnableVertexAttribArray(SDRI_POSITION);
386                         glVertexAttribPointer(SDRI_POSITION, 2, GL_FLOAT, GL_FALSE, 0, &ver_coord);
387
388                         glEnableVertexAttribArray(SDRI_TEXCOORD);
389                         glVertexAttribPointer(SDRI_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, &tex_coord);
390
391                         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
392
393                         glDisableVertexAttribArray(SDRI_TEXCOORD);
394                         glDisableVertexAttribArray(SDRI_POSITION);
395                 }
396 #ifndef NDEBUG
397                 else {
398                         gr_set_color(255,255,255);
399                         gr_opengl2_line(mx, my, mx+7, my + 7);
400                         gr_opengl2_line(mx, my, mx+5, my );
401                         gr_opengl2_line(mx, my, mx, my+5);
402                 }
403 #endif
404         }
405
406 #ifndef NDEBUG
407         GLenum error = glGetError();
408
409         if (error != GL_NO_ERROR) {
410                 mprintf(("!!DEBUG!! OpenGL Error: %d\n", error));
411         }
412 #endif
413
414         SDL_GL_SwapWindow(GL_window);
415
416         opengl2_tcache_frame();
417
418         glBindFramebuffer(GL_FRAMEBUFFER, FB_id);
419
420         // set viewport to game screen size
421         glViewport(0, 0, gr_screen.max_w, gr_screen.max_h);
422 }
423
424 void gr_opengl2_set_clip(int x, int y, int w, int h)
425 {
426         // check for sanity of parameters
427         CAP(x, 0, gr_screen.max_w - 1);
428         CAP(y, 0, gr_screen.max_h - 1);
429         CAP(w, 0, gr_screen.max_w - x);
430         CAP(h, 0, gr_screen.max_h - y);
431
432         gr_screen.offset_x = x;
433         gr_screen.offset_y = y;
434         gr_screen.clip_left = 0;
435         gr_screen.clip_right = w-1;
436         gr_screen.clip_top = 0;
437         gr_screen.clip_bottom = h-1;
438         gr_screen.clip_width = w;
439         gr_screen.clip_height = h;
440
441         glEnable(GL_SCISSOR_TEST);
442         glScissor(x, gr_screen.max_h-y-h, w, h);
443 }
444
445 void gr_opengl2_fog_set(int fog_mode, int r, int g, int b, float fog_near, float fog_far)
446 {
447         gr_screen.current_fog_mode = fog_mode;
448
449         if (fog_mode == GR_FOGMODE_NONE) {
450                 return;
451         }
452
453         gr_screen.fog_near = fog_near;
454         gr_screen.fog_far = fog_far;
455
456         gr_init_color(&gr_screen.current_fog_color, r, g, b);
457 }
458
459 void gr_opengl2_zbuffer_clear(int mode)
460 {
461         if (mode) {
462                 Gr_zbuffering = 1;
463                 Gr_zbuffering_mode = GR_ZBUFF_FULL;
464                 Gr_global_zbuffering = 1;
465
466                 opengl2_set_state(TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_FULL);
467                 glClear(GL_DEPTH_BUFFER_BIT);
468         } else {
469                 Gr_zbuffering = 0;
470                 Gr_zbuffering_mode = GR_ZBUFF_NONE;
471                 Gr_global_zbuffering = 0;
472         }
473 }
474
475 void gr_opengl2_print_screen(const char *filename)
476 {
477         char tmp[MAX_FILENAME_LEN];
478         ubyte *buf = NULL;
479
480         SDL_strlcpy( tmp, filename, SDL_arraysize(tmp) );
481         SDL_strlcat( tmp, NOX(".tga"), SDL_arraysize(tmp) );
482
483         int b_size = gr_screen.max_w * gr_screen.max_h;
484
485         buf = (ubyte*)malloc(b_size * 4);
486
487         if (buf == NULL) {
488                 return;
489         }
490
491         CFILE *f = cfopen(tmp, "wb", CFILE_NORMAL, CF_TYPE_ROOT);
492
493         if (f == NULL) {
494                 free(buf);
495                 return;
496         }
497
498         // Write the TGA header
499         cfwrite_ubyte( 0, f );  //      IDLength;
500         cfwrite_ubyte( 0, f );  //      ColorMapType;
501         cfwrite_ubyte( 2, f );  //      ImageType;              // 2 = 24bpp, uncompressed, 10=24bpp rle compressed
502         cfwrite_ushort( 0, f ); // CMapStart;
503         cfwrite_ushort( 0, f ); //      CMapLength;
504         cfwrite_ubyte( 0, f );  // CMapDepth;
505         cfwrite_ushort( 0, f ); //      XOffset;
506         cfwrite_ushort( 0, f ); //      YOffset;
507         cfwrite_ushort( (ushort)gr_screen.max_w, f );   //      Width;
508         cfwrite_ushort( (ushort)gr_screen.max_h, f );   //      Height;
509         cfwrite_ubyte( 24, f ); //PixelDepth;
510         cfwrite_ubyte( 0, f );  //ImageDesc;
511
512         memset(buf, 0, b_size * 4);
513
514         glReadPixels(0, 0, gr_screen.max_w, gr_screen.max_h, GL_RGBA, GL_UNSIGNED_BYTE, buf);
515
516         int b_offset = 0;
517
518         // convert from rgba to bgr
519         for (int i = 0; i < (b_size * 4); i += 4) {
520                 ubyte r = buf[i];
521                 ubyte g = buf[i+1];
522                 ubyte b = buf[i+2];
523
524                 buf[b_offset++] = b;
525                 buf[b_offset++] = g;
526                 buf[b_offset++] = r;
527         }
528
529         cfwrite(buf, b_size * 3, 1, f);
530
531         cfclose(f);
532
533         free(buf);
534 }
535
536 void gr_opengl2_fade_in(int instantaneous)
537 {
538
539 }
540
541 void gr_opengl2_fade_out(int instantaneous)
542 {
543
544 }
545
546 void gr_opengl2_get_region(int, int w, int h, ubyte *data)
547 {
548         opengl2_set_state(TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE);
549
550         glReadPixels(0, gr_screen.max_h-h-1, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);
551 }
552
553 int gr_opengl2_save_screen()
554 {
555         gr_opengl_reset_clip();
556
557         if (GL_saved_screen_tex) {
558                 mprintf(( "Screen already saved!\n" ));
559                 return -1;
560         }
561
562         glGenTextures(1, &GL_saved_screen_tex);
563
564         if ( !GL_saved_screen_tex ) {
565                 mprintf(( "Couldn't create texture for saved screen!\n" ));
566                 return -1;
567         }
568
569         glBindTexture(GL_TEXTURE_2D, GL_saved_screen_tex);
570
571         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
572         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
573         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
574         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
575
576         glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0,
577                         gr_screen.max_w, gr_screen.max_h, 0);
578
579         glBindTexture(GL_TEXTURE_2D, 0);
580
581         return 0;
582 }
583
584 void gr_opengl2_restore_screen(int)
585 {
586         gr_opengl_reset_clip();
587
588         if ( !GL_saved_screen_tex ) {
589                 gr_opengl_clear();
590                 return;
591         }
592
593         float x = 0.0f;
594         float y = 0.0f;
595         float w = i2fl(gr_screen.max_w);
596         float h = i2fl(gr_screen.max_h);
597
598         const float tex_coord[] = { 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f };   // y-flipped
599         const float ver_coord[] = { x, y, x, h, w, y, w, h };
600
601         opengl2_shader_use(PROG_TEX);
602
603         glVertexAttrib4f(SDRI_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
604
605         glEnableVertexAttribArray(SDRI_POSITION);
606         glVertexAttribPointer(SDRI_POSITION, 2, GL_FLOAT, GL_FALSE, 0, &ver_coord);
607
608         glEnableVertexAttribArray(SDRI_TEXCOORD);
609         glVertexAttribPointer(SDRI_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, &tex_coord);
610
611         glBindTexture(GL_TEXTURE_2D, GL_saved_screen_tex);
612
613         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
614
615         glBindTexture(GL_TEXTURE_2D, 0);
616
617         glDisableVertexAttribArray(SDRI_TEXCOORD);
618         glDisableVertexAttribArray(SDRI_POSITION);
619 }
620
621 void gr_opengl2_free_screen(int)
622 {
623         if (GL_saved_screen_tex) {
624                 glDeleteTextures(1, &GL_saved_screen_tex);
625                 GL_saved_screen_tex = 0;
626         }
627 }
628
629 void gr_opengl2_dump_frame_start(int first_frame, int frames_between_dumps)
630 {
631
632 }
633
634 void gr_opengl2_dump_frame_stop()
635 {
636
637 }
638
639 void gr_opengl2_dump_frame()
640 {
641
642 }
643
644 static int GL_stream_w = 0;
645 static int GL_stream_h = 0;
646
647 static rb_t GL_stream[4];
648
649 void gr_opengl2_stream_start(int x, int y, int w, int h)
650 {
651         if (GL_stream_tex) {
652                 return;
653         }
654
655         glGenTextures(1, &GL_stream_tex);
656
657         glBindTexture(GL_TEXTURE_2D, GL_stream_tex);
658
659         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
660         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
661         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
662         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
663
664         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, NULL);
665
666         glBindTexture(GL_TEXTURE_2D, 0);
667
668         uint scale = os_config_read_uint("Video", "ScaleMovies", 1);
669
670         int sx, sy;
671         int sw, sh;
672
673         if (x < 0) {
674                 sx = scale ? 0 : ((gr_screen.max_w - w) / 2);
675         } else {
676                 sx = x;
677         }
678
679         float h_factor = scale ? (gr_screen.max_w / i2fl(w)) : 1.0f;
680
681         if (y < 0) {
682                 sy = (gr_screen.max_h - fl2i(h * h_factor)) / 2;
683         } else {
684                 sy = y;
685         }
686
687         GL_stream_w = w;
688         GL_stream_h = h;
689
690         if (scale) {
691                 sw = gr_screen.max_w - (sx * 2);
692                 sh = gr_screen.max_h - (sy * 2);
693         } else {
694                 sw = w;
695                 sh = h;
696         }
697
698         GL_stream[0].x = i2fl(sx);
699         GL_stream[0].y = i2fl(sy);
700         GL_stream[0].u = 0.0f;
701         GL_stream[0].v = 0.0f;
702
703         GL_stream[1].x = i2fl(sx);
704         GL_stream[1].y = i2fl(sy + sh);
705         GL_stream[1].u = 0.0f;
706         GL_stream[1].v = 1.0f;
707
708         GL_stream[2].x = i2fl(sx + sw);
709         GL_stream[2].y = i2fl(sy);
710         GL_stream[2].u = 1.0f;
711         GL_stream[2].v = 0.0f;
712
713         GL_stream[3].x = i2fl(sx + sw);
714         GL_stream[3].y = i2fl(sy + sh);
715         GL_stream[3].u = 1.0f;
716         GL_stream[3].v = 1.0f;
717
718         glDisable(GL_DEPTH_TEST);
719 }
720
721 void gr_opengl2_stream_frame(ubyte *frame)
722 {
723         if ( !GL_stream_tex ) {
724                 return;
725         }
726
727         opengl2_shader_use(PROG_TEX);
728
729         glVertexAttrib4f(SDRI_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
730
731         glEnableVertexAttribArray(SDRI_POSITION);
732         glVertexAttribPointer(SDRI_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &GL_stream[0].x);
733
734         glEnableVertexAttribArray(SDRI_TEXCOORD);
735         glVertexAttribPointer(SDRI_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &GL_stream[0].u);
736
737         glBindTexture(GL_TEXTURE_2D, GL_stream_tex);
738
739         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GL_stream_w, GL_stream_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, frame);
740
741         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
742
743         glBindTexture(GL_TEXTURE_2D, 0);
744
745         glDisableVertexAttribArray(SDRI_TEXCOORD);
746         glDisableVertexAttribArray(SDRI_POSITION);
747 }
748
749 void gr_opengl2_stream_stop()
750 {
751         if (GL_stream_tex) {
752                 glBindTexture(GL_TEXTURE_2D, 0);
753                 glDeleteTextures(1, &GL_stream_tex);
754                 GL_stream_tex = 0;
755
756                 glEnable(GL_DEPTH_TEST);
757         }
758 }
759
760 void gr_opengl2_set_viewport(int width, int height)
761 {
762         int w, h, x, y;
763
764         float ratio = gr_screen.max_w / i2fl(gr_screen.max_h);
765
766         w = width;
767         h = fl2i((width / ratio) + 0.5f);
768
769         if (h > height) {
770                 h = height;
771                 w = fl2i((height * ratio) + 0.5f);
772         }
773
774         x = (width - w) / 2;
775         y = (height - h) / 2;
776
777         GL_viewport_x = x;
778         GL_viewport_y = y;
779         GL_viewport_w = w;
780         GL_viewport_h = h;
781         GL_viewport_scale_w = w / i2fl(gr_screen.max_w);
782         GL_viewport_scale_h = h / i2fl(gr_screen.max_h);
783
784         opengl2_shader_update();
785 }