naev 0.12.5
opengl.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
31#include "SDL.h"
32#include "SDL_error.h"
33#include "SDL_image.h"
34#include "physfsrwops.h"
35
36#include "naev.h"
38
39#include "opengl.h"
40
41#include "conf.h"
42#include "debug.h" // IWYU pragma: keep
43#include "gltf.h"
44#include "log.h"
45#include "render.h"
46
48 .window = NULL, /* Should be initialized to NULL as is used for cases of
49 SDL_ShowSimpleMessageBox. */
50};
51static int gl_activated = 0;
52
53static unsigned int cb_correct_pp =
54 0;
55static unsigned int cb_simulate_pp =
56 0;
57
58/*
59 * Viewport offsets
60 */
61static int gl_view_x = 0; /* X viewport offset. */
62static int gl_view_y = 0; /* Y viewport offset. */
63static int gl_view_w = 0; /* Viewport width. */
64static int gl_view_h = 0; /* Viewport height. */
65mat4 gl_view_matrix = { { { { 0 } } } };
66
67/*
68 * prototypes
69 */
70/* gl */
71static int gl_setupAttributes( int fallback );
72static int gl_createWindow( unsigned int flags );
73static int gl_getFullscreenMode( void );
74static int gl_getGLInfo( void );
75static int gl_defState( void );
76static int gl_setupScaling( void );
77
82static void gl_applyFixes( void )
83{
84#if __LINUX__
85 // Set AMD_DEBUG environment variable before initializing OpenGL to
86 // workaround driver bug.
87 if ( setenv( "AMD_DEBUG", "nooptvariant", 1 ) != 0 ) {
88 WARN( _( "Failed to set AMD_DEBUG environment variable" ) );
89 } else {
90 DEBUG( _( "Set AMD_DEBUG environment variable to 'nooptvariant'" ) );
91 }
92#endif
93}
94
95/*
96 *
97 * M I S C
98 *
99 */
106void gl_screenshot( const char *filename )
107{
108 GLubyte *screenbuf;
109 SDL_RWops *rw;
110 SDL_Surface *surface;
111 int w, h;
112
113 /* Allocate data. */
114 w = gl_screen.rw;
115 h = gl_screen.rh;
116 screenbuf = malloc( sizeof( GLubyte ) * 3 * w * h );
117 surface = SDL_CreateRGBSurface( 0, w, h, 24, RGBAMASK );
118
119 /* Read pixels from buffer -- SLOW. */
120 glPixelStorei( GL_PACK_ALIGNMENT, 1 ); /* Force them to pack the bytes. */
121 glReadPixels( 0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, screenbuf );
122
123 /* Convert data. */
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 );
127 free( screenbuf );
128
129 /* Save PNG. */
130 if ( !( rw = PHYSFSRWOPS_openWrite( filename ) ) )
131 WARN( _( "Aborting screenshot" ) );
132 else
133 IMG_SavePNG_RW( surface, rw, 1 );
134
135 /* Check to see if an error occurred. */
136 gl_checkErr();
137
138 /* Free memory. */
139 SDL_FreeSurface( surface );
140}
141
142void gl_saveFboDepth( GLuint fbo, const char *filename )
143{
144 GLfloat *screenbuf;
145 SDL_Surface *s;
146 int w, h;
147
148 /* Allocate data. */
149 w = gl_screen.rw; /* TODO get true size. */
150 h = gl_screen.rh;
151 screenbuf = malloc( sizeof( GLfloat ) * 1 * w * h );
152 s = SDL_CreateRGBSurface( 0, w, h, 24, RGBAMASK );
153
154 /* Read pixels from buffer -- SLOW. */
155 glBindFramebuffer( GL_FRAMEBUFFER, fbo );
156 GLint value;
157 glGetFramebufferAttachmentParameteriv( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
158 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
159 &value );
160 if ( value != GL_TEXTURE ) {
161 WARN( "Trying to save depth of FBO with no depth attachment!" );
162 free( screenbuf );
163 glBindFramebuffer( GL_FRAMEBUFFER, gl_screen.current_fbo );
164 return;
165 }
166 glPixelStorei( GL_PACK_ALIGNMENT, 1 ); /* Force them to pack the bytes. */
167 glReadPixels( 0, 0, w, h, GL_DEPTH_COMPONENT, GL_FLOAT, screenbuf );
168 glBindFramebuffer( GL_FRAMEBUFFER, gl_screen.current_fbo );
169
170 /* Check to see if an error occurred. */
171 gl_checkErr();
172
173 /* Convert data. */
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];
178 Uint8 v = f * 255.;
179 for ( int k = 0; k < 3; k++ ) {
180 d[i * s->pitch + j * s->format->BytesPerPixel + k] = v;
181 }
182 }
183 }
184 free( screenbuf );
185
186 /* Save PNG. */
187 IMG_SavePNG( s, filename );
188
189 /* Free memory. */
190 SDL_FreeSurface( s );
191}
192
193/*
194 *
195 * G L O B A L
196 *
197 */
205GLboolean gl_hasVersion( int major, int minor )
206{
207 if ( GLVersion.major >= major && GLVersion.minor >= minor )
208 return GL_TRUE;
209 return GL_FALSE;
210}
211
212#ifdef DEBUGGING
216int gl_checkHandleError( const char *func, int line )
217{
218 (void)func;
219 (void)line;
220#if !DEBUG_GL
221 const char *errstr;
222 GLenum err = glGetError();
223
224 /* No error. */
225 if ( err == GL_NO_ERROR )
226 return 0;
227
228 switch ( err ) {
229 case GL_INVALID_ENUM:
230 errstr = _( "GL invalid enum" );
231 break;
232 case GL_INVALID_VALUE:
233 errstr = _( "GL invalid value" );
234 break;
235 case GL_INVALID_OPERATION:
236 errstr = _( "GL invalid operation" );
237 break;
238 case GL_INVALID_FRAMEBUFFER_OPERATION:
239 errstr = _( "GL invalid framebuffer operation" );
240 break;
241 case GL_OUT_OF_MEMORY:
242 errstr = _( "GL out of memory" );
243 break;
244
245 default:
246 errstr = _( "GL unknown error" );
247 break;
248 }
249 WARN( _( "OpenGL error [%s:%d]: %s" ), func, line, errstr );
250 return 1;
251#endif /* !DEBUG_GL */
252 return 0;
253}
254
255#if DEBUG_GL
259static void GLAPIENTRY gl_debugCallback( GLenum source, GLenum type, GLuint id,
260 GLenum severity, GLsizei length,
261 const GLchar *message, const void *p )
262{
263 static int errors_seen = 0;
264 (void)source;
265 (void)id;
266 (void)length;
267 (void)p;
268 const char *typestr;
269
270 if ( ++errors_seen == 10 )
271 WARN( _( "Too many OpenGL diagnostics reported! Suppressing further "
272 "reports." ) );
273 if ( errors_seen >= 10 )
274 return;
275
276 switch ( type ) {
277 case GL_DEBUG_TYPE_ERROR:
278 typestr = " GL_DEBUG_TYPE_ERROR";
279 break;
280 case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
281 typestr = " GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR";
282 break;
283 case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
284 typestr = " GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR";
285 break;
286 case GL_DEBUG_TYPE_PORTABILITY:
287 typestr = " GL_DEBUG_TYPE_PORTABILITY";
288 break;
289 case GL_DEBUG_TYPE_PERFORMANCE:
290 typestr = " GL_DEBUG_TYPE_PERFORMANCE";
291 break;
292 case GL_DEBUG_TYPE_OTHER:
293 typestr = " GL_DEBUG_TYPE_OTHER";
294 break;
295 case GL_DEBUG_TYPE_MARKER: /* fallthrough */
296 case GL_DEBUG_TYPE_PUSH_GROUP: /* fallthrough */
297 case GL_DEBUG_TYPE_POP_GROUP: /* fallthrough */
298 return;
299 default:
300 typestr = "";
301 }
302 WARN( _( "[type = 0x%x%s], severity = 0x%x, message = %s backtrace:" ), type,
303 typestr, severity, message );
304 debug_logBacktrace();
305}
306#endif /* DEBUG_GL */
307#endif /* DEBUGGING */
308
314static int gl_setupAttributes( int fallback )
315{
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,
321 1 ); /* Ideally want double buffering. */
322 if ( conf.fsaa > 1 ) {
323 SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 );
324 SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, conf.fsaa );
325 }
326 SDL_GL_SetAttribute( SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1 );
327#if DEBUG_GL
328 SDL_GL_SetAttribute( SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG );
329#endif /* DEBUG_GL */
330
331 return 0;
332}
333
341{
342 int ok;
343 int display_index = SDL_GetWindowDisplayIndex( gl_screen.window );
344 if ( conf.fullscreen && conf.modesetting ) {
345 SDL_DisplayMode target, closest;
346 /* Try to use desktop resolution if nothing is specifically set. */
347 if ( conf.explicit_dim ) {
348 SDL_GetWindowDisplayMode( gl_screen.window, &target );
349 target.w = conf.width;
350 target.h = conf.height;
351 } else
352 SDL_GetDesktopDisplayMode( display_index, &target );
353
354 if ( SDL_GetClosestDisplayMode( display_index, &target, &closest ) ==
355 NULL )
356 SDL_GetDisplayMode( display_index, 0,
357 &closest ); /* fall back to the best one */
358
359 SDL_SetWindowDisplayMode( gl_screen.window, &closest );
360 }
361 ok = SDL_SetWindowFullscreen( gl_screen.window, gl_getFullscreenMode() );
362 /* HACK: Force pending resize events to be processed, particularly on
363 * Wayland. */
364 SDL_PumpEvents();
365 SDL_GL_SwapWindow( gl_screen.window );
366 SDL_GL_SwapWindow( gl_screen.window );
367 return ok;
368}
369
375static int gl_getFullscreenMode( void )
376{
377 if ( conf.fullscreen )
378 return conf.modesetting ? SDL_WINDOW_FULLSCREEN
379 : SDL_WINDOW_FULLSCREEN_DESKTOP;
380 return 0;
381}
382
388static int gl_createWindow( unsigned int flags )
389{
390 flags |= SDL_WINDOW_ALLOW_HIGHDPI;
391 if ( !conf.notresizable )
392 flags |= SDL_WINDOW_RESIZABLE;
393 if ( conf.borderless )
394 flags |= SDL_WINDOW_BORDERLESS;
395
396 /* Create the window. */
397 gl_screen.window =
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 );
401 if ( gl_screen.window == NULL ) {
402 char buf[STRMAX];
403 snprintf( buf, sizeof( buf ), _( "Unable to create window! %s" ),
404 SDL_GetError() );
405#if SDL_VERSION_ATLEAST( 3, 0, 0 )
406 SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR,
407 _( "Naev Critical Error" ), buf,
408 gl_screen.window );
409#endif /* SDL_VERSION_ATLEAST( 3, 0, 0 ) */
410 ERR( "%s", buf );
411 }
412
413 /* We want to enforce minimum window size or a ton of things break. */
414 SDL_SetWindowMinimumSize( gl_screen.window, RESOLUTION_W_MIN,
415 RESOLUTION_H_MIN );
416
417 /* Set focus loss behaviour. */
418 SDL_SetHint( SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS,
419 conf.minimize ? "1" : "0" );
420
421 /* Create the OpenGL context, note we don't need an actual renderer. */
422 for ( int fallback = 0; fallback <= 1; fallback++ ) {
423 gl_setupAttributes( fallback );
424 gl_screen.context = SDL_GL_CreateContext( gl_screen.window );
425 if ( gl_screen.context != NULL )
426 break;
427 }
428 if ( !gl_screen.context ) {
429 char buf[STRMAX];
430 snprintf( buf, sizeof( buf ), _( "Unable to create OpenGL context! %s" ),
431 SDL_GetError() );
432#if SDL_VERSION_ATLEAST( 3, 0, 0 )
433 SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR,
434 _( "Naev Critical Error" ), buf,
435 gl_screen.window );
436#endif /* SDL_VERSION_ATLEAST( 3, 0, 0 ) */
437 ERR( "%s", buf );
438 }
439
440 /* Save and store version. */
441 SDL_GL_GetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, &gl_screen.major );
442 SDL_GL_GetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, &gl_screen.minor );
443 if ( gl_screen.major * 100 + gl_screen.minor * 10 > 320 )
444 gl_screen.glsl = 100 * gl_screen.major + 10 * gl_screen.minor;
445 else
446 gl_screen.glsl = 150;
447
448 /* Set Vsync. */
449 if ( conf.vsync ) {
450 int ret = SDL_GL_SetSwapInterval( 1 );
451 if ( ret == 0 )
452 gl_screen.flags |= OPENGL_VSYNC;
453 } else {
454 SDL_GL_SetSwapInterval( 0 );
455 }
456
457 /* Finish getting attributes. */
458 gl_screen.current_fbo = 0; /* No FBO set. */
459 for ( int i = 0; i < OPENGL_NUM_FBOS; i++ ) {
460 gl_screen.fbo[i] = GL_INVALID_VALUE;
461 gl_screen.fbo_tex[i] = GL_INVALID_VALUE;
462 }
463 SDL_GL_GetAttribute( SDL_GL_DEPTH_SIZE, &gl_screen.depth );
464 int srgb_capable;
465 SDL_GL_GetAttribute( SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, &srgb_capable );
466 if ( !srgb_capable )
467 WARN( _( "Unable to set framebuffer to SRGB!" ) );
468 gl_activated = 1; /* Opengl is now activated. */
469
470 return 0;
471}
472
478static int gl_getGLInfo( void )
479{
480 int doublebuf;
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 );
487 if ( doublebuf )
488 gl_screen.flags |= OPENGL_DOUBLEBUF;
489 if ( GLAD_GL_ARB_shader_subroutine && glGetSubroutineIndex &&
490 glGetSubroutineUniformLocation && glUniformSubroutinesuiv )
491 gl_screen.flags |= OPENGL_SUBROUTINES;
492 /* Calculate real depth. */
493 gl_screen.depth = gl_screen.r + gl_screen.g + gl_screen.b + gl_screen.a;
494
495 /* Texture information */
496 glGetIntegerv( GL_MAX_TEXTURE_SIZE, &gl_screen.tex_max );
497 glGetIntegerv( GL_MAX_TEXTURE_IMAGE_UNITS, &gl_screen.multitex_max );
498
499 /* Debug happiness */
500 DEBUG( _( "OpenGL Drawable Created: %dx%d@%dbpp" ), gl_screen.rw,
501 gl_screen.rh, gl_screen.depth );
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,
505 gl_screen.tex_max );
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 ) );
510
511 /* Now check for things that can be bad. */
512 if ( ( conf.fsaa > 1 ) && ( gl_screen.fsaa != conf.fsaa ) )
513 WARN( _( "Unable to get requested FSAA level (%d requested, got %d)" ),
514 conf.fsaa, gl_screen.fsaa );
515
516 return 0;
517}
518
524static int gl_defState( void )
525{
526 glDisable( GL_DEPTH_TEST ); /* set for doing 2d */
527 glEnable( GL_BLEND ); /* alpha blending ftw */
528 glEnable(
529 GL_LINE_SMOOTH ); /* We use SDF shaders for most shapes, but star trails &
530 map routes are thin & anti-aliased. */
531#if DEBUG_GL
532 glEnable( GL_DEBUG_OUTPUT ); /* Log errors immediately.. */
533 glDebugMessageCallback( gl_debugCallback, 0 );
534 glDebugMessageControl( GL_DONT_CARE, GL_DEBUG_TYPE_PERFORMANCE, GL_DONT_CARE,
535 0, NULL, GL_FALSE );
536 glDebugMessageControl( GL_DONT_CARE, GL_DEBUG_TYPE_OTHER, GL_DONT_CARE, 0,
537 NULL, GL_FALSE );
538#endif /* DEBUG_GL */
539
540 /* Set the blending/shading model to use. */
541 glBlendEquation( GL_FUNC_ADD );
542 glBlendFuncSeparate( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE,
543 GL_ONE_MINUS_SRC_ALPHA );
544
545 return 0;
546}
547
553static int gl_setupScaling( void )
554{
555 /* Get the basic dimensions from SDL2. */
556 SDL_GetWindowSize( gl_screen.window, &gl_screen.w, &gl_screen.h );
557 SDL_GL_GetDrawableSize( gl_screen.window, &gl_screen.rw, &gl_screen.rh );
558 /* Calculate scale factor, if OS has native HiDPI scaling. */
559 gl_screen.dwscale = (double)gl_screen.w / (double)gl_screen.rw;
560 gl_screen.dhscale = (double)gl_screen.h / (double)gl_screen.rh;
561
562 /* Combine scale factor from OS with the one in Naev's config */
563 gl_screen.scale =
564 fmax( gl_screen.dwscale, gl_screen.dhscale ) / conf.scalefactor;
565 glLineWidth( 1. / gl_screen.scale );
566 glPointSize( 1. / gl_screen.scale + 2.0 );
567
568 /* New window is real window scaled. */
569 gl_screen.nw = (double)gl_screen.rw * gl_screen.scale;
570 gl_screen.nh = (double)gl_screen.rh * gl_screen.scale;
571 /* Small windows get handled here. */
572 if ( ( gl_screen.nw < RESOLUTION_W_MIN ) ||
573 ( gl_screen.nh < RESOLUTION_H_MIN ) ) {
574 double scalew, scaleh;
575 if ( gl_screen.scale != 1. )
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;
579 gl_screen.scale *= MAX( scalew, scaleh );
580 /* Rescale. */
581 gl_screen.nw = (double)gl_screen.rw * gl_screen.scale;
582 gl_screen.nh = (double)gl_screen.rh * gl_screen.scale;
583 }
584 /* Viewport matches new window size. */
585 gl_screen.w = gl_screen.nw;
586 gl_screen.h = gl_screen.nh;
587 /* Set scale factors. */
588 gl_screen.wscale = (double)gl_screen.nw / (double)gl_screen.w;
589 gl_screen.hscale = (double)gl_screen.nh / (double)gl_screen.h;
590 gl_screen.mxscale = (double)gl_screen.w / (double)gl_screen.rw;
591 gl_screen.myscale = (double)gl_screen.h / (double)gl_screen.rh;
592
593 return 0;
594}
595
600int gl_init( unsigned int extra_flags )
601{
602 unsigned int flags;
603 GLuint VaoId;
604
605 /* Apply driver hacks and workarounds before we initialize the window. */
607
608 /* Defaults. */
609 memset( &gl_screen, 0, sizeof( gl_screen ) );
610 SDL_SetHint( "SDL_WINDOWS_DPI_SCALING", "1" );
611 flags = SDL_WINDOW_OPENGL | gl_getFullscreenMode() | extra_flags;
612
613 /* Initializes Video */
614 if ( SDL_InitSubSystem( SDL_INIT_VIDEO ) < 0 ) {
615 WARN( _( "Unable to initialize SDL Video: %s" ), SDL_GetError() );
616 return -1;
617 }
618
619 /* Create the window. */
620 gl_createWindow( flags );
621
622 /* Apply the configured fullscreen display mode, if any. */
624
625 /* Load extensions. */
626 if ( !gladLoadGLLoader( SDL_GL_GetProcAddress ) ) {
627 char buf[STRMAX];
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,
632 gl_screen.window );
633#endif /* SDL_VERSION_ATLEAST( 3, 0, 0 ) */
634 ERR( "%s", buf );
635 }
636
637 /* We are interested in 3.1 because it drops all the deprecated stuff. */
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 );
641
642 /* Some OpenGL options. */
643 glClearColor( 0., 0., 0., 0. );
644
645 /* Set default opengl state. */
646 gl_defState();
647
648 /* Handles resetting the viewport and scaling, rw/rh are set in createWindow.
649 */
650 gl_resize();
651
652 /* Finishing touches. */
653 glClear( GL_COLOR_BUFFER_BIT |
654 GL_DEPTH_BUFFER_BIT ); /* must clear the buffer first */
655 gl_checkErr();
656
657 /* Initialize subsystems.*/
659 gl_initVBO();
661
662 /* Get info about the OpenGL window */
663 gl_getGLInfo();
664
665 /* Modern OpenGL requires at least one VAO */
666 glGenVertexArrays( 1, &VaoId );
667 glBindVertexArray( VaoId );
668
669 shaders_load();
670
671 /* Set colourblind shader if necessary. */
673
674 /* Set colourspace. */
675 glEnable( GL_FRAMEBUFFER_SRGB );
676
677 /* Load the gltf framework. */
678 gltf_init();
679
680 /* Cosmetic new line. */
681 DEBUG_BLANK();
682
683 return 0;
684}
685
689void gl_resize( void )
690{
692 glViewport( 0, 0, gl_screen.rw, gl_screen.rh );
693 gl_setDefViewport( 0, 0, gl_screen.nw, gl_screen.nh );
695
696 /* Set up framebuffer. */
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] );
702 }
703 gl_fboCreate( &gl_screen.fbo[i], &gl_screen.fbo_tex[i], gl_screen.rw,
704 gl_screen.rh );
705 gl_fboAddDepth( gl_screen.fbo[i], &gl_screen.fbo_depth_tex[i],
706 gl_screen.rw, gl_screen.rh );
707 }
708
709 gl_checkErr();
710}
711
715void gl_viewport( int x, int y, int w, int h )
716{
717 mat4 proj = mat4_ortho( 0., /* Left edge. */
718 gl_screen.nw, /* Right edge. */
719 0., /* Bottom edge. */
720 gl_screen.nh, /* Top edge. */
721 -1., /* near */
722 1. ); /* far */
723
724 /* Take into account possible translation. */
725 gl_screen.x = x;
726 gl_screen.y = y;
727 mat4_translate_xy( &proj, x, y );
728
729 /* Set screen size. */
730 gl_screen.w = w;
731 gl_screen.h = h;
732
733 /* Take into account possible scaling. */
734 if ( gl_screen.scale != 1. )
735 mat4_scale( &proj, gl_screen.wscale, gl_screen.hscale, 1. );
736
737 gl_view_matrix = proj;
738}
739
743void gl_setDefViewport( int x, int y, int w, int h )
744{
745 gl_view_x = x;
746 gl_view_y = y;
747 gl_view_w = w;
748 gl_view_h = h;
749}
750
754void gl_defViewport( void )
755{
756 gl_viewport( gl_view_x, gl_view_y, gl_view_w, gl_view_h );
757}
758
762void gl_windowToScreenPos( int *sx, int *sy, int wx, int wy )
763{
764 wx /= gl_screen.dwscale;
765 wy /= gl_screen.dhscale;
766
767 *sx = gl_screen.mxscale * (double)wx - (double)gl_screen.x;
768 *sy =
769 gl_screen.myscale * (double)( gl_screen.rh - wy ) - (double)gl_screen.y;
770}
771
775void gl_screenToWindowPos( int *wx, int *wy, int sx, int sy )
776{
777 *wx = ( sx + (double)gl_screen.x ) / gl_screen.mxscale;
778 *wy =
779 (double)gl_screen.rh - ( sy + (double)gl_screen.y ) / gl_screen.myscale;
780
781 *wx *= gl_screen.dwscale;
782 *wy *= gl_screen.dhscale;
783}
784
791GLenum gl_stringToFilter( const char *s )
792{
793 if ( strcasecmp( s, "linear" ) == 0 )
794 return GL_LINEAR;
795 else if ( strcasecmp( s, "nearest" ) == 0 )
796 return GL_NEAREST;
797 WARN( _( "Unknown %s '%s'!" ), "OpenGL Filter", s );
798 return 0;
799}
800
807GLenum gl_stringToClamp( const char *s )
808{
809 if ( strcasecmp( s, "clamp" ) == 0 )
810 return GL_CLAMP_TO_EDGE;
811 else if ( strcasecmp( s, "repeat" ) == 0 )
812 return GL_REPEAT;
813 else if ( strcasecmp( s, "mirroredrepeat" ) == 0 )
814 return GL_MIRRORED_REPEAT;
815 WARN( _( "Unknown %s '%s'!" ), "OpenGL Clamp", s );
816 return 0;
817}
818
825GLenum gl_stringToBlendFunc( const char *s )
826{
827 if ( strcasecmp( s, "add" ) == 0 )
828 return GL_FUNC_ADD;
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 )
834 return GL_MIN;
835 else if ( strcasecmp( s, "max" ) == 0 )
836 return GL_MAX;
837 WARN( _( "Unknown %s '%s'!" ), "OpenGL BlendFunc", s );
838 return 0;
839}
840
847GLenum gl_stringToBlendFactor( const char *s )
848{
849 if ( strcasecmp( s, "zero" ) == 0 )
850 return GL_ZERO;
851 else if ( strcasecmp( s, "one" ) == 0 )
852 return GL_ONE;
853 else if ( strcasecmp( s, "src_color" ) == 0 )
854 return GL_SRC_COLOR;
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 )
858 return GL_SRC_ALPHA;
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 )
862 return GL_DST_COLOR;
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 )
866 return GL_DST_ALPHA;
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 );
872 return 0;
873}
874
878void gl_colourblind( void )
879{
880 /* Load up shader uniforms. */
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 );
888 glUseProgram( 0 );
889
890 /* See if we have to correct. */
891 if ( conf.colourblind_sim > 0. ) {
892 LuaShader_t shader;
893 if ( cb_simulate_pp != 0 )
894 return;
895 memset( &shader, 0, sizeof( LuaShader_t ) );
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 );
902 } else {
903 if ( cb_simulate_pp != 0 )
904 render_postprocessRm( cb_simulate_pp );
905 cb_simulate_pp = 0;
906 }
907
908 /* See if we have to correct. */
909 if ( conf.colourblind_correct > 0. ) {
910 LuaShader_t shader;
911 if ( cb_correct_pp != 0 )
912 return;
913 memset( &shader, 0, sizeof( LuaShader_t ) );
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 );
921 } else {
922 if ( cb_correct_pp != 0 )
923 render_postprocessRm( cb_correct_pp );
924 cb_correct_pp = 0;
925 }
926}
927
931void gl_exit( void )
932{
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] );
938 gl_screen.fbo[i] = GL_INVALID_VALUE;
939 gl_screen.fbo_tex[i] = GL_INVALID_VALUE;
940 gl_screen.fbo_depth_tex[i] = GL_INVALID_VALUE;
941 }
942 }
943
944 /* Exit the OpenGL subsystems. */
945 gltf_exit();
947 gl_exitVBO();
949
950 shaders_unload();
951
952 /* Shut down the subsystem */
953 SDL_QuitSubSystem( SDL_INIT_VIDEO );
954}
void mat4_scale(mat4 *m, double x, double y, double z)
Scales a homogeneous transformation matrix.
Definition mat4.c:113
mat4 mat4_ortho(double left, double right, double bottom, double top, double nearVal, double farVal)
Creates an orthographic projection matrix.
Definition mat4.c:347
Header file with generic functions and naev-specifics.
#define APPNAME
Definition naev.h:30
#define MAX(x, y)
Definition naev.h:37
void gl_setDefViewport(int x, int y, int w, int h)
Sets the default viewport.
Definition opengl.c:743
static void gl_applyFixes(void)
Applies driver-specific fixes and workarounds before initializing OpenGL.
Definition opengl.c:82
void gl_screenshot(const char *filename)
Takes a screenshot.
Definition opengl.c:106
static int gl_defState(void)
Sets the opengl state to its default parameters.
Definition opengl.c:524
static unsigned int cb_correct_pp
Definition opengl.c:53
static int gl_getGLInfo(void)
Gets some information about the OpenGL window.
Definition opengl.c:478
void gl_defViewport(void)
Resets viewport to default.
Definition opengl.c:754
void gl_colourblind(void)
Enables or disables the colourblind shader.
Definition opengl.c:878
GLenum gl_stringToBlendFactor(const char *s)
Gets a blend factor from a string.
Definition opengl.c:847
void gl_resize(void)
Handles a window resize and resets gl_screen parameters.
Definition opengl.c:689
void gl_screenToWindowPos(int *wx, int *wy, int sx, int sy)
Translates the screen position to windos position.
Definition opengl.c:775
void gl_exit(void)
Cleans up OpenGL, the works.
Definition opengl.c:931
void gl_viewport(int x, int y, int w, int h)
Sets the opengl viewport.
Definition opengl.c:715
static int gl_activated
Definition opengl.c:51
int gl_init(unsigned int extra_flags)
Initializes SDL/OpenGL and the works.
Definition opengl.c:600
void gl_windowToScreenPos(int *sx, int *sy, int wx, int wy)
Translates the window position to screen position.
Definition opengl.c:762
static int gl_getFullscreenMode(void)
Returns the fullscreen configuration as SDL2 flags.
Definition opengl.c:375
GLenum gl_stringToBlendFunc(const char *s)
Gets a blend function from a string.
Definition opengl.c:825
static int gl_setupAttributes(int fallback)
Tries to set up the OpenGL attributes for the OpenGL context.
Definition opengl.c:314
static int gl_setupScaling(void)
Sets up dimensions in gl_screen, including scaling as needed.
Definition opengl.c:553
static int gl_createWindow(unsigned int flags)
Creates the OpenGL window.
Definition opengl.c:388
GLenum gl_stringToFilter(const char *s)
Gets the associated min/mag filter from a string.
Definition opengl.c:791
GLboolean gl_hasVersion(int major, int minor)
Checks to see if opengl version is at least major.minor.
Definition opengl.c:205
glInfo gl_screen
Definition opengl.c:47
static unsigned int cb_simulate_pp
Definition opengl.c:55
GLenum gl_stringToClamp(const char *s)
Gets the associated min/mag filter from a string.
Definition opengl.c:807
int gl_setupFullscreen(void)
Tries to apply the configured display mode to the window.
Definition opengl.c:340
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.
Definition opengl_tex.c:268
int gl_fboAddDepth(GLuint fbo, GLuint *tex, GLsizei width, GLsizei height)
Adds a depth attachment to an FBO.
Definition opengl_tex.c:313
int gl_initTextures(void)
Initializes the opengl texture subsystem.
int gl_initVBO(void)
Initializes the OpenGL VBO subsystem.
Definition opengl_vbo.c:45
void gl_exitVBO(void)
Exits the OpenGL VBO subsystem.
Definition opengl_vbo.c:53
static const double d[]
Definition rng.c:263
Stores data about the current opengl environment.
Definition opengl.h:37
Definition mat4.h:12