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_opengl.h"
12 #include "gropenglinternal.h"
19 #include "grinternal.h"
21 #include "osregistry.h"
26 int GL_one_inited = 0;
29 static GLuint Gr_saved_screen_tex = 0;
31 static int Gr_opengl_mouse_saved = 0;
32 static int Gr_opengl_mouse_saved_x = 0;
33 static int Gr_opengl_mouse_saved_y = 0;
34 static int Gr_opengl_mouse_saved_w = 0;
35 static int Gr_opengl_mouse_saved_h = 0;
36 static ubyte *Gr_opengl_mouse_saved_data = NULL;
39 PFNGLSECONDARYCOLORPOINTERPROC vglSecondaryColorPointer = NULL;
42 static gr_alpha_blend GL_current_alpha_blend = (gr_alpha_blend) -1;
43 static gr_zbuffer_type GL_current_zbuffer_type = (gr_zbuffer_type) -1;
45 void opengl1_set_state(gr_texture_source ts, gr_alpha_blend ab, gr_zbuffer_type zt)
47 opengl1_set_texture_state(ts);
49 if (ab != GL_current_alpha_blend) {
51 case ALPHA_BLEND_NONE: // 1*SrcPixel + 0*DestPixel
52 glBlendFunc(GL_ONE, GL_ZERO);
54 case ALPHA_BLEND_ADDITIVE: // 1*SrcPixel + 1*DestPixel
55 glBlendFunc(GL_ONE, GL_ONE);
57 case ALPHA_BLEND_ALPHA_ADDITIVE: // Alpha*SrcPixel + 1*DestPixel
58 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
60 case ALPHA_BLEND_ALPHA_BLEND_ALPHA: // Alpha*SrcPixel + (1-Alpha)*DestPixel
61 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
63 case ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR: // Alpha*SrcPixel + (1-SrcPixel)*DestPixel
64 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
70 GL_current_alpha_blend = ab;
73 if (zt != GL_current_zbuffer_type) {
75 case ZBUFFER_TYPE_NONE:
76 glDepthFunc(GL_ALWAYS);
77 glDepthMask(GL_FALSE);
79 case ZBUFFER_TYPE_READ:
81 glDepthMask(GL_FALSE);
83 case ZBUFFER_TYPE_WRITE:
84 glDepthFunc(GL_ALWAYS);
87 case ZBUFFER_TYPE_FULL:
95 GL_current_zbuffer_type = zt;
99 void opengl1_cleanup()
101 if ( !GL_one_inited ) {
105 gr_opengl_reset_clip();
109 gr_opengl1_free_screen(0);
111 if (Gr_opengl_mouse_saved_data) {
112 free(Gr_opengl_mouse_saved_data);
113 Gr_opengl_mouse_saved_data = NULL;
116 opengl1_tcache_cleanup();
121 static void opengl1_init_func_pointers()
123 gr_screen.gf_flip = gr_opengl1_flip;
124 gr_screen.gf_set_clip = gr_opengl1_set_clip;
125 gr_screen.gf_reset_clip = gr_opengl_reset_clip;
127 gr_screen.gf_clear = gr_opengl_clear;
129 gr_screen.gf_aabitmap = gr_opengl1_aabitmap;
130 gr_screen.gf_aabitmap_ex = gr_opengl1_aabitmap_ex;
132 gr_screen.gf_rect = gr_opengl1_rect;
133 gr_screen.gf_shade = gr_opengl1_shade;
134 gr_screen.gf_string = gr_opengl1_string;
135 gr_screen.gf_circle = gr_opengl1_circle;
137 gr_screen.gf_line = gr_opengl1_line;
138 gr_screen.gf_aaline = gr_opengl1_aaline;
139 gr_screen.gf_pixel = gr_opengl1_pixel;
140 gr_screen.gf_scaler = gr_opengl1_scaler;
141 gr_screen.gf_tmapper = gr_opengl1_tmapper;
143 gr_screen.gf_gradient = gr_opengl1_gradient;
145 gr_screen.gf_print_screen = gr_opengl_print_screen;
147 gr_screen.gf_fade_in = gr_opengl1_fade_in;
148 gr_screen.gf_fade_out = gr_opengl1_fade_out;
149 gr_screen.gf_flash = gr_opengl1_flash;
151 gr_screen.gf_zbuffer_clear = gr_opengl1_zbuffer_clear;
153 gr_screen.gf_save_screen = gr_opengl1_save_screen;
154 gr_screen.gf_restore_screen = gr_opengl1_restore_screen;
155 gr_screen.gf_free_screen = gr_opengl1_free_screen;
157 gr_screen.gf_dump_frame_start = gr_opengl1_dump_frame_start;
158 gr_screen.gf_dump_frame_stop = gr_opengl1_dump_frame_stop;
159 gr_screen.gf_dump_frame = gr_opengl1_dump_frame;
161 gr_screen.gf_set_gamma = gr_opengl1_set_gamma;
163 gr_screen.gf_lock = gr_opengl_lock;
164 gr_screen.gf_unlock = gr_opengl_unlock;
166 gr_screen.gf_fog_set = gr_opengl1_fog_set;
168 gr_screen.gf_get_region = gr_opengl1_get_region;
170 gr_screen.gf_set_cull = gr_opengl_set_cull;
172 gr_screen.gf_cross_fade = gr_opengl1_cross_fade;
174 gr_screen.gf_preload_init = gr_opengl1_preload_init;
175 gr_screen.gf_preload = gr_opengl1_preload;
177 gr_screen.gf_zbias = gr_opengl_zbias;
179 gr_screen.gf_force_windowed = gr_opengl_force_windowed;
180 gr_screen.gf_force_fullscreen = gr_opengl_force_fullscreen;
181 gr_screen.gf_toggle_fullscreen = gr_opengl_toggle_fullscreen;
183 gr_screen.gf_set_viewport = gr_opengl1_set_viewport;
185 gr_screen.gf_activate = gr_opengl_activate;
187 gr_screen.gf_release_texture = gr_opengl1_release_texture;
196 GL_context = SDL_GL_CreateContext(GL_window);
202 mprintf((" Vendor : %s\n", glGetString(GL_VENDOR)));
203 mprintf((" Renderer : %s\n", glGetString(GL_RENDERER)));
204 mprintf((" Version : %s\n", glGetString(GL_VERSION)));
206 // set up generic variables
207 opengl_set_variables();
209 opengl1_init_func_pointers();
210 opengl1_tcache_init();
212 // initial viewport setup
213 gr_opengl1_set_viewport(gr_screen.max_w, gr_screen.max_h);
216 1 = use secondary color ext
217 2 = use opengl linear fog
221 // only available with OpenGL 1.2+, must get ptr for Windows
222 vglSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)SDL_GL_GetProcAddress("glSecondaryColorPointer");
224 if (vglSecondaryColorPointer) {
228 mprintf((" Fog mode : %s\n", (OGL_fog_mode == 1) ? "secondary color" : "linear"));
230 glShadeModel(GL_SMOOTH);
232 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
233 glHint(GL_FOG_HINT, GL_NICEST);
235 glEnable(GL_DEPTH_TEST);
238 glEnable(GL_TEXTURE_2D);
240 glDepthRange(0.0, 1.0);
242 glPixelStorei(GL_PACK_ALIGNMENT, 1);
243 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
248 gr_opengl_set_cull(1);
255 void gr_opengl1_flip()
257 if ( !GL_one_inited ) {
265 Gr_opengl_mouse_saved = 0;
267 if ( mouse_is_visible() ) {
270 mouse_get_pos( &mx, &my );
272 gr_opengl1_save_mouse_area(mx,my,32,32);
274 if (Gr_cursor == -1) {
276 gr_set_color(255,255,255);
277 gr_line(mx, my, mx+7, my + 7);
278 gr_line(mx, my, mx+5, my );
279 gr_line(mx, my, mx, my+5);
282 gr_set_bitmap(Gr_cursor);
288 GLenum error = GL_NO_ERROR;
291 error = glGetError();
293 if (error != GL_NO_ERROR) {
294 nprintf(("Warning", "!!DEBUG!! OpenGL Error: %d\n", error));
296 } while (error != GL_NO_ERROR);
299 SDL_GL_SwapWindow(GL_window);
301 opengl1_tcache_frame();
303 int cnt = GL_activate;
306 opengl1_tcache_flush();
307 // gr_opengl_clip_cursor(1); /* mouse grab, see opengl_activate */
313 // gr_opengl_clip_cursor(0); /* mouse grab, see opengl_activate */
317 void gr_opengl1_set_clip(int x, int y, int w, int h)
319 // check for sanity of parameters
320 CAP(x, 0, gr_screen.max_w - 1);
321 CAP(y, 0, gr_screen.max_h - 1);
322 CAP(w, 0, gr_screen.max_w - x);
323 CAP(h, 0, gr_screen.max_h - y);
325 gr_screen.offset_x = x;
326 gr_screen.offset_y = y;
327 gr_screen.clip_left = 0;
328 gr_screen.clip_right = w-1;
329 gr_screen.clip_top = 0;
330 gr_screen.clip_bottom = h-1;
331 gr_screen.clip_width = w;
332 gr_screen.clip_height = h;
334 x = fl2i((x * GL_viewport_scale_w) + 0.5f) + GL_viewport_x;
335 y = fl2i((y * GL_viewport_scale_h) + 0.5f) + GL_viewport_y;
336 w = fl2i((w * GL_viewport_scale_w) + 0.5f);
337 h = fl2i((h * GL_viewport_scale_h) + 0.5f);
339 glEnable(GL_SCISSOR_TEST);
340 glScissor(x, GL_viewport_h-y-h, w, h);
343 void gr_opengl1_fog_set(int fog_mode, int r, int g, int b, float fog_near, float fog_far)
345 SDL_assert((r >= 0) && (r < 256));
346 SDL_assert((g >= 0) && (g < 256));
347 SDL_assert((b >= 0) && (b < 256));
349 if (fog_mode == GR_FOGMODE_NONE) {
350 if (gr_screen.current_fog_mode != fog_mode) {
353 if (OGL_fog_mode == 1) {
354 glDisable(GL_COLOR_SUM);
358 gr_screen.current_fog_mode = fog_mode;
363 if (gr_screen.current_fog_mode != fog_mode) {
366 if (OGL_fog_mode == 1) {
367 glEnable(GL_COLOR_SUM);
368 } else if (OGL_fog_mode == 2) {
369 glFogi(GL_FOG_MODE, GL_LINEAR);
372 gr_screen.current_fog_mode = fog_mode;
375 if ( (gr_screen.current_fog_color.red != r) ||
376 (gr_screen.current_fog_color.green != g) ||
377 (gr_screen.current_fog_color.blue != b) ) {
380 gr_init_color( &gr_screen.current_fog_color, r, g, b );
387 glFogfv(GL_FOG_COLOR, fc);
390 if( (fog_near >= 0.0f) && (fog_far >= 0.0f) &&
391 ((fog_near != gr_screen.fog_near) ||
392 (fog_far != gr_screen.fog_far)) ) {
393 gr_screen.fog_near = fog_near;
394 gr_screen.fog_far = fog_far;
396 if (OGL_fog_mode == 2) {
397 glFogf(GL_FOG_START, fog_near);
398 glFogf(GL_FOG_END, fog_far);
403 void gr_opengl1_zbuffer_clear(int mode)
407 Gr_zbuffering_mode = GR_ZBUFF_FULL;
408 Gr_global_zbuffering = 1;
410 opengl1_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_FULL );
411 glClear ( GL_DEPTH_BUFFER_BIT );
414 Gr_zbuffering_mode = GR_ZBUFF_NONE;
415 Gr_global_zbuffering = 0;
419 void gr_opengl1_fade_in(int instantaneous)
424 void gr_opengl1_fade_out(int instantaneous)
429 void gr_opengl1_get_region(int front, int w, int h, ubyte *data)
432 glReadBuffer(GL_FRONT);
434 glReadBuffer(GL_BACK);
437 opengl1_set_state(TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE);
439 glPixelStorei(GL_UNPACK_ROW_LENGTH, GL_viewport_w);
441 int x = GL_viewport_x;
442 int y = (GL_viewport_y+GL_viewport_h)-h-1;
444 GLenum pxtype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
446 if (gr_screen.bytes_per_pixel == 4) {
447 pxtype = GL_UNSIGNED_BYTE;
450 glReadPixels(x, y, w, h, GL_RGBA, pxtype, data);
452 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
455 void gr_opengl1_save_mouse_area(int x, int y, int w, int h)
459 if (Gr_saved_screen_tex) {
460 // already saved, don't need it again
464 w = fl2i((w * GL_viewport_scale_w) + 0.5f);
465 h = fl2i((h * GL_viewport_scale_h) + 0.5f);
472 CAP(x1, 0, GL_viewport_w);
473 CAP(x2, 0, GL_viewport_w);
474 CAP(y1, 0, GL_viewport_h);
475 CAP(y2, 0, GL_viewport_h);
477 Gr_opengl_mouse_saved_x = x1;
478 Gr_opengl_mouse_saved_y = y1;
479 Gr_opengl_mouse_saved_w = x2 - x1 + 1;
480 Gr_opengl_mouse_saved_h = y2 - y1 + 1;
482 if ( (Gr_opengl_mouse_saved_w < 1) || (Gr_opengl_mouse_saved_h < 1) ) {
486 if (Gr_opengl_mouse_saved_data == NULL) {
487 Gr_opengl_mouse_saved_data = (ubyte*)malloc(w * h * 3);
489 if ( !Gr_opengl_mouse_saved_data ) {
494 x1 = GL_viewport_x+Gr_opengl_mouse_saved_x;
495 y1 = (GL_viewport_y+GL_viewport_h)-Gr_opengl_mouse_saved_y-Gr_opengl_mouse_saved_h;
497 glReadBuffer(GL_BACK);
499 glReadPixels(x1, y1, Gr_opengl_mouse_saved_w, Gr_opengl_mouse_saved_h,
500 GL_RGB, GL_UNSIGNED_BYTE, Gr_opengl_mouse_saved_data);
502 Gr_opengl_mouse_saved = 1;
505 int gr_opengl1_save_screen()
509 if (Gr_saved_screen_tex) {
510 mprintf(( "Screen already saved!\n" ));
514 glGenTextures(1, &Gr_saved_screen_tex);
516 if ( !Gr_saved_screen_tex ) {
517 mprintf(( "Couldn't create texture for saved screen!\n" ));
521 glBindTexture(GL_TEXTURE_2D, Gr_saved_screen_tex);
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_REPEAT);
526 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
527 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
529 glReadBuffer(GL_FRONT);
531 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GL_viewport_x, GL_viewport_y,
532 GL_viewport_w, GL_viewport_h, 0);
534 if (Gr_opengl_mouse_saved) {
535 int x = Gr_opengl_mouse_saved_x;
536 int y = GL_viewport_h-Gr_opengl_mouse_saved_y-Gr_opengl_mouse_saved_h;
538 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, Gr_opengl_mouse_saved_w,
539 Gr_opengl_mouse_saved_h, GL_RGB, GL_UNSIGNED_BYTE,
540 Gr_opengl_mouse_saved_data);
543 glBindTexture(GL_TEXTURE_2D, 0);
548 void gr_opengl1_restore_screen(int)
552 if ( !Gr_saved_screen_tex ) {
559 int w = fl2i(GL_viewport_w / GL_viewport_scale_w + 0.5f);
560 int h = fl2i(GL_viewport_h / GL_viewport_scale_h + 0.5f);
562 const int tex_coord[] = { 0, 1, 0, 0, 1, 1, 1, 0 }; // y-flipped
563 const int ver_coord[] = { x, y, x, h, w, y, w, h };
565 glColor4ub(255, 255, 255, 255);
567 glBindTexture(GL_TEXTURE_2D, Gr_saved_screen_tex);
569 opengl1_set_state(TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE);
571 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
572 glEnableClientState(GL_VERTEX_ARRAY);
574 glTexCoordPointer(2, GL_INT, 0, &tex_coord);
575 glVertexPointer(2, GL_INT, 0, &ver_coord);
577 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
579 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
580 glDisableClientState(GL_VERTEX_ARRAY);
582 glBindTexture(GL_TEXTURE_2D, 0);
585 void gr_opengl1_free_screen(int)
587 if (Gr_saved_screen_tex) {
588 glDeleteTextures(1, &Gr_saved_screen_tex);
589 Gr_saved_screen_tex = 0;
593 void gr_opengl1_dump_frame_start(int first_frame, int frames_between_dumps)
598 void gr_opengl1_dump_frame_stop()
603 void gr_opengl1_dump_frame()
608 void gr_opengl1_set_viewport(int width, int height)
612 float ratio = gr_screen.max_w / i2fl(gr_screen.max_h);
615 h = fl2i((width / ratio) + 0.5f);
619 w = fl2i((height * ratio) + 0.5f);
623 y = (height - h) / 2;
629 GL_viewport_scale_w = w / i2fl(gr_screen.max_w);
630 GL_viewport_scale_h = h / i2fl(gr_screen.max_h);
632 glViewport(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h);
634 glMatrixMode(GL_PROJECTION);
636 glOrtho(0, GL_viewport_w, GL_viewport_h, 0, 0.0, 1.0);
637 glMatrixMode(GL_MODELVIEW);
639 glScalef(GL_viewport_scale_w, GL_viewport_scale_h, 1.0f);
641 // free mouse cursor storage, since the size might have changed
642 if (Gr_opengl_mouse_saved_data) {
643 free(Gr_opengl_mouse_saved_data);
644 Gr_opengl_mouse_saved_data = NULL;
647 // clear screen once to fix issues with edges on non-4:3