Files
fs2open.github.com/code/graphics/gropengl.cpp
T
asarium 0c705fee6f Merge branch 'master' into antipodes
Conflicts:
	code/debugconsole/timerbar.cpp
	code/graphics/gropengl.cpp
	projects/MSVC_2010/code.vcxproj
	projects/MSVC_2012/code.vcxproj
	projects/MSVC_2012/code.vcxproj.filters
2015-05-29 17:47:58 +02:00

1770 lines
45 KiB
C++

#include "globalincs/pstypes.h"
#include "cmdline/cmdline.h"
#include "osapi/osapi.h"
#include "graphics/2d.h"
#include "render/3d.h"
#include "bmpman/bmpman.h"
#include "math/floating.h"
#include "palman/palman.h"
#include "globalincs/systemvars.h"
#include "graphics/grinternal.h"
#include "graphics/gropengl.h"
#include "graphics/line.h"
#include "nebula/neb.h"
#include "io/mouse.h"
#include "osapi/osregistry.h"
#include "cfile/cfile.h"
#include "io/timer.h"
#include "ddsutils/ddsutils.h"
#include "model/model.h"
#include "debugconsole/console.h"
#include "graphics/gropenglbmpman.h"
#include "graphics/gropengllight.h"
#include "graphics/gropengltexture.h"
#include "graphics/gropenglextension.h"
#include "graphics/gropengltnl.h"
#include "graphics/gropenglbmpman.h"
#include "graphics/gropengldraw.h"
#include "graphics/gropenglshader.h"
#include "graphics/gropenglstate.h"
#include "graphics/gropenglpostprocessing.h"
#if defined(_WIN32)
#include <windows.h>
#include <windowsx.h>
#include <direct.h>
#elif defined(__APPLE__)
#include "OpenGL.h"
#else
typedef int ( * PFNGLXSWAPINTERVALSGIPROC) (int interval);
#endif
#if defined(_WIN32) && !defined(__GNUC__)
#pragma comment (lib, "opengl32")
#pragma comment (lib, "glu32")
#endif
// minimum GL version we can reliably support is 1.2
static const int MIN_REQUIRED_GL_VERSION = 12;
int GL_version = 0;
bool GL_initted = 0;
//0==no fog
//1==linear
//2==fog coord EXT
//3==NV Radial
int OGL_fogmode = 0;
static ushort *GL_original_gamma_ramp = NULL;
int Use_VBOs = 0;
int Use_PBOs = 0;
int Use_GLSL = 0;
static int GL_dump_frames = 0;
static ubyte *GL_dump_buffer = NULL;
static int GL_dump_frame_number = 0;
static int GL_dump_frame_count = 0;
static int GL_dump_frame_count_max = 0;
static int GL_dump_frame_size = 0;
static ubyte *GL_saved_screen = NULL;
static int GL_saved_screen_id = -1;
static GLuint GL_screen_pbo = 0;
extern const char *Osreg_title;
extern GLfloat GL_anisotropy;
extern float FreeSpace_gamma;
void gr_opengl_set_gamma(float gamma);
extern float FreeSpace_gamma;
void gr_opengl_set_gamma(float gamma);
static int GL_fullscreen = 0;
static int GL_windowed = 0;
static int GL_minimized = 0;
static GLenum GL_read_format = GL_BGRA;
SDL_GLContext GL_context = NULL;
void opengl_go_fullscreen()
{
if (Cmdline_fullscreen_window || Cmdline_window || GL_fullscreen || Fred_running)
return;
if ( (os_config_read_uint(NULL, NOX("Fullscreen"), 1) == 1) && (!os_get_window() || !(SDL_GetWindowFlags(os_get_window()) & SDL_WINDOW_FULLSCREEN)) ) {
os_suspend();
if(os_get_window())
{
SDL_SetWindowFullscreen(os_get_window(), SDL_WINDOW_FULLSCREEN);
}
else
{
SDL_Window* window = SDL_CreateWindow(Osreg_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, gr_screen.max_w, gr_screen.max_h, SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);
if (window == NULL) {
mprintf(("Couldn't go fullscreen!\n"));
if ((window = SDL_CreateWindow(Osreg_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, gr_screen.max_w, gr_screen.max_h, SDL_WINDOW_OPENGL)) == NULL) {
mprintf(("Couldn't drop back to windowed mode either!\n"));
exit(1);
}
}
os_set_window(window);
}
os_resume();
}
gr_opengl_set_gamma(FreeSpace_gamma);
GL_fullscreen = 1;
GL_minimized = 0;
GL_windowed = 0;
}
void opengl_go_windowed()
{
if ( ( !Cmdline_fullscreen_window && !Cmdline_window ) /*|| GL_windowed*/ || Fred_running )
return;
if (!os_get_window() || SDL_GetWindowFlags(os_get_window()) & SDL_WINDOW_FULLSCREEN) {
os_suspend();
if(os_get_window())
{
SDL_SetWindowFullscreen(os_get_window(), Cmdline_fullscreen_window ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0 );
}
else
{
SDL_Window* new_window = SDL_CreateWindow(Osreg_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, gr_screen.max_w, gr_screen.max_h, SDL_WINDOW_OPENGL);
if (new_window == NULL) {
Warning( LOCATION, "Unable to enter windowed mode: %s!", SDL_GetError() );
}
os_set_window(new_window);
}
os_resume();
}
GL_windowed = 1;
GL_minimized = 0;
GL_fullscreen = 0;
}
void opengl_minimize()
{
// don't attempt to minimize if we are already in a window, or already minimized, or when playing a movie
if (GL_minimized /*|| GL_windowed || Cmdline_window*/ || Fred_running)
return;
// lets not minimize if we are in windowed mode
if ( !(SDL_GetWindowFlags(os_get_window()) & SDL_WINDOW_FULLSCREEN) )
return;
os_suspend();
if (GL_original_gamma_ramp != NULL) {
SDL_SetWindowGammaRamp( os_get_window(), GL_original_gamma_ramp, (GL_original_gamma_ramp+256), (GL_original_gamma_ramp+512) );
}
SDL_MinimizeWindow(os_get_window());
os_resume();
GL_minimized = 1;
GL_windowed = 0;
GL_fullscreen = 0;
}
void gr_opengl_activate(int active)
{
if (active) {
if (Cmdline_fullscreen_window||Cmdline_window)
opengl_go_windowed();
else
opengl_go_fullscreen();
} else {
opengl_minimize();
}
}
void gr_opengl_clear()
{
glClearColor(gr_screen.current_clear_color.red / 255.0f,
gr_screen.current_clear_color.green / 255.0f,
gr_screen.current_clear_color.blue / 255.0f, gr_screen.current_clear_color.alpha / 255.0f);
glClear ( GL_COLOR_BUFFER_BIT );
}
void gr_opengl_flip()
{
if ( !GL_initted )
return;
gr_reset_clip();
mouse_reset_deltas();
if (Cmdline_gl_finish)
glFinish();
SDL_GL_SwapWindow(os_get_window());
opengl_tcache_frame();
#ifndef NDEBUG
int ic = opengl_check_for_errors();
if (ic) {
mprintf(("!!DEBUG!! OpenGL Errors this frame: %i\n", ic));
}
#endif
}
void gr_opengl_set_clip(int x, int y, int w, int h, int resize_mode)
{
// check for sanity of parameters
if (x < 0) {
x = 0;
}
if (y < 0) {
y = 0;
}
int to_resize = (resize_mode != GR_RESIZE_NONE && (gr_screen.custom_size || (gr_screen.rendering_to_texture != -1)));
int max_w = ((to_resize) ? gr_screen.max_w_unscaled : gr_screen.max_w);
int max_h = ((to_resize) ? gr_screen.max_h_unscaled : gr_screen.max_h);
if ((gr_screen.rendering_to_texture != -1) && to_resize) {
gr_unsize_screen_pos(&max_w, &max_h);
}
if (x >= max_w) {
x = max_w - 1;
}
if (y >= max_h) {
y = max_h - 1;
}
if (x + w > max_w) {
w = max_w - x;
}
if (y + h > max_h) {
h = max_h - y;
}
if (w > max_w) {
w = max_w;
}
if (h > max_h) {
h = max_h;
}
gr_screen.offset_x_unscaled = x;
gr_screen.offset_y_unscaled = y;
gr_screen.clip_left_unscaled = 0;
gr_screen.clip_right_unscaled = w-1;
gr_screen.clip_top_unscaled = 0;
gr_screen.clip_bottom_unscaled = h-1;
gr_screen.clip_width_unscaled = w;
gr_screen.clip_height_unscaled = h;
if (to_resize) {
gr_resize_screen_pos(&x, &y, &w, &h, resize_mode);
} else {
gr_unsize_screen_pos( &gr_screen.offset_x_unscaled, &gr_screen.offset_y_unscaled );
gr_unsize_screen_pos( &gr_screen.clip_right_unscaled, &gr_screen.clip_bottom_unscaled );
gr_unsize_screen_pos( &gr_screen.clip_width_unscaled, &gr_screen.clip_height_unscaled );
}
gr_screen.offset_x = x;
gr_screen.offset_y = y;
gr_screen.clip_left = 0;
gr_screen.clip_right = w-1;
gr_screen.clip_top = 0;
gr_screen.clip_bottom = h-1;
gr_screen.clip_width = w;
gr_screen.clip_height = h;
gr_screen.clip_aspect = i2fl(w) / i2fl(h);
gr_screen.clip_center_x = (gr_screen.clip_left + gr_screen.clip_right) * 0.5f;
gr_screen.clip_center_y = (gr_screen.clip_top + gr_screen.clip_bottom) * 0.5f;
// just return early if we aren't actually going to need the scissor test
if ( (x == 0) && (y == 0) && (w == max_w) && (h == max_h) ) {
GL_state.ScissorTest(GL_FALSE);
return;
}
GL_state.ScissorTest(GL_TRUE);
if(GL_rendering_to_texture) {
glScissor(x, y, w, h);
} else {
glScissor(x, gr_screen.max_h-y-h, w, h);
}
}
void gr_opengl_reset_clip()
{
gr_screen.offset_x = gr_screen.offset_x_unscaled = 0;
gr_screen.offset_y = gr_screen.offset_y_unscaled = 0;
gr_screen.clip_left = gr_screen.clip_left_unscaled = 0;
gr_screen.clip_top = gr_screen.clip_top_unscaled = 0;
gr_screen.clip_right = gr_screen.clip_right_unscaled = gr_screen.max_w - 1;
gr_screen.clip_bottom = gr_screen.clip_bottom_unscaled = gr_screen.max_h - 1;
gr_screen.clip_width = gr_screen.clip_width_unscaled = gr_screen.max_w;
gr_screen.clip_height = gr_screen.clip_height_unscaled = gr_screen.max_h;
if (gr_screen.custom_size) {
gr_unsize_screen_pos( &gr_screen.clip_right_unscaled, &gr_screen.clip_bottom_unscaled );
gr_unsize_screen_pos( &gr_screen.clip_width_unscaled, &gr_screen.clip_height_unscaled );
}
gr_screen.clip_aspect = i2fl(gr_screen.clip_width) / i2fl(gr_screen.clip_height);
gr_screen.clip_center_x = (gr_screen.clip_left + gr_screen.clip_right) * 0.5f;
gr_screen.clip_center_y = (gr_screen.clip_top + gr_screen.clip_bottom) * 0.5f;
GL_state.ScissorTest(GL_FALSE);
}
void gr_opengl_set_palette(ubyte *new_palette, int is_alphacolor)
{
}
void gr_opengl_print_screen(const char *filename)
{
char tmp[MAX_PATH_LEN];
ubyte tga_hdr[18];
int i;
ushort width, height;
GLubyte *pixels = NULL;
GLuint pbo = 0;
// save to a "screenshots" directory and tack on the filename
#ifdef SCP_UNIX
snprintf( tmp, MAX_PATH_LEN-1, "%s/%s/screenshots/%s.tga", detect_home(), Osreg_user_dir, filename);
_mkdir( tmp );
#else
_getcwd( tmp, MAX_PATH_LEN-1 );
strcat_s( tmp, "\\screenshots\\" );
_mkdir( tmp );
strcat_s( tmp, filename );
strcat_s( tmp, ".tga" );
#endif
FILE *fout = fopen(tmp, "wb");
if (fout == NULL) {
return;
}
// glReadBuffer(GL_FRONT);
// now for the data
if (Use_PBOs) {
Assert( !pbo );
vglGenBuffersARB(1, &pbo);
if ( !pbo ) {
if (fout != NULL)
fclose(fout);
return;
}
vglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, pbo);
vglBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, (gr_screen.max_w * gr_screen.max_h * 4), NULL, GL_STATIC_READ);
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, gr_screen.max_w, gr_screen.max_h, GL_read_format, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
// map the image data so that we can save it to file
pixels = (GLubyte*) vglMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
} else {
pixels = (GLubyte*) vm_malloc_q(gr_screen.max_w * gr_screen.max_h * 4);
if (pixels == NULL) {
if (fout != NULL) {
fclose(fout);
}
return;
}
glReadPixels(0, 0, gr_screen.max_w, gr_screen.max_h, GL_read_format, GL_UNSIGNED_INT_8_8_8_8_REV, pixels);
glFlush();
}
// Write the TGA header
width = INTEL_SHORT((ushort)gr_screen.max_w);
height = INTEL_SHORT((ushort)gr_screen.max_h);
memset( tga_hdr, 0, sizeof(tga_hdr) );
tga_hdr[2] = 2; // ImageType 2 = 24bpp, uncompressed
memcpy( tga_hdr + 12, &width, sizeof(ushort) ); // Width
memcpy( tga_hdr + 14, &height, sizeof(ushort) ); // Height
tga_hdr[16] = 24; // PixelDepth
fwrite( tga_hdr, sizeof(tga_hdr), 1, fout );
// now for the data, we convert it from 32-bit to 24-bit
for (i = 0; i < (gr_screen.max_w * gr_screen.max_h * 4); i += 4) {
#if BYTE_ORDER == BIG_ENDIAN
int pix, *pix_tmp;
pix_tmp = (int*)(pixels + i);
pix = INTEL_INT(*pix_tmp);
fwrite( &pix, 1, 3, fout );
#else
fwrite( pixels + i, 1, 3, fout );
#endif
}
if (pbo) {
vglUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
pixels = NULL;
vglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
vglDeleteBuffersARB(1, &pbo);
}
// done!
fclose(fout);
if (pixels != NULL) {
vm_free(pixels);
}
}
void gr_opengl_cleanup(int minimize)
{
if ( !GL_initted ) {
return;
}
if ( !Fred_running ) {
gr_reset_clip();
gr_clear();
gr_flip();
gr_clear();
gr_flip();
gr_clear();
}
GL_initted = false;
opengl_tcache_flush();
opengl_minimize();
if (minimize) {
}
}
void gr_opengl_fog_set(int fog_mode, int r, int g, int b, float fog_near, float fog_far)
{
// mprintf(("gr_opengl_fog_set(%d,%d,%d,%d,%f,%f)\n",fog_mode,r,g,b,fog_near,fog_far));
Assert((r >= 0) && (r < 256));
Assert((g >= 0) && (g < 256));
Assert((b >= 0) && (b < 256));
if (fog_mode == GR_FOGMODE_NONE) {
if ( GL_state.Fog() ) {
GL_state.Fog(GL_FALSE);
}
gr_screen.current_fog_mode = fog_mode;
return;
}
if (OGL_fogmode == 3) {
glFogf(GL_FOG_DISTANCE_MODE_NV, GL_EYE_RADIAL_NV);
glFogf(GL_FOG_COORDINATE_SOURCE, GL_FRAGMENT_DEPTH);
}
// Um.. this is not the correct way to fog in software, probably doesn't matter though
else if ( (OGL_fogmode == 2) && Cmdline_nohtl ) {
glFogf(GL_FOG_COORDINATE_SOURCE_EXT, GL_FOG_COORDINATE_EXT);
fog_near *= fog_near; // it's faster this way
fog_far *= fog_far;
} else {
glFogf(GL_FOG_COORDINATE_SOURCE, GL_FRAGMENT_DEPTH);
}
GL_state.Fog(GL_TRUE);
glFogf(GL_FOG_MODE, GL_LINEAR);
glFogf(GL_FOG_START, fog_near);
glFogf(GL_FOG_END, fog_far);
gr_screen.current_fog_mode = fog_mode;
if ( (gr_screen.current_fog_color.red != r) ||
(gr_screen.current_fog_color.green != g) ||
(gr_screen.current_fog_color.blue != b) )
{
GLfloat fc[4];
gr_init_color( &gr_screen.current_fog_color, r, g, b );
fc[0] = (float)r/255.0f;
fc[1] = (float)g/255.0f;
fc[2] = (float)b/255.0f;
fc[3] = 1.0f;
glFogfv(GL_FOG_COLOR, fc);
}
}
int gr_opengl_set_cull(int cull)
{
GLboolean enabled = GL_FALSE;
if (cull) {
enabled = GL_state.CullFace(GL_TRUE);
GL_state.FrontFaceValue(GL_CCW);
GL_state.CullFaceValue(GL_BACK);
} else {
enabled = GL_state.CullFace(GL_FALSE);
}
return (enabled) ? 1 : 0;
}
void gr_opengl_set_clear_color(int r, int g, int b)
{
gr_init_color(&gr_screen.current_clear_color, r, g, b);
}
int gr_opengl_set_color_buffer(int mode)
{
GLboolean enabled = GL_FALSE;
if ( mode ) {
enabled = GL_state.ColorMask(GL_TRUE);
} else {
enabled = GL_state.ColorMask(GL_FALSE);
}
GL_state.SetAlphaBlendMode(ALPHA_BLEND_ALPHA_BLEND_ALPHA);
return (enabled) ? 1 : 0;
}
int gr_opengl_zbuffer_get()
{
if ( !gr_global_zbuffering ) {
return GR_ZBUFF_NONE;
}
return gr_zbuffering_mode;
}
int gr_opengl_zbuffer_set(int mode)
{
int tmp = gr_zbuffering_mode;
gr_zbuffering_mode = mode;
if (gr_zbuffering_mode == GR_ZBUFF_NONE) {
gr_zbuffering = 0;
GL_state.SetZbufferType(ZBUFFER_TYPE_NONE);
} else if ( gr_zbuffering_mode == GR_ZBUFF_READ ) {
gr_zbuffering = 1;
GL_state.SetZbufferType(ZBUFFER_TYPE_READ);
} else {
gr_zbuffering = 1;
GL_state.SetZbufferType(ZBUFFER_TYPE_FULL);
}
return tmp;
}
void gr_opengl_zbuffer_clear(int mode)
{
if (mode) {
gr_zbuffering = 1;
gr_zbuffering_mode = GR_ZBUFF_FULL;
gr_global_zbuffering = 1;
GL_state.SetTextureSource(TEXTURE_SOURCE_NONE);
GL_state.SetAlphaBlendMode(ALPHA_BLEND_NONE);
GL_state.SetZbufferType(ZBUFFER_TYPE_FULL);
glClear(GL_DEPTH_BUFFER_BIT);
} else {
gr_zbuffering = 0;
gr_zbuffering_mode = GR_ZBUFF_NONE;
gr_global_zbuffering = 0;
GL_state.DepthTest(GL_FALSE);
}
}
int gr_opengl_stencil_set(int mode)
{
int tmp = gr_stencil_mode;
gr_stencil_mode = mode;
if ( mode == GR_STENCIL_READ ) {
GL_state.StencilTest(1);
GL_state.SetStencilType(STENCIL_TYPE_READ);
} else if ( mode == GR_STENCIL_WRITE ) {
GL_state.StencilTest(1);
GL_state.SetStencilType(STENCIL_TYPE_WRITE);
} else {
GL_state.StencilTest(0);
GL_state.SetStencilType(STENCIL_TYPE_NONE);
}
return tmp;
}
void gr_opengl_stencil_clear()
{
glClear(GL_STENCIL_BUFFER_BIT);
}
int gr_opengl_alpha_mask_set(int mode, float alpha)
{
int tmp = gr_alpha_test;
gr_alpha_test = mode;
if ( mode ) {
GL_state.AlphaTest(GL_TRUE);
GL_state.AlphaFunc(GL_GREATER, alpha);
} else {
GL_state.AlphaTest(GL_FALSE);
GL_state.AlphaFunc(GL_ALWAYS, 1.0f);
}
return tmp;
}
// I feel dirty...
static void opengl_make_gamma_ramp(float gamma, ushort *ramp)
{
ushort x, y;
ushort base_ramp[256];
Assert( ramp != NULL );
// generate the base ramp values first off
// if no gamma set then just do this quickly
if (gamma <= 0.0f) {
memset( ramp, 0, 3 * 256 * sizeof(ushort) );
return;
}
// identity gamma, avoid all of the math
else if ( (gamma == 1.0f) || (GL_original_gamma_ramp == NULL) ) {
if (GL_original_gamma_ramp != NULL) {
memcpy( ramp, GL_original_gamma_ramp, 3 * 256 * sizeof(ushort) );
}
// set identity if no original ramp
else {
for (x = 0; x < 256; x++) {
ramp[x] = (x << 8) | x;
ramp[x + 256] = (x << 8) | x;
ramp[x + 512] = (x << 8) | x;
}
}
return;
}
// for everything else we need to actually figure it up
else {
double g = 1.0 / (double)gamma;
double val;
Assert( GL_original_gamma_ramp != NULL );
for (x = 0; x < 256; x++) {
val = (pow(x/255.0, g) * 65535.0 + 0.5);
CLAMP( val, 0, 65535 );
base_ramp[x] = (ushort)val;
}
for (y = 0; y < 3; y++) {
for (x = 0; x < 256; x++) {
val = (base_ramp[x] * 2) - GL_original_gamma_ramp[x + y * 256];
CLAMP( val, 0, 65535 );
ramp[x + y * 256] = (ushort)val;
}
}
}
}
void gr_opengl_set_gamma(float gamma)
{
ushort *gamma_ramp = NULL;
Gr_gamma = gamma;
Gr_gamma_int = int (Gr_gamma*10);
// new way - but not while running FRED
if (!Fred_running && !Cmdline_no_set_gamma) {
gamma_ramp = (ushort*) vm_malloc_q( 3 * 256 * sizeof(ushort) );
if (gamma_ramp == NULL) {
Int3();
return;
}
memset( gamma_ramp, 0, 3 * 256 * sizeof(ushort) );
// Create the Gamma lookup table
opengl_make_gamma_ramp(gamma, gamma_ramp);
SDL_SetWindowGammaRamp( os_get_window(), gamma_ramp, (gamma_ramp+256), (gamma_ramp+512) );
vm_free(gamma_ramp);
}
}
void gr_opengl_get_region(int front, int w, int h, ubyte *data)
{
// if (front) {
// glReadBuffer(GL_FRONT);
// } else {
glReadBuffer(GL_BACK);
// }
GL_state.SetTextureSource(TEXTURE_SOURCE_NO_FILTERING);
GL_state.SetAlphaBlendMode(ALPHA_BLEND_NONE);
GL_state.SetZbufferType(ZBUFFER_TYPE_NONE);
if (gr_screen.bits_per_pixel == 16) {
glReadPixels(0, gr_screen.max_h-h, w, h, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, data);
} else if (gr_screen.bits_per_pixel == 32) {
glReadPixels(0, gr_screen.max_h-h, w, h, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
}
}
int gr_opengl_save_screen()
{
int i;
ubyte *sptr = NULL, *dptr = NULL;
ubyte *opengl_screen_tmp = NULL;
int width_times_pixel;
gr_opengl_reset_clip();
if (GL_saved_screen || GL_screen_pbo) {
// already have a screen saved so just bail...
return -1;
}
GL_saved_screen = (ubyte*)vm_malloc_q( gr_screen.max_w * gr_screen.max_h * 4 );
if (!GL_saved_screen) {
mprintf(( "Couldn't get memory for saved screen!\n" ));
return -1;
}
GLboolean save_state = GL_state.DepthTest(GL_FALSE);
glReadBuffer(GL_FRONT_LEFT);
if ( Use_PBOs ) {
GLubyte *pixels = NULL;
vglGenBuffersARB(1, &GL_screen_pbo);
if (!GL_screen_pbo) {
if (GL_saved_screen) {
vm_free(GL_saved_screen);
GL_saved_screen = NULL;
}
return -1;
}
vglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_screen_pbo);
vglBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, gr_screen.max_w * gr_screen.max_h * 4, NULL, GL_STATIC_READ);
glReadPixels(0, 0, gr_screen.max_w, gr_screen.max_h, GL_read_format, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
pixels = (GLubyte*)vglMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
width_times_pixel = (gr_screen.max_w * 4);
sptr = (ubyte *)pixels;
dptr = (ubyte *)&GL_saved_screen[gr_screen.max_w * gr_screen.max_h * 4];
for (i = 0; i < gr_screen.max_h; i++) {
dptr -= width_times_pixel;
memcpy(dptr, sptr, width_times_pixel);
sptr += width_times_pixel;
}
vglUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
vglBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0);
vglDeleteBuffersARB(1, &GL_screen_pbo);
GL_screen_pbo = 0;
GL_saved_screen_id = bm_create(32, gr_screen.max_w, gr_screen.max_h, GL_saved_screen, 0);
} else {
opengl_screen_tmp = (ubyte*)vm_malloc_q( gr_screen.max_w * gr_screen.max_h * 4 );
if (!opengl_screen_tmp) {
if (GL_saved_screen) {
vm_free(GL_saved_screen);
GL_saved_screen = NULL;
}
mprintf(( "Couldn't get memory for temporary saved screen!\n" ));
GL_state.DepthTest(save_state);
return -1;
}
glReadPixels(0, 0, gr_screen.max_w, gr_screen.max_h, GL_read_format, GL_UNSIGNED_INT_8_8_8_8_REV, opengl_screen_tmp);
sptr = (ubyte *)&opengl_screen_tmp[gr_screen.max_w * gr_screen.max_h * 4];
dptr = (ubyte *)GL_saved_screen;
width_times_pixel = (gr_screen.max_w * 4);
for (i = 0; i < gr_screen.max_h; i++) {
sptr -= width_times_pixel;
memcpy(dptr, sptr, width_times_pixel);
dptr += width_times_pixel;
}
vm_free(opengl_screen_tmp);
GL_saved_screen_id = bm_create(32, gr_screen.max_w, gr_screen.max_h, GL_saved_screen, 0);
}
GL_state.DepthTest(save_state);
return GL_saved_screen_id;
}
void gr_opengl_restore_screen(int bmp_id)
{
gr_reset_clip();
if ( !GL_saved_screen ) {
gr_clear();
return;
}
Assert( (bmp_id < 0) || (bmp_id == GL_saved_screen_id) );
if (GL_saved_screen_id < 0)
return;
gr_set_bitmap(GL_saved_screen_id);
gr_bitmap(0, 0, GR_RESIZE_NONE); // don't scale here since we already have real screen size
}
void gr_opengl_free_screen(int bmp_id)
{
if (!GL_saved_screen)
return;
vm_free(GL_saved_screen);
GL_saved_screen = NULL;
Assert( (bmp_id < 0) || (bmp_id == GL_saved_screen_id) );
if (GL_saved_screen_id < 0)
return;
bm_release(GL_saved_screen_id);
GL_saved_screen_id = -1;
}
static void opengl_flush_frame_dump()
{
char filename[MAX_FILENAME_LEN];
Assert( GL_dump_buffer != NULL);
for (int i = 0; i < GL_dump_frame_count; i++) {
sprintf(filename, NOX("frm%04d.tga"), GL_dump_frame_number );
GL_dump_frame_number++;
CFILE *f = cfopen(filename, "wb", CFILE_NORMAL, CF_TYPE_DATA);
// Write the TGA header
cfwrite_ubyte( 0, f ); // IDLength;
cfwrite_ubyte( 0, f ); // ColorMapType;
cfwrite_ubyte( 2, f ); // ImageType; // 2 = 24bpp, uncompressed, 10=24bpp rle compressed
cfwrite_ushort( 0, f ); // CMapStart;
cfwrite_ushort( 0, f ); // CMapLength;
cfwrite_ubyte( 0, f ); // CMapDepth;
cfwrite_ushort( 0, f ); // XOffset;
cfwrite_ushort( 0, f ); // YOffset;
cfwrite_ushort( (ushort)gr_screen.max_w, f ); // Width;
cfwrite_ushort( (ushort)gr_screen.max_h, f ); // Height;
cfwrite_ubyte( 24, f ); //PixelDepth;
cfwrite_ubyte( 0, f ); //ImageDesc;
glReadBuffer(GL_FRONT);
glReadPixels(0, 0, gr_screen.max_w, gr_screen.max_h, GL_BGR_EXT, GL_UNSIGNED_BYTE, GL_dump_buffer);
// save the data out
cfwrite( GL_dump_buffer, GL_dump_frame_size, 1, f );
cfclose(f);
}
GL_dump_frame_count = 0;
}
void gr_opengl_dump_frame_start(int first_frame, int frames_between_dumps)
{
if ( GL_dump_frames ) {
Int3(); // We're already dumping frames. See John.
return;
}
GL_dump_frames = 1;
GL_dump_frame_number = first_frame;
GL_dump_frame_count = 0;
GL_dump_frame_count_max = frames_between_dumps; // only works if it's 1
GL_dump_frame_size = gr_screen.max_w * gr_screen.max_h * 3;
if ( !GL_dump_buffer ) {
int size = GL_dump_frame_count_max * GL_dump_frame_size;
GL_dump_buffer = (ubyte *)vm_malloc(size);
if ( !GL_dump_buffer ) {
Error(LOCATION, "Unable to malloc %d bytes for dump buffer", size );
}
}
}
void gr_opengl_dump_frame_stop()
{
if ( !GL_dump_frames ) {
Int3(); // We're not dumping frames. See John.
return;
}
// dump any remaining frames
opengl_flush_frame_dump();
GL_dump_frames = 0;
if ( GL_dump_buffer ) {
vm_free(GL_dump_buffer);
GL_dump_buffer = NULL;
}
}
void gr_opengl_dump_frame()
{
GL_dump_frame_count++;
if ( GL_dump_frame_count == GL_dump_frame_count_max ) {
opengl_flush_frame_dump();
}
}
//fill mode, solid/wire frame
void gr_opengl_set_fill_mode(int mode)
{
if (mode == GR_FILL_MODE_SOLID) {
GL_state.SetPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
return;
}
if (mode == GR_FILL_MODE_WIRE) {
GL_state.SetPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
return;
}
// default setting
GL_state.SetPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
void gr_opengl_zbias(int bias)
{
if (bias) {
GL_state.PolygonOffsetFill(GL_TRUE);
if(bias < 0) {
GL_state.SetPolygonOffset(1.0, -i2fl(bias));
}
else {
GL_state.SetPolygonOffset(0.0, -i2fl(bias));
}
} else {
GL_state.PolygonOffsetFill(GL_FALSE);
}
}
void gr_opengl_push_texture_matrix(int unit)
{
GLint current_matrix;
if (unit > GL_supported_texture_units)
return;
glGetIntegerv(GL_MATRIX_MODE, &current_matrix);
vglActiveTextureARB(GL_TEXTURE0_ARB+unit);
glMatrixMode(GL_TEXTURE);
glPushMatrix();
glMatrixMode(current_matrix);
}
void gr_opengl_pop_texture_matrix(int unit)
{
GLint current_matrix;
if (unit > GL_supported_texture_units)
return;
glGetIntegerv(GL_MATRIX_MODE, &current_matrix);
vglActiveTextureARB(GL_TEXTURE0_ARB+unit);
glMatrixMode(GL_TEXTURE);
glPopMatrix();
glMatrixMode(current_matrix);
}
void gr_opengl_translate_texture_matrix(int unit, vec3d *shift)
{
GLint current_matrix;
if (unit > GL_supported_texture_units) {
/*tex_shift=*shift;*/
return;
}
glGetIntegerv(GL_MATRIX_MODE, &current_matrix);
vglActiveTextureARB(GL_TEXTURE0_ARB+unit);
glMatrixMode(GL_TEXTURE);
glTranslated(shift->xyz.x, shift->xyz.y, shift->xyz.z);
glMatrixMode(current_matrix);
// tex_shift=vmd_zero_vector;
}
void gr_opengl_setup_background_fog(bool set)
{
if (Cmdline_nohtl) {
return;
}
}
void gr_opengl_set_line_width(float width)
{
glLineWidth(width);
}
// Returns the human readable error string if there is an error or NULL if not
const char *opengl_error_string()
{
GLenum error = GL_NO_ERROR;
error = glGetError();
if ( error != GL_NO_ERROR ) {
return (const char *)gluErrorString(error);
}
return NULL;
}
int opengl_check_for_errors(char *err_at)
{
#ifdef NDEBUG
return 0;
#endif
const char *error_str = NULL;
int num_errors = 0;
error_str = opengl_error_string();
if (error_str) {
if (err_at != NULL) {
nprintf(("OpenGL", "OpenGL Error from %s: %s\n", err_at, error_str));
} else {
nprintf(("OpenGL", "OpenGL Error: %s\n", error_str));
}
num_errors++;
}
return num_errors;
}
void opengl_set_vsync(int status)
{
if ( (status < 0) || (status > 1) ) {
Int3();
return;
}
SDL_GL_SetSwapInterval(status);
GL_CHECK_FOR_ERRORS("end of set_vsync()");
}
void opengl_setup_viewport()
{
glViewport(0, 0, gr_screen.max_w, gr_screen.max_h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// the top and bottom positions are reversed on purpose, but RTT needs them the other way
if (GL_rendering_to_texture) {
glOrtho(0, gr_screen.max_w, 0, gr_screen.max_h, -1.0, 1.0);
} else {
glOrtho(0, gr_screen.max_w, gr_screen.max_h, 0, -1.0, 1.0);
}
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
// NOTE: This should only ever be called through os_cleanup(), or when switching video APIs
void gr_opengl_shutdown()
{
opengl_tcache_shutdown();
opengl_light_shutdown();
opengl_tnl_shutdown();
opengl_scene_texture_shutdown();
opengl_post_process_shutdown();
opengl_shader_shutdown();
GL_initted = false;
if (GL_original_gamma_ramp != NULL) {
SDL_SetWindowGammaRamp( os_get_window(), GL_original_gamma_ramp, (GL_original_gamma_ramp+256), (GL_original_gamma_ramp+512) );
}
if (GL_original_gamma_ramp != NULL) {
vm_free(GL_original_gamma_ramp);
GL_original_gamma_ramp = NULL;
}
SDL_GL_DeleteContext(GL_context);
GL_context = NULL;
}
// NOTE: This should only ever be called through atexit()!!!
void opengl_close()
{
// if ( !GL_initted )
// return;
}
int opengl_init_display_device()
{
int bpp = gr_screen.bits_per_pixel;
if ((bpp != 16) && (bpp != 32)) {
Int3();
return 1;
}
// screen format
switch (bpp) {
case 16: {
Gr_red.bits = 5;
Gr_red.shift = 11;
Gr_red.scale = 8;
Gr_red.mask = 0xF800;
Gr_green.bits = 6;
Gr_green.shift = 5;
Gr_green.scale = 4;
Gr_green.mask = 0x7E0;
Gr_blue.bits = 5;
Gr_blue.shift = 0;
Gr_blue.scale = 8;
Gr_blue.mask = 0x1F;
break;
}
case 32: {
Gr_red.bits = 8;
Gr_red.shift = 16;
Gr_red.scale = 1;
Gr_red.mask = 0xff0000;
Gr_green.bits = 8;
Gr_green.shift = 8;
Gr_green.scale = 1;
Gr_green.mask = 0x00ff00;
Gr_blue.bits = 8;
Gr_blue.shift = 0;
Gr_blue.scale = 1;
Gr_blue.mask = 0x0000ff;
Gr_alpha.bits = 8;
Gr_alpha.shift = 24;
Gr_alpha.mask = 0xff000000;
Gr_alpha.scale = 1;
break;
}
}
// texture format
Gr_t_red.bits = 5;
Gr_t_red.mask = 0x7c00;
Gr_t_red.shift = 10;
Gr_t_red.scale = 8;
Gr_t_green.bits = 5;
Gr_t_green.mask = 0x03e0;
Gr_t_green.shift = 5;
Gr_t_green.scale = 8;
Gr_t_blue.bits = 5;
Gr_t_blue.mask = 0x001f;
Gr_t_blue.shift = 0;
Gr_t_blue.scale = 8;
Gr_t_alpha.bits = 1;
Gr_t_alpha.mask = 0x8000;
Gr_t_alpha.scale = 255;
Gr_t_alpha.shift = 15;
// alpha-texture format
Gr_ta_red.bits = 4;
Gr_ta_red.mask = 0x0f00;
Gr_ta_red.shift = 8;
Gr_ta_red.scale = 17;
Gr_ta_green.bits = 4;
Gr_ta_green.mask = 0x00f0;
Gr_ta_green.shift = 4;
Gr_ta_green.scale = 17;
Gr_ta_blue.bits = 4;
Gr_ta_blue.mask = 0x000f;
Gr_ta_blue.shift = 0;
Gr_ta_blue.scale = 17;
Gr_ta_alpha.bits = 4;
Gr_ta_alpha.mask = 0xf000;
Gr_ta_alpha.shift = 12;
Gr_ta_alpha.scale = 17;
// allocate storage for original gamma settings
if ( !Cmdline_no_set_gamma && (GL_original_gamma_ramp == NULL) ) {
GL_original_gamma_ramp = (ushort*) vm_malloc_q( 3 * 256 * sizeof(ushort) );
if (GL_original_gamma_ramp == NULL) {
mprintf((" Unable to allocate memory for gamma ramp! Disabling...\n"));
Cmdline_no_set_gamma = 1;
} else {
// assume identity ramp by default, to be overwritten by true ramp later
for (ushort x = 0; x < 256; x++) {
GL_original_gamma_ramp[x] = GL_original_gamma_ramp[x + 256] = GL_original_gamma_ramp[x + 512] = (x << 8) | x;
}
}
}
int r = 0, g = 0, b = 0, depth = 0, stencil = 1, db = 1;
mprintf((" Initializing SDL video...\n"));
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
fprintf(stderr, "Couldn't init SDL video: %s", SDL_GetError());
return 1;
}
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, Gr_red.bits);
SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, Gr_green.bits);
SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, Gr_blue.bits);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, (bpp == 32) ? 24 : 16);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, (bpp == 32) ? 8 : 1);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, db);
int fsaa_samples = os_config_read_uint(NULL, "OGL_AntiAliasSamples", 0);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa_samples == 0) ? 0 : 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, fsaa_samples);
#ifdef SCP_UNIX
// Slight hack to make Mesa advertise S3TC support without libtxc_dxtn
setenv("force_s3tc_enable", "true", 1);
#endif
mprintf((" Requested SDL Video values = R: %d, G: %d, B: %d, depth: %d, stencil: %d, double-buffer: %d, FSAA: %d\n", Gr_red.bits, Gr_green.bits, Gr_blue.bits, (bpp == 32) ? 24 : 16, (bpp == 32) ? 8 : 1, db, fsaa_samples));
int windowflags = SDL_WINDOW_OPENGL;
if (Cmdline_fullscreen_window)
windowflags |= SDL_WINDOW_BORDERLESS;
// This code also gets called in the FRED initialization, that means we possibly already have a window!
if (os_get_window() == NULL)
{
SDL_Window* window = SDL_CreateWindow(Osreg_title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, gr_screen.max_w, gr_screen.max_h, windowflags);
if (window == NULL)
{
fprintf(stderr, "Couldn't set video mode: %s", SDL_GetError());
return 1;
}
os_set_window(window);
}
GL_context = SDL_GL_CreateContext(os_get_window());
SDL_GL_MakeCurrent(os_get_window(), GL_context);
//TODO: set up bpp settings
SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &r);
SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &g);
SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &b);
SDL_GL_GetAttribute(SDL_GL_DEPTH_SIZE, &depth);
SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &db);
SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &stencil);
SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &fsaa_samples);
mprintf((" Actual SDL Video values = R: %d, G: %d, B: %d, depth: %d, stencil: %d, double-buffer: %d, FSAA: %d\n", r, g, b, depth, stencil, db, fsaa_samples));
if (GL_original_gamma_ramp != NULL) {
SDL_GetWindowGammaRamp( os_get_window(), GL_original_gamma_ramp, (GL_original_gamma_ramp+256), (GL_original_gamma_ramp+512) );
}
return 0;
}
void opengl_setup_function_pointers()
{
// *****************************************************************************
// NOTE: All function pointers here should have a Cmdline_nohtl check at the top
// if they shouldn't be run in non-HTL mode, Don't keep separate entries.
gr_screen.gf_flip = gr_opengl_flip;
gr_screen.gf_set_clip = gr_opengl_set_clip;
gr_screen.gf_reset_clip = gr_opengl_reset_clip;
gr_screen.gf_clear = gr_opengl_clear;
// gr_screen.gf_bitmap = gr_opengl_bitmap;
gr_screen.gf_bitmap_ex = gr_opengl_bitmap_ex;
gr_screen.gf_aabitmap = gr_opengl_aabitmap;
gr_screen.gf_aabitmap_ex = gr_opengl_aabitmap_ex;
// gr_screen.gf_rect = gr_opengl_rect;
// gr_screen.gf_shade = gr_opengl_shade;
gr_screen.gf_string = gr_opengl_string;
gr_screen.gf_circle = gr_opengl_circle;
gr_screen.gf_unfilled_circle = gr_opengl_unfilled_circle;
gr_screen.gf_arc = gr_opengl_arc;
gr_screen.gf_curve = gr_opengl_curve;
gr_screen.gf_line = gr_opengl_line;
gr_screen.gf_aaline = gr_opengl_aaline;
gr_screen.gf_pixel = gr_opengl_pixel;
gr_screen.gf_scaler = gr_opengl_scaler;
gr_screen.gf_tmapper = gr_opengl_tmapper;
gr_screen.gf_render = gr_opengl_render;
gr_screen.gf_render_effect = gr_opengl_render_effect;
gr_screen.gf_gradient = gr_opengl_gradient;
gr_screen.gf_set_palette = gr_opengl_set_palette;
gr_screen.gf_print_screen = gr_opengl_print_screen;
gr_screen.gf_fade_in = gr_opengl_fade_in;
gr_screen.gf_fade_out = gr_opengl_fade_out;
gr_screen.gf_flash = gr_opengl_flash;
gr_screen.gf_flash_alpha = gr_opengl_flash_alpha;
gr_screen.gf_zbuffer_get = gr_opengl_zbuffer_get;
gr_screen.gf_zbuffer_set = gr_opengl_zbuffer_set;
gr_screen.gf_zbuffer_clear = gr_opengl_zbuffer_clear;
gr_screen.gf_stencil_set = gr_opengl_stencil_set;
gr_screen.gf_stencil_clear = gr_opengl_stencil_clear;
gr_screen.gf_alpha_mask_set = gr_opengl_alpha_mask_set;
gr_screen.gf_save_screen = gr_opengl_save_screen;
gr_screen.gf_restore_screen = gr_opengl_restore_screen;
gr_screen.gf_free_screen = gr_opengl_free_screen;
gr_screen.gf_dump_frame_start = gr_opengl_dump_frame_start;
gr_screen.gf_dump_frame_stop = gr_opengl_dump_frame_stop;
gr_screen.gf_dump_frame = gr_opengl_dump_frame;
gr_screen.gf_set_gamma = gr_opengl_set_gamma;
gr_screen.gf_fog_set = gr_opengl_fog_set;
// UnknownPlayer : Don't recognize this - MAY NEED DEBUGGING
gr_screen.gf_get_region = gr_opengl_get_region;
// now for the bitmap functions
gr_screen.gf_bm_free_data = gr_opengl_bm_free_data;
gr_screen.gf_bm_create = gr_opengl_bm_create;
gr_screen.gf_bm_init = gr_opengl_bm_init;
gr_screen.gf_bm_load = gr_opengl_bm_load;
gr_screen.gf_bm_page_in_start = gr_opengl_bm_page_in_start;
gr_screen.gf_bm_lock = gr_opengl_bm_lock;
gr_screen.gf_bm_make_render_target = gr_opengl_bm_make_render_target;
gr_screen.gf_bm_set_render_target = gr_opengl_bm_set_render_target;
gr_screen.gf_set_cull = gr_opengl_set_cull;
gr_screen.gf_set_color_buffer = gr_opengl_set_color_buffer;
gr_screen.gf_cross_fade = gr_opengl_cross_fade;
gr_screen.gf_tcache_set = gr_opengl_tcache_set;
gr_screen.gf_set_clear_color = gr_opengl_set_clear_color;
gr_screen.gf_preload = gr_opengl_preload;
gr_screen.gf_push_texture_matrix = gr_opengl_push_texture_matrix;
gr_screen.gf_pop_texture_matrix = gr_opengl_pop_texture_matrix;
gr_screen.gf_translate_texture_matrix = gr_opengl_translate_texture_matrix;
gr_screen.gf_set_texture_addressing = gr_opengl_set_texture_addressing;
gr_screen.gf_zbias = gr_opengl_zbias;
gr_screen.gf_set_fill_mode = gr_opengl_set_fill_mode;
gr_screen.gf_set_texture_panning = gr_opengl_set_texture_panning;
gr_screen.gf_create_buffer = gr_opengl_create_buffer;
gr_screen.gf_config_buffer = gr_opengl_config_buffer;
gr_screen.gf_pack_buffer = gr_opengl_pack_buffer;
gr_screen.gf_destroy_buffer = gr_opengl_destroy_buffer;
gr_screen.gf_render_buffer = gr_opengl_render_buffer;
gr_screen.gf_set_buffer = gr_opengl_set_buffer;
gr_screen.gf_update_buffer_object = gr_opengl_update_buffer_object;
gr_screen.gf_update_transform_buffer = gr_opengl_update_transform_buffer;
gr_screen.gf_set_transform_buffer_offset = gr_opengl_set_transform_buffer_offset;
gr_screen.gf_create_stream_buffer = gr_opengl_create_stream_buffer_object;
gr_screen.gf_render_stream_buffer = gr_opengl_render_stream_buffer;
gr_screen.gf_start_instance_matrix = gr_opengl_start_instance_matrix;
gr_screen.gf_end_instance_matrix = gr_opengl_end_instance_matrix;
gr_screen.gf_start_angles_instance_matrix = gr_opengl_start_instance_angles;
gr_screen.gf_make_light = gr_opengl_make_light;
gr_screen.gf_modify_light = gr_opengl_modify_light;
gr_screen.gf_destroy_light = gr_opengl_destroy_light;
gr_screen.gf_set_light = gr_opengl_set_light;
gr_screen.gf_reset_lighting = gr_opengl_reset_lighting;
gr_screen.gf_set_ambient_light = gr_opengl_set_ambient_light;
gr_screen.gf_post_process_set_effect = gr_opengl_post_process_set_effect;
gr_screen.gf_post_process_set_defaults = gr_opengl_post_process_set_defaults;
gr_screen.gf_post_process_begin = gr_opengl_post_process_begin;
gr_screen.gf_post_process_end = gr_opengl_post_process_end;
gr_screen.gf_post_process_save_zbuffer = gr_opengl_post_process_save_zbuffer;
gr_screen.gf_scene_texture_begin = gr_opengl_scene_texture_begin;
gr_screen.gf_scene_texture_end = gr_opengl_scene_texture_end;
gr_screen.gf_copy_effect_texture = gr_opengl_copy_effect_texture;
gr_screen.gf_deferred_lighting_begin = gr_opengl_deferred_lighting_begin;
gr_screen.gf_deferred_lighting_end = gr_opengl_deferred_lighting_end;
gr_screen.gf_deferred_lighting_finish = gr_opengl_deferred_lighting_finish;
gr_screen.gf_start_clip_plane = gr_opengl_start_clip_plane;
gr_screen.gf_end_clip_plane = gr_opengl_end_clip_plane;
gr_screen.gf_lighting = gr_opengl_set_lighting;
gr_screen.gf_set_light_factor = gr_opengl_set_light_factor;
gr_screen.gf_set_proj_matrix = gr_opengl_set_projection_matrix;
gr_screen.gf_end_proj_matrix = gr_opengl_end_projection_matrix;
gr_screen.gf_set_view_matrix = gr_opengl_set_view_matrix;
gr_screen.gf_end_view_matrix = gr_opengl_end_view_matrix;
gr_screen.gf_push_scale_matrix = gr_opengl_push_scale_matrix;
gr_screen.gf_pop_scale_matrix = gr_opengl_pop_scale_matrix;
gr_screen.gf_center_alpha = gr_opengl_center_alpha;
gr_screen.gf_set_thrust_scale = gr_opengl_set_thrust_scale;
gr_screen.gf_setup_background_fog = gr_opengl_setup_background_fog;
gr_screen.gf_start_state_block = gr_opengl_start_state_block;
gr_screen.gf_end_state_block = gr_opengl_end_state_block;
gr_screen.gf_set_state_block = gr_opengl_set_state_block;
gr_screen.gf_draw_line_list = gr_opengl_draw_line_list;
gr_screen.gf_set_line_width = gr_opengl_set_line_width;
gr_screen.gf_line_htl = gr_opengl_line_htl;
gr_screen.gf_sphere_htl = gr_opengl_sphere_htl;
gr_screen.gf_set_animated_effect = gr_opengl_shader_set_animated_effect;
gr_screen.gf_maybe_create_shader = gr_opengl_maybe_create_shader;
gr_screen.gf_shadow_map_start = gr_opengl_shadow_map_start;
gr_screen.gf_shadow_map_end = gr_opengl_shadow_map_end;
gr_screen.gf_update_texture = gr_opengl_update_texture;
gr_screen.gf_get_bitmap_from_texture = gr_opengl_get_bitmap_from_texture;
gr_screen.gf_clear_states = gr_opengl_clear_states;
gr_screen.gf_set_team_color = gr_opengl_set_team_color;
// NOTE: All function pointers here should have a Cmdline_nohtl check at the top
// if they shouldn't be run in non-HTL mode, Don't keep separate entries.
// *****************************************************************************
}
bool gr_opengl_init()
{
char *ver;
int major = 0, minor = 0;
if ( !GL_initted )
atexit(opengl_close);
if (GL_initted) {
gr_opengl_cleanup();
GL_initted = false;
}
mprintf(( "Initializing OpenGL graphics device at %ix%i with %i-bit color...\n", gr_screen.max_w, gr_screen.max_h, gr_screen.bits_per_pixel ));
if ( opengl_init_display_device() ) {
Error(LOCATION, "Unable to initialize display device!\n");
}
// version check
ver = (char *)glGetString(GL_VERSION);
sscanf(ver, "%d.%d", &major, &minor);
GL_version = (major * 10) + minor;
if (GL_version < MIN_REQUIRED_GL_VERSION) {
Error(LOCATION, "Current GL Version of %d.%d is less than the required version of %d.%d.\nSwitch video modes or update your drivers.", major, minor, (MIN_REQUIRED_GL_VERSION / 10), (MIN_REQUIRED_GL_VERSION % 10));
}
GL_initted = true;
// this MUST be done before any other gr_opengl_* or opengl_* funcion calls!!
opengl_setup_function_pointers();
mprintf(( " OpenGL Vendor : %s\n", glGetString(GL_VENDOR) ));
mprintf(( " OpenGL Renderer : %s\n", glGetString(GL_RENDERER) ));
mprintf(( " OpenGL Version : %s\n", ver ));
mprintf(( "\n" ));
if (Cmdline_fullscreen_window || Cmdline_window) {
opengl_go_windowed();
} else {
opengl_go_fullscreen();
}
// initialize the extensions and make sure we aren't missing something that we need
opengl_extensions_init();
// setup the lighting stuff that will get used later
opengl_light_init();
// init state system (must come AFTER light is set up)
GL_state.init();
GLint max_texture_units = GL_supported_texture_units;
GLint max_texture_coords = GL_supported_texture_units;
if (Use_GLSL) {
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS_ARB, &max_texture_units);
}
glGetIntegerv(GL_MAX_TEXTURE_COORDS, &max_texture_coords);
GL_state.Texture.init(max_texture_units);
GL_state.Array.init(max_texture_coords);
opengl_set_texture_target();
GL_state.Texture.SetActiveUnit(0);
GL_state.Texture.SetTarget(GL_TEXTURE_2D);
GL_state.Texture.Enable();
// ready the texture system
opengl_tcache_init();
extern void opengl_tnl_init();
opengl_tnl_init();
// setup default shaders, and shader related items
opengl_shader_init();
// post processing effects, after shaders are initialized
opengl_setup_scene_textures();
opengl_post_process_init();
// must be called after extensions are setup
opengl_set_vsync( !Cmdline_no_vsync );
opengl_setup_viewport();
glClear(GL_DEPTH_BUFFER_BIT);
glClear(GL_STENCIL_BUFFER_BIT);
glShadeModel(GL_SMOOTH);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glHint(GL_FOG_HINT, GL_NICEST);
glDepthRange(0.0, 1.0);
glPixelStorei(GL_PACK_ALIGNMENT, 1);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glFlush();
Gr_current_red = &Gr_red;
Gr_current_blue = &Gr_blue;
Gr_current_green = &Gr_green;
Gr_current_alpha = &Gr_alpha;
gr_opengl_reset_clip();
gr_opengl_clear();
gr_opengl_flip();
gr_opengl_clear();
gr_opengl_flip();
gr_opengl_clear();
glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &GL_max_elements_vertices);
glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &GL_max_elements_indices);
mprintf(( " Max texture units: %i (%i)\n", GL_supported_texture_units, max_texture_units ));
mprintf(( " Max client texture states: %i (%i)\n", GL_supported_texture_units, max_texture_coords ));
mprintf(( " Max elements vertices: %i\n", GL_max_elements_vertices ));
mprintf(( " Max elements indices: %i\n", GL_max_elements_indices ));
mprintf(( " Max texture size: %ix%i\n", GL_max_texture_width, GL_max_texture_height ));
if ( Is_Extension_Enabled(OGL_EXT_FRAMEBUFFER_OBJECT) ) {
mprintf(( " Max render buffer size: %ix%i\n", GL_max_renderbuffer_size, GL_max_renderbuffer_size ));
}
mprintf(( " Can use compressed textures: %s\n", Use_compressed_textures ? NOX("YES") : NOX("NO") ));
mprintf(( " Texture compression available: %s\n", Texture_compression_available ? NOX("YES") : NOX("NO") ));
mprintf(( " Post-processing enabled: %s\n", (Cmdline_postprocess) ? "YES" : "NO"));
mprintf(( " Using %s texture filter.\n", (GL_mipmap_filter) ? NOX("trilinear") : NOX("bilinear") ));
if (Use_GLSL) {
mprintf(( " OpenGL Shader Version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION_ARB) ));
}
// This stops fred crashing if no textures are set
gr_screen.current_bitmap = -1;
mprintf(("... OpenGL init is complete!\n"));
if (Cmdline_ati_color_swap)
GL_read_format = GL_RGBA;
return true;
}
DCF(ogl_minimize, "Minimizes opengl")
{
bool minimize_ogl = false;
if ( gr_screen.mode != GR_OPENGL ) {
dc_printf("Command only available in OpenGL mode.\n");
return;
}
if (dc_optional_string_either("help", "--help")) {
dc_printf("[bool] If true is passed, then the OpenGL window will minimize.\n");
return;
}
dc_stuff_boolean(&minimize_ogl);
if (minimize_ogl) {
opengl_minimize();
}
}
DCF(ogl_anisotropy, "toggles anisotropic filtering")
{
bool process = true;
int value;
if ( gr_screen.mode != GR_OPENGL ) {
dc_printf("Can only set anisotropic filter in OpenGL mode.\n");
return;
}
if (dc_optional_string_either("help", "--help")) {
dc_printf("Sets OpenGL anisotropic filtering level.\n");
dc_printf("GL_anisotropy [int] Valid values are 0 to %i. 0 turns off anisotropic filtering.\n", (int)opengl_get_max_anisotropy());
process = false;
}
if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
dc_printf("Current anisotropic filter value is %i\n", (int)GL_anisotropy);
process = false;
}
if (!process) {
return;
}
if ( !Is_Extension_Enabled(OGL_EXT_TEXTURE_FILTER_ANISOTROPIC) ) {
dc_printf("Error: Anisotropic filter is not settable!\n");
return;
}
if (!dc_maybe_stuff_int(&value)) {
// No arg passed, set to default
GL_anisotropy = 1.0f;
// opengl_set_anisotropy();
dc_printf("Anisotropic filter value reset to default level.\n");
} else {
GL_anisotropy = (GLfloat)value;
// opengl_set_anisotropy( (float)Dc_arg_float );
}
}