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
11 #include "gropenglinternal.h"
17 #include "grinternal.h"
22 int GL_one_inited = 0;
25 volatile int GL_activate = 0;
26 volatile int GL_deactivate = 0;
28 static GLuint Gr_saved_screen_tex = 0;
30 static int Gr_opengl_mouse_saved = 0;
31 static int Gr_opengl_mouse_saved_x = 0;
32 static int Gr_opengl_mouse_saved_y = 0;
33 static int Gr_opengl_mouse_saved_w = 0;
34 static int Gr_opengl_mouse_saved_h = 0;
35 static ubyte *Gr_opengl_mouse_saved_data = NULL;
38 PFNGLSECONDARYCOLORPOINTERPROC vglSecondaryColorPointer = NULL;
41 static gr_alpha_blend GL_current_alpha_blend = (gr_alpha_blend) -1;
42 static gr_zbuffer_type GL_current_zbuffer_type = (gr_zbuffer_type) -1;
44 void opengl1_set_state(gr_texture_source ts, gr_alpha_blend ab, gr_zbuffer_type zt)
46 opengl1_set_texture_state(ts);
48 if (ab != GL_current_alpha_blend) {
50 case ALPHA_BLEND_NONE: // 1*SrcPixel + 0*DestPixel
51 glBlendFunc(GL_ONE, GL_ZERO);
53 case ALPHA_BLEND_ADDITIVE: // 1*SrcPixel + 1*DestPixel
54 glBlendFunc(GL_ONE, GL_ONE);
56 case ALPHA_BLEND_ALPHA_ADDITIVE: // Alpha*SrcPixel + 1*DestPixel
57 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
59 case ALPHA_BLEND_ALPHA_BLEND_ALPHA: // Alpha*SrcPixel + (1-Alpha)*DestPixel
60 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
62 case ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR: // Alpha*SrcPixel + (1-SrcPixel)*DestPixel
63 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
69 GL_current_alpha_blend = ab;
72 if (zt != GL_current_zbuffer_type) {
74 case ZBUFFER_TYPE_NONE:
75 glDepthFunc(GL_ALWAYS);
76 glDepthMask(GL_FALSE);
78 case ZBUFFER_TYPE_READ:
80 glDepthMask(GL_FALSE);
82 case ZBUFFER_TYPE_WRITE:
83 glDepthFunc(GL_ALWAYS);
86 case ZBUFFER_TYPE_FULL:
94 GL_current_zbuffer_type = zt;
98 void opengl1_cleanup()
100 if ( !GL_one_inited ) {
104 gr_opengl1_reset_clip();
108 opengl1_tcache_cleanup();
113 static void opengl1_init_func_pointers()
115 gr_screen.gf_flip = gr_opengl1_flip;
116 gr_screen.gf_set_clip = gr_opengl1_set_clip;
117 gr_screen.gf_reset_clip = gr_opengl1_reset_clip;
119 gr_screen.gf_clear = gr_opengl1_clear;
121 gr_screen.gf_aabitmap = gr_opengl1_aabitmap;
122 gr_screen.gf_aabitmap_ex = gr_opengl1_aabitmap_ex;
124 gr_screen.gf_rect = gr_opengl1_rect;
125 gr_screen.gf_shade = gr_opengl1_shade;
126 gr_screen.gf_string = gr_opengl1_string;
127 gr_screen.gf_circle = gr_opengl1_circle;
129 gr_screen.gf_line = gr_opengl1_line;
130 gr_screen.gf_aaline = gr_opengl1_aaline;
131 gr_screen.gf_pixel = gr_opengl1_pixel;
132 gr_screen.gf_scaler = gr_opengl1_scaler;
133 gr_screen.gf_tmapper = gr_opengl1_tmapper;
135 gr_screen.gf_gradient = gr_opengl1_gradient;
137 gr_screen.gf_print_screen = gr_opengl1_print_screen;
139 gr_screen.gf_fade_in = gr_opengl1_fade_in;
140 gr_screen.gf_fade_out = gr_opengl1_fade_out;
141 gr_screen.gf_flash = gr_opengl1_flash;
143 gr_screen.gf_zbuffer_clear = gr_opengl1_zbuffer_clear;
145 gr_screen.gf_save_screen = gr_opengl1_save_screen;
146 gr_screen.gf_restore_screen = gr_opengl1_restore_screen;
147 gr_screen.gf_free_screen = gr_opengl1_free_screen;
149 gr_screen.gf_dump_frame_start = gr_opengl1_dump_frame_start;
150 gr_screen.gf_dump_frame_stop = gr_opengl1_dump_frame_stop;
151 gr_screen.gf_dump_frame = gr_opengl1_dump_frame;
153 gr_screen.gf_set_gamma = gr_opengl1_set_gamma;
155 gr_screen.gf_lock = gr_opengl1_lock;
156 gr_screen.gf_unlock = gr_opengl1_unlock;
158 gr_screen.gf_fog_set = gr_opengl1_fog_set;
160 gr_screen.gf_get_region = gr_opengl1_get_region;
162 gr_screen.gf_set_cull = gr_opengl1_set_cull;
164 gr_screen.gf_cross_fade = gr_opengl1_cross_fade;
166 gr_screen.gf_preload_init = gr_opengl1_preload_init;
167 gr_screen.gf_preload = gr_opengl1_preload;
169 gr_screen.gf_zbias = gr_opengl1_zbias;
171 gr_screen.gf_force_windowed = gr_opengl_force_windowed;
172 gr_screen.gf_force_fullscreen = gr_opengl_force_fullscreen;
173 gr_screen.gf_toggle_fullscreen = gr_opengl_toggle_fullscreen;
175 gr_screen.gf_set_viewport = gr_opengl1_set_viewport;
177 gr_screen.gf_activate = gr_opengl1_activate;
187 1 = use secondary color ext
188 2 = use opengl linear fog
192 // only available with OpenGL 1.2+, must get ptr for Windows
193 vglSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)SDL_GL_GetProcAddress("glSecondaryColorPointer");
195 if (vglSecondaryColorPointer) {
199 mprintf((" Fog mode: %s\n", (OGL_fog_mode == 1) ? "secondary color" : "linear"));
201 glShadeModel(GL_SMOOTH);
203 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
204 glHint(GL_FOG_HINT, GL_NICEST);
206 glEnable(GL_DEPTH_TEST);
209 glEnable(GL_TEXTURE_2D);
211 glDepthRange(0.0, 1.0);
213 glPixelStorei(GL_PACK_ALIGNMENT, 1);
214 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
218 opengl1_init_func_pointers();
219 opengl1_tcache_init();
226 void gr_opengl1_activate(int active)
231 // don't grab key/mouse if cmdline says so or if we're fullscreen
232 // if(!Cmdline_no_grab && !(SDL_GetVideoSurface()->flags & SDL_FULLSCREEN)) {
233 // SDL_WM_GrabInput(SDL_GRAB_ON);
238 // let go of mouse/keyboard
239 // SDL_WM_GrabInput(SDL_GRAB_OFF);
243 void gr_opengl1_clear()
245 glClearColor(gr_screen.current_clear_color.red / 255.0,
246 gr_screen.current_clear_color.green / 255.0,
247 gr_screen.current_clear_color.blue / 255.0, 1.0);
249 glClear( GL_COLOR_BUFFER_BIT );
252 void gr_opengl1_flip()
254 if ( !GL_one_inited ) {
262 Gr_opengl_mouse_saved = 0;
264 if ( mouse_is_visible() ) {
268 mouse_get_pos( &mx, &my );
270 gr_opengl1_save_mouse_area(mx,my,32,32);
272 if (Gr_cursor == -1) {
274 gr_set_color(255,255,255);
275 gr_line(mx, my, mx+7, my + 7);
276 gr_line(mx, my, mx+5, my );
277 gr_line(mx, my, mx, my+5);
280 gr_set_bitmap(Gr_cursor);
286 GLenum error = GL_NO_ERROR;
289 error = glGetError();
291 if (error != GL_NO_ERROR) {
292 nprintf(("Warning", "!!DEBUG!! OpenGL Error: %d\n", error));
294 } while (error != GL_NO_ERROR);
297 SDL_GL_SwapWindow(GL_window);
299 opengl1_tcache_frame();
301 int cnt = GL_activate;
304 opengl1_tcache_flush();
305 // gr_opengl_clip_cursor(1); /* mouse grab, see opengl_activate */
311 // gr_opengl_clip_cursor(0); /* mouse grab, see opengl_activate */
315 void gr_opengl1_set_clip(int x,int y,int w,int h)
317 // check for sanity of parameters
323 if (x >= gr_screen.max_w)
324 x = gr_screen.max_w - 1;
325 if (y >= gr_screen.max_h)
326 y = gr_screen.max_h - 1;
328 if (x + w > gr_screen.max_w)
329 w = gr_screen.max_w - x;
330 if (y + h > gr_screen.max_h)
331 h = gr_screen.max_h - y;
333 if (w > gr_screen.max_w)
335 if (h > gr_screen.max_h)
338 gr_screen.offset_x = x;
339 gr_screen.offset_y = y;
340 gr_screen.clip_left = 0;
341 gr_screen.clip_right = w-1;
342 gr_screen.clip_top = 0;
343 gr_screen.clip_bottom = h-1;
344 gr_screen.clip_width = w;
345 gr_screen.clip_height = h;
347 x = fl2i((x * GL_viewport_scale_w) + 0.5f) + GL_viewport_x;
348 y = fl2i((y * GL_viewport_scale_h) + 0.5f) + GL_viewport_y;
349 w = fl2i((w * GL_viewport_scale_w) + 0.5f);
350 h = fl2i((h * GL_viewport_scale_h) + 0.5f);
352 glEnable(GL_SCISSOR_TEST);
353 glScissor(x, GL_viewport_h-y-h, w, h);
356 void gr_opengl1_reset_clip()
358 gr_screen.offset_x = 0;
359 gr_screen.offset_y = 0;
360 gr_screen.clip_left = 0;
361 gr_screen.clip_top = 0;
362 gr_screen.clip_right = gr_screen.max_w - 1;
363 gr_screen.clip_bottom = gr_screen.max_h - 1;
364 gr_screen.clip_width = gr_screen.max_w;
365 gr_screen.clip_height = gr_screen.max_h;
367 glDisable(GL_SCISSOR_TEST);
370 void gr_opengl1_print_screen(const char *filename)
372 char tmp[MAX_FILENAME_LEN];
375 strcpy( tmp, filename );
376 strcat( tmp, NOX(".tga"));
378 buf = (ubyte*)malloc(GL_viewport_w * GL_viewport_h * 3);
384 CFILE *f = cfopen(tmp, "wb", CFILE_NORMAL, CF_TYPE_ROOT);
391 // Write the TGA header
392 cfwrite_ubyte( 0, f ); // IDLength;
393 cfwrite_ubyte( 0, f ); // ColorMapType;
394 cfwrite_ubyte( 2, f ); // ImageType; // 2 = 24bpp, uncompressed, 10=24bpp rle compressed
395 cfwrite_ushort( 0, f ); // CMapStart;
396 cfwrite_ushort( 0, f ); // CMapLength;
397 cfwrite_ubyte( 0, f ); // CMapDepth;
398 cfwrite_ushort( 0, f ); // XOffset;
399 cfwrite_ushort( 0, f ); // YOffset;
400 cfwrite_ushort( (ushort)GL_viewport_w, f ); // Width;
401 cfwrite_ushort( (ushort)GL_viewport_h, f ); // Height;
402 cfwrite_ubyte( 24, f ); //PixelDepth;
403 cfwrite_ubyte( 0, f ); //ImageDesc;
405 memset(buf, 0, GL_viewport_w * GL_viewport_h * 3);
407 glReadPixels(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h, GL_BGR, GL_UNSIGNED_BYTE, buf);
409 cfwrite(buf, GL_viewport_w * GL_viewport_h * 3, 1, f);
416 void gr_opengl1_fog_set(int fog_mode, int r, int g, int b, float fog_near, float fog_far)
418 SDL_assert((r >= 0) && (r < 256));
419 SDL_assert((g >= 0) && (g < 256));
420 SDL_assert((b >= 0) && (b < 256));
422 if (fog_mode == GR_FOGMODE_NONE) {
423 if (gr_screen.current_fog_mode != fog_mode) {
426 if (OGL_fog_mode == 1) {
427 glDisable(GL_COLOR_SUM);
431 gr_screen.current_fog_mode = fog_mode;
436 if (gr_screen.current_fog_mode != fog_mode) {
439 if (OGL_fog_mode == 1) {
440 glEnable(GL_COLOR_SUM);
441 } else if (OGL_fog_mode == 2) {
442 glFogi(GL_FOG_MODE, GL_LINEAR);
445 gr_screen.current_fog_mode = fog_mode;
448 if ( (gr_screen.current_fog_color.red != r) ||
449 (gr_screen.current_fog_color.green != g) ||
450 (gr_screen.current_fog_color.blue != b) ) {
453 gr_init_color( &gr_screen.current_fog_color, r, g, b );
455 fc[0] = (float)r/255.0;
456 fc[1] = (float)g/255.0;
457 fc[2] = (float)b/255.0;
460 glFogfv(GL_FOG_COLOR, fc);
463 if( (fog_near >= 0.0f) && (fog_far >= 0.0f) &&
464 ((fog_near != gr_screen.fog_near) ||
465 (fog_far != gr_screen.fog_far)) ) {
466 gr_screen.fog_near = fog_near;
467 gr_screen.fog_far = fog_far;
469 if (OGL_fog_mode == 2) {
470 glFogf(GL_FOG_START, fog_near);
471 glFogf(GL_FOG_END, fog_far);
476 void gr_opengl1_set_cull(int cull)
479 glEnable (GL_CULL_FACE);
480 glFrontFace (GL_CCW);
482 glDisable (GL_CULL_FACE);
486 void gr_opengl1_zbuffer_clear(int mode)
490 Gr_zbuffering_mode = GR_ZBUFF_FULL;
491 Gr_global_zbuffering = 1;
493 opengl1_set_state( TEXTURE_SOURCE_NONE, ALPHA_BLEND_NONE, ZBUFFER_TYPE_FULL );
494 glClear ( GL_DEPTH_BUFFER_BIT );
497 Gr_zbuffering_mode = GR_ZBUFF_NONE;
498 Gr_global_zbuffering = 0;
502 void gr_opengl1_fade_in(int instantaneous)
507 void gr_opengl1_fade_out(int instantaneous)
512 void gr_opengl1_get_region(int front, int w, int h, ubyte *data)
515 glReadBuffer(GL_FRONT);
517 glReadBuffer(GL_BACK);
520 opengl1_set_state(TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE);
522 glPixelStorei(GL_UNPACK_ROW_LENGTH, GL_viewport_w);
524 int x = GL_viewport_x;
525 int y = (GL_viewport_y+GL_viewport_h)-h-1;
527 GLenum pxtype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
529 if (gr_screen.bytes_per_pixel == 4) {
530 pxtype = GL_UNSIGNED_BYTE;
533 glReadPixels(x, y, w, h, GL_BGRA, pxtype, data);
535 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
538 void gr_opengl1_save_mouse_area(int x, int y, int w, int h)
542 w = fl2i((w * GL_viewport_scale_w) + 0.5f);
543 h = fl2i((h * GL_viewport_scale_h) + 0.5f);
550 CAP(x1, 0, GL_viewport_w);
551 CAP(x2, 0, GL_viewport_w);
552 CAP(y1, 0, GL_viewport_h);
553 CAP(y2, 0, GL_viewport_h);
555 Gr_opengl_mouse_saved_x = x1;
556 Gr_opengl_mouse_saved_y = y1;
557 Gr_opengl_mouse_saved_w = x2 - x1 + 1;
558 Gr_opengl_mouse_saved_h = y2 - y1 + 1;
560 if ( (Gr_opengl_mouse_saved_w < 1) || (Gr_opengl_mouse_saved_h < 1) ) {
564 if (Gr_opengl_mouse_saved_data == NULL) {
565 Gr_opengl_mouse_saved_data = (ubyte*)malloc(w * h * gr_screen.bytes_per_pixel);
567 if ( !Gr_opengl_mouse_saved_data ) {
572 opengl1_set_state(TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE);
574 x1 = GL_viewport_x+Gr_opengl_mouse_saved_x;
575 y1 = (GL_viewport_y+GL_viewport_h)-Gr_opengl_mouse_saved_y-Gr_opengl_mouse_saved_h;
577 GLenum pxtype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
579 if (gr_screen.bytes_per_pixel == 4) {
580 pxtype = GL_UNSIGNED_BYTE;
583 glReadBuffer(GL_BACK);
584 glReadPixels(x1, y1, Gr_opengl_mouse_saved_w, Gr_opengl_mouse_saved_h,
585 GL_BGRA, pxtype, Gr_opengl_mouse_saved_data);
587 Gr_opengl_mouse_saved = 1;
590 int gr_opengl1_save_screen()
594 if (Gr_saved_screen_tex) {
595 mprintf(( "Screen already saved!\n" ));
599 glGenTextures(1, &Gr_saved_screen_tex);
601 if ( !Gr_saved_screen_tex ) {
602 mprintf(( "Couldn't create texture for saved screen!\n" ));
606 opengl1_set_state(TEXTURE_SOURCE_NO_FILTERING, ALPHA_BLEND_NONE, ZBUFFER_TYPE_NONE);
608 glBindTexture(GL_TEXTURE_2D, Gr_saved_screen_tex);
610 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
611 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
612 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
613 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
614 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
616 glReadBuffer(GL_FRONT);
617 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, GL_viewport_x, GL_viewport_y,
618 GL_viewport_w, GL_viewport_h, 0);
620 if (Gr_opengl_mouse_saved) {
621 int x = Gr_opengl_mouse_saved_x;
622 int y = GL_viewport_h-Gr_opengl_mouse_saved_y-Gr_opengl_mouse_saved_h;
624 GLenum pxtype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
626 if (gr_screen.bytes_per_pixel == 4) {
627 pxtype = GL_UNSIGNED_BYTE;
630 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, Gr_opengl_mouse_saved_w,
631 Gr_opengl_mouse_saved_h, GL_BGRA, pxtype,
632 Gr_opengl_mouse_saved_data);
635 glBindTexture(GL_TEXTURE_2D, 0);
640 void gr_opengl1_restore_screen(int id)
644 if ( !Gr_saved_screen_tex ) {
649 glBindTexture(GL_TEXTURE_2D, Gr_saved_screen_tex);
651 if (Gr_opengl_mouse_saved) {
652 int x = Gr_opengl_mouse_saved_x;
653 int y = GL_viewport_h-Gr_opengl_mouse_saved_y-Gr_opengl_mouse_saved_h;
655 GLenum pxtype = GL_UNSIGNED_SHORT_1_5_5_5_REV;
657 if (gr_screen.bytes_per_pixel == 4) {
658 pxtype = GL_UNSIGNED_BYTE;
661 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, Gr_opengl_mouse_saved_w,
662 Gr_opengl_mouse_saved_h, GL_BGRA, pxtype,
663 Gr_opengl_mouse_saved_data);
666 glMatrixMode(GL_MODELVIEW);
669 glScalef(1.0f, -1.0f, 1.0f);
671 int tex_coord[] = { 0, 0, 0, 1, 1, 0, 1, 1 };
672 int ver_coord[] = { GL_viewport_x, GL_viewport_y, GL_viewport_x,
673 GL_viewport_h, GL_viewport_w, GL_viewport_y, GL_viewport_w,
677 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
678 glEnableClientState(GL_VERTEX_ARRAY);
680 glTexCoordPointer(2, GL_INT, 0, &tex_coord);
681 glVertexPointer(2, GL_INT, 0, &ver_coord);
683 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
685 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
686 glDisableClientState(GL_VERTEX_ARRAY);
690 glBindTexture(GL_TEXTURE_2D, 0);
693 void gr_opengl1_free_screen(int id)
695 if (Gr_saved_screen_tex) {
696 glDeleteTextures(1, &Gr_saved_screen_tex);
697 Gr_saved_screen_tex = 0;
701 void gr_opengl1_dump_frame_start(int first_frame, int frames_between_dumps)
706 void gr_opengl1_dump_frame_stop()
711 void gr_opengl1_dump_frame()
716 uint gr_opengl1_lock()
721 void gr_opengl1_unlock()
725 void gr_opengl1_zbias(int bias)
728 glEnable(GL_POLYGON_OFFSET_FILL);
729 glPolygonOffset(0.0, -bias);
731 glDisable(GL_POLYGON_OFFSET_FILL);
735 void gr_opengl1_set_viewport(int width, int height)
739 float ratio = gr_screen.max_w / i2fl(gr_screen.max_h);
742 h = i2fl((width / ratio) + 0.5f);
746 w = i2fl((height * ratio) + 0.5f);
750 y = (height - h) / 2;
756 GL_viewport_scale_w = w / i2fl(gr_screen.max_w);
757 GL_viewport_scale_h = h / i2fl(gr_screen.max_h);
759 glViewport(GL_viewport_x, GL_viewport_y, GL_viewport_w, GL_viewport_h);
761 glMatrixMode(GL_PROJECTION);
763 glOrtho(0, GL_viewport_w, GL_viewport_h, 0, 0.0, 1.0);
764 glMatrixMode(GL_MODELVIEW);
766 glScalef(GL_viewport_scale_w, GL_viewport_scale_h, 1.0f);