34#include "physfsrwops.h"
61static int gl_view_x = 0;
62static int gl_view_y = 0;
63static int gl_view_w = 0;
64static int gl_view_h = 0;
65mat4 gl_view_matrix = { { { { 0 } } } };
87 if ( setenv(
"AMD_DEBUG",
"nooptvariant", 1 ) != 0 ) {
88 WARN( _(
"Failed to set AMD_DEBUG environment variable" ) );
90 DEBUG( _(
"Set AMD_DEBUG environment variable to 'nooptvariant'" ) );
110 SDL_Surface *surface;
116 screenbuf = malloc(
sizeof( GLubyte ) * 3 * w * h );
117 surface = SDL_CreateRGBSurface( 0, w, h, 24, RGBAMASK );
120 glPixelStorei( GL_PACK_ALIGNMENT, 1 );
121 glReadPixels( 0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, screenbuf );
124 for (
int i = 0; i < h; i++ )
125 memcpy( (GLubyte *)surface->pixels + i * surface->pitch,
126 &screenbuf[( h - i - 1 ) * ( 3 * w )], 3 * w );
130 if ( !( rw = PHYSFSRWOPS_openWrite( filename ) ) )
131 WARN( _(
"Aborting screenshot" ) );
133 IMG_SavePNG_RW( surface, rw, 1 );
139 SDL_FreeSurface( surface );
142void gl_saveFboDepth( GLuint fbo,
const char *filename )
151 screenbuf = malloc(
sizeof( GLfloat ) * 1 * w * h );
152 s = SDL_CreateRGBSurface( 0, w, h, 24, RGBAMASK );
155 glBindFramebuffer( GL_FRAMEBUFFER, fbo );
157 glGetFramebufferAttachmentParameteriv( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
158 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
160 if ( value != GL_TEXTURE ) {
161 WARN(
"Trying to save depth of FBO with no depth attachment!" );
163 glBindFramebuffer( GL_FRAMEBUFFER,
gl_screen.current_fbo );
166 glPixelStorei( GL_PACK_ALIGNMENT, 1 );
167 glReadPixels( 0, 0, w, h, GL_DEPTH_COMPONENT, GL_FLOAT, screenbuf );
168 glBindFramebuffer( GL_FRAMEBUFFER,
gl_screen.current_fbo );
174 Uint8 *
d = s->pixels;
175 for (
int i = 0; i < h; i++ ) {
176 for (
int j = 0; j < w; j++ ) {
177 float f = screenbuf[( h - i - 1 ) * w + j];
179 for (
int k = 0; k < 3; k++ ) {
180 d[i * s->pitch + j * s->format->BytesPerPixel + k] = v;
187 IMG_SavePNG( s, filename );
190 SDL_FreeSurface( s );
207 if ( GLVersion.major >= major && GLVersion.minor >= minor )
216int gl_checkHandleError(
const char *func,
int line )
222 GLenum err = glGetError();
225 if ( err == GL_NO_ERROR )
229 case GL_INVALID_ENUM:
230 errstr = _(
"GL invalid enum" );
232 case GL_INVALID_VALUE:
233 errstr = _(
"GL invalid value" );
235 case GL_INVALID_OPERATION:
236 errstr = _(
"GL invalid operation" );
238 case GL_INVALID_FRAMEBUFFER_OPERATION:
239 errstr = _(
"GL invalid framebuffer operation" );
241 case GL_OUT_OF_MEMORY:
242 errstr = _(
"GL out of memory" );
246 errstr = _(
"GL unknown error" );
249 WARN( _(
"OpenGL error [%s:%d]: %s" ), func, line, errstr );
259static void GLAPIENTRY gl_debugCallback( GLenum source, GLenum type, GLuint
id,
260 GLenum severity, GLsizei length,
261 const GLchar *message,
const void *p )
263 static int errors_seen = 0;
270 if ( ++errors_seen == 10 )
271 WARN( _(
"Too many OpenGL diagnostics reported! Suppressing further "
273 if ( errors_seen >= 10 )
277 case GL_DEBUG_TYPE_ERROR:
278 typestr =
" GL_DEBUG_TYPE_ERROR";
280 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
281 typestr =
" GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR";
283 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
284 typestr =
" GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR";
286 case GL_DEBUG_TYPE_PORTABILITY:
287 typestr =
" GL_DEBUG_TYPE_PORTABILITY";
289 case GL_DEBUG_TYPE_PERFORMANCE:
290 typestr =
" GL_DEBUG_TYPE_PERFORMANCE";
292 case GL_DEBUG_TYPE_OTHER:
293 typestr =
" GL_DEBUG_TYPE_OTHER";
295 case GL_DEBUG_TYPE_MARKER:
296 case GL_DEBUG_TYPE_PUSH_GROUP:
297 case GL_DEBUG_TYPE_POP_GROUP:
302 WARN( _(
"[type = 0x%x%s], severity = 0x%x, message = %s backtrace:" ), type,
303 typestr, severity, message );
304 debug_logBacktrace();
316 SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, fallback ? 3 : 4 );
317 SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, fallback ? 2 : 6 );
318 SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK,
319 SDL_GL_CONTEXT_PROFILE_CORE );
320 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER,
322 if ( conf.fsaa > 1 ) {
323 SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 );
324 SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, conf.fsaa );
326 SDL_GL_SetAttribute( SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1 );
328 SDL_GL_SetAttribute( SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG );
343 int display_index = SDL_GetWindowDisplayIndex(
gl_screen.window );
344 if ( conf.fullscreen && conf.modesetting ) {
345 SDL_DisplayMode target, closest;
347 if ( conf.explicit_dim ) {
348 SDL_GetWindowDisplayMode(
gl_screen.window, &target );
349 target.w = conf.width;
350 target.h = conf.height;
352 SDL_GetDesktopDisplayMode( display_index, &target );
354 if ( SDL_GetClosestDisplayMode( display_index, &target, &closest ) ==
356 SDL_GetDisplayMode( display_index, 0,
359 SDL_SetWindowDisplayMode(
gl_screen.window, &closest );
377 if ( conf.fullscreen )
378 return conf.modesetting ? SDL_WINDOW_FULLSCREEN
379 : SDL_WINDOW_FULLSCREEN_DESKTOP;
390 flags |= SDL_WINDOW_ALLOW_HIGHDPI;
391 if ( !conf.notresizable )
392 flags |= SDL_WINDOW_RESIZABLE;
393 if ( conf.borderless )
394 flags |= SDL_WINDOW_BORDERLESS;
398 SDL_CreateWindow(
APPNAME, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
399 MAX( RESOLUTION_W_MIN, conf.width ),
400 MAX( RESOLUTION_H_MIN, conf.height ), flags );
403 snprintf( buf,
sizeof( buf ), _(
"Unable to create window! %s" ),
405#if SDL_VERSION_ATLEAST( 3, 0, 0 )
406 SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR,
407 _(
"Naev Critical Error" ), buf,
414 SDL_SetWindowMinimumSize(
gl_screen.window, RESOLUTION_W_MIN,
418 SDL_SetHint( SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS,
419 conf.minimize ?
"1" :
"0" );
422 for (
int fallback = 0; fallback <= 1; fallback++ ) {
430 snprintf( buf,
sizeof( buf ), _(
"Unable to create OpenGL context! %s" ),
432#if SDL_VERSION_ATLEAST( 3, 0, 0 )
433 SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR,
434 _(
"Naev Critical Error" ), buf,
441 SDL_GL_GetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, &
gl_screen.major );
442 SDL_GL_GetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, &
gl_screen.minor );
450 int ret = SDL_GL_SetSwapInterval( 1 );
454 SDL_GL_SetSwapInterval( 0 );
459 for (
int i = 0; i < OPENGL_NUM_FBOS; i++ ) {
463 SDL_GL_GetAttribute( SDL_GL_DEPTH_SIZE, &
gl_screen.depth );
465 SDL_GL_GetAttribute( SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, &srgb_capable );
467 WARN( _(
"Unable to set framebuffer to SRGB!" ) );
481 SDL_GL_GetAttribute( SDL_GL_RED_SIZE, &
gl_screen.r );
482 SDL_GL_GetAttribute( SDL_GL_GREEN_SIZE, &
gl_screen.g );
483 SDL_GL_GetAttribute( SDL_GL_BLUE_SIZE, &
gl_screen.b );
484 SDL_GL_GetAttribute( SDL_GL_ALPHA_SIZE, &
gl_screen.a );
485 SDL_GL_GetAttribute( SDL_GL_DOUBLEBUFFER, &doublebuf );
486 SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES, &
gl_screen.fsaa );
489 if ( GLAD_GL_ARB_shader_subroutine && glGetSubroutineIndex &&
490 glGetSubroutineUniformLocation && glUniformSubroutinesuiv )
496 glGetIntegerv( GL_MAX_TEXTURE_SIZE, &
gl_screen.tex_max );
497 glGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS, &
gl_screen.multitex_max );
500 DEBUG( _(
"OpenGL Drawable Created: %dx%d@%dbpp" ),
gl_screen.rw,
502 DEBUG( _(
"r: %d, g: %d, b: %d, a: %d, db: %s, fsaa: %d, tex: %d" ),
504 gl_has( OPENGL_DOUBLEBUF ) ? _(
"yes" ) : _(
"no" ),
gl_screen.fsaa,
506 DEBUG( _(
"VSync: %s" ), gl_has( OPENGL_VSYNC ) ? _(
"yes" ) : _(
"no" ) );
507 DEBUG( _(
"Renderer: %s" ), glGetString( GL_RENDERER ) );
508 DEBUG( _(
"Vendor: %s" ), glGetString( GL_VENDOR ) );
509 DEBUG( _(
"Version: %s" ), glGetString( GL_VERSION ) );
512 if ( ( conf.fsaa > 1 ) && (
gl_screen.fsaa != conf.fsaa ) )
513 WARN( _(
"Unable to get requested FSAA level (%d requested, got %d)" ),
526 glDisable( GL_DEPTH_TEST );
527 glEnable( GL_BLEND );
532 glEnable( GL_DEBUG_OUTPUT );
533 glDebugMessageCallback( gl_debugCallback, 0 );
534 glDebugMessageControl( GL_DONT_CARE, GL_DEBUG_TYPE_PERFORMANCE, GL_DONT_CARE,
536 glDebugMessageControl( GL_DONT_CARE, GL_DEBUG_TYPE_OTHER, GL_DONT_CARE, 0,
541 glBlendEquation( GL_FUNC_ADD );
542 glBlendFuncSeparate( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE,
543 GL_ONE_MINUS_SRC_ALPHA );
566 glPointSize( 1. /
gl_screen.scale + 2.0 );
572 if ( (
gl_screen.nw < RESOLUTION_W_MIN ) ||
574 double scalew, scaleh;
576 WARN( _(
"Screen size too small, upscaling..." ) );
577 scalew = RESOLUTION_W_MIN / (double)
gl_screen.nw;
578 scaleh = RESOLUTION_H_MIN / (double)
gl_screen.nh;
610 SDL_SetHint(
"SDL_WINDOWS_DPI_SCALING",
"1" );
614 if ( SDL_InitSubSystem( SDL_INIT_VIDEO ) < 0 ) {
615 WARN( _(
"Unable to initialize SDL Video: %s" ), SDL_GetError() );
626 if ( !gladLoadGLLoader( SDL_GL_GetProcAddress ) ) {
628 snprintf( buf,
sizeof( buf ), _(
"Unable to load OpenGL using GLAD!" ) );
629#if SDL_VERSION_ATLEAST( 3, 0, 0 )
630 SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR,
631 _(
"Naev Critical Error" ), buf,
638 if ( !GLAD_GL_VERSION_3_2 )
639 WARN(
"Naev requires OpenGL %d.%d, but got OpenGL %d.%d!", 3, 2,
640 GLVersion.major, GLVersion.minor );
643 glClearColor( 0., 0., 0., 0. );
653 glClear( GL_COLOR_BUFFER_BIT |
654 GL_DEPTH_BUFFER_BIT );
666 glGenVertexArrays( 1, &VaoId );
667 glBindVertexArray( VaoId );
675 glEnable( GL_FRAMEBUFFER_SRGB );
697 for (
int i = 0; i < OPENGL_NUM_FBOS; i++ ) {
698 if (
gl_screen.fbo[i] != GL_INVALID_VALUE ) {
699 glDeleteFramebuffers( 1, &
gl_screen.fbo[i] );
700 glDeleteTextures( 1, &
gl_screen.fbo_tex[i] );
701 glDeleteTextures( 1, &
gl_screen.fbo_depth_tex[i] );
727 mat4_translate_xy( &proj, x, y );
737 gl_view_matrix = proj;
756 gl_viewport( gl_view_x, gl_view_y, gl_view_w, gl_view_h );
793 if ( strcasecmp( s,
"linear" ) == 0 )
795 else if ( strcasecmp( s,
"nearest" ) == 0 )
797 WARN( _(
"Unknown %s '%s'!" ),
"OpenGL Filter", s );
809 if ( strcasecmp( s,
"clamp" ) == 0 )
810 return GL_CLAMP_TO_EDGE;
811 else if ( strcasecmp( s,
"repeat" ) == 0 )
813 else if ( strcasecmp( s,
"mirroredrepeat" ) == 0 )
814 return GL_MIRRORED_REPEAT;
815 WARN( _(
"Unknown %s '%s'!" ),
"OpenGL Clamp", s );
827 if ( strcasecmp( s,
"add" ) == 0 )
829 else if ( strcasecmp( s,
"subrtract" ) == 0 )
830 return GL_FUNC_SUBTRACT;
831 else if ( strcasecmp( s,
"reverse_subtract" ) == 0 )
832 return GL_FUNC_REVERSE_SUBTRACT;
833 else if ( strcasecmp( s,
"min" ) == 0 )
835 else if ( strcasecmp( s,
"max" ) == 0 )
837 WARN( _(
"Unknown %s '%s'!" ),
"OpenGL BlendFunc", s );
849 if ( strcasecmp( s,
"zero" ) == 0 )
851 else if ( strcasecmp( s,
"one" ) == 0 )
853 else if ( strcasecmp( s,
"src_color" ) == 0 )
855 else if ( strcasecmp( s,
"one_minus_src_color" ) == 0 )
856 return GL_ONE_MINUS_SRC_COLOR;
857 else if ( strcasecmp( s,
"src_alpha" ) == 0 )
859 else if ( strcasecmp( s,
"one_minus_src_alpha" ) == 0 )
860 return GL_ONE_MINUS_SRC_ALPHA;
861 else if ( strcasecmp( s,
"dst_color" ) == 0 )
863 else if ( strcasecmp( s,
"one_minus_dst_color" ) == 0 )
864 return GL_ONE_MINUS_DST_COLOR;
865 else if ( strcasecmp( s,
"dst_alpha" ) == 0 )
867 else if ( strcasecmp( s,
"one_minus_dst_alpha" ) == 0 )
868 return GL_ONE_MINUS_DST_ALPHA;
869 else if ( strcasecmp( s,
"src_alpha_saturate" ) == 0 )
870 return GL_SRC_ALPHA_SATURATE;
871 WARN( _(
"Unknown %s '%s'!" ),
"OpenGL BlendFactor", s );
881 glUseProgram( shaders.colourblind_sim.program );
882 glUniform1i( shaders.colourblind_sim.type, conf.colourblind_type );
883 glUniform1f( shaders.colourblind_sim.intensity, conf.colourblind_sim );
884 glUseProgram( shaders.colourblind_correct.program );
885 glUniform1i( shaders.colourblind_correct.type, conf.colourblind_type );
886 glUniform1f( shaders.colourblind_correct.intensity,
887 conf.colourblind_correct );
891 if ( conf.colourblind_sim > 0. ) {
896 shader.program = shaders.colourblind_sim.program;
897 shader.VertexPosition = shaders.colourblind_sim.VertexPosition;
898 shader.ClipSpaceFromLocal = shaders.colourblind_sim.ClipSpaceFromLocal;
899 shader.MainTex = shaders.colourblind_sim.MainTex;
900 cb_simulate_pp = render_postprocessAdd( &shader, PP_LAYER_CORE, 99,
901 PP_SHADER_PERMANENT );
909 if ( conf.colourblind_correct > 0. ) {
914 shader.program = shaders.colourblind_correct.program;
915 shader.VertexPosition = shaders.colourblind_correct.VertexPosition;
916 shader.ClipSpaceFromLocal =
917 shaders.colourblind_correct.ClipSpaceFromLocal;
918 shader.MainTex = shaders.colourblind_correct.MainTex;
919 cb_correct_pp = render_postprocessAdd( &shader, PP_LAYER_CORE, 100,
920 PP_SHADER_PERMANENT );
933 for (
int i = 0; i < OPENGL_NUM_FBOS; i++ ) {
934 if (
gl_screen.fbo[i] != GL_INVALID_VALUE ) {
935 glDeleteFramebuffers( 1, &
gl_screen.fbo[i] );
936 glDeleteTextures( 1, &
gl_screen.fbo_tex[i] );
937 glDeleteTextures( 1, &
gl_screen.fbo_depth_tex[i] );
940 gl_screen.fbo_depth_tex[i] = GL_INVALID_VALUE;
953 SDL_QuitSubSystem( SDL_INIT_VIDEO );
void mat4_scale(mat4 *m, double x, double y, double z)
Scales a homogeneous transformation matrix.
mat4 mat4_ortho(double left, double right, double bottom, double top, double nearVal, double farVal)
Creates an orthographic projection matrix.
Header file with generic functions and naev-specifics.
void gl_setDefViewport(int x, int y, int w, int h)
Sets the default viewport.
static void gl_applyFixes(void)
Applies driver-specific fixes and workarounds before initializing OpenGL.
void gl_screenshot(const char *filename)
Takes a screenshot.
static int gl_defState(void)
Sets the opengl state to its default parameters.
static unsigned int cb_correct_pp
static int gl_getGLInfo(void)
Gets some information about the OpenGL window.
void gl_defViewport(void)
Resets viewport to default.
void gl_colourblind(void)
Enables or disables the colourblind shader.
GLenum gl_stringToBlendFactor(const char *s)
Gets a blend factor from a string.
void gl_resize(void)
Handles a window resize and resets gl_screen parameters.
void gl_screenToWindowPos(int *wx, int *wy, int sx, int sy)
Translates the screen position to windos position.
void gl_exit(void)
Cleans up OpenGL, the works.
void gl_viewport(int x, int y, int w, int h)
Sets the opengl viewport.
int gl_init(unsigned int extra_flags)
Initializes SDL/OpenGL and the works.
void gl_windowToScreenPos(int *sx, int *sy, int wx, int wy)
Translates the window position to screen position.
static int gl_getFullscreenMode(void)
Returns the fullscreen configuration as SDL2 flags.
GLenum gl_stringToBlendFunc(const char *s)
Gets a blend function from a string.
static int gl_setupAttributes(int fallback)
Tries to set up the OpenGL attributes for the OpenGL context.
static int gl_setupScaling(void)
Sets up dimensions in gl_screen, including scaling as needed.
static int gl_createWindow(unsigned int flags)
Creates the OpenGL window.
GLenum gl_stringToFilter(const char *s)
Gets the associated min/mag filter from a string.
GLboolean gl_hasVersion(int major, int minor)
Checks to see if opengl version is at least major.minor.
static unsigned int cb_simulate_pp
GLenum gl_stringToClamp(const char *s)
Gets the associated min/mag filter from a string.
int gl_setupFullscreen(void)
Tries to apply the configured display mode to the window.
void gl_exitRender(void)
Cleans up the OpenGL rendering routines.
int gl_initRender(void)
Initializes the OpenGL rendering routines.
void gl_exitTextures(void)
Cleans up the opengl texture subsystem.
int gl_fboCreate(GLuint *fbo, GLuint *tex, GLsizei width, GLsizei height)
Creates a framebuffer and its associated texture.
int gl_fboAddDepth(GLuint fbo, GLuint *tex, GLsizei width, GLsizei height)
Adds a depth attachment to an FBO.
int gl_initTextures(void)
Initializes the opengl texture subsystem.
int gl_initVBO(void)
Initializes the OpenGL VBO subsystem.
void gl_exitVBO(void)
Exits the OpenGL VBO subsystem.
Stores data about the current opengl environment.