Compare commits

..

13 Commits

14 changed files with 104 additions and 75 deletions

View File

@@ -99,10 +99,6 @@ IncludeIsMainSourceRegex: ''
IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<glad/gl\.h>'
Priority: 1
SortPriority: 0
CaseSensitive: true
- Regex: '^<.*\.h>'
Priority: 2
SortPriority: 0

View File

@@ -41,7 +41,7 @@ jobs:
restore-keys: ${{runner.os}}_${{runner.arch}}-lib/obj-
- run: make -Bj libs
if: ${{steps.cache-deps.outputs.cache-hit}} != 'true'
if: steps.cache-deps.outputs.cache-hit != 'true'
- run: make -j all
- run: make -j test

View File

@@ -12,6 +12,7 @@ CMAKE ?= cmake -G 'Unix Makefiles'
CPPFLAGS ?=
CFLAGS ?= -O2 -Wall -Wextra -Wpedantic -Wno-pointer-arith
LDFLAGS ?= -flto
CPPFLAGS += -DGLFW_INCLUDE_NONE
CFLAGS += -std=gnu99
# add a few extra flags depending on whether

View File

@@ -1,3 +1,5 @@
/* Copyright (c) 2025 Quinn
* Licensed under the MIT Licence. See LICENSE for details */
#include "error.h"
#include <stdarg.h>
@@ -13,35 +15,41 @@ static void error_log(FILE *restrict stream, const char *restrict pfx, uint ln,
fprintf(stream, "'\n");
}
void error_dbg(uint ln, const char *restrict file, const char *restrict fmt, ...) {
void error_debug(uint ln, const char *restrict file, const char *restrict fmt, ...) {
#ifndef NDEBUG
#else
char *env = getenv("DEBUG");
if (env && env[0] != '1')
return;
#endif
va_list ap;
va_start(ap, fmt);
error_log(stdout, "\033[95mDBG\033[0m", ln, file, fmt, ap);
va_end(ap);
}
void error_inf(uint ln, const char *restrict file, const char *restrict fmt, ...) {
void error_info(uint ln, const char *restrict file, const char *restrict fmt, ...) {
va_list ap;
va_start(ap, fmt);
error_log(stdout, "\033[94mINF\033[0m", ln, file, fmt, ap);
va_end(ap);
}
void error_war(uint ln, const char *restrict file, const char *restrict fmt, ...) {
void error_warn(uint ln, const char *restrict file, const char *restrict fmt, ...) {
va_list ap;
va_start(ap, fmt);
error_log(stdout, "\033[93mWAR\033[0m", ln, file, fmt, ap);
va_end(ap);
}
void error_err(uint ln, const char *restrict file, const char *restrict fmt, ...) {
void error_error(uint ln, const char *restrict file, const char *restrict fmt, ...) {
va_list ap;
va_start(ap, fmt);
error_log(stdout, "\033[91mERR\033[0m", ln, file, fmt, ap);
va_end(ap);
}
void error_fat(uint ln, const char *restrict file, const char *restrict fmt, ...) {
void error_fatal(uint ln, const char *restrict file, const char *restrict fmt, ...) {
va_list ap;
va_start(ap, fmt);
error_log(stdout, "\033[101mFAT\033[0m", ln, file, fmt, ap);

View File

@@ -9,14 +9,14 @@
#include "util/intdef.h"
#include "util/macro.h"
void error_dbg(uint ln, const char *restrict file, const char *restrict fmt, ...);
void error_inf(uint ln, const char *restrict file, const char *restrict fmt, ...);
void error_war(uint ln, const char *restrict file, const char *restrict fmt, ...);
void error_err(uint ln, const char *restrict file, const char *restrict fmt, ...);
void error_fat(uint ln, const char *restrict file, const char *restrict fmt, ...) NORET;
void error_debug(uint ln, const char *restrict file, const char *restrict fmt, ...);
void error_info(uint ln, const char *restrict file, const char *restrict fmt, ...);
void error_warn(uint ln, const char *restrict file, const char *restrict fmt, ...);
void error_error(uint ln, const char *restrict file, const char *restrict fmt, ...);
void error_fatal(uint ln, const char *restrict file, const char *restrict fmt, ...) NORET;
#define debug(...) error_dbg(__LINE__, __FILE__ __VA_OPT__(, ) __VA_ARGS__)
#define info(...) error_inf(__LINE__, __FILE__ __VA_OPT__(, ) __VA_ARGS__)
#define warn(...) error_war(__LINE__, __FILE__ __VA_OPT__(, ) __VA_ARGS__)
#define error(...) error_err(__LINE__, __FILE__ __VA_OPT__(, ) __VA_ARGS__)
#define fatal(...) error_fat(__LINE__, __FILE__ __VA_OPT__(, ) __VA_ARGS__)
#define debug(...) error_debug(__LINE__, __FILE__ __VA_OPT__(, ) __VA_ARGS__)
#define info(...) error_info(__LINE__, __FILE__ __VA_OPT__(, ) __VA_ARGS__)
#define warn(...) error_warn(__LINE__, __FILE__ __VA_OPT__(, ) __VA_ARGS__)
#define error(...) error_error(__LINE__, __FILE__ __VA_OPT__(, ) __VA_ARGS__)
#define fatal(...) error_fatal(__LINE__, __FILE__ __VA_OPT__(, ) __VA_ARGS__)

View File

@@ -4,7 +4,7 @@
#include <GLFW/glfw3.h>
void key_callback(GLFWwindow *win, int key, int scancode, int action, int mods) {
void input_callback(GLFWwindow *win, int key, int scancode, int action, int mods) {
(void)win, (void)key, (void)scancode, (void)action, (void)mods; // make the compiler shut up as this is fine
#ifndef NDEBUG
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)

View File

@@ -4,4 +4,6 @@
#include <GLFW/glfw3.h>
void key_callback(GLFWwindow *win, int key, int scancode, int action, int mods);
/* Handles incoming key inputs for `win`.
* Intended to be given as an argument to `glfwSetKeyCallback`. */
void input_callback(GLFWwindow *win, int key, int scancode, int action, int mods);

View File

@@ -2,9 +2,8 @@
* Licensed under the MIT Licence. See LICENSE for details */
#include "render.h"
#include <glad/gl.h>
#include <GLFW/glfw3.h>
#include <glad/gl.h>
#include <stdint.h>
#include "../error.h"
@@ -80,3 +79,12 @@ void render_update(GLFWwindow *win) {
glBindVertexArray(vao);
glDrawArrays(GL_POINTS, 0, VERTC);
}
void render_free(void) {
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glDeleteProgram(pipe);
vbo = 0;
vao = 0;
pipe = 0;
}

View File

@@ -2,9 +2,9 @@
* Licensed under the MIT Licence. See LICENSE for details */
#pragma once
#include <glad/gl.h>
#include <GLFW/glfw3.h>
#include <glad/gl.h>
int render_init(void);
void render_update(GLFWwindow *win);
void render_free(void);

View File

@@ -17,7 +17,8 @@ extern const uint sh_vert_glsl_len;
extern const uint sh_frag_glsl_len;
extern const uint sh_geom_glsl_len;
/* compile a shader */
/* Compiles a shader of `type` from `src` with `len` bytes.
* Returns the integer for the shader. */
static GLuint shader_compile(GLenum type, const char *src, size_t len) {
int ilen = len;
GLuint shader = glCreateShader(type);
@@ -45,6 +46,7 @@ int shader_init(GLuint pipe) {
glAttachShader(pipe, fs);
glAttachShader(pipe, gs);
// mark shaders off for deletion
glDeleteShader(vs);
glDeleteShader(fs);
glDeleteShader(gs);

View File

@@ -3,8 +3,8 @@
#pragma once
#include <glad/gl.h>
#include <stddef.h>
#include <stdint.h>
/* Initialises the (embedded) shaders onto `pipe` */
int shader_init(GLuint pipe);

View File

@@ -2,49 +2,44 @@
* Licensed under the MIT Licence. See LICENSE for details */
#include "window.h"
#include <glad/gl.h>
#include <GLFW/glfw3.h>
#include <assert.h>
#include <glad/gl.h>
#include "../error.h"
#include "../util/intdef.h"
#include "input.h"
#include "render.h"
// macros for ease of access
#define WIN_NAME "MCA Selector Lite"
#define WIN_DEFAULT_WIDTH 640
#define WIN_DEFAULT_HEIGHT 480
static GLFWwindow *win = NULL;
static struct GLFWwindow *win = NULL;
/* Initialises the GLFW window with some defaults,
* then proceed to activate OpenGL on it. */
int window_init(void) {
// initialise the window
#ifndef NDEBUG
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
#endif
// initialize the window
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // sets the profile to "core", so old, deprecated functions are disabled.
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, 1);
glfwWindowHint(GLFW_RED_BITS, 8);
glfwWindowHint(GLFW_GREEN_BITS, 8);
glfwWindowHint(GLFW_BLUE_BITS, 8);
glfwWindowHint(GLFW_ALPHA_BITS, 0);
win = glfwCreateWindow(WIN_DEFAULT_WIDTH, WIN_DEFAULT_HEIGHT, WIN_NAME, NULL, NULL);
/* NOTE: on my system; x86_64, GTX 1650 580.82.09-2, X11, i3, this causes one direct, 2 indirect memory leaks.
* This is not my fault, and can safely be ignored. */
win = glfwCreateWindow(640, 480, "MCA-Selector lite", NULL, NULL);
if (!win) return 1;
// setup OpenGL for the window
glfwMakeContextCurrent(win);
if (!gladLoadGL(glfwGetProcAddress)) return 1;
glfwSwapInterval(1); // wait 1 screen update for a redraw a.k.a. "vsync". (not really applicable in this case but eh)
// configure callbacks
glfwSetKeyCallback(win, key_callback);
glfwSetKeyCallback(win, input_callback);
// print the OpenGL version information
debug(
"version info:\n"
"\tvendor: %s\n"
@@ -55,20 +50,33 @@ int window_init(void) {
glGetString(GL_RENDERER),
glGetString(GL_VERSION),
glGetString(GL_SHADING_LANGUAGE_VERSION));
return 0;
}
void window_loop(void) {
assert(win != NULL);
assert(win);
render_init();
while (!glfwWindowShouldClose(win)) {
glfwWaitEvents(); // wait till an update has been given
glfwWaitEvents();
render_update(win);
glfwSwapBuffers(win);
glfwPollEvents();
}
}
void window_close(void) {
assert(win);
glfwSetWindowShouldClose(win, 1);
}
void window_free(void) {
if (!win) {
debug("window has already been freed.");
return;
}
glfwDestroyWindow(win);
render_free();
win = NULL;
}

View File

@@ -2,5 +2,18 @@
* Licensed under the MIT Licence. See LICENSE for details */
#pragma once
int window_init(void); // initializes the global window, returns non-zero upon failure
void window_loop(void); // performs the window updates
/* Set up the window, enabling OpenGL, and
* configuring the settings that are needed.
* Returns `0` upon success, otherwise `1`. */
int window_init(void);
/* Calls the update loop for the window.
* This function does not exit until the window does. */
void window_loop(void);
/* Requests the window to close (gracefully). */
void window_close(void);
/* Cleans up all resources held by the window.
* If the window is still open, it will be terminated. */
void window_free(void);

View File

@@ -1,50 +1,41 @@
/* Copyright (c) 2025 Quinn
* Licensed under the MIT Licence. See LICENSE for details */
#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>
#undef GLAD_GL_IMPLEMENTATION
#include <GLFW/glfw3.h>
#include <glad/gl.h>
#include <stdio.h>
#include <stdlib.h>
#include "error.h"
#include "io/window.h"
#define WIN_NAME "MCA Selector Lite"
#define WIN_DEFAULT_WIDTH 640
#define WIN_DEFAULT_HEIGHT 480
// callback for GLFW errors
/* reroutes GLFW errors to our logging system. */
static void error_callback(int err, const char *const msg) {
fprintf(stderr, "\033[91mE: glfw returned (%i); \"%s\"\033[0m\n", err, msg);
}
static inline int init(void) {
glfwSetErrorCallback(error_callback);
glfwInitHint(GLFW_JOYSTICK_HAT_BUTTONS, GLFW_FALSE); // disable joystick buttons
if (!glfwInit()) return 1; // initialize GLFW
if (window_init()) return 1;
return 0;
error("glfw returned (%i); \"%s\"", err, msg);
}
static void quit(void) {
window_free();
/* terminates GLFW; destroying any
* remaining windows, or other resources held by GLFW. */
glfwTerminate();
}
/* Entry-point of the application. */
int main(int argc, char **argv) {
(void)argc, (void)argv;
printf("debug: [DBG], info: [INF], warning: [WAR], error: [ERR], fatal: [FAT]\n");
atexit(quit);
if (init()) fatal("failed to initialize!");
glfwSetErrorCallback(error_callback);
glfwInitHint(GLFW_JOYSTICK_HAT_BUTTONS, GLFW_FALSE); // disable joystick buttons; since we won't need them
if (!glfwInit() || window_init())
fatal("failed to initialise!");
window_loop();
quit();
// return success, since some architectures do not follow 0=success
/* return success, since some architectures do not follow 0=success
* This action will call `quit`. */
return EXIT_SUCCESS;
}