medfall

A super great game engine
Log | Files | Refs

gl.cc (7862B)


      1 #include <stdlib.h>
      2 #include <string.h>
      3 
      4 #include "game.h"
      5 #include "log.h"
      6 #include "gl.h"
      7 
      8 #include "glad.h"
      9 
     10 #define GLFW_INCLUDE_NONE
     11 #include "libs/glfw/include/GLFW/glfw3.h"
     12 
     13 #define RESET "\x1b[0m"
     14 #define RED "\x1b[1;31m"
     15 #define YELLOW "\x1b[1;32m"
     16 #define GREEN "\x1b[1;33m"
     17 
     18 static v2u32 window_size;
     19 
     20 static const char * type_string( GLenum type ) {
     21 	switch( type ) {
     22 		case GL_DEBUG_TYPE_ERROR:
     23 		case GL_DEBUG_CATEGORY_API_ERROR_AMD:
     24 			return "error";
     25 		case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
     26 		case GL_DEBUG_CATEGORY_DEPRECATION_AMD:
     27 			return "deprecated";
     28 		case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
     29 		case GL_DEBUG_CATEGORY_UNDEFINED_BEHAVIOR_AMD:
     30 			return "undefined";
     31 		case GL_DEBUG_TYPE_PORTABILITY:
     32 			return "nonportable";
     33 		case GL_DEBUG_TYPE_PERFORMANCE:
     34 		case GL_DEBUG_CATEGORY_PERFORMANCE_AMD:
     35 			return "performance";
     36 		case GL_DEBUG_CATEGORY_WINDOW_SYSTEM_AMD:
     37 			return "window system";
     38 		case GL_DEBUG_CATEGORY_SHADER_COMPILER_AMD:
     39 			return "shader compiler";
     40 		case GL_DEBUG_CATEGORY_APPLICATION_AMD:
     41 			return "application";
     42 		case GL_DEBUG_TYPE_OTHER:
     43 		case GL_DEBUG_CATEGORY_OTHER_AMD:
     44 			return "other";
     45 		default:
     46 			return "idk";
     47 	}
     48 }
     49 
     50 static const char * severity_string( GLenum severity ) {
     51 	switch( severity ) {
     52 		case GL_DEBUG_SEVERITY_LOW:
     53 		// case GL_DEBUG_SEVERITY_LOW_AMD:
     54 			return GREEN "low" RESET;
     55 		case GL_DEBUG_SEVERITY_MEDIUM:
     56 		// case GL_DEBUG_SEVERITY_MEDIUM_AMD:
     57 			return YELLOW "medium" RESET;
     58 		case GL_DEBUG_SEVERITY_HIGH:
     59 		// case GL_DEBUG_SEVERITY_HIGH_AMD:
     60 			return RED "high" RESET;
     61 		case GL_DEBUG_SEVERITY_NOTIFICATION:
     62 			return "notice";
     63 		default:
     64 			return "idk";
     65 	}
     66 }
     67 
     68 static void gl_debug_output_callback(
     69 	GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
     70 	const GLchar * message, const void * _
     71 ) {
     72 	if(
     73 	    source == 33352 || // shader compliation errors
     74 	    id == 131169 ||
     75 	    id == 131185 ||
     76 	    id == 131218 ||
     77 	    id == 131204
     78 	) {
     79 		return;
     80 	}
     81 
     82 	if( severity == GL_DEBUG_SEVERITY_NOTIFICATION || severity == GL_DEBUG_SEVERITY_NOTIFICATION_KHR ) {
     83 		return;
     84 	}
     85 
     86 	// remove trailing \n if there is one
     87 	str< 1024 > buf;
     88 	buf += message;
     89 	if( buf.len() > 0 && buf[ buf.len() - 1 ] == '\n' ) {
     90 		buf.truncate( buf.len() - 1 );
     91 	}
     92 
     93 	WARN( "GL {} [{} - {}]: {}",
     94 		source,
     95 		type_string( type ),
     96 		severity_string( severity ),
     97 		buf );
     98 
     99 	if( severity == GL_DEBUG_SEVERITY_HIGH ) {
    100 		ASSERT( 0 );
    101 	}
    102 }
    103 
    104 static void gl_debug_output_callback_amd(
    105 	GLuint id, GLenum type, GLenum severity, GLsizei length,
    106 	const GLchar * message, const void * _
    107 ) {
    108 	gl_debug_output_callback( GL_DONT_CARE, type, id, severity, length, message, _ );
    109 }
    110 
    111 static void glfw_error_callback( int code, const char * message ) {
    112 	WARN( "GLFW error {}: {}", code, message );
    113 }
    114 
    115 static void glfw_focus_callback( GLFWwindow * window, int focused ) {
    116 	if( focused == GLFW_TRUE ) {
    117 		glfwSetCursorPos( window, window_size.x / 2, window_size.y / 2 );
    118 	}
    119 }
    120 
    121 static void glfw_resize_callback( GLFWwindow * window, int w, int h ) {
    122 	window_size.x = checked_cast< u32 >( w );
    123 	window_size.y = checked_cast< u32 >( h );
    124 }
    125 
    126 GLFWwindow * gl_init( WindowType window_type ) {
    127 	glfwSetErrorCallback( glfw_error_callback );
    128 
    129 	if( !glfwInit() ) {
    130 		FATAL( "glfwInit" );
    131 	}
    132 
    133 #if RELEASE_BUILD
    134 	if( window_type == WINDOW_LAUNCHER ) {
    135 		glfwWindowHint( GLFW_RESIZABLE, 0 );
    136 	}
    137 #else
    138 	glfwWindowHint( GLFW_RESIZABLE, 0 );
    139 #endif
    140 
    141 	int width = 800;
    142 	int height = 265;
    143 
    144 	GLFWmonitor * monitor = glfwGetPrimaryMonitor();
    145 	const GLFWvidmode * mode = glfwGetVideoMode( monitor );
    146 
    147 	if( window_type == WINDOW_GAME ) {
    148 // #if RELEASE_BUILD
    149 // 		width = mode->width;
    150 // 		height = mode->height;
    151 // #else
    152 		width = mode->width * 3 / 4;
    153 		height = mode->height * 3 / 4;
    154 // #endif
    155 	}
    156 
    157 	glfwWindowHint( GLFW_CLIENT_API, GLFW_OPENGL_API );
    158 	glfwWindowHint( GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE );
    159 	glfwWindowHint( GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE );
    160 	glfwWindowHint( GLFW_CONTEXT_VERSION_MAJOR, 3 );
    161 	glfwWindowHint( GLFW_CONTEXT_VERSION_MINOR, 3 );
    162 #if !RELEASE_BUILD
    163 	glfwWindowHint( GLFW_OPENGL_DEBUG_CONTEXT, 1 );
    164 #endif
    165 
    166 // #if RELEASE_BUILD
    167 // 	GLFWmonitor * window_monitor = window_type == WINDOW_GAME ? monitor : NULL;
    168 // #else
    169 	GLFWmonitor * window_monitor = NULL;
    170 // #endif
    171 
    172 	GLFWwindow * window = glfwCreateWindow( width, height, "Medfall", window_monitor, NULL );
    173 	if( !window ) {
    174 		FATAL( "glfwCreateWindow" );
    175 	}
    176 
    177 	int frame_top, frame_bottom, frame_left, frame_right;
    178 	glfwGetWindowFrameSize( window, &frame_left, &frame_top, &frame_right, &frame_bottom );
    179 
    180 	int monitor_top, monitor_left;
    181 	glfwGetMonitorPos( monitor, &monitor_left, &monitor_top );
    182 
    183 	int total_width = width + frame_left + frame_right;
    184 	int total_height = height + frame_top + frame_bottom;
    185 
    186 	glfwSetWindowPos( window,
    187 		monitor_left + mode->width / 2 - total_width / 2,
    188 		monitor_top + mode->height / 2 - total_height / 2 );
    189 
    190 	window_size = v2u32( checked_cast< u32 >( width ), checked_cast< u32 >( height ) );
    191 
    192 #if RELEASE_BUILD
    193 	if( window_type == WINDOW_GAME ) {
    194 		glfwSetCursorPos( window, width / 2, height / 2 );
    195 		glfwSetWindowFocusCallback( window, glfw_focus_callback );
    196 	}
    197 #endif
    198 
    199 	glfwSetFramebufferSizeCallback( window, glfw_resize_callback );
    200 
    201 	glfwMakeContextCurrent( window );
    202 
    203 	if( gladLoadGLLoader( ( GLADloadproc ) glfwGetProcAddress ) != 1 ) {
    204 		FATAL( "gladLoadGL" );
    205 	}
    206 
    207 	struct {
    208 		const char * name;
    209 		int enabled;
    210 	} exts[] = {
    211 #if !RELEASE_BUILD
    212 		{ "KHR_debug", GLAD_GL_KHR_debug },
    213 		{ "AMD_debug_output", GLAD_GL_AMD_debug_output },
    214 #endif
    215 		{ "EXT_texture_sRGB", GLAD_GL_EXT_texture_sRGB },
    216 		{ "EXT_texture_sRGB_decode", GLAD_GL_EXT_texture_sRGB_decode },
    217 		{ "EXT_texture_compression_s3tc", GLAD_GL_EXT_texture_compression_s3tc },
    218 	};
    219 
    220 	const char * vendor = ( const char * ) glGetString( GL_VENDOR );
    221 	const char * version = ( const char * ) glGetString( GL_VERSION );
    222 	INFO( "Version {}", version );
    223 	INFO( "Vendor {}", vendor );
    224 
    225 	INFO( "OpenGL extensions:" );
    226 	for( size_t i = 0; i < ARRAY_COUNT( exts ); i++ ) {
    227 		INFO( "{}: {}", exts[ i ].name, exts[ i ].enabled == 0 ? "missing" : "present" );
    228 	}
    229 
    230 #if !RELEASE_BUILD
    231 	bool nvidia_and_windows = false;
    232 #if PLATFORM_WINDOWS
    233 	if( strstr( vendor, "NVIDIA" ) ) {
    234 		nvidia_and_windows = true;
    235 	}
    236 #endif
    237 
    238 	if( GLAD_GL_KHR_debug != 0 && !nvidia_and_windows ) {
    239 		GLint context_flags;
    240 		glGetIntegerv( GL_CONTEXT_FLAGS, &context_flags );
    241 		if( context_flags & GL_CONTEXT_FLAG_DEBUG_BIT ) {
    242 			INFO( "Initialising debug output" );
    243 
    244 			glEnable( GL_DEBUG_OUTPUT );
    245 			glEnable( GL_DEBUG_OUTPUT_SYNCHRONOUS );
    246 			glDebugMessageCallback( ( GLDEBUGPROC ) gl_debug_output_callback, NULL );
    247 			glDebugMessageControl( GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, NULL, GL_TRUE );
    248 		}
    249 	}
    250 	else if( GLAD_GL_AMD_debug_output != 0 ) {
    251 		INFO( "Initialising AMD debug output" );
    252 
    253 		glDebugMessageCallbackAMD( ( GLDEBUGPROCAMD ) gl_debug_output_callback_amd, NULL );
    254 		glDebugMessageEnableAMD( 0, 0, 0, NULL, GL_TRUE );
    255 	}
    256 #endif
    257 
    258 	glEnable( GL_DEPTH_TEST );
    259 	glDepthFunc( GL_LESS );
    260 
    261 	glEnable( GL_CULL_FACE );
    262 	glCullFace( GL_BACK );
    263 
    264 	return window;
    265 }
    266 
    267 // https://gist.github.com/rygorous/9559632
    268 static void gl_check_for_leaks() {
    269 	GLuint max_id = 10000; // better idea would be to keep track of assigned names.
    270 
    271 	// if brute force doesn't work, you're not applying it hard enough
    272 	for( GLuint id = 1 ; id <= max_id ; id++ ) {
    273 #define CHECK( type ) if ( glIs##type( id ) ) fprintf( stderr, "GLX: leaked " #type " handle 0x%x\n", (unsigned int) id )
    274 		CHECK( Texture );
    275 		CHECK( Buffer );
    276 		CHECK( Framebuffer );
    277 		CHECK( Renderbuffer );
    278 		CHECK( VertexArray );
    279 		CHECK( Shader );
    280 		CHECK( Program );
    281 		// CHECK( ProgramPipeline );
    282 #undef CHECK
    283 	}
    284 }
    285 
    286 void gl_term() {
    287 	// gl_check_for_leaks();
    288 	glfwTerminate();
    289 }
    290 
    291 v2u32 get_window_size() {
    292 	return window_size;
    293 }
    294 
    295 float get_aspect_ratio() {
    296 	return float( window_size.x ) / float( window_size.y );
    297 }