]> icculus.org git repositories - taylor/freespace2.git/blob - src/graphics/grgl2.cpp
simply fullscreen<->window switching
[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_set_viewport = gr_opengl2_set_viewport;
156
157         gr_screen.gf_activate = gr_opengl_activate;
158
159         gr_screen.gf_release_texture = gr_opengl2_release_texture;
160 }
161
162 static int opengl2_create_framebuffer()
163 {
164         // create texture
165         glGenTextures(1, &FB_texture);
166         glBindTexture(GL_TEXTURE_2D, FB_texture);
167
168         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
169         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
170         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
171         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
172
173         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gr_screen.max_w, gr_screen.max_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
174
175         glBindTexture(GL_TEXTURE_2D, 0);
176
177         // create renderbuffer
178         glGenRenderbuffers(1, &FB_rb_id);
179         glBindRenderbuffer(GL_RENDERBUFFER, FB_rb_id);
180
181         glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, gr_screen.max_w, gr_screen.max_h);
182
183         // create framebuffer
184         glGenFramebuffers(1, &FB_id);
185         glBindFramebuffer(GL_FRAMEBUFFER, FB_id);
186
187         // attach texture and renderbuffer
188         glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, FB_texture, 0);
189         glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, FB_rb_id);
190
191         GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
192
193         glBindFramebuffer(GL_FRAMEBUFFER, 0);
194
195         if (status != GL_FRAMEBUFFER_COMPLETE) {
196                 glBindFramebuffer(GL_FRAMEBUFFER, 0);
197
198                 if (FB_texture) {
199                         glDeleteTextures(1, &FB_texture);
200                         FB_texture = 0;
201                 }
202
203                 if (FB_rb_id) {
204                         glDeleteRenderbuffers(1, &FB_rb_id);
205                         FB_rb_id = 0;
206                 }
207
208                 if (FB_id) {
209                         glDeleteFramebuffers(1, &FB_id);
210                         FB_id = 0;
211                 }
212
213                 return 0;
214         }
215
216         return 1;
217 }
218
219 void opengl2_cleanup()
220 {
221         if ( !GL_two_inited ) {
222                 return;
223         }
224
225         glBindFramebuffer(GL_FRAMEBUFFER, 0);
226
227         if (FB_texture) {
228                 glDeleteTextures(1, &FB_texture);
229                 FB_texture = 0;
230         }
231
232         if (FB_rb_id) {
233                 glDeleteRenderbuffers(1, &FB_rb_id);
234                 FB_rb_id = 0;
235         }
236
237         if (FB_id) {
238                 glDeleteFramebuffers(1, &FB_id);
239                 FB_id = 0;
240         }
241
242         opengl2_tcache_cleanup();
243         opengl2_shader_cleanup();
244
245         if (GL_context) {
246                 SDL_GL_DeleteContext(GL_context);
247                 GL_context = NULL;
248         }
249
250         GL_two_inited = 0;
251 }
252
253 int opengl2_init()
254 {
255         if (GL_two_inited) {
256                 return 1;
257         }
258
259         GL_two_inited = 1;
260
261         SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
262         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
263         SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
264
265         GL_context = SDL_GL_CreateContext(GL_window);
266
267         if ( !GL_context ) {
268                 opengl2_cleanup();
269                 return 0;
270         }
271
272         mprintf(("  Vendor   : %s\n", glGetString(GL_VENDOR)));
273         mprintf(("  Renderer : %s\n", glGetString(GL_RENDERER)));
274         mprintf(("  Version  : %s\n", glGetString(GL_VERSION)));
275
276         // initial viewport setup
277         gr_opengl2_set_viewport(gr_screen.max_w, gr_screen.max_h);
278
279         // set up generic variables
280         opengl_set_variables();
281
282         opengl2_init_func_pointers();
283         opengl2_tcache_init();
284
285         if ( !opengl2_shader_init() ) {
286                 opengl2_cleanup();
287                 return 0;
288         }
289
290         if ( !opengl2_create_framebuffer() ) {
291                 opengl2_cleanup();
292                 return 0;
293         }
294
295         glEnable(GL_DITHER);
296         glEnable(GL_DEPTH_TEST);
297         glEnable(GL_BLEND);
298         glEnable(GL_TEXTURE_2D);
299
300         glDepthRangef(0.0f, 1.0f);
301
302         glPixelStorei(GL_PACK_ALIGNMENT, 1);
303         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
304
305         if ( SDL_GL_ExtensionSupported("GL_OES_texture_npot") ) {
306                 Use_mipmaps     = true;
307         }
308
309         mprintf(("  Mipmaps  : %s\n", Use_mipmaps ? "Enabled" : "Disabled"));
310
311         glFlush();
312
313         gr_opengl_clear();
314         gr_opengl_set_cull(1);
315
316         return 1;
317 }
318
319 void gr_opengl2_flip()
320 {
321         if ( !GL_two_inited ) {
322                 return;
323         }
324
325 #ifndef NDEBUG
326         static bool show_cursor = false;
327 #endif
328
329         glBindFramebuffer(GL_FRAMEBUFFER, 0);
330
331         gr_opengl_reset_clip();
332
333         // set viewport to window size
334         glViewport(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h);
335
336         glClear(GL_COLOR_BUFFER_BIT);
337
338         {
339                 float x = 0.0f;
340                 float y = 0.0f;
341                 float w = i2fl(GL_viewport_w);
342                 float h = i2fl(GL_viewport_h);
343
344                 const float tex_coord[] = { 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f };
345                 const float ver_coord[] = { x, y, x, h, w, y, w, h };
346
347                 opengl2_shader_use(PROG_WINDOW);
348
349                 glEnableVertexAttribArray(SDRI_POSITION);
350                 glVertexAttribPointer(SDRI_POSITION, 2, GL_FLOAT, GL_FALSE, 0, &ver_coord);
351
352                 glEnableVertexAttribArray(SDRI_TEXCOORD);
353                 glVertexAttribPointer(SDRI_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, &tex_coord);
354
355                 glBindTexture(GL_TEXTURE_2D, FB_texture);
356
357                 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
358
359                 glBindTexture(GL_TEXTURE_2D, 0);
360
361                 glDisableVertexAttribArray(SDRI_TEXCOORD);
362                 glDisableVertexAttribArray(SDRI_POSITION);
363         }
364
365         mouse_eval_deltas();
366
367         if ( mouse_is_visible() ) {
368                 int mx, my;
369
370                 mouse_get_pos(&mx, &my);
371
372                 float u_scale, v_scale;
373
374                 if ( opengl2_tcache_set(Gr_cursor, TCACHE_TYPE_BITMAP_INTERFACE, &u_scale, &v_scale, 0) ) {
375                         opengl2_set_state(TEXTURE_SOURCE_DECAL, ALPHA_BLEND_ALPHA_BLEND_ALPHA, ZBUFFER_TYPE_NONE);
376
377                         int bw, bh;
378                         bm_get_info(Gr_cursor, &bw, &bh);
379
380                         float x = i2fl(mx) * GL_viewport_scale_w;
381                         float y = i2fl(my) * GL_viewport_scale_h;
382                         float w = x + (bw * GL_viewport_scale_w);
383                         float h = y + (bh * GL_viewport_scale_h);
384
385                         const float tex_coord[] = { 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f };
386                         const float ver_coord[] = { x, y, x, h, w, y, w, h };
387
388                         opengl2_shader_use(PROG_WINDOW);
389
390                         glEnableVertexAttribArray(SDRI_POSITION);
391                         glVertexAttribPointer(SDRI_POSITION, 2, GL_FLOAT, GL_FALSE, 0, &ver_coord);
392
393                         glEnableVertexAttribArray(SDRI_TEXCOORD);
394                         glVertexAttribPointer(SDRI_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, &tex_coord);
395
396                         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
397
398                         glDisableVertexAttribArray(SDRI_TEXCOORD);
399                         glDisableVertexAttribArray(SDRI_POSITION);
400                 }
401 #ifndef NDEBUG
402                 else if ( !show_cursor ) {
403                         SDL_ShowCursor(1);
404                         show_cursor = true;
405                 }
406 #endif
407         }
408
409 #ifndef NDEBUG
410         GLenum error = GL_NO_ERROR;
411
412         do {
413                 error = glGetError();
414
415                 if (error != GL_NO_ERROR) {
416                         nprintf(("Warning", "!!DEBUG!! OpenGL Error: %d\n", error));
417                 }
418         } while (error != GL_NO_ERROR);
419 #endif
420
421         SDL_GL_SwapWindow(GL_window);
422
423         opengl2_tcache_frame();
424
425         glBindFramebuffer(GL_FRAMEBUFFER, FB_id);
426
427         // set viewport to game screen size
428         glViewport(0, 0, gr_screen.max_w, gr_screen.max_h);
429 }
430
431 void gr_opengl2_set_clip(int x, int y, int w, int h)
432 {
433         // check for sanity of parameters
434         CAP(x, 0, gr_screen.max_w - 1);
435         CAP(y, 0, gr_screen.max_h - 1);
436         CAP(w, 0, gr_screen.max_w - x);
437         CAP(h, 0, gr_screen.max_h - y);
438
439         gr_screen.offset_x = x;
440         gr_screen.offset_y = y;
441         gr_screen.clip_left = 0;
442         gr_screen.clip_right = w-1;
443         gr_screen.clip_top = 0;
444         gr_screen.clip_bottom = h-1;
445         gr_screen.clip_width = w;
446         gr_screen.clip_height = h;
447
448         glEnable(GL_SCISSOR_TEST);
449         glScissor(x, gr_screen.max_h-y-h, w, h);
450 }
451
452 void gr_opengl2_fog_set(int fog_mode, int r, int g, int b, float fog_near, float fog_far)
453 {
454         gr_screen.current_fog_mode = fog_mode;
455
456         if (fog_mode == GR_FOGMODE_NONE) {
457                 return;
458         }
459
460         gr_screen.fog_near = fog_near;
461         gr_screen.fog_far = fog_far;
462
463         gr_init_color(&gr_screen.current_fog_color, r, g, b);
464 }
465
466 void gr_opengl2_zbuffer_clear(int mode)
467 {
468         if (mode) {
469                 Gr_zbuffering = 1;
470                 Gr_zbuffering_mode = GR_ZBUFF_FULL;
471                 Gr_global_zbuffering = 1;
472
473                 opengl2_set_state(TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_FULL);
474                 glClear(GL_DEPTH_BUFFER_BIT);
475         } else {
476                 Gr_zbuffering = 0;
477                 Gr_zbuffering_mode = GR_ZBUFF_NONE;
478                 Gr_global_zbuffering = 0;
479         }
480 }
481
482 void gr_opengl2_fade_in(int instantaneous)
483 {
484
485 }
486
487 void gr_opengl2_fade_out(int instantaneous)
488 {
489
490 }
491
492 void gr_opengl2_get_region(int front, int w, int h, ubyte *data)
493 {
494         opengl2_set_state(TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE);
495
496         GLenum pxtype = GL_UNSIGNED_SHORT_5_5_5_1;
497
498         if (gr_screen.bytes_per_pixel == 4) {
499                 pxtype = GL_UNSIGNED_BYTE;
500         }
501
502         glReadPixels(0, gr_screen.max_h-h-1, w, h, GL_RGBA, pxtype, data);
503 }
504
505 int gr_opengl2_save_screen()
506 {
507         gr_opengl_reset_clip();
508
509         if (GL_saved_screen_tex) {
510                 mprintf(( "Screen already saved!\n" ));
511                 return -1;
512         }
513
514         glGenTextures(1, &GL_saved_screen_tex);
515
516         if ( !GL_saved_screen_tex ) {
517                 mprintf(( "Couldn't create texture for saved screen!\n" ));
518                 return -1;
519         }
520
521         glBindTexture(GL_TEXTURE_2D, GL_saved_screen_tex);
522
523         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
524         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
525         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
526         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
527
528         glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0,
529                         gr_screen.max_w, gr_screen.max_h, 0);
530
531         glBindTexture(GL_TEXTURE_2D, 0);
532
533         return 0;
534 }
535
536 void gr_opengl2_restore_screen(int)
537 {
538         gr_opengl_reset_clip();
539
540         if ( !GL_saved_screen_tex ) {
541                 gr_opengl_clear();
542                 return;
543         }
544
545         float x = 0.0f;
546         float y = 0.0f;
547         float w = i2fl(gr_screen.max_w);
548         float h = i2fl(gr_screen.max_h);
549
550         const float tex_coord[] = { 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f };   // y-flipped
551         const float ver_coord[] = { x, y, x, h, w, y, w, h };
552
553         opengl2_shader_use(PROG_TEX);
554
555         glVertexAttrib4f(SDRI_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
556
557         glEnableVertexAttribArray(SDRI_POSITION);
558         glVertexAttribPointer(SDRI_POSITION, 2, GL_FLOAT, GL_FALSE, 0, &ver_coord);
559
560         glEnableVertexAttribArray(SDRI_TEXCOORD);
561         glVertexAttribPointer(SDRI_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, &tex_coord);
562
563         glBindTexture(GL_TEXTURE_2D, GL_saved_screen_tex);
564
565         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
566
567         glBindTexture(GL_TEXTURE_2D, 0);
568
569         glDisableVertexAttribArray(SDRI_TEXCOORD);
570         glDisableVertexAttribArray(SDRI_POSITION);
571 }
572
573 void gr_opengl2_free_screen(int)
574 {
575         if (GL_saved_screen_tex) {
576                 glDeleteTextures(1, &GL_saved_screen_tex);
577                 GL_saved_screen_tex = 0;
578         }
579 }
580
581 void gr_opengl2_dump_frame_start(int first_frame, int frames_between_dumps)
582 {
583
584 }
585
586 void gr_opengl2_dump_frame_stop()
587 {
588
589 }
590
591 void gr_opengl2_dump_frame()
592 {
593
594 }
595
596 static int GL_stream_w = 0;
597 static int GL_stream_h = 0;
598
599 static rb_t GL_stream[4];
600
601 void gr_opengl2_stream_start(int x, int y, int w, int h)
602 {
603         if (GL_stream_tex) {
604                 return;
605         }
606
607         glGenTextures(1, &GL_stream_tex);
608
609         glBindTexture(GL_TEXTURE_2D, GL_stream_tex);
610
611         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
612         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
613         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
614         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
615
616         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, NULL);
617
618         glBindTexture(GL_TEXTURE_2D, 0);
619
620         uint scale = os_config_read_uint("Video", "ScaleMovies", 1);
621
622         int sx, sy;
623         int sw, sh;
624
625         if (x < 0) {
626                 sx = scale ? 0 : ((gr_screen.max_w - w) / 2);
627         } else {
628                 sx = x;
629         }
630
631         float h_factor = scale ? (gr_screen.max_w / i2fl(w)) : 1.0f;
632
633         if (y < 0) {
634                 sy = (gr_screen.max_h - fl2i(h * h_factor)) / 2;
635         } else {
636                 sy = y;
637         }
638
639         GL_stream_w = w;
640         GL_stream_h = h;
641
642         if (scale) {
643                 sw = gr_screen.max_w - (sx * 2);
644                 sh = gr_screen.max_h - (sy * 2);
645         } else {
646                 sw = w;
647                 sh = h;
648         }
649
650         GL_stream[0].x = i2fl(sx);
651         GL_stream[0].y = i2fl(sy);
652         GL_stream[0].u = 0.0f;
653         GL_stream[0].v = 0.0f;
654
655         GL_stream[1].x = i2fl(sx);
656         GL_stream[1].y = i2fl(sy + sh);
657         GL_stream[1].u = 0.0f;
658         GL_stream[1].v = 1.0f;
659
660         GL_stream[2].x = i2fl(sx + sw);
661         GL_stream[2].y = i2fl(sy);
662         GL_stream[2].u = 1.0f;
663         GL_stream[2].v = 0.0f;
664
665         GL_stream[3].x = i2fl(sx + sw);
666         GL_stream[3].y = i2fl(sy + sh);
667         GL_stream[3].u = 1.0f;
668         GL_stream[3].v = 1.0f;
669
670         glDisable(GL_DEPTH_TEST);
671 }
672
673 void gr_opengl2_stream_frame(ubyte *frame)
674 {
675         if ( !GL_stream_tex ) {
676                 return;
677         }
678
679         opengl2_shader_use(PROG_TEX);
680
681         glVertexAttrib4f(SDRI_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
682
683         glEnableVertexAttribArray(SDRI_POSITION);
684         glVertexAttribPointer(SDRI_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &GL_stream[0].x);
685
686         glEnableVertexAttribArray(SDRI_TEXCOORD);
687         glVertexAttribPointer(SDRI_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &GL_stream[0].u);
688
689         glBindTexture(GL_TEXTURE_2D, GL_stream_tex);
690
691         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GL_stream_w, GL_stream_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, frame);
692
693         glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
694
695         glBindTexture(GL_TEXTURE_2D, 0);
696
697         glDisableVertexAttribArray(SDRI_TEXCOORD);
698         glDisableVertexAttribArray(SDRI_POSITION);
699 }
700
701 void gr_opengl2_stream_stop()
702 {
703         if (GL_stream_tex) {
704                 glBindTexture(GL_TEXTURE_2D, 0);
705                 glDeleteTextures(1, &GL_stream_tex);
706                 GL_stream_tex = 0;
707
708                 glEnable(GL_DEPTH_TEST);
709         }
710 }
711
712 void gr_opengl2_set_viewport(int width, int height)
713 {
714         int w, h, x, y;
715
716         float ratio = gr_screen.max_w / i2fl(gr_screen.max_h);
717
718         w = width;
719         h = fl2i((width / ratio) + 0.5f);
720
721         if (h > height) {
722                 h = height;
723                 w = fl2i((height * ratio) + 0.5f);
724         }
725
726         x = (width - w) / 2;
727         y = (height - h) / 2;
728
729         GL_viewport_x = x;
730         GL_viewport_y = y;
731         GL_viewport_w = w;
732         GL_viewport_h = h;
733         GL_viewport_scale_w = w / i2fl(gr_screen.max_w);
734         GL_viewport_scale_h = h / i2fl(gr_screen.max_h);
735
736         opengl2_shader_update();
737 }