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 }