2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
9 #include "SDL_opengles2.h"
12 #include "gropenglinternal.h"
19 #include "grinternal.h"
21 #include "osregistry.h"
24 int GL_two_inited = 0;
26 bool Use_mipmaps = false;
28 static GLuint FB_texture = 0;
29 static GLuint FB_id = 0;
30 static GLuint FB_rb_id = 0;
32 static GLuint GL_saved_screen_tex = 0;
33 static GLuint GL_stream_tex = 0;
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;
39 void opengl2_set_state(gr_texture_source ts, gr_alpha_blend ab, gr_zbuffer_type zt)
41 opengl2_set_texture_state(ts);
43 if (ab != GL_current_alpha_blend) {
45 case ALPHA_BLEND_NONE: // 1*SrcPixel + 0*DestPixel
46 glBlendFunc(GL_ONE, GL_ZERO);
48 case ALPHA_BLEND_ADDITIVE: // 1*SrcPixel + 1*DestPixel
49 glBlendFunc(GL_ONE, GL_ONE);
51 case ALPHA_BLEND_ALPHA_ADDITIVE: // Alpha*SrcPixel + 1*DestPixel
52 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
54 case ALPHA_BLEND_ALPHA_BLEND_ALPHA: // Alpha*SrcPixel + (1-Alpha)*DestPixel
55 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
57 case ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR: // Alpha*SrcPixel + (1-SrcPixel)*DestPixel
58 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
64 GL_current_alpha_blend = ab;
67 if (zt != GL_current_zbuffer_type) {
69 case ZBUFFER_TYPE_NONE:
70 glDepthFunc(GL_ALWAYS);
71 glDepthMask(GL_FALSE);
73 case ZBUFFER_TYPE_READ:
75 glDepthMask(GL_FALSE);
77 case ZBUFFER_TYPE_WRITE:
78 glDepthFunc(GL_ALWAYS);
81 case ZBUFFER_TYPE_FULL:
89 GL_current_zbuffer_type = zt;
93 static void opengl2_init_func_pointers()
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;
99 gr_screen.gf_clear = gr_opengl_clear;
101 gr_screen.gf_aabitmap = gr_opengl2_aabitmap;
102 gr_screen.gf_aabitmap_ex = gr_opengl2_aabitmap_ex;
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;
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;
115 gr_screen.gf_gradient = gr_opengl2_gradient;
117 gr_screen.gf_print_screen = gr_opengl_print_screen;
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;
123 gr_screen.gf_zbuffer_clear = gr_opengl2_zbuffer_clear;
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;
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;
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;
137 gr_screen.gf_set_gamma = gr_opengl2_set_gamma;
139 gr_screen.gf_lock = gr_opengl_lock;
140 gr_screen.gf_unlock = gr_opengl_unlock;
142 gr_screen.gf_fog_set = gr_opengl2_fog_set;
144 gr_screen.gf_get_region = gr_opengl2_get_region;
146 gr_screen.gf_set_cull = gr_opengl_set_cull;
148 gr_screen.gf_cross_fade = gr_opengl2_cross_fade;
150 gr_screen.gf_preload_init = gr_opengl2_preload_init;
151 gr_screen.gf_preload = gr_opengl2_preload;
153 gr_screen.gf_zbias = gr_opengl_zbias;
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;
159 gr_screen.gf_set_viewport = gr_opengl2_set_viewport;
161 gr_screen.gf_activate = gr_opengl_activate;
163 gr_screen.gf_release_texture = gr_opengl2_release_texture;
166 static int opengl2_create_framebuffer()
169 glGenTextures(1, &FB_texture);
170 glBindTexture(GL_TEXTURE_2D, FB_texture);
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);
177 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gr_screen.max_w, gr_screen.max_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
179 glBindTexture(GL_TEXTURE_2D, 0);
181 // create renderbuffer
182 glGenRenderbuffers(1, &FB_rb_id);
183 glBindRenderbuffer(GL_RENDERBUFFER, FB_rb_id);
185 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, gr_screen.max_w, gr_screen.max_h);
187 // create framebuffer
188 glGenFramebuffers(1, &FB_id);
189 glBindFramebuffer(GL_FRAMEBUFFER, FB_id);
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);
195 GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
197 glBindFramebuffer(GL_FRAMEBUFFER, 0);
199 if (status != GL_FRAMEBUFFER_COMPLETE) {
200 glBindFramebuffer(GL_FRAMEBUFFER, 0);
203 glDeleteTextures(1, &FB_texture);
208 glDeleteRenderbuffers(1, &FB_rb_id);
213 glDeleteFramebuffers(1, &FB_id);
223 void opengl2_cleanup()
225 if ( !GL_two_inited ) {
229 glBindFramebuffer(GL_FRAMEBUFFER, 0);
232 glDeleteTextures(1, &FB_texture);
237 glDeleteRenderbuffers(1, &FB_rb_id);
242 glDeleteFramebuffers(1, &FB_id);
246 opengl2_tcache_cleanup();
247 opengl2_shader_cleanup();
250 SDL_GL_DeleteContext(GL_context);
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);
269 GL_context = SDL_GL_CreateContext(GL_window);
276 mprintf((" Vendor : %s\n", glGetString(GL_VENDOR)));
277 mprintf((" Renderer : %s\n", glGetString(GL_RENDERER)));
278 mprintf((" Version : %s\n", glGetString(GL_VERSION)));
280 // initial viewport setup
281 gr_opengl2_set_viewport(gr_screen.max_w, gr_screen.max_h);
283 // set up generic variables
284 opengl_set_variables();
286 opengl2_init_func_pointers();
287 opengl2_tcache_init();
289 if ( !opengl2_shader_init() ) {
294 if ( !opengl2_create_framebuffer() ) {
300 glEnable(GL_DEPTH_TEST);
302 glEnable(GL_TEXTURE_2D);
304 glDepthRangef(0.0f, 1.0f);
306 glPixelStorei(GL_PACK_ALIGNMENT, 1);
307 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
309 if ( SDL_GL_ExtensionSupported("GL_OES_texture_npot") ) {
313 mprintf((" Mipmaps : %s\n", Use_mipmaps ? "Enabled" : "Disabled"));
318 gr_opengl_set_cull(1);
323 void gr_opengl2_flip()
325 if ( !GL_two_inited ) {
330 static bool show_cursor = false;
333 glBindFramebuffer(GL_FRAMEBUFFER, 0);
335 gr_opengl_reset_clip();
337 // set viewport to window size
338 glViewport(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h);
340 glClear(GL_COLOR_BUFFER_BIT);
345 float w = i2fl(GL_viewport_w);
346 float h = i2fl(GL_viewport_h);
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 };
351 opengl2_shader_use(PROG_WINDOW);
353 glEnableVertexAttribArray(SDRI_POSITION);
354 glVertexAttribPointer(SDRI_POSITION, 2, GL_FLOAT, GL_FALSE, 0, &ver_coord);
356 glEnableVertexAttribArray(SDRI_TEXCOORD);
357 glVertexAttribPointer(SDRI_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, &tex_coord);
359 glBindTexture(GL_TEXTURE_2D, FB_texture);
361 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
363 glBindTexture(GL_TEXTURE_2D, 0);
365 glDisableVertexAttribArray(SDRI_TEXCOORD);
366 glDisableVertexAttribArray(SDRI_POSITION);
371 if ( mouse_is_visible() ) {
374 mouse_get_pos(&mx, &my);
376 float u_scale, v_scale;
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);
382 bm_get_info(Gr_cursor, &bw, &bh);
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);
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 };
392 opengl2_shader_use(PROG_WINDOW);
394 glEnableVertexAttribArray(SDRI_POSITION);
395 glVertexAttribPointer(SDRI_POSITION, 2, GL_FLOAT, GL_FALSE, 0, &ver_coord);
397 glEnableVertexAttribArray(SDRI_TEXCOORD);
398 glVertexAttribPointer(SDRI_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, &tex_coord);
400 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
402 glDisableVertexAttribArray(SDRI_TEXCOORD);
403 glDisableVertexAttribArray(SDRI_POSITION);
406 else if ( !show_cursor ) {
414 GLenum error = GL_NO_ERROR;
417 error = glGetError();
419 if (error != GL_NO_ERROR) {
420 nprintf(("Warning", "!!DEBUG!! OpenGL Error: %d\n", error));
422 } while (error != GL_NO_ERROR);
425 SDL_GL_SwapWindow(GL_window);
427 opengl2_tcache_frame();
429 glBindFramebuffer(GL_FRAMEBUFFER, FB_id);
431 // set viewport to game screen size
432 glViewport(0, 0, gr_screen.max_w, gr_screen.max_h);
435 void gr_opengl2_set_clip(int x, int y, int w, int h)
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);
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;
452 glEnable(GL_SCISSOR_TEST);
453 glScissor(x, gr_screen.max_h-y-h, w, h);
456 void gr_opengl2_fog_set(int fog_mode, int r, int g, int b, float fog_near, float fog_far)
458 gr_screen.current_fog_mode = fog_mode;
460 if (fog_mode == GR_FOGMODE_NONE) {
464 gr_screen.fog_near = fog_near;
465 gr_screen.fog_far = fog_far;
467 gr_init_color(&gr_screen.current_fog_color, r, g, b);
470 void gr_opengl2_zbuffer_clear(int mode)
474 Gr_zbuffering_mode = GR_ZBUFF_FULL;
475 Gr_global_zbuffering = 1;
477 opengl2_set_state(TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_FULL);
478 glClear(GL_DEPTH_BUFFER_BIT);
481 Gr_zbuffering_mode = GR_ZBUFF_NONE;
482 Gr_global_zbuffering = 0;
486 void gr_opengl2_fade_in(int instantaneous)
491 void gr_opengl2_fade_out(int instantaneous)
496 void gr_opengl2_get_region(int front, int w, int h, ubyte *data)
498 opengl2_set_state(TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE);
500 GLenum pxtype = GL_UNSIGNED_SHORT_5_5_5_1;
502 if (gr_screen.bytes_per_pixel == 4) {
503 pxtype = GL_UNSIGNED_BYTE;
506 glReadPixels(0, gr_screen.max_h-h-1, w, h, GL_RGBA, pxtype, data);
509 int gr_opengl2_save_screen()
511 gr_opengl_reset_clip();
513 if (GL_saved_screen_tex) {
514 mprintf(( "Screen already saved!\n" ));
518 glGenTextures(1, &GL_saved_screen_tex);
520 if ( !GL_saved_screen_tex ) {
521 mprintf(( "Couldn't create texture for saved screen!\n" ));
525 glBindTexture(GL_TEXTURE_2D, GL_saved_screen_tex);
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);
532 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0,
533 gr_screen.max_w, gr_screen.max_h, 0);
535 glBindTexture(GL_TEXTURE_2D, 0);
540 void gr_opengl2_restore_screen(int)
542 gr_opengl_reset_clip();
544 if ( !GL_saved_screen_tex ) {
551 float w = i2fl(gr_screen.max_w);
552 float h = i2fl(gr_screen.max_h);
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 };
557 opengl2_shader_use(PROG_TEX);
559 glVertexAttrib4f(SDRI_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
561 glEnableVertexAttribArray(SDRI_POSITION);
562 glVertexAttribPointer(SDRI_POSITION, 2, GL_FLOAT, GL_FALSE, 0, &ver_coord);
564 glEnableVertexAttribArray(SDRI_TEXCOORD);
565 glVertexAttribPointer(SDRI_TEXCOORD, 2, GL_FLOAT, GL_FALSE, 0, &tex_coord);
567 glBindTexture(GL_TEXTURE_2D, GL_saved_screen_tex);
569 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
571 glBindTexture(GL_TEXTURE_2D, 0);
573 glDisableVertexAttribArray(SDRI_TEXCOORD);
574 glDisableVertexAttribArray(SDRI_POSITION);
577 void gr_opengl2_free_screen(int)
579 if (GL_saved_screen_tex) {
580 glDeleteTextures(1, &GL_saved_screen_tex);
581 GL_saved_screen_tex = 0;
585 void gr_opengl2_dump_frame_start(int first_frame, int frames_between_dumps)
590 void gr_opengl2_dump_frame_stop()
595 void gr_opengl2_dump_frame()
600 static int GL_stream_w = 0;
601 static int GL_stream_h = 0;
603 static rb_t GL_stream[4];
605 void gr_opengl2_stream_start(int x, int y, int w, int h)
611 glGenTextures(1, &GL_stream_tex);
613 glBindTexture(GL_TEXTURE_2D, GL_stream_tex);
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);
620 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, NULL);
622 glBindTexture(GL_TEXTURE_2D, 0);
624 uint scale = os_config_read_uint("Video", "ScaleMovies", 1);
630 sx = scale ? 0 : ((gr_screen.max_w - w) / 2);
635 float h_factor = scale ? (gr_screen.max_w / i2fl(w)) : 1.0f;
638 sy = (gr_screen.max_h - fl2i(h * h_factor)) / 2;
647 sw = gr_screen.max_w - (sx * 2);
648 sh = gr_screen.max_h - (sy * 2);
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;
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;
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;
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;
674 glDisable(GL_DEPTH_TEST);
677 void gr_opengl2_stream_frame(ubyte *frame)
679 if ( !GL_stream_tex ) {
683 opengl2_shader_use(PROG_TEX);
685 glVertexAttrib4f(SDRI_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);
687 glEnableVertexAttribArray(SDRI_POSITION);
688 glVertexAttribPointer(SDRI_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &GL_stream[0].x);
690 glEnableVertexAttribArray(SDRI_TEXCOORD);
691 glVertexAttribPointer(SDRI_TEXCOORD, 2, GL_FLOAT, GL_FALSE, sizeof(rb_t), &GL_stream[0].u);
693 glBindTexture(GL_TEXTURE_2D, GL_stream_tex);
695 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, GL_stream_w, GL_stream_h, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, frame);
697 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
699 glBindTexture(GL_TEXTURE_2D, 0);
701 glDisableVertexAttribArray(SDRI_TEXCOORD);
702 glDisableVertexAttribArray(SDRI_POSITION);
705 void gr_opengl2_stream_stop()
708 glBindTexture(GL_TEXTURE_2D, 0);
709 glDeleteTextures(1, &GL_stream_tex);
712 glEnable(GL_DEPTH_TEST);
716 void gr_opengl2_set_viewport(int width, int height)
720 float ratio = gr_screen.max_w / i2fl(gr_screen.max_h);
723 h = fl2i((width / ratio) + 0.5f);
727 w = fl2i((height * ratio) + 0.5f);
731 y = (height - h) / 2;
737 GL_viewport_scale_w = w / i2fl(gr_screen.max_w);
738 GL_viewport_scale_h = h / i2fl(gr_screen.max_h);
740 opengl2_shader_update();