diff --git a/source/app/src/App.cpp b/source/app/src/App.cpp index f0dac6d..71aa212 100644 --- a/source/app/src/App.cpp +++ b/source/app/src/App.cpp @@ -16,10 +16,12 @@ namespace ugly { int App::main(std::vector &args) { + // Initialize global log. auto cerrLog = TimestampLog{"ugly::log", std::cerr}; log = LogAlias{&cerrLog}; log("hello, world! app started."); + // Initialize GLFW. glfwSetErrorCallback(error_callback_s); glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); @@ -27,6 +29,7 @@ int App::main(std::vector &args) { glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + // Create GLFW window and OpenGL context for GLEW. auto window = glfwCreateWindow(640, 480, "uGLy", NULL, NULL); glfwMakeContextCurrent(window); glewExperimental = GL_TRUE; @@ -34,9 +37,11 @@ int App::main(std::vector &args) { log("glewInit() failed!"); } + // Run app. auto app = App{window}; app.game_loop(); + // Clean up. glfwTerminate(); glfwSetErrorCallback(NULL); log("app quitting."); @@ -57,7 +62,8 @@ void App::key_callback_s(GLFWwindow *window, int key, int scancode, int action, App::App(GLFWwindow *window): - mpWindow{window} { + mpWindow{window}, + mShaderProgram{} { glfwSetWindowUserPointer(mpWindow, this); glfwSetKeyCallback(mpWindow, key_callback_s); diff --git a/source/log/include/ILogFacility.hpp b/source/log/include/ILogFacility.hpp index e9bd8eb..948c9cd 100644 --- a/source/log/include/ILogFacility.hpp +++ b/source/log/include/ILogFacility.hpp @@ -5,9 +5,17 @@ namespace ugly { +/** + * \brief Interface for a generic log-like object. + */ class ILogFacility { public: ~ILogFacility() = default; + /** + * \brief Put a message into the log, \c std::vformat -style. + * \param fmt Format string. + * \param args Format arguments. + */ virtual void vlog(std::string_view fmt, std::format_args args) = 0; }; diff --git a/source/log/include/LogUtils.hpp b/source/log/include/LogUtils.hpp index 7e7156d..3a90532 100644 --- a/source/log/include/LogUtils.hpp +++ b/source/log/include/LogUtils.hpp @@ -6,6 +6,9 @@ namespace ugly { +/** + * \brief Provides \c std::format -style variadic template functions for \ref ILogFacility. + */ class LogAlias { public: ILogFacility *mpLog; @@ -19,6 +22,11 @@ public: } }; +/** + * \brief Globally-shared log. + * + * Should be assigned to by the user, defaults to a null log. + */ extern LogAlias log; } diff --git a/source/log/include/TimestampLog.hpp b/source/log/include/TimestampLog.hpp index 07eedf3..cf309ec 100644 --- a/source/log/include/TimestampLog.hpp +++ b/source/log/include/TimestampLog.hpp @@ -10,6 +10,9 @@ namespace ugly { +/** + * \brief Log that automatically annotates messages with time and name. + */ class TimestampLog: virtual public ILogFacility { private: std::chrono::high_resolution_clock::time_point mStartTime; @@ -17,6 +20,10 @@ private: std::string mDescription; public: + /** + * \param description Name of the log to appear in the messages. + * \param os Output stream. + */ TimestampLog(std::string_view description, std::ostream &os); void vlog(std::string_view fmt, std::format_args args) override; }; diff --git a/source/log/src/TimestampLog.cpp b/source/log/src/TimestampLog.cpp index 41a1844..c7003d1 100644 --- a/source/log/src/TimestampLog.cpp +++ b/source/log/src/TimestampLog.cpp @@ -12,6 +12,7 @@ TimestampLog::TimestampLog(std::string_view description, std::ostream &os): void TimestampLog::vlog(std::string_view fmt, std::format_args args) { + // Format message as "[123.4567] Name: User Message\n" using namespace std::chrono; auto now = high_resolution_clock::now(); auto timestamp = duration_cast>(now - mStartTime).count(); diff --git a/source/shader/include/ShaderProgramBuilder.hpp b/source/shader/include/ShaderProgramBuilder.hpp index 98e65e9..c43d855 100644 --- a/source/shader/include/ShaderProgramBuilder.hpp +++ b/source/shader/include/ShaderProgramBuilder.hpp @@ -6,6 +6,13 @@ namespace ugly{ +/** + * \brief Builder class for OpenGL shader and programs. + * + * On initialization, creates a new OpenGL program. Attach and compile shader + * sources using `attachFrom*`. Link and get the program with `link()`. User is + * responsible of managing returned program's lifetime, including destroying it. + */ class ShaderProgramBuilder { private: GLuint mProgram; @@ -13,10 +20,36 @@ private: public: ShaderProgramBuilder(); ~ShaderProgramBuilder(); + /** + * \brief Deletes program and starts from scratch. + */ void reset(); + /** + * \brief Creates, compiles, and attaches a shader. + * \param type Specifies the type of shader to be created. Must be one of + * \c GL_VERTEX_SHADER, \c GL_GEOMETRY_SHADER or + * \c GL_FRAGMENT_SHADER . + * \param string Shader source code. + * \param length Bytes to read from \p string, \c 0 reads until NUL byte. + * \returns *this + */ ShaderProgramBuilder &attachFromMemory(GLenum type, const GLchar *string, GLint length = 0); + /** + * \brief Creates, compiles, and attaches a shader. Reads source from file. + * \param type Specifies the type of shader to be created. Must be one of + * \c GL_VERTEX_SHADER, \c GL_GEOMETRY_SHADER or + * \c GL_FRAGMENT_SHADER . + * \param filename Shader source code file. + * \returns \c *this + */ ShaderProgramBuilder &attachFromFile(GLenum type, const char *filename); - GLuint link(); + /** + * \brief Links OpenGL program after attaching sources. + * + * After this function is called the builder object is reset. + * \return OpenGL object name. User is reponsible for managing it. + */ + [[nodiscard]] GLuint link(); }; } diff --git a/source/shader/src/ShaderProgramBuilder.cpp b/source/shader/src/ShaderProgramBuilder.cpp index 31ff29b..98ef3ca 100644 --- a/source/shader/src/ShaderProgramBuilder.cpp +++ b/source/shader/src/ShaderProgramBuilder.cpp @@ -13,6 +13,7 @@ ShaderProgramBuilder::ShaderProgramBuilder(): ShaderProgramBuilder::~ShaderProgramBuilder() { + // link() sets mProgram=0 to prevent it from being deleted after being given to the user. if(mProgram != 0) { glDeleteProgram(mProgram); } @@ -21,8 +22,8 @@ ShaderProgramBuilder::~ShaderProgramBuilder() { void ShaderProgramBuilder::reset() { using namespace std; - ShaderProgramBuilder b; - swap(*this, b); + ShaderProgramBuilder newBuilder; + swap(*this, newBuilder); } @@ -31,6 +32,7 @@ ShaderProgramBuilder &ShaderProgramBuilder::attachFromMemory(GLenum type, const glShaderSource(shader, 1, &string, length != 0 ? &length : NULL); glCompileShader(shader); + // Check for shader compilation errors GLint status; glGetShaderiv(shader, GL_COMPILE_STATUS, &status); if(status != GL_TRUE) { @@ -40,6 +42,7 @@ ShaderProgramBuilder &ShaderProgramBuilder::attachFromMemory(GLenum type, const log("failed to compile shader:\n\t{}", buf); } + // After the shader is attached, it can safely be marked for deletion and OpenGL will handle it. glAttachShader(mProgram, shader); glDeleteShader(shader); return *this; @@ -47,6 +50,7 @@ ShaderProgramBuilder &ShaderProgramBuilder::attachFromMemory(GLenum type, const ShaderProgramBuilder &ShaderProgramBuilder::attachFromFile(GLenum type, const char *filename) { + // Load entire file to memory then let attachFromMemory handle it. auto file = std::filebuf{}; auto ss = std::ostringstream{}; @@ -64,6 +68,7 @@ ShaderProgramBuilder &ShaderProgramBuilder::attachFromFile(GLenum type, const ch GLuint ShaderProgramBuilder::link() { glLinkProgram(mProgram); + // Check for program linking errors GLint status; glGetProgramiv(mProgram, GL_LINK_STATUS, &status); if(status != GL_TRUE) { @@ -72,6 +77,7 @@ GLuint ShaderProgramBuilder::link() { log("failed to link program:\n\t{}", buf); } + // reset() this object but take care of not deleting the program returned to the caller. auto result = mProgram; mProgram = 0; reset();