diff --git a/Framework/Platform.cs b/Framework/Platform.cs index 63a6fb8..b872f35 100644 --- a/Framework/Platform.cs +++ b/Framework/Platform.cs @@ -33,7 +33,7 @@ public enum FosterEventType : int } [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate void FosterLogFn(IntPtr msg); + public delegate void FosterLogFn(IntPtr msg, int type); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void FosterWriteFn(IntPtr context, IntPtr data, int size); @@ -191,21 +191,29 @@ public static void FreeUTF8(IntPtr ptr) Marshal.FreeHGlobal(ptr); } + private static void HandleLog(IntPtr msg, int type) + { + switch (type) + { + case 0: Log.Info(msg); break; + case 1: Log.Warning(msg); break; + case 2: Log.Error(msg); break; + default: Log.Info(msg); break; + } + } + // need to store static references otherwise the delegates will get collected - private static readonly FosterLogFn logInfo = Log.Info; - private static readonly FosterLogFn logWarn = Log.Warning; - private static readonly FosterLogFn logErr = Log.Error; + private static readonly FosterLogFn handleLog = HandleLog; static Platform() { - // initialize logging immediately - FosterRegisterLogMethods(logInfo, logWarn, logErr, 0); + FosterSetLogCallback(handleLog, 0); } [DllImport(DLL)] public static extern void FosterStartup(FosterDesc desc); [DllImport(DLL)] - public static extern void FosterRegisterLogMethods(FosterLogFn info, FosterLogFn warn, FosterLogFn error, int level); + public static extern void FosterSetLogCallback(FosterLogFn logFn, int level); [DllImport(DLL)] public static extern void FosterBeginFrame(); [DllImport(DLL)] diff --git a/Framework/Utility/Log.cs b/Framework/Utility/Log.cs index 84a25b6..51e6bcc 100644 --- a/Framework/Utility/Log.cs +++ b/Framework/Utility/Log.cs @@ -4,9 +4,14 @@ namespace Foster.Framework; public static class Log { + public delegate void LogFn(ReadOnlySpan text); + + // TODO: this can potentially be written to from other threads + // The user shouldn't have access to this directly as they need to lock + // around it. Instead there should be some safe way to iterate over it or + // request lines from it. Ideally without creating tons of garbage. public static readonly StringBuilder Logs = new(); - public delegate void LogFn(ReadOnlySpan text); public static LogFn? OnInfo; public static LogFn? OnWarn; public static LogFn? OnError; diff --git a/Platform/include/foster_platform.h b/Platform/include/foster_platform.h index c79ec8f..69bb6c2 100644 --- a/Platform/include/foster_platform.h +++ b/Platform/include/foster_platform.h @@ -387,12 +387,19 @@ typedef enum FosterIndexFormat FOSTER_INDEX_FORMAT_THIRTY_TWO } FosterIndexFormat; -typedef enum FosterLogging +typedef enum FosterLogLevel { - FOSTER_LOGGING_DEFAULT, - FOSTER_LOGGING_ALL, - FOSTER_LOGGING_NONE -} FosterLogging; + FOSTER_LOG_LEVEL_INFO, + FOSTER_LOG_LEVEL_WARNING, + FOSTER_LOG_LEVEL_ERROR +} FosterLogLevel; + +typedef enum FosterLogFilter +{ + FOSTER_LOG_FILTER_DEFAULT, + FOSTER_LOG_FILTER_VERBOSE, + FOSTER_LOG_FILTER_IGNORE_ALL +} FosterLogFilter; typedef enum FosterImageWriteFormat { @@ -415,7 +422,7 @@ typedef enum FosterEventType FOSTER_EVENT_TYPE_CONTROLLER_AXIS, } FosterEventType; -typedef void (FOSTER_CALL * FosterLogFn)(const char *msg); +typedef void (FOSTER_CALL * FosterLogFn)(const char *msg, FosterLogLevel level); typedef void (FOSTER_CALL * FosterWriteFn)(void *context, void *data, int size); typedef struct FosterTexture FosterTexture; @@ -566,7 +573,7 @@ extern "C" { FOSTER_API void FosterStartup(FosterDesc desc); -FOSTER_API void FosterRegisterLogMethods(FosterLogFn logInfo, FosterLogFn logWarn, FosterLogFn logErr, FosterLogging level); +FOSTER_API void FosterSetLogCallback(FosterLogFn logFn, FosterLogFilter filter); FOSTER_API void FosterBeginFrame(); diff --git a/Platform/libs/lib64/libFosterPlatform.so b/Platform/libs/lib64/libFosterPlatform.so index 0ad3d52..a5efe72 100755 Binary files a/Platform/libs/lib64/libFosterPlatform.so and b/Platform/libs/lib64/libFosterPlatform.so differ diff --git a/Platform/src/foster_internal.h b/Platform/src/foster_internal.h index 98a34d9..3caff01 100644 --- a/Platform/src/foster_internal.h +++ b/Platform/src/foster_internal.h @@ -5,6 +5,10 @@ #include "foster_renderer.h" #include +#define FOSTER_LOG_INFO(...) FosterLog(FOSTER_LOG_LEVEL_INFO, __VA_ARGS__) +#define FOSTER_LOG_WARN(...) FosterLog(FOSTER_LOG_LEVEL_WARNING, __VA_ARGS__) +#define FOSTER_LOG_ERROR(...) FosterLog(FOSTER_LOG_LEVEL_ERROR, __VA_ARGS__) + // foster global state typedef struct { @@ -18,19 +22,13 @@ typedef struct SDL_GameController* gamepads[FOSTER_MAX_CONTROLLERS]; char* clipboardText; char* userPath; - FosterLogFn logInfo; - FosterLogFn logWarn; - FosterLogFn logError; - FosterLogging logLevel; + FosterLogFn logFn; + FosterLogFilter logFilter; FosterBool polledMouseMovement; } FosterState; FosterState* FosterGetState(); -void FosterLogInfo(const char* fmt, ...); - -void FosterLogWarn(const char* fmt, ...); - -void FosterLogError(const char* fmt, ...); +void FosterLog(FosterLogLevel level, const char* fmt, ...); #endif diff --git a/Platform/src/foster_platform.c b/Platform/src/foster_platform.c index 94091c4..195aeb7 100644 --- a/Platform/src/foster_platform.c +++ b/Platform/src/foster_platform.c @@ -13,10 +13,10 @@ (((flags) & (flag)) != 0) #define FOSTER_ASSERT_RUNNING_RET(func, ret) \ - do { if (!fstate.running) { FosterLogError("Failed '%s', Foster is not running", #func); return ret; } } while(0) + do { if (!fstate.running) { FOSTER_LOG_ERROR("Failed '%s', Foster is not running", #func); return ret; } } while(0) #define FOSTER_ASSERT_RUNNING(func) \ - do { if (!fstate.running) { FosterLogError("Failed '%s', Foster is not running", #func); return; } } while(0) + do { if (!fstate.running) { FOSTER_LOG_ERROR("Failed '%s', Foster is not running", #func); return; } } while(0) FosterKeys FosterGetKeyFromSDL(SDL_Scancode key); FosterButtons FosterGetButtonFromSDL(SDL_GameControllerButton button); @@ -38,18 +38,18 @@ void FosterLog_SDL(void *userdata, int category, SDL_LogPriority priority, const { case SDL_LOG_PRIORITY_VERBOSE: case SDL_LOG_PRIORITY_DEBUG: - if (fstate.logLevel == FOSTER_LOGGING_ALL) - FosterLogInfo("%s", message); + if (fstate.logFilter == FOSTER_LOG_FILTER_VERBOSE) + FOSTER_LOG_INFO("%s", message); break; case SDL_LOG_PRIORITY_INFO: - FosterLogInfo("%s", message); + FOSTER_LOG_INFO("%s", message); break; case SDL_LOG_PRIORITY_WARN: - FosterLogWarn("%s", message); + FOSTER_LOG_WARN("%s", message); break; case SDL_LOG_PRIORITY_ERROR: case SDL_LOG_PRIORITY_CRITICAL: - FosterLogError("%s", message); + FOSTER_LOG_ERROR("%s", message); break; } } @@ -67,18 +67,17 @@ void FosterStartup(FosterDesc desc) if (fstate.desc.width <= 0 || fstate.desc.height <= 0) { - FosterLogError("Foster invalid application width/height (%i, %i)", desc.width, desc.height); + FOSTER_LOG_ERROR("Foster invalid application width/height (%i, %i)", desc.width, desc.height); return; } // Get SDL version SDL_version version; SDL_GetVersion(&version); - FosterLogInfo("SDL: v%i.%i.%i", version.major, version.minor, version.patch); + FOSTER_LOG_INFO("SDL: v%i.%i.%i", version.major, version.minor, version.patch); // track SDL output - if (fstate.logLevel != FOSTER_LOGGING_NONE && - (fstate.logInfo || fstate.logWarn || fstate.logError)) + if (fstate.logFilter != FOSTER_LOG_FILTER_IGNORE_ALL && fstate.logFn) { SDL_LogSetOutputFunction(FosterLog_SDL, NULL); } @@ -96,14 +95,14 @@ void FosterStartup(FosterDesc desc) int sdl_init_flags = SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER; if (SDL_Init(sdl_init_flags) != 0) { - FosterLogError("Foster SDL_Init Failed: %s", SDL_GetError()); + FOSTER_LOG_ERROR("Foster SDL_Init Failed: %s", SDL_GetError()); return; } // determine renderer type if (!FosterGetDevice(fstate.desc.renderer, &fstate.device)) { - FosterLogError("Foster Failed to get Renderer Device"); + FOSTER_LOG_ERROR("Foster Failed to get Renderer Device"); return; } @@ -122,7 +121,7 @@ void FosterStartup(FosterDesc desc) if (fstate.window == NULL) { - FosterLogError("Foster SDL_CreateWindow Failed: %s", SDL_GetError()); + FOSTER_LOG_ERROR("Foster SDL_CreateWindow Failed: %s", SDL_GetError()); return; } @@ -133,7 +132,7 @@ void FosterStartup(FosterDesc desc) { if (!fstate.device.initialize()) { - FosterLogError("Foster Failed to initialize Renderer Device"); + FOSTER_LOG_ERROR("Foster Failed to initialize Renderer Device"); fstate.running = false; SDL_DestroyWindow(fstate.window); return; @@ -145,12 +144,10 @@ void FosterStartup(FosterDesc desc) SDL_ShowWindow(fstate.window); } -void FosterRegisterLogMethods(FosterLogFn logInfo, FosterLogFn logWarn, FosterLogFn logError, FosterLogging logLevel) +void FosterSetLogCallback(FosterLogFn logFn, FosterLogFilter logFiler) { - fstate.logInfo = logInfo; - fstate.logWarn = logWarn; - fstate.logError = logError; - fstate.logLevel = logLevel; + fstate.logFn = logFn; + fstate.logFilter = logFiler; } void FosterBeginFrame() @@ -433,7 +430,7 @@ void FosterSetFlags(FosterFlags flags) { int result = SDL_GL_SetSwapInterval(FOSTER_CHECK(flags, FOSTER_FLAG_VSYNC) ? 1 : 0); if (result != 0) - FosterLogWarn("Setting V-Sync Failed: %s", SDL_GetError()); + FOSTER_LOG_WARN("Setting V-Sync Failed: %s", SDL_GetError()); } fstate.flags = flags; @@ -488,7 +485,7 @@ FosterFont* FosterFontInit(unsigned char* data, int length) { if (stbtt_GetNumberOfFonts(data) <= 0) { - FosterLogError("Unable to parse Font File"); + FOSTER_LOG_ERROR("Unable to parse Font File"); return NULL; } @@ -496,7 +493,7 @@ FosterFont* FosterFontInit(unsigned char* data, int length) if (stbtt_InitFont(info, data, 0) == 0) { - FosterLogError("Unable to parse Font File"); + FOSTER_LOG_ERROR("Unable to parse Font File"); SDL_free(info); return NULL; } @@ -705,10 +702,10 @@ void FosterClear(FosterClearCommand* clear) fstate.device.clear(clear); } -void FosterLogInfo(const char* fmt, ...) +void FosterLog(FosterLogLevel level, const char* fmt, ...) { - if (fstate.logLevel == FOSTER_LOGGING_NONE || - fstate.logInfo == NULL) + if (fstate.logFilter == FOSTER_LOG_FILTER_IGNORE_ALL || + fstate.logFn == NULL) return; char msg[FOSTER_MAX_MESSAGE_SIZE]; @@ -717,37 +714,7 @@ void FosterLogInfo(const char* fmt, ...) SDL_vsnprintf(msg, sizeof(msg), fmt, ap); va_end(ap); - fstate.logInfo(msg); -} - -void FosterLogWarn(const char* fmt, ...) -{ - if (fstate.logLevel == FOSTER_LOGGING_NONE || - fstate.logWarn == NULL) - return; - - char msg[FOSTER_MAX_MESSAGE_SIZE]; - va_list ap; - va_start(ap, fmt); - SDL_vsnprintf(msg, sizeof(msg), fmt, ap); - va_end(ap); - - fstate.logWarn(msg); -} - -void FosterLogError(const char* fmt, ...) -{ - if (fstate.logLevel == FOSTER_LOGGING_NONE || - fstate.logError == NULL) - return; - - char msg[FOSTER_MAX_MESSAGE_SIZE]; - va_list ap; - va_start(ap, fmt); - SDL_vsnprintf(msg, sizeof(msg), fmt, ap); - va_end(ap); - - fstate.logError(msg); + fstate.logFn(msg, level); } int FosterFindJoystickIndexSDL(SDL_Joystick** joysticks, SDL_JoystickID instanceID) diff --git a/Platform/src/foster_renderer_opengl.c b/Platform/src/foster_renderer_opengl.c index 32ecdda..74f9569 100644 --- a/Platform/src/foster_renderer_opengl.c +++ b/Platform/src/foster_renderer_opengl.c @@ -458,7 +458,7 @@ static FosterOpenGLState fgl; // debug callback void APIENTRY FosterMessage_OpenGL(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { - if (FosterGetState()->logLevel != FOSTER_LOGGING_ALL) + if (FosterGetState()->logFilter != FOSTER_LOG_FILTER_VERBOSE) { if (severity == GL_DEBUG_SEVERITY_NOTIFICATION && type == GL_DEBUG_TYPE_OTHER) @@ -490,11 +490,11 @@ void APIENTRY FosterMessage_OpenGL(GLenum source, GLenum type, GLuint id, GLenum } if (type == GL_DEBUG_TYPE_ERROR) - FosterLogError("GL (%s:%s) %s", typeName, severityName, message); + FOSTER_LOG_ERROR("GL (%s:%s) %s", typeName, severityName, message); else if (severity != GL_DEBUG_SEVERITY_NOTIFICATION) - FosterLogWarn("GL (%s:%s) %s", typeName, severityName, message); + FOSTER_LOG_WARN("GL (%s:%s) %s", typeName, severityName, message); else - FosterLogInfo("GL (%s) %s", typeName, message); + FOSTER_LOG_INFO("GL (%s) %s", typeName, message); } // conversion methods @@ -794,7 +794,7 @@ void FosterTextureReturnReference(FosterTexture_OpenGL* texture) if (texture->refCount <= 0) { if (!texture->disposed) - FosterLogError("Texture is being free'd without deleting its GPU Texture Data"); + FOSTER_LOG_ERROR("Texture is being free'd without deleting its GPU Texture Data"); SDL_free(texture); } } @@ -1010,7 +1010,7 @@ bool FosterInitialize_OpenGL() fgl.context = SDL_GL_CreateContext(state->window); if (fgl.context == NULL) { - FosterLogError("Failed to create OpenGL Context: %s", SDL_GetError()); + FOSTER_LOG_ERROR("Failed to create OpenGL Context: %s", SDL_GetError()); return false; } SDL_GL_MakeCurrent(state->window, fgl.context); @@ -1021,7 +1021,7 @@ bool FosterInitialize_OpenGL() #undef GL_FUNC // bind debug message callback - if (fgl.glDebugMessageCallback != NULL && state->logLevel != FOSTER_LOGGING_NONE) + if (fgl.glDebugMessageCallback != NULL && state->logFilter != FOSTER_LOG_FILTER_IGNORE_ALL) { fgl.glEnable(GL_DEBUG_OUTPUT); fgl.glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); @@ -1072,7 +1072,7 @@ bool FosterInitialize_OpenGL() fgl.stateTextureSlots[i] = 0; // log - FosterLogInfo("OpenGL: v%s, %s", fgl.glGetString(GL_VERSION), fgl.glGetString(GL_RENDERER)); + FOSTER_LOG_INFO("OpenGL: v%s, %s", fgl.glGetString(GL_VERSION), fgl.glGetString(GL_RENDERER)); return true; } @@ -1118,7 +1118,7 @@ FosterTexture* FosterTextureCreate_OpenGL(int width, int height, FosterTextureFo if (width > fgl.max_texture_size || height > fgl.max_texture_size) { - FosterLogError("Exceeded Max Texture Size of %i", fgl.max_texture_size); + FOSTER_LOG_ERROR("Exceeded Max Texture Size of %i", fgl.max_texture_size); return NULL; } @@ -1140,14 +1140,14 @@ FosterTexture* FosterTextureCreate_OpenGL(int width, int height, FosterTextureFo result.glType = GL_UNSIGNED_INT_24_8; break; default: - FosterLogError("Invalid Texture Format (%i)", format); + FOSTER_LOG_ERROR("Invalid Texture Format (%i)", format); return NULL; } fgl.glGenTextures(1, &result.id); if (result.id == 0) { - FosterLogError("Failed to create Texture"); + FOSTER_LOG_ERROR("Failed to create Texture"); return NULL; } @@ -1216,7 +1216,7 @@ FosterTarget* FosterTargetCreate_OpenGL(int width, int height, FosterTextureForm { for (int j = 0; j < i; j++) FosterTextureDestroy_OpenGL((FosterTexture*)tex); - FosterLogError("Failed to create Target Attachment"); + FOSTER_LOG_ERROR("Failed to create Target Attachment"); FosterBindFrameBuffer(NULL); return NULL; } @@ -1275,13 +1275,13 @@ FosterShader* FosterShaderCreate_OpenGL(FosterShaderData* data) if (data->vertexShader == NULL) { - FosterLogError("Invalid Vertex Shader"); + FOSTER_LOG_ERROR("Invalid Vertex Shader"); return NULL; } if (data->fragmentShader == NULL) { - FosterLogError("Invalid Fragment Shader"); + FOSTER_LOG_ERROR("Invalid Fragment Shader"); return NULL; } @@ -1300,12 +1300,12 @@ FosterShader* FosterShaderCreate_OpenGL(FosterShaderData* data) { fgl.glDeleteShader(vertexShader); if (logLength > 0) - FosterLogError("%s", log); + FOSTER_LOG_ERROR("%s", log); return NULL; } else if (logLength > 0) { - FosterLogInfo("%s", log); + FOSTER_LOG_INFO("%s", log); } } @@ -1325,12 +1325,12 @@ FosterShader* FosterShaderCreate_OpenGL(FosterShaderData* data) fgl.glDeleteShader(vertexShader); fgl.glDeleteShader(fragmentShader); if (logLength > 0) - FosterLogError("%s", log); + FOSTER_LOG_ERROR("%s", log); return NULL; } else if (logLength > 0) { - FosterLogInfo("%s", log); + FOSTER_LOG_INFO("%s", log); } } @@ -1352,12 +1352,12 @@ FosterShader* FosterShaderCreate_OpenGL(FosterShaderData* data) if (!linkResult) { if (logLength > 0) - FosterLogError("%s", log); + FOSTER_LOG_ERROR("%s", log); return NULL; } else if (logLength > 0) { - FosterLogInfo("%s", log); + FOSTER_LOG_INFO("%s", log); } FosterShader_OpenGL* shader = (FosterShader_OpenGL*)SDL_malloc(sizeof(FosterShader_OpenGL)); @@ -1471,7 +1471,7 @@ void FosterShaderSetUniform_OpenGL(FosterShader* shader, int index, float* value if (index < 0 || index > it->uniformCount) { - FosterLogError("Failed to set uniform '%i': index out of bounds"); + FOSTER_LOG_ERROR("Failed to set uniform '%i': index out of bounds"); return; } @@ -1501,7 +1501,7 @@ void FosterShaderSetUniform_OpenGL(FosterShader* shader, int index, float* value return; } - FosterLogError("Failed to set uniform '%s', unsupported type '%i'", uniform->name, uniform->glType); + FOSTER_LOG_ERROR("Failed to set uniform '%s', unsupported type '%i'", uniform->name, uniform->glType); } void FosterShaderSetTexture_OpenGL(FosterShader* shader, int index, FosterTexture** values) @@ -1510,14 +1510,14 @@ void FosterShaderSetTexture_OpenGL(FosterShader* shader, int index, FosterTextur if (index < 0 || index > it->uniformCount) { - FosterLogError("Failed to set uniform '%i': index out of bounds", index); + FOSTER_LOG_ERROR("Failed to set uniform '%i': index out of bounds", index); return; } FosterUniform_OpenGL* uniform = it->uniforms + index; if (uniform->glType != GL_SAMPLER_2D) { - FosterLogError("Failed to set uniform '%s': not a Texture", uniform->name); + FOSTER_LOG_ERROR("Failed to set uniform '%s': not a Texture", uniform->name); return; } @@ -1535,14 +1535,14 @@ void FosterShaderSetSampler_OpenGL(FosterShader* shader, int index, FosterTextur if (index < 0 || index > it->uniformCount) { - FosterLogError("Failed to set uniform '%i': index out of bounds", index); + FOSTER_LOG_ERROR("Failed to set uniform '%i': index out of bounds", index); return; } FosterUniform_OpenGL* uniform = it->uniforms + index; if (uniform->glType != GL_SAMPLER_2D) { - FosterLogError("Failed to set uniform '%s': not a Sampler", uniform->name); + FOSTER_LOG_ERROR("Failed to set uniform '%s': not a Sampler", uniform->name); return; } @@ -1583,7 +1583,7 @@ FosterMesh* FosterMeshCreate_OpenGL() fgl.glGenVertexArrays(1, &result.id); if (result.id == 0) { - FosterLogError("%s", "Failed to create Mesh"); + FOSTER_LOG_ERROR("%s", "Failed to create Mesh"); return NULL; } @@ -1646,7 +1646,7 @@ void FosterMeshSetIndexFormat_OpenGL(FosterMesh* mesh, FosterIndexFormat format) it->indexSize = 4; break; default: - FosterLogError("Invalid Index Format '%i'", format); + FOSTER_LOG_ERROR("Invalid Index Format '%i'", format); break; } }