From c74e8fcf13228812e1fb34ee96873d6b7abd6108 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Mon, 18 Jul 2022 23:01:42 +0100 Subject: [PATCH] azur: restructure to adhere to a more consistent C++ style --- README.md | 6 +- azur/CMakeLists.txt | 6 +- azur/include/azur/azur.h | 2 +- azur/include/azur/gl/gl.h | 75 ++++++++++++++ azur/include/azur/log.h | 102 +++++++++++--------- azur/include/azur/sdl_opengl/gl.h | 65 ------------- azur/src/{sdl_opengl/init.c => gl/init.cpp} | 9 +- azur/src/{sdl_opengl/util.c => gl/util.cpp} | 78 ++++++++------- azur/src/log.c | 59 ----------- azur/src/log.cpp | 89 +++++++++++++++++ 10 files changed, 279 insertions(+), 212 deletions(-) create mode 100644 azur/include/azur/gl/gl.h delete mode 100644 azur/include/azur/sdl_opengl/gl.h rename azur/src/{sdl_opengl/init.c => gl/init.cpp} (98%) rename azur/src/{sdl_opengl/util.c => gl/util.cpp} (69%) delete mode 100644 azur/src/log.c create mode 100644 azur/src/log.cpp diff --git a/README.md b/README.md index b63905d..f55c96b 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ The following are Azur libraries: * **libazrp** is C library that implements Azur's Rendering Pipeline. On fx-CG, Azur uses a very unique rendering method that sacrifices some generality for a significant boost in performance, and this system has uses beyond games. (TODO: Currently still in the `azur/` folder) * **azur** is of course the engine itself. -The following external projects are Azur by some of Azur's features, and maintained as submodules in `3rdparty/`: +The following external projects are used by some of Azur's features, and maintained as submodules in `3rdparty/`: * [**gl3w**](https://github.com/skaslev/gl3w) is a minimalist OpenGL loader, which is used in Azur's OpenGL backend to load the core profile. * [**GLM**](https://glm.g-truc.net/0.9.9/index.html) is math library for graphics, which is interoperable with OpenGL shaders. In the future I hope to use libnum everywhere, but GLM is still useful in OpenGL-related code. @@ -29,7 +29,7 @@ The following external projects are Azur by some of Azur's features, and maintai ## Building -You *must* install into a different folder for each platform, as the headers would otherwise clash (particulary the auto-generated ``. The library names are different (eg. `libazur_emscripten.a`), but this is just to avoid confusing errors; the folders must still be different. +You *must* install into a different folder for each platform, as the headers would otherwise clash (particulary the auto-generated ``). The library names are different (eg. `libazur_emscripten.a`), but this is just to avoid confusing errors; the folders must still be different. **Building for fx-CG** @@ -90,4 +90,4 @@ endif() Back in 2021 I made a single repository for this engine, along with other programs that I intended to write with it. At the time I didn't intend to distribute the engine in any serious fashion, but that changed after people expressed interest in playing with [After Burner](https://www.planet-casio.com/Fr/programmes/programme4238-1-after-burner-lephenixnoir-jeux-add-ins.html). -I split the original repository in May 2022 with `git filter-branch`, extracting Azur-related contents to this repository. I edited the history so that old commits can still be built, but mostly for the sake of preserving history; don't expect to be able to use these early commits out-of-the-box. +I split the original repository in May 2022 with `git filter-branch`, extracting Azur-related contents to this repository. I patched old commits so they can still be built, but mostly for the sake of preserving history; don't expect to be able to use these early commits out-of-the-box. diff --git a/azur/CMakeLists.txt b/azur/CMakeLists.txt index 41c0b42..8d6ce40 100644 --- a/azur/CMakeLists.txt +++ b/azur/CMakeLists.txt @@ -8,14 +8,14 @@ configure_file(include/azur/config.h.in include/azur/config.h) set(SOURCES - src/log.c) + src/log.cpp) set(ASSETS) # SDL/OpenGL rendering if(AZUR_TOOLKIT_SDL AND AZUR_GRAPHICS_OPENGL) list(APPEND SOURCES - src/sdl_opengl/init.c - src/sdl_opengl/util.c + src/gl/init.cpp + src/gl/util.cpp "${CMAKE_CURRENT_BINARY_DIR}/src/glsl.c") list(APPEND ASSETS diff --git a/azur/include/azur/azur.h b/azur/include/azur/azur.h index f990851..fc4da1b 100644 --- a/azur/include/azur/azur.h +++ b/azur/include/azur/azur.h @@ -43,7 +43,7 @@ int azur_init(char const *title, int window_width, int window_height); The update framerate is determined second. If AZUR_MAIN_LOOP_TIED is set, updates are set to run before renders (except before the very first render), - and update_ups is ignored is ignored. Otherwise, the target UPS is used. + and update_ups is ignored. Otherwise, the target UPS is used. The main loop stops whenever update() returns non-zero. */ int azur_main_loop( diff --git a/azur/include/azur/gl/gl.h b/azur/include/azur/gl/gl.h new file mode 100644 index 0000000..43cc0b0 --- /dev/null +++ b/azur/include/azur/gl/gl.h @@ -0,0 +1,75 @@ +//---------------------------------------------------------------------------// +// ," /\ ", Azur: A game engine for CASIO fx-CG and PC // +// | _/__\_ | Designed by Lephe' and the Planète Casio community. // +// "._`\/'_." License: MIT // +//---------------------------------------------------------------------------// +// azur.gl.gl: OpenGL 3.3 / OpenGL ES 2.0 compatibility and utilities +// +// This header is specific to OpenGL targets. It provides helpers for some +// degree of compatibility between OpenGL ES 2.0 (with some extensions) and +// OpenGL 3.3. We always use OpenGL 3.3 as the reference and try to expose +// everything as if we are running OpenGL 3.3 on every platform. +// +// This header also provides utility functions to load and compile shaders. +// Azur provides a header for all shader files, which includes the `#version` +// string, modern keywords on OpenGL ES 2.0 (in/out/layout), and two macros +// _GL() and _GLES() that expand to their argument on the corresponding +// platform and nothing otherwise, for when differences in GLSL aren't easily +// fixable by preprocessor. See glsl/prelude*.glsl for details. +//--- + +#pragma once +#include + +#ifdef AZUR_GRAPHICS_OPENGL_3_3 +# include +# include +#endif /* OpenGL 3.3 */ + +#ifdef AZUR_GRAPHICS_OPENGL_ES_2_0 +# define GL_GLEXT_PROTOTYPES +# include + +/* We expose vertex array objects through OES_vertex_array_object. */ +# define glGenVertexArrays glGenVertexArraysOES +# define glBindVertexArray glBindVertexArrayOES +# define glDeleteVertexArrays glDeleteVertexArraysOES +# define glIsVertexArray glIsVertexArrayOES +#endif /* OpenGL ES 2.0 */ + +namespace azur::gl { + +/* Returns a string description of an OpenGL error code. The return value if + the GLenum is not recognized is the address of a static buffer, which can + be modified by further calls to the function. */ +char const *errorString(GLenum errorCode); + +/* Loads the file at `path` and compiles it as a shader of the specified type. + Returns the new shader's ID, or 0 in case of error. Errors are logged. */ +GLuint compileShaderFile(GLenum type, char const *path); + +/* Compiles the provided code string as a shader of the specified type. If size + is -1, `code` is assumed to be NUL-terminated and strlen(code) is used. + Returns the shader ID, 0 in case of error. Errors are logged. */ +GLuint compileShaderSource(GLenum type, char const *code, ssize_t size); + +/* Link a program. This function takes a 0-terminated list of shaders IDs and + links them into a new program. Returns the new program's ID, or 0 in case + of error. Errors are logged. */ +GLuint linkProgram(GLuint shader_1, ... /* 0-terminated */); + +/* Loads a program from shader source files. The arguments come in pairs of + type and file path until a 0-type terminates the list. Each file is loaded + and compiled with compileShaderFile(), then the whole program is linked + with linkProgram(). Returns the program ID, or 0 in case of error. */ +GLuint loadProgramFiles( + GLenum type_1, char const *path_1, + ... /* Pairs repeat until 0-terminated */); + +/* Analoguous to loadProgramFiles(), but takes string inputs and compiles them + with loadShaderSource() with size=-1. */ +GLuint loadProgramSources( + GLenum type_1, char const *code_1, + ... /* Pairs repeat until 0-terminated */); + +} /* namespace azur::gl */ diff --git a/azur/include/azur/log.h b/azur/include/azur/log.h index cfe6bb1..25288b1 100644 --- a/azur/include/azur/log.h +++ b/azur/include/azur/log.h @@ -1,54 +1,70 @@ -//--- +//---------------------------------------------------------------------------// +// ," /\ ", Azur: A game engine for CASIO fx-CG and PC // +// | _/__\_ | Designed by Lephe' and the Planète Casio community. // +// "._`\/'_." License: MIT // +//---------------------------------------------------------------------------// // azur.log: Logging utilities +// +// This header provides the basic logging utilities. Logs are emitted with the +// azlog() macro, then filtered by level and printed to file. +// +// The main function is the azlog() macro, which takes a level parameter and a +// printf()-style format: +// +// azlog(ERROR, "rc = %d\n", rc); +// azlog(INFO, "Game saved!\n"); //--- #pragma once #include -AZUR_BEGIN_DECLS +#include -/* Message levels, numbered by "severity". */ -enum { - AZLOG_DEBUG = 0, - AZLOG_INFO = 1, - AZLOG_WARN = 2, - AZLOG_ERROR = 3, - AZLOG_FATAL = 4, -}; +namespace azur::log { -/* azlog_level(): Get the current logging level - Any message with a level at least the current logging level is printed. The - default logging level is AZLOG_ERROR in release builds, AZLOG_DEBUG in - development builds. */ -int azlog_level(void); +/* DEBUG: Disabled by default unless debug build; includes source file/line + INFO: General information that is meaningful to the user (not developer) + WARN: Unexpected behavior but program can still keep going + ERROR: Erroneous behavior, abandoning some tasks + FATAL: Complete panic; provokes exit(1); highest priority */ +enum class LogLevel { DEBUG, INFO, WARN, ERROR, FATAL }; -/* azlog_set_level(): Set the current logging level */ -void azlog_set_level(int level); +/* Coloring options. + PLAIN: No escape sequences; suitable for files and plain terminals. + ANSI: ANSI escape sequences; suitable for terminals. */ +enum class LogStyle { PLAIN, ANSI }; -/* azlog(): Write an error message - - This macro produces a line of log at the specified level. The AZLOG_ prefix - is added automatically by the macro, as well as standard function/line - information in development builds. */ -#define azlog(level, fmt, ...) \ - azlog_write(AZLOG_ ## level, __FILE__, __LINE__, __func__, false, fmt, \ - ## __VA_ARGS__) - -/* azlogc(): Continue an error message - Same as azlog(), but inhibits prefixes, for multi-part messages. */ -#define azlogc(level, fmt, ...) \ - azlog_write(AZLOG_ ## level, __FILE__, __LINE__, __func__, true, fmt, \ - ## __VA_ARGS__) - -/* Disable output in gint. */ -#ifdef AZUR_TERMINAL_NONE -# undef azlog -# undef azlogc -# define azlog(level, fmt, ...) -# define azlogc(level, fmt, ...) -#endif - -/* azlog_write(): Support function for azlog() */ -void azlog_write(int level, char const *file, int line, char const *func, +/* Produce a log message. See also azlog() and azlogc() for shorter versions. + level: Message level + file: File name (normally __FILE__) + line: Line number (normally __LINE__) + func: Function name (normally __func__) + cont: Whether this is the continuation of a previous message + fmt...: print()-style format */ +void write(LogLevel level, char const *file, int line, char const *func, bool cont, char const *fmt, ...); -AZUR_END_DECLS +/* Get the minimum-level filter. Messages below the minimum level are filtered + out. The default is INFO in release builds, DEBUG in debug builds. */ +LogLevel minimumLevelFilter(); + +/* Set the minimum-level filter. */ +void setMinimumLevelFilter(LogLevel level); + +/* Get the output stream for log messages. Default is stderr. */ +FILE *outputStream(); + +/* Set the output stream for log messages. Since the library might output + messages until very late in execution, a valid output stream should always + be specified. When using a file, stderr should be set as the output stream + before closing the file at the end of execution. */ +void setOutputStream(FILE *fp, LogStyle style); + +} /* namespace azur::log */ + +/* Quick macros that insert parameters automatically. */ +#define azlog(LEVEL, FMT, ...) \ + azur::log::write(azur::log::LogLevel::LEVEL, __FILE__, __LINE__, \ + __func__, false, FMT, ## __VA_ARGS__) +#define azlogc(LEVEL, FMT, ...) \ + azur::log::write(azur::log::LogLevel::LEVEL, __FILE__, __LINE__, \ + __func__, true, FMT, ## __VA_ARGS__) diff --git a/azur/include/azur/sdl_opengl/gl.h b/azur/include/azur/sdl_opengl/gl.h deleted file mode 100644 index 0985690..0000000 --- a/azur/include/azur/sdl_opengl/gl.h +++ /dev/null @@ -1,65 +0,0 @@ -//--- -// azur.sdl_opengl.gl: General OpenGL utilities -//--- - -#pragma once -#include -AZUR_BEGIN_DECLS - -#ifdef AZUR_GRAPHICS_OPENGL_3_3 -# include -# include -#endif /* OpenGL 3.3 */ - -#ifdef AZUR_GRAPHICS_OPENGL_ES_2_0 -# define GL_GLEXT_PROTOTYPES -# include - -# define glGenVertexArrays glGenVertexArraysOES -# define glBindVertexArray glBindVertexArrayOES -# define glDeleteVertexArrays glDeleteVertexArraysOES -#endif /* OpenGL ES 2.0 */ - -/* azgl_error(): String description of a GLenum error code. - The returned pointer might be a static buffer modified by further calls. */ -char const *azgl_error(GLenum error_code); - -/* azgl_compile_shader_file(): Load and compile a shader from file. - - This function loads the file at [path], and compiles it into a shader of the - specified type. If the file cannot be loaded, the shader cannot be created, - or there are compilation errors, this function returns 0. Otherwise, it - returns the shader ID. */ -GLuint azgl_compile_shader_file(GLenum type, char const *path); - -/* azgl_compile_shader_source(): Load and compile a shader from its code. - - Like azgl_load_shader(), but without the filesystem step. If the size is set - to -1, [code] is assumed to be NUL-terminated. */ -GLuint azgl_compile_shader_source(GLenum type, char const *code, ssize_t size); - -/* azgl_link_program(): Link a program. - - This function attaches the 0-terminated list of shaders to a program, links - it, and returns the program ID (0 if link fails). */ -GLuint azgl_link_program(GLuint shader_1, ... /* 0-terminated */); - -/* azgl_load_program_file(): Load a program from shader source files. - - This function runs both azgl_compile_shader_file() and azgl_link_program() - for all specified files. Each argument should be a pair with a shader type - and a file name, with a final 0. - - Returns the program ID, or 0 if any loading/compilation/link step fails. */ -GLuint azgl_load_program_file( - GLenum type_1, char const *path_1, - ... /* Pairs repeat until 0-terminated */); - -/* azgl_load_program_source(): Load a program from shader source strings. - - Like azgl_load_program_file(), but takes code directly as input. */ -GLuint azgl_load_program_source( - GLenum type_1, char const *code_1, - ... /* Pairs repeat until 0-terminated */); - -AZUR_END_DECLS diff --git a/azur/src/sdl_opengl/init.c b/azur/src/gl/init.cpp similarity index 98% rename from azur/src/sdl_opengl/init.c rename to azur/src/gl/init.cpp index 594b9e3..10d187d 100644 --- a/azur/src/sdl_opengl/init.c +++ b/azur/src/gl/init.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include @@ -214,10 +214,9 @@ static Uint32 handler(Uint32 interval, void *param) { *(int *)param = 1; - SDL_Event e = { - .user.type = SDL_USEREVENT, - .user.code = ml_event, - }; + SDL_Event e; + e.user.type = SDL_USEREVENT; + e.user.code = ml_event; SDL_PushEvent(&e); return interval; } diff --git a/azur/src/sdl_opengl/util.c b/azur/src/gl/util.cpp similarity index 69% rename from azur/src/sdl_opengl/util.c rename to azur/src/gl/util.cpp index 88d1d3f..8ffde87 100644 --- a/azur/src/sdl_opengl/util.c +++ b/azur/src/gl/util.cpp @@ -1,13 +1,21 @@ -#include +//---------------------------------------------------------------------------// +// ," /\ ", Azur: A game engine for CASIO fx-CG and PC // +// | _/__\_ | Designed by Lephe' and the Planète Casio community. // +// "._`\/'_." License: MIT // +//---------------------------------------------------------------------------// + +#include #include #include #include #include #include +#include /* Read the full contents of a file into the heap. Returns an malloc'd pointer on success, NULL if an error occurs. */ +// TODO: Move the load_file() function to a more convenient fs util header static char *load_file(char const *path, size_t *out_size) { char *contents = NULL; @@ -20,7 +28,7 @@ static char *load_file(char const *path, size_t *out_size) size = ftell(fp); fseek(fp, 0, SEEK_SET); - contents = malloc(size + 1); + contents = new char[size + 1]; if(!contents) goto load_file_end; if(out_size) *out_size = size; @@ -32,7 +40,14 @@ load_file_end: return contents; } -char const *azgl_error(GLenum ec) +extern char const *azur_glsl__vs_prelude_gles2; +extern char const *azur_glsl__vs_prelude_gl3; +extern char const *azur_glsl__fs_prelude_gles2; +extern char const *azur_glsl__fs_prelude_gl3; + +namespace azur::gl { + +char const *errorString(GLenum ec) { static char str[32]; @@ -54,7 +69,7 @@ char const *azgl_error(GLenum ec) } /* Common code for the shader compiling functions. */ -static GLuint azgl_compile_shader(GLenum type, char const *code, ssize_t size, +static GLuint compileShader(GLenum type, char const *code, ssize_t size, char const *origin) { /* Shader prelude; this gives shader version, some macro definitions and @@ -65,19 +80,15 @@ static GLuint azgl_compile_shader(GLenum type, char const *code, ssize_t size, if(!vs_prelude) { #if defined AZUR_GRAPHICS_OPENGL_ES_2_0 - extern char const *azur_glsl__vs_prelude_gles2; vs_prelude = azur_glsl__vs_prelude_gles2; #elif defined AZUR_GRAPHICS_OPENGL_3_3 - extern char const *azur_glsl__vs_prelude_gl3; vs_prelude = azur_glsl__vs_prelude_gl3; #endif } if(!fs_prelude) { #if defined AZUR_GRAPHICS_OPENGL_ES_2_0 - extern char const *azur_glsl__fs_prelude_gles2; fs_prelude = azur_glsl__fs_prelude_gles2; #elif defined AZUR_GRAPHICS_OPENGL_3_3 - extern char const *azur_glsl__fs_prelude_gl3; fs_prelude = azur_glsl__fs_prelude_gl3; #endif } @@ -99,11 +110,10 @@ static GLuint azgl_compile_shader(GLenum type, char const *code, ssize_t size, GLint rc = GL_FALSE; GLsizei log_length = 0; - if(size < 0) - size = (int)strlen(code); - char const *string_array[] = { prelude, code }; - GLint size_array[] = { strlen(prelude), size }; + GLint size_array[] = { + (int)strlen(prelude), + (int)(size < 0 ? strlen(code) : size) }; azlog(INFO, "Compiling shader: %s\n", origin); glShaderSource(id, 2, string_array, size_array); @@ -111,24 +121,24 @@ static GLuint azgl_compile_shader(GLenum type, char const *code, ssize_t size, glGetShaderiv(id, GL_COMPILE_STATUS, &rc); if(rc == GL_FALSE) - azlog(ERROR, "compilation failed!\n"); + azlog(ERROR, "Compilation failed!\n"); glGetShaderiv(id, GL_INFO_LOG_LENGTH, &log_length); if(log_length > 0) { - GLchar *log = malloc((log_length + 1) * sizeof *log); + GLchar *log = new GLchar[log_length + 1]; glGetShaderInfoLog(id, log_length, &log_length, log); if(log_length > 0) { azlogc(ERROR, "%s", log); if(log[log_length - 1] != '\n') azlogc(ERROR, "\n"); } - free(log); + delete[] log; } return id; } -GLuint azgl_compile_shader_file(GLenum type, char const *path) +GLuint compileShaderFile(GLenum type, char const *path) { size_t size; char *source = load_file(path, &size); @@ -137,17 +147,17 @@ GLuint azgl_compile_shader_file(GLenum type, char const *path) return 0; } - GLuint id = azgl_compile_shader(type, source, size, path); - free(source); + GLuint id = compileShader(type, source, size, path); + delete[] source; return id; } -GLuint azgl_compile_shader_source(GLenum type, char const *code, ssize_t size) +GLuint compileShaderSource(GLenum type, char const *code, ssize_t size) { - return azgl_compile_shader(type, code, size, ""); + return compileShader(type, code, size, ""); } -static GLuint azgl_link(GLuint *shaders, int count) +static GLuint link(GLuint *shaders, int count) { GLuint prog = glCreateProgram(); if(prog == 0) { @@ -171,14 +181,14 @@ static GLuint azgl_link(GLuint *shaders, int count) glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &log_length); if(log_length > 0) { - GLchar *log = malloc((log_length + 1) * sizeof *log); + GLchar *log = new GLchar[log_length + 1]; glGetProgramInfoLog(prog, log_length, &log_length, log); if(log_length > 0) { azlogc(ERROR, "%s", log); if(log[log_length - 1] != '\n') azlogc(ERROR, "\n"); } - free(log); + delete[] log; } /* Detach all shaders */ @@ -188,7 +198,7 @@ static GLuint azgl_link(GLuint *shaders, int count) return prog; } -GLuint azgl_link_program(GLuint shader_1, ... /* 0-terminated */) +GLuint linkProgram(GLuint shader_1, ... /* 0-terminated */) { va_list args; va_start(args, shader_1); @@ -203,10 +213,10 @@ GLuint azgl_link_program(GLuint shader_1, ... /* 0-terminated */) while(count < 32 && shader_1 != 0); va_end(args); - return azgl_link(shaders, count); + return link(shaders, count); } -static GLuint azgl_load_program(bool is_file, GLenum type, char const *input, +static GLuint loadProgram_v(bool is_file, GLenum type, char const *input, va_list *args) { GLuint shaders[32]; @@ -214,14 +224,14 @@ static GLuint azgl_load_program(bool is_file, GLenum type, char const *input, do { shaders[count++] = is_file - ? azgl_compile_shader_file(type, input) - : azgl_compile_shader_source(type, input, -1); + ? compileShaderFile(type, input) + : compileShaderSource(type, input, -1); type = va_arg(*args, GLenum); input = va_arg(*args, char const *); } while(count < 32 && type != 0); - GLuint prog = azgl_link(shaders, count); + GLuint prog = link(shaders, count); for(int i = 0; i < count; i++) glDeleteShader(shaders[i]); @@ -229,20 +239,22 @@ static GLuint azgl_load_program(bool is_file, GLenum type, char const *input, return prog; } -GLuint azgl_load_program_file(GLenum type, char const *path, ...) +GLuint loadProgramFiles(GLenum type, char const *path, ...) { va_list args; va_start(args, path); - GLuint prog = azgl_load_program(true, type, path, &args); + GLuint prog = loadProgram_v(true, type, path, &args); va_end(args); return prog; } -GLuint azgl_load_program_source(GLenum type, char const *code, ...) +GLuint loadProgramSources(GLenum type, char const *code, ...) { va_list args; va_start(args, code); - GLuint prog = azgl_load_program(false, type, code, &args); + GLuint prog = loadProgram_v(false, type, code, &args); va_end(args); return prog; } + +} /* namespace azur::gl */ diff --git a/azur/src/log.c b/azur/src/log.c deleted file mode 100644 index b49ccb3..0000000 --- a/azur/src/log.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include - -#ifdef AZUR_DEBUG -static int _level = AZLOG_DEBUG; -#else -static int _level = AZLOG_INFO; -#endif - -#ifdef AZUR_TERMINAL_ANSI -# define RED "\e[31m" -# define CYAN "\e[36m" -# define YELLOW "\e[33m" -# define STOP "\e[0m" -#else /* AZUR_TERMINAL_PLAIN, by default */ -# define RED -# define CYAN -# define YELLOW -# define STOP -#endif - -int azlog_level(void) -{ - return _level; -} - -void azlog_set_level(int level) -{ - _level = level; -} - -void azlog_write(int level, char const *file, int line, char const *func, - bool cont, char const *fmt, ...) -{ - if(level < _level) return; - - if(!cont) { - #ifdef AZUR_DEBUG - fprintf(stderr, CYAN "%s:%d: " STOP YELLOW "%s: " STOP, - file, line, func); - #else - (void)file; - (void)line; - fprintf(stderr, "%s: ", func); - #endif - - if(level == AZLOG_ERROR) - fprintf(stderr, RED "error: " STOP); - if(level == AZLOG_FATAL) - fprintf(stderr, RED "fatal error: " STOP); - } - - va_list args; - va_start(args, fmt); - - vfprintf(stderr, fmt, args); - - va_end(args); -} diff --git a/azur/src/log.cpp b/azur/src/log.cpp new file mode 100644 index 0000000..94219b1 --- /dev/null +++ b/azur/src/log.cpp @@ -0,0 +1,89 @@ +//---------------------------------------------------------------------------// +// ," /\ ", Azur: A game engine for CASIO fx-CG and PC // +// | _/__\_ | Designed by Lephe' and the Planète Casio community. // +// "._`\/'_." License: MIT // +//---------------------------------------------------------------------------// + +#include +#include +#include +#include + +namespace azur::log { + +#ifdef AZUR_DEBUG + static LogLevel levelFilter = LogLevel::DEBUG; +#else + static LogLevel levelFilter = LogLevel::INFO; +#endif + +#ifdef AZUR_TERMINAL_ANSI + static LogStyle style = LogStyle::ANSI; +#else + static LogStyle style = LogStyle::PLAIN; +#endif + +static FILE *fp = stderr; + +#define ANSI_RED "\e[31m" +#define ANSI_CYAN "\e[36m" +#define ANSI_YELLOW "\e[33m" +#define ANSI_CLEAR "\e[0m" + +void write(LogLevel level, char const *file, int line, char const *func, + bool cont, char const *fmt, ...) +{ + if(level < levelFilter) + return; + + char const *RED = ANSI_RED; + char const *CYAN = ANSI_CYAN; + char const *YELLOW = ANSI_YELLOW; + char const *CLEAR = ANSI_CLEAR; + + if(style == LogStyle::PLAIN) + RED = CYAN = YELLOW = CLEAR = ""; + + if(!cont) { + if(level == LogLevel::DEBUG) + fprintf(fp, "%s%s:%d:", CYAN, file, line); + + fprintf(fp, "%s%s:%s ", YELLOW, func, CLEAR); + + if(level == LogLevel::ERROR) + fprintf(fp, "%serror:%s ", RED, CLEAR); + if(level == LogLevel::FATAL) + fprintf(fp, "%sfatal error:%s ", RED, CLEAR); + } + + va_list args; + va_start(args, fmt); + vfprintf(fp, fmt, args); + va_end(args); + + if(level == LogLevel::FATAL) + exit(1); +} + +LogLevel minimumLevelFilter() +{ + return levelFilter; +} + +void setMinimumLevelFilter(LogLevel lv) +{ + levelFilter = lv; +} + +FILE *outputStream() +{ + return fp; +} + +void setOutputStream(FILE *new_fp, LogStyle new_style) +{ + fp = new_fp; + style = new_style; +} + +} /* namespace azur::log */