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