summaryrefslogtreecommitdiff
path: root/shaders
diff options
context:
space:
mode:
authorHunter Kvalevog <hunter@kvog.sh>2026-02-03 22:05:09 -0600
committerHunter Kvalevog <hunter@kvog.sh>2026-02-03 22:05:09 -0600
commitbf18c18430c4cacb8c0fddbef0c2bf1962177dec (patch)
treea95f5576680ce7d43c0ddc94ccc4f40c1d42fc75 /shaders
parent440612338695a73509c8bf3b72ef0e0786446cb7 (diff)
shaders: Refactor
Diffstat (limited to 'shaders')
-rw-r--r--shaders/CMakeLists.txt8
-rw-r--r--shaders/aero.cc31
-rw-r--r--shaders/aero.glsl7
-rw-r--r--shaders/polygon.cc27
-rw-r--r--shaders/polygon.glsl5
-rw-r--r--shaders/shaders.cc (renamed from shaders/main.cc)501
-rw-r--r--shaders/shaders.hh69
-rw-r--r--shaders/vfog.cc35
-rw-r--r--shaders/vfog.glsl5
9 files changed, 337 insertions, 351 deletions
diff --git a/shaders/CMakeLists.txt b/shaders/CMakeLists.txt
index 437476b..c78d42b 100644
--- a/shaders/CMakeLists.txt
+++ b/shaders/CMakeLists.txt
@@ -5,5 +5,11 @@ set(DEMO_NEEDS_DEAR_IMGUI TRUE)
set(DEMO_NEEDS_SDL3 TRUE)
include("${CMAKE_CURRENT_LIST_DIR}/../common/c_cpp/CMakeLists.txt")
-add_executable(shaders main.cc)
+add_executable(shaders
+ shaders.cc
+
+ aero.cc
+ polygon.cc
+ vfog.cc
+)
target_link_libraries(shaders PRIVATE common)
diff --git a/shaders/aero.cc b/shaders/aero.cc
new file mode 100644
index 0000000..8b7e27b
--- /dev/null
+++ b/shaders/aero.cc
@@ -0,0 +1,31 @@
+#include "shaders.hh"
+
+static int u_checker = 16;
+static float u_checker_c1[4] = { 0.9f, 0.9f, 0.9f, 1.0f };
+static float u_checker_c2[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+static float u_ww = 500;
+static float u_wh = 400;
+
+static void ui()
+{
+ ImGui::InputInt("Checker", &u_checker);
+ ImGui::SliderFloat("window w", &u_ww, 10, 1000);
+ ImGui::SliderFloat("window h", &u_wh, 10, 1000);
+}
+
+static void uniforms(Shader* shader)
+{
+ GL(glUniform1i(shader->get_required_uniform("u_checker"), u_checker));
+ GL(glUniform4fv(shader->get_required_uniform("u_checker_c1"), 1, u_checker_c1));
+ GL(glUniform4fv(shader->get_required_uniform("u_checker_c2"), 1, u_checker_c2));
+ GL(glUniform1f(shader->get_required_uniform("u_ww"), u_ww));
+ GL(glUniform1f(shader->get_required_uniform("u_wh"), u_wh));
+}
+
+static Shader aero = {
+ .path = "aero.glsl",
+ .model = MODEL_QUAD,
+ .ui_fn = ui,
+ .uf_fn = uniforms,
+};
+ENABLE_SHADER(aero);
diff --git a/shaders/aero.glsl b/shaders/aero.glsl
index 82d3c83..b321af3 100644
--- a/shaders/aero.glsl
+++ b/shaders/aero.glsl
@@ -3,13 +3,6 @@
// --------------------------------------------------------------------------------
// Windows 7-style "aero" effect
//
-// @model quad
-// @uniform int u_checker 16 4 64
-// @uniform color u_checker_c1 0.9 0.9 0.9 1
-// @uniform color u_checker_c2 1.0 1.0 1.0 1
-// @uniform float u_ww 500
-// @uniform float u_wh 400
-//
// SPDX-License-Identifier: 0BSD
// --------------------------------------------------------------------------------
diff --git a/shaders/polygon.cc b/shaders/polygon.cc
new file mode 100644
index 0000000..c881475
--- /dev/null
+++ b/shaders/polygon.cc
@@ -0,0 +1,27 @@
+#include "shaders.hh"
+
+static int u_n = 3;
+static float u_bg[4] = { 0, 0, 0, 1 };
+static float u_fg[4] = { 1, 1, 1, 1 };
+
+static void ui()
+{
+ ImGui::SliderInt("N", &u_n, 3, 24);
+ ImGui::ColorPicker4("bg", u_bg);
+ ImGui::ColorPicker4("fg", u_fg);
+}
+
+static void uniforms(Shader* shader)
+{
+ GL(glUniform1i(shader->get_required_uniform("u_n"), u_n));
+ GL(glUniform4fv(shader->get_required_uniform("u_bg"), 1, u_bg));
+ GL(glUniform4fv(shader->get_required_uniform("u_fg"), 1, u_fg));
+}
+
+static Shader polygon = {
+ .path = "polygon.glsl",
+ .model = MODEL_QUAD,
+ .ui_fn = ui,
+ .uf_fn = uniforms,
+};
+ENABLE_SHADER(polygon);
diff --git a/shaders/polygon.glsl b/shaders/polygon.glsl
index e33aaf7..a213f13 100644
--- a/shaders/polygon.glsl
+++ b/shaders/polygon.glsl
@@ -6,11 +6,6 @@
// ref: https://thndl.com/square-shaped-shaders.html
// ref: https://thebookofshaders.com/07/
//
-// @model quad
-// @uniform int u_n 3 3 12
-// @uniform color u_bg 0 0 0 1
-// @uniform color u_fg 1 1 1 1
-//
// SPDX-License-Identifier: 0BSD
// --------------------------------------------------------------------------------
diff --git a/shaders/main.cc b/shaders/shaders.cc
index c026eb2..214d598 100644
--- a/shaders/main.cc
+++ b/shaders/shaders.cc
@@ -1,11 +1,7 @@
-// --------------------------------------------------------------------------------
-// OpenGL shader sandbox
-//
// SPDX-License-Identifier: 0BSD
-// --------------------------------------------------------------------------------
#define GLAD_GL_IMPLEMENTATION
-#include "../common/c_cpp/thirdparty/glad33/glad33.h"
+#include "shaders.hh"
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL.h>
@@ -13,7 +9,6 @@
#include <SDL3/SDL_opengl.h>
#define IMGUI_IMPL_OPENGL_LOADER_CUSTOM
-#include "imgui.h"
#include "imgui_impl_opengl3.cpp"
#include "imgui_impl_sdl3.cpp"
@@ -194,223 +189,37 @@ public:
};
// --------------------------------------------------------------------------------
-// Shader metadata parser
+// Application
// --------------------------------------------------------------------------------
-enum : int
-{
- SHADER_MODEL_TYPE_INVALID = 0,
- SHADER_MODEL_TYPE_QUAD,
- SHADER_MODEL_TYPE_CUBE,
-};
-
-enum : int
-{
- SHADER_UNIFORM_TYPE_INVALID = 0,
- SHADER_UNIFORM_TYPE_INT,
- SHADER_UNIFORM_TYPE_FLOAT,
- SHADER_UNIFORM_TYPE_COLOR,
-};
-
-struct ShaderUniform
+typedef struct Model Model;
+struct Model
{
- char name[32];
- int type;
- int val_i1;
- float val_fl;
- Vec4 val_v4;
- int min_i;
- int max_i;
-};
-
-struct ShaderMetadata
-{
- int model;
- ImVector<ShaderUniform> uniforms;
+ GLuint vao;
+ GLuint vbo;
+ GLuint ibo;
+ GLuint vs;
+ int ibo_len;
+ bool is_3d;
};
-static bool ReadToken(const char** src, const char** out, int* len)
-{
- while (isspace(**src)) {
- ++*src;
- }
- if (!**src) {
- return false;
- }
-
- *len = 0;
- *out = *src;
- while (**src && !isspace(**src)) {
- ++*src;
- ++*len;
- }
-
- return true;
-}
-
-static bool TokenEq(const char* tok, int len, const char* str)
-{
- return (int)strlen(str) == len && !strncmp(tok, str, len);
-}
-
-static int TokenInt(const char* tok, int len)
-{
- char tmp[64] = { };
- strncpy(tmp, tok, Min((int)sizeof(tmp), len));
- return atoi(tmp);
-}
-
-static float TokenFloat(const char* tok, int len)
-{
- char tmp[64] = { };
- strncpy(tmp, tok, Min((int)sizeof(tmp), len));
- return strtof(tmp, NULL);
-}
-
-static void ParseShaderMetadata(ShaderMetadata* sm, const char* src)
-{
- *sm = ShaderMetadata();
-
- while ((src = strchr(src, '@'))) {
- // @model <quad|cube>
- if (!strncmp(src, "@model", 6)) {
- src += 6;
-
- const char* tok;
- int len;
- if (!ReadToken(&src, &tok, &len)) {
- SDL_Log("@model: Missing parameter");
- continue;
- }
-
- if (TokenEq(tok, len, "quad")) {
- sm->model = SHADER_MODEL_TYPE_QUAD;
- } else if (TokenEq(tok, len, "cube")) {
- sm->model = SHADER_MODEL_TYPE_CUBE;
- } else {
- SDL_Log("@model: Invalid parameter: %.*s", len, tok);
- }
-
- continue;
- }
-
- // @uniform <type> <name> <val>
- else if (!strncmp(src, "@uniform", 8)) {
- src += 8;
-
- ShaderUniform u = { };
-
- const char* tok;
- int len;
- if (!ReadToken(&src, &tok, &len)) {
- SDL_Log("@uniform: Missing parameter");
- continue;
- }
- const char* type_tok = tok;
- int type_len = len;
-
- if (!ReadToken(&src, &tok, &len)) {
- SDL_Log("@uniform: Missing parameter");
- continue;
- }
- strncpy(u.name, tok, Min((int)sizeof(u.name), len));
-
- // i min max
- if (TokenEq(type_tok, type_len, "int")) {
- u.type = SHADER_UNIFORM_TYPE_INT;
-
- if (!ReadToken(&src, &tok, &len)) {
- SDL_Log("@uniform: No value");
- continue;
- }
- u.val_i1 = TokenInt(tok, len);
- if (!ReadToken(&src, &tok, &len)) {
- SDL_Log("@uniform: No value");
- continue;
- }
- u.min_i = TokenInt(tok, len);
- if (!ReadToken(&src, &tok, &len)) {
- SDL_Log("@uniform: No value");
- continue;
- }
- u.max_i = TokenInt(tok, len);
- }
- // f
- else if (TokenEq(type_tok, type_len, "float")) {
- u.type = SHADER_UNIFORM_TYPE_FLOAT;
-
- if (!ReadToken(&src, &tok, &len)) {
- SDL_Log("@uniform: No value");
- continue;
- }
- u.val_fl = TokenFloat(tok, len);
- }
- // f f f f
- else if (TokenEq(type_tok, type_len, "color")) {
- u.type = SHADER_UNIFORM_TYPE_COLOR;
-
- if (!ReadToken(&src, &tok, &len)) {
- SDL_Log("@uniform: No value");
- continue;
- }
- u.val_v4.x = TokenFloat(tok, len);
- if (!ReadToken(&src, &tok, &len)) {
- SDL_Log("@uniform: No value");
- continue;
- }
- u.val_v4.y = TokenFloat(tok, len);
- if (!ReadToken(&src, &tok, &len)) {
- SDL_Log("@uniform: No value");
- continue;
- }
- u.val_v4.z = TokenFloat(tok, len);
- if (!ReadToken(&src, &tok, &len)) {
- SDL_Log("@uniform: No value");
- continue;
- }
- u.val_v4.w = TokenFloat(tok, len);
- } else {
- SDL_Log("@uniform: Unsupported type: %.*s", type_len, type_tok);
- continue;
- }
-
- sm->uniforms.push_back(u);
-
- continue;
- }
- }
-}
-
-// --------------------------------------------------------------------------------
-// Application
-// --------------------------------------------------------------------------------
-
static struct
{
- SDL_Window* wnd;
- ShaderMetadata sm;
- bool ui_hidden;
- bool pause;
+ SDL_Window* wnd;
+ bool ui_hidden;
+ bool pause;
- GLuint shader;
+ int shader_index = 0;
float cam_dist = 3.5f;
Vec2 cam_ang = Vec2(0, 0);
- GLuint vao;
- GLuint vbo;
- GLuint ibo;
- int ibo_len;
+ Model models[_MODEL_COUNT];
} G = { };
-static inline bool Is3D()
-{
- return G.sm.model == SHADER_MODEL_TYPE_CUBE;
-}
-
// Helper: Report errors via glGetError() after every OpenGL function call.
// macOS does not support glDebugMessageCallback
-static void AssertGL(GLenum error, const char* expr, int line)
+void AssertGL(GLenum error, const char* expr, int line)
{
if (error != GL_NO_ERROR) {
const char* error_string;
@@ -427,44 +236,30 @@ static void AssertGL(GLenum error, const char* expr, int line)
SDL_Log("[Line #%u] %s caused %s\n", line, expr, error_string);
}
}
-#define GL(expr) \
- expr; \
- for (GLenum _glcode; (_glcode = glGetError()) != GL_NO_ERROR; ) { \
- AssertGL(_glcode, #expr, __LINE__); \
- }
-SDL_AppResult SDLCALL SDL_AppInit(void**, int argc, char* argv[])
+std::vector<Shader*>& GetShaders()
+{
+ static std::vector<Shader*> s_shaders = { };
+ return s_shaders;
+}
+
+SDL_AppResult SDLCALL SDL_AppInit(void**, int, char**)
{
if (!SDL_Init(SDL_INIT_VIDEO)) {
SDL_Log("Failed to initialize SDL: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
- const char* path = (argc > 1) ? argv[1] : NULL;
- if (!path) {
- SDL_Log("No shader file supplied");
- return SDL_APP_FAILURE;
- }
-
- char* src = (char*)SDL_LoadFile(path, NULL);
- if (!src) {
- SDL_Log("Failed to load %s: %s", path, SDL_GetError());
- return SDL_APP_FAILURE;
- }
-
- ParseShaderMetadata(&G.sm, src);
-
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 4);
- char title[64]; snprintf(title, sizeof(title), "shaders: %s", path);
Uint32 wflags = SDL_WINDOW_OPENGL |
SDL_WINDOW_HIGH_PIXEL_DENSITY |
SDL_WINDOW_RESIZABLE;
- G.wnd = SDL_CreateWindow(title, 1024, 768, wflags);
+ G.wnd = SDL_CreateWindow("shaders", 1024, 768, wflags);
if (!G.wnd) {
SDL_Log("Failed to create window: %s", SDL_GetError());
return SDL_APP_FAILURE;
@@ -481,27 +276,28 @@ SDL_AppResult SDLCALL SDL_AppInit(void**, int argc, char* argv[])
return SDL_APP_FAILURE;
}
- GL(glGenVertexArrays(1, &G.vao));
- GL(glBindVertexArray(G.vao));
-
- GL(glGenBuffers(1, &G.vbo));
- GL(glBindBuffer(GL_ARRAY_BUFFER, G.vbo));
-
- GL(glGenBuffers(1, &G.ibo));
- GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, G.ibo));
-
- switch (G.sm.model) {
- case SHADER_MODEL_TYPE_QUAD: {
- //
- // 0 1
- // +------------+
- // | |
- // | |
- // | |
- // | |
- // | 3 | 2
- // +------------+
- //
+ // Quad mesh
+ // 0 1
+ // +------------+
+ // | |
+ // | |
+ // | |
+ // | |
+ // | 3 | 2
+ // +------------+
+ //
+ {
+ Model* m = &G.models[MODEL_QUAD];
+
+ GL(glGenVertexArrays(1, &m->vao));
+ GL(glBindVertexArray(m->vao));
+
+ GL(glGenBuffers(1, &m->vbo));
+ GL(glBindBuffer(GL_ARRAY_BUFFER, m->vbo));
+
+ GL(glGenBuffers(1, &m->ibo));
+ GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->ibo));
+
struct V { Vec2 p; Vec2 t; };
const V vdata[] = {
{ Vec2(-1.0f, 1.0f), Vec2(0, 1) },
@@ -519,21 +315,34 @@ SDL_AppResult SDLCALL SDL_AppInit(void**, int argc, char* argv[])
GL(glEnableVertexAttribArray(0));
GL(glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(V), (void*)offsetof(V, t)));
GL(glEnableVertexAttribArray(1));
- G.ibo_len = sizeof(idata) / sizeof(*idata);
- } break;
- case SHADER_MODEL_TYPE_CUBE: {
- //
- // +------------+
- // /| /|
- // / | / |
- // +------------+ |
- // | | | |
- // | | | |
- // | +---------|--+
- // | / | /
- // |/ |/
- // +------------+
- //
+ m->ibo_len = COUNTOF(idata);
+ m->is_3d = false;
+ }
+
+ // Cube mesh
+ // +------------+
+ // /| /|
+ // / | / |
+ // +------------+ |
+ // | | | |
+ // | | | |
+ // | +---------|--+
+ // | / | /
+ // |/ |/
+ // +------------+
+ //
+ {
+ Model* m = &G.models[MODEL_CUBE];
+
+ GL(glGenVertexArrays(1, &m->vao));
+ GL(glBindVertexArray(m->vao));
+
+ GL(glGenBuffers(1, &m->vbo));
+ GL(glBindBuffer(GL_ARRAY_BUFFER, m->vbo));
+
+ GL(glGenBuffers(1, &m->ibo));
+ GL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m->ibo));
+
struct V { Vec3 p; Vec2 t; Vec3 n; };
const V vdata[] = {
// Front
@@ -589,46 +398,40 @@ SDL_AppResult SDLCALL SDL_AppInit(void**, int argc, char* argv[])
GL(glEnableVertexAttribArray(1));
GL(glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(V), (void*)offsetof(V, n)));
GL(glEnableVertexAttribArray(2));
- G.ibo_len = sizeof(idata) / sizeof(*idata);
- } break;
- default: return SDL_APP_FAILURE;
+ m->ibo_len = COUNTOF(idata);
+ m->is_3d = true;
}
- const char* vs_table[] = {
- NULL,
+ const char* vshaders[] = {
"vert_quad.glsl",
- "vert_cube.glsl",
- };
- char* vs_src = (char*)SDL_LoadFile(vs_table[G.sm.model], NULL);
- if (!vs_src) {
- SDL_Log("Failed to load vertex shader %s: %s", vs_table[G.sm.model], SDL_GetError());
- return SDL_APP_FAILURE;
- }
- char* fs_src = src;
-
- struct {
- GLenum type;
- const char* src;
- } shaders[] = {
- { .type = GL_VERTEX_SHADER, .src = vs_src },
- { .type = GL_FRAGMENT_SHADER, .src = fs_src },
+ "vert_cube.glsl"
};
- G.shader = GL(glCreateProgram());
- for (size_t i = 0; i < sizeof(shaders) / sizeof(*shaders); ++i) {
- GLuint shader = GL(glCreateShader(shaders[i].type));
- GL(glShaderSource(shader, 1, &shaders[i].src, NULL));
+ static_assert(COUNTOF(vshaders) == _MODEL_COUNT);
+ for (size_t i = 0; i < COUNTOF(vshaders); ++i) {
+ char* vs_src = (char*)SDL_LoadFile(vshaders[i], NULL);
+ if (!vs_src) {
+ SDL_Log("Failed to load vertex shader %s: %s", vshaders[i], SDL_GetError());
+ return SDL_APP_FAILURE;
+ }
+
+ GLuint shader = GL(glCreateShader(GL_VERTEX_SHADER));
+ GL(glShaderSource(shader, 1, &vs_src, NULL));
GL(glCompileShader(shader));
+
GLint compile_status = 0;
GL(glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status));
if (compile_status != GL_TRUE) {
char error[1024] = { 0 };
GL(glGetShaderInfoLog(shader, sizeof(error), NULL, error));
- SDL_Log("Error compiling shader %s", error);
+ SDL_Log("Error compiling shader %s: %s", vshaders[i], error);
return SDL_APP_FAILURE;
}
- GL(glAttachShader(G.shader, shader));
+
+ G.models[i].vs = shader;
+ SDL_Log("Compiled vertex shader %s", vshaders[i]);
+
+ SDL_free(vs_src);
}
- GL(glLinkProgram(G.shader));
IMGUI_CHECKVERSION();
ImGui::CreateContext();
@@ -654,20 +457,67 @@ SDL_AppResult SDLCALL SDL_AppIterate(void*)
GL(glClearColor(0.1f, 0.1f, 0.1f, 1.0f));
GL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
- GL(glUseProgram(G.shader));
- GL(glBindVertexArray(G.vao));
+ Shader* shader = GetShaders()[G.shader_index];
+ Model* model = &G.models[shader->model];
+
+ if (!shader->ready) {
+ shader->program = GL(glCreateProgram());
+
+ char* fs_src = (char*)SDL_LoadFile(shader->path, NULL);
+ if (!fs_src) {
+ SDL_Log("Failed to load fragment shader %s: %s", shader->path, SDL_GetError());
+ return SDL_APP_FAILURE;
+ }
+
+ GLuint fs = GL(glCreateShader(GL_FRAGMENT_SHADER));
+ GL(glShaderSource(fs, 1, &fs_src, NULL));
+ GL(glCompileShader(fs));
+
+ GLint compile_status = 0;
+ GL(glGetShaderiv(fs, GL_COMPILE_STATUS, &compile_status));
+ if (compile_status != GL_TRUE) {
+ char error[1024] = { 0 };
+ GL(glGetShaderInfoLog(fs, sizeof(error), NULL, error));
+ SDL_Log("Error compiling shader %s: %s", shader->path, error);
+ return SDL_APP_FAILURE;
+ }
+
+ SDL_Log("Compiled fragment shader %s", shader->path);
+
+ SDL_free(fs_src);
+
+ GL(glAttachShader(shader->program, model->vs));
+ GL(glAttachShader(shader->program, fs));
+ GL(glLinkProgram(shader->program));
+
+ GLint link_status = 0;
+ GL(glGetProgramiv(shader->program, GL_LINK_STATUS, &link_status));
+ if (link_status != GL_TRUE) {
+ char error[1024] = { 0 };
+ GL(glGetProgramInfoLog(shader->program, sizeof(error), NULL, error));
+ SDL_Log("Error linking program %s: %s", shader->path, error);
+ return SDL_APP_FAILURE;
+ }
+
+ SDL_Log("Linked program");
+
+ shader->ready = true;
+ }
+
+ GL(glBindVertexArray(model->vao));
+ GL(glUseProgram(shader->program));
GLint u_id = -1;
- if ((u_id = glGetUniformLocation(G.shader, "u_res")) != -1) {
+ if ((u_id = glGetUniformLocation(shader->program, "u_res")) != -1) {
GL(glUniform2f(u_id, (float)wnd_x, (float)wnd_y));
}
- if ((u_id = glGetUniformLocation(G.shader, "u_time")) != -1) {
+ if ((u_id = glGetUniformLocation(shader->program, "u_time")) != -1) {
if (!G.pause) {
GL(glUniform1f(u_id, SDL_GetTicks() / 1e3f));
}
}
- if (Is3D()) {
+ if (model->is_3d) {
const Vec3 cam = Vec3::FromEuler(G.cam_ang) * G.cam_dist;
const Vec3 tgt = Vec3(0, 0, 0);
const float fov = 75.0f;
@@ -676,36 +526,22 @@ SDL_AppResult SDLCALL SDL_AppIterate(void*)
Mat4x4 m_proj = Mat4x4::Perspective(fov, (float)wnd_x / (float)wnd_y, 0.1f, 100.0f);
Mat4x4 m_view = m_proj * m_look;
- if ((u_id = glGetUniformLocation(G.shader, "u_vmat")) == -1) {
+ if ((u_id = glGetUniformLocation(shader->program, "u_vmat")) == -1) {
SDL_Log("Warning: u_vmat uniform not found");
} else {
GL(glUniformMatrix4fv(u_id, 1, GL_FALSE, m_view.Base()));
}
- if ((u_id = glGetUniformLocation(G.shader, "u_cam")) != -1) {
+ if ((u_id = glGetUniformLocation(shader->program, "u_cam")) != -1) {
GL(glUniform3f(u_id, cam.x, cam.y, cam.z));
}
}
- for (auto& u : G.sm.uniforms) {
- if ((u_id = glGetUniformLocation(G.shader, u.name)) == -1) {
- SDL_Log("Warning: Couldn't find a uniform with the name %s", u.name);
- continue;
- }
- switch (u.type) {
- case SHADER_UNIFORM_TYPE_INT: {
- GL(glUniform1i(u_id, u.val_i1));
- } break;
- case SHADER_UNIFORM_TYPE_FLOAT: {
- GL(glUniform1f(u_id, u.val_fl));
- } break;
- case SHADER_UNIFORM_TYPE_COLOR: {
- GL(glUniform4f(u_id, u.val_v4.x, u.val_v4.y, u.val_v4.z, u.val_v4.w));
- } break;
- }
+ if (shader->uf_fn) {
+ shader->uf_fn(shader);
}
- GL(glDrawElements(GL_TRIANGLES, G.ibo_len, GL_UNSIGNED_SHORT, NULL));
+ GL(glDrawElements(GL_TRIANGLES, model->ibo_len, GL_UNSIGNED_SHORT, NULL));
ImGui_ImplSDL3_NewFrame();
ImGui_ImplOpenGL3_NewFrame();
@@ -720,25 +556,22 @@ SDL_AppResult SDLCALL SDL_AppIterate(void*)
ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoResize;
- if (ImGui::Begin("Test", NULL, flags)) {
+ if (ImGui::Begin("ControlsWindow", NULL, flags)) {
+ if (ImGui::BeginCombo("Shader", GetShaders()[G.shader_index]->path)) {
+ for (int i = 0; i < (int)GetShaders().size(); ++i) {
+ if (ImGui::Selectable(GetShaders()[i]->path, i == G.shader_index)) {
+ G.shader_index = i;
+ }
+ }
+ ImGui::EndCombo();
+ }
ImGui::SeparatorText("Controls");
ImGui::Text("Tab: Toggle UI");
ImGui::Checkbox("Pause time", &G.pause);
- if (G.sm.uniforms.size() > 0) {
+
+ if (shader->ui_fn) {
ImGui::SeparatorText("Uniforms");
- for (auto& u : G.sm.uniforms) {
- switch (u.type) {
- case SHADER_UNIFORM_TYPE_INT: {
- ImGui::SliderInt(u.name, &u.val_i1, u.min_i, u.max_i);
- } break;
- case SHADER_UNIFORM_TYPE_FLOAT: {
- ImGui::DragFloat(u.name, &u.val_fl, 0.01f);
- } break;
- case SHADER_UNIFORM_TYPE_COLOR: {
- ImGui::ColorEdit4(u.name, &u.val_v4.x);
- } break;
- }
- }
+ shader->ui_fn();
}
}
ImGui::End();
@@ -757,6 +590,8 @@ SDL_AppResult SDLCALL SDL_AppIterate(void*)
SDL_AppResult SDLCALL SDL_AppEvent(void*, SDL_Event* event)
{
+ bool is_3d = G.models[GetShaders()[G.shader_index]->model].is_3d;
+
ImGui_ImplSDL3_ProcessEvent(event);
switch (event->type) {
case SDL_EVENT_KEY_DOWN: {
@@ -765,7 +600,7 @@ SDL_AppResult SDLCALL SDL_AppEvent(void*, SDL_Event* event)
}
} break;
case SDL_EVENT_MOUSE_MOTION: {
- if (Is3D() && (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_MASK(SDL_BUTTON_LEFT))) {
+ if (is_3d && (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_MASK(SDL_BUTTON_LEFT))) {
const float sens = 0.4f;
G.cam_ang.x -= event->motion.xrel * sens;
G.cam_ang.y += event->motion.yrel * sens;
@@ -773,7 +608,7 @@ SDL_AppResult SDLCALL SDL_AppEvent(void*, SDL_Event* event)
}
} break;
case SDL_EVENT_MOUSE_WHEEL: {
- if (Is3D()) {
+ if (is_3d) {
G.cam_dist -= event->wheel.y * 0.1f;
G.cam_dist = Max(G.cam_dist, 1.0f);
}
diff --git a/shaders/shaders.hh b/shaders/shaders.hh
new file mode 100644
index 0000000..00365fb
--- /dev/null
+++ b/shaders/shaders.hh
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: 0BSD
+
+#ifndef _SHADERS_HH_
+#define _SHADERS_HH_
+
+#include "../common/c_cpp/thirdparty/glad33/glad33.h"
+#include "imgui.h"
+
+#include <algorithm>
+#include <vector>
+
+#include <SDL3/SDL.h>
+
+#define COUNTOF(arr) (sizeof(arr) / sizeof(*(arr)))
+
+// Model type
+enum
+{
+ MODEL_QUAD = 0,
+ MODEL_CUBE,
+ _MODEL_COUNT
+};
+
+struct Shader
+{
+ const char* path;
+ int model;
+ void(*ui_fn)(void);
+ void(*uf_fn)(Shader* prog);
+
+ // Private
+ bool ready = false;
+ GLuint program;
+
+ inline GLint get_required_uniform(const char* name)
+ {
+ GLint id = glGetUniformLocation(program, name);
+ if (id == -1) {
+ SDL_Log("Shader %s missing required uniform %s", path, name);
+ }
+ return id;
+ }
+};
+
+std::vector<Shader*>& GetShaders();
+
+void AssertGL(GLenum error, const char* expr, int line);
+#define GL(expr) \
+ expr; \
+ for (GLenum _glcode; (_glcode = glGetError()) != GL_NO_ERROR; ) { \
+ AssertGL(_glcode, #expr, __LINE__); \
+ }
+
+
+class ShaderRegisterHelper
+{
+public:
+ ShaderRegisterHelper(Shader* shader)
+ {
+ std::vector<Shader*>& shaders = GetShaders();
+ shaders.push_back(shader);
+ std::sort(shaders.begin(), shaders.end(), [](const Shader* a, const Shader* b) {
+ return std::strcmp(a->path, b->path) < 0;
+ });
+ }
+};
+#define ENABLE_SHADER(shader) static ShaderRegisterHelper _shader_reg = ShaderRegisterHelper(&shader);
+
+#endif // _SHADERS_HH_
diff --git a/shaders/vfog.cc b/shaders/vfog.cc
new file mode 100644
index 0000000..116d433
--- /dev/null
+++ b/shaders/vfog.cc
@@ -0,0 +1,35 @@
+#include "shaders.hh"
+
+static int u_mode = 0;
+static int u_steps = 8;
+static float u_sigma = 4.0f;
+
+static void ui()
+{
+ const char* modes[] = { "basic", "vfade", "waves" };
+ if (ImGui::BeginCombo("mode", modes[u_mode])) {
+ for (int i = 0; i < (int)COUNTOF(modes); ++i) {
+ if (ImGui::Selectable(modes[i], i == u_mode)) {
+ u_mode = i;
+ }
+ }
+ ImGui::EndCombo();
+ }
+ ImGui::SliderInt("steps", &u_steps, 1, 8);
+ ImGui::InputFloat("sigma", &u_sigma);
+}
+
+static void uniforms(Shader* shader)
+{
+ GL(glUniform1i(shader->get_required_uniform("u_mode"), u_mode));
+ GL(glUniform1i(shader->get_required_uniform("u_steps"), u_steps));
+ GL(glUniform1f(shader->get_required_uniform("u_sigma"), u_sigma));
+}
+
+static Shader vfog = {
+ .path = "vfog.glsl",
+ .model = MODEL_CUBE,
+ .ui_fn = ui,
+ .uf_fn = uniforms,
+};
+ENABLE_SHADER(vfog);
diff --git a/shaders/vfog.glsl b/shaders/vfog.glsl
index f638b27..e92e957 100644
--- a/shaders/vfog.glsl
+++ b/shaders/vfog.glsl
@@ -3,11 +3,6 @@
// --------------------------------------------------------------------------------
// Volumetric fog
//
-// @model cube
-// @uniform int u_mode 0 0 2
-// @uniform int u_steps 8 1 64
-// @uniform float u_sigma 4.0f
-//
// SPDX-License-Identifier: 0BSD
// --------------------------------------------------------------------------------