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