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