modularized shaders

This commit is contained in:
Lauchmelder 2022-10-20 17:32:27 +02:00
parent 18d817e6bf
commit 5e61cd8c50
12 changed files with 215 additions and 160 deletions

View file

@ -36,7 +36,10 @@ int init_application(Application* app, const char* name)
app->scenes = (Scene*)malloc(1 * sizeof(Scene));
app->active_scene = app->scenes; // First scene is active scene
create_spinning_cubes_scene(&app->window, app->scenes);
if (create_spinning_cubes_scene(&app->window, app->scenes) != 0)
{
return 1;
}
return 0;
}

View file

@ -4,7 +4,6 @@
#include <glad/glad.h>
static VertexArrayObject* vao = NULL;
static Shader shader = 0;
static size_t num_cubes = 0;
static int init_cube_object(void)
@ -78,72 +77,10 @@ static int init_cube_object(void)
};
set_vertex_layout(vao, attributes, sizeof(attributes) / sizeof(VertexAttribute));
shader = create_shader(
"#version 460 core\n"
""
"layout (location = 0) in vec3 pos;"
"layout (location = 1) in vec3 normal;"
""
"out vec3 frag_normal;"
"out vec3 frag_pos;"
""
"uniform mat4 model;"
"uniform mat4 view;"
"uniform mat4 projection;"
""
"void main() {"
" frag_normal = mat3(transpose(inverse(model))) * normal;"
" frag_pos = vec3(model * vec4(pos, 1.0));"
" gl_Position = projection * view * model * vec4(pos, 1.0);"
"}",
"#version 460 core\n"
""
"in vec3 frag_pos;"
"in vec3 frag_normal;"
""
"uniform vec3 ambient_color = vec3(1.0, 1.0, 1.0);"
"uniform float ambient_intens = 1.0f;"
""
"uniform vec3 point_pos = vec3(0.0, 0.0, 0.0);"
"uniform vec3 point_col = vec3(1.0, 1.0, 1.0);"
"uniform float point_intens = 1.0f;"
""
"uniform vec3 cam_pos = vec3(0.0, 0.0, 0.0);"
"float specular_strength = 0.5f;"
""
"uniform vec3 cube_color;"
""
"out vec4 FragColor;"
""
"void main() {"
" vec3 ambient = ambient_intens * ambient_color;"
""
" vec3 norm = normalize(frag_normal);"
" vec3 light_dir = normalize(point_pos - frag_pos);"
" float diff = max(dot(norm, light_dir), 0.0);"
" vec3 diffuse = diff * point_col;"
""
" vec3 view_dir = normalize(cam_pos - frag_pos);"
" vec3 reflect_dir = reflect(-light_dir, norm);"
""
" float spec = pow(max(dot(view_dir, reflect_dir), 0.0), 32);"
" vec3 specular = specular_strength * spec * point_col; "
""
" vec3 result = (ambient + diffuse + specular) * cube_color;"
" FragColor = vec4(result, 1.0);"
"}"
);
if (shader == 0)
{
fprintf(stderr, "failed to create shader for cube\n");
return 1;
}
return 0;
}
static void on_shader_bind(Cube* cube)
static void on_shader_bind(Cube* cube, Shader* shader)
{
set_uniform_vec3(shader, "cube_color", cube->color);
}
@ -171,7 +108,7 @@ static void on_update(Cube* cube)
int create_cube(Cube* cube)
{
if (vao == NULL || shader == 0)
if (vao == NULL)
{
if (init_cube_object() != 0)
{
@ -187,7 +124,6 @@ int create_cube(Cube* cube)
cube->color_mod[2] = 0.005f;
cube->object.vao = vao;
cube->object.shader = shader;
cube->object.child = cube;
cube->object.on_shader_use_obj = on_shader_bind;
@ -203,9 +139,6 @@ void destroy_cube(Cube* cube)
if (num_cubes == 0)
{
destroy_shader(shader);
shader = 0;
destroy_vao(*vao);
vao = NULL;
}

View file

@ -17,10 +17,8 @@ void update_object(Object* obj)
obj->on_update(obj->child);
}
void render_object(Object* obj, Camera* camera)
void render_object(Object* obj, Shader* shader)
{
bind_shader(obj->shader);
glm_mat4_identity(obj->transform);
float angle = glm_vec3_norm(obj->rotation);
vec3 normalized_rot;
@ -30,12 +28,9 @@ void render_object(Object* obj, Camera* camera)
glm_rotate(obj->transform, angle, normalized_rot);
glm_scale(obj->transform, obj->scale);
set_uniform_mat4(obj->shader, "model", obj->transform);
set_uniform_mat4(obj->shader, "view", get_camera_view(camera));
set_uniform_mat4(obj->shader, "projection", camera->projection);
set_uniform_mat4(shader, "model", obj->transform);
obj->on_shader_use_obj(obj->child);
obj->on_shader_use_scene(obj, obj->scene);
obj->on_shader_use_obj(obj->child, shader);
ctx_draw_elements(obj->vao);
}

View file

@ -11,7 +11,6 @@ typedef struct Camera Camera;
typedef struct Object
{
VertexArrayObject* vao;
Shader shader;
mat4 transform;
vec3 position;
@ -20,8 +19,7 @@ typedef struct Object
void* child;
void* scene;
void(*on_shader_use_obj)(void*);
void(*on_shader_use_scene)(void*, void*);
void(*on_shader_use_obj)(void*, void*);
void(*on_update)(void*);
void(*on_destroy)(void*);
} Object;
@ -33,6 +31,6 @@ void object_set_position(Object* obj, vec3 position);
void object_move(Object* obj, vec3 direction);
void update_object(Object* obj);
void render_object(Object* obj, Camera* camera);
void render_object(Object* obj, Shader* shader);
#endif // OBJECT_H

View file

@ -4,8 +4,11 @@
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#include <glad/glad.h>
#include "object.h"
static int set_and_compile_shader(GLuint program, GLuint shader, const char* code, char** error)
{
int result;
@ -32,47 +35,54 @@ static int set_and_compile_shader(GLuint program, GLuint shader, const char* cod
return 0;
}
Shader create_shader(const char* vertex_shader_code, const char* fragment_shader_code)
int create_shader(Shader* shader, const char* vertex_shader_code, const char* fragment_shader_code)
{
assert(shader);
assert(vertex_shader_code && fragment_shader_code);
int shader = glCreateProgram();
int return_val = 0;
shader->objects = create_dynamic_array(Object*);
shader->id = glCreateProgram();
char* error;
int vertex_shader = glCreateShader(GL_VERTEX_SHADER);
if (set_and_compile_shader(shader, vertex_shader, vertex_shader_code, &error) != 0)
if (set_and_compile_shader(shader->id, vertex_shader, vertex_shader_code, &error) != 0)
{
fprintf(stderr, "vertex shader compilation failed: %s\n", error);
free(error);
glDeleteProgram(shader);
shader = 0;
glDeleteProgram(shader->id);
shader->id = 0;
return_val = 1;
goto vertex_failed;
}
int fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
if (set_and_compile_shader(shader, fragment_shader, fragment_shader_code, &error) != 0)
if (set_and_compile_shader(shader->id, fragment_shader, fragment_shader_code, &error) != 0)
{
fprintf(stderr, "fragment shader compilation failed: %s\n", error);
free(error);
glDeleteProgram(shader);
shader = 0;
glDeleteProgram(shader->id);
shader->id = 0;
return_val = 1;
goto fragment_failed;
}
glLinkProgram(shader);
glLinkProgram(shader->id);
int result;
glGetProgramiv(shader, GL_LINK_STATUS, &result);
if (result == GL_FALSE)
{
char error[512];
glGetProgramInfoLog(shader, 512, NULL, error);
glGetProgramInfoLog(shader->id, 512, NULL, error);
fprintf(stderr, "shader linking failed: %s\n", error);
glDeleteProgram(shader);
shader = 0;
shader->id = 0;
return_val = 1;
}
fragment_failed:
@ -80,33 +90,49 @@ fragment_failed:
vertex_failed:
glDeleteShader(vertex_shader);
return shader;
return return_val;
}
void destroy_shader(Shader shader)
{
glDeleteProgram(shader);
destroy_dynamic_array(shader.objects);
glDeleteProgram(shader.id);
}
void bind_shader(Shader shader)
void bind_shader(Shader* shader)
{
glUseProgram(shader);
dynamic_array_clear(&shader->objects);
glUseProgram(shader->id);
}
void set_uniform_mat4(Shader shader, const char* name, mat4 mat)
void shader_add_object(Shader* shader, Object* object)
{
int location = glGetUniformLocation(shader, name);
dynamic_array_push(&shader->objects, (void*)&object);
}
void shader_render(Shader* shader)
{
for (int i = 0; i < shader->objects.size; i++)
{
Object* obj = *(Object**)dynamic_array_get(&shader->objects, i);
render_object(obj, shader);
}
}
void set_uniform_mat4(Shader* shader, const char* name, mat4 mat)
{
int location = glGetUniformLocation(shader->id, name);
glUniformMatrix4fv(location, 1, GL_FALSE, (float*)mat);
}
void set_uniform_float(Shader shader, const char* name, float val)
void set_uniform_float(Shader* shader, const char* name, float val)
{
int location = glGetUniformLocation(shader, name);
int location = glGetUniformLocation(shader->id, name);
glUniform1f(location, val);
}
void set_uniform_vec3(Shader shader, const char* name, vec3 vec)
void set_uniform_vec3(Shader* shader, const char* name, vec3 vec)
{
int location = glGetUniformLocation(shader, name);
int location = glGetUniformLocation(shader->id, name);
glUniform3fv(location, 1, vec);
}

View file

@ -2,16 +2,25 @@
#define SHADER_H
#include <cglm/mat4.h>
#include "util/dynarray.h"
typedef int Shader;
typedef struct Object Object;
Shader create_shader(const char* vertex_shader_code, const char* fragment_shader_code);
typedef struct Shader
{
int id;
DynamicArray objects;
} Shader;
int create_shader(Shader* shader, const char* vertex_shader_code, const char* fragment_shader_code);
void destroy_shader(Shader shader);
void bind_shader(Shader shader);
void bind_shader(Shader* shader);
void shader_add_object(Shader* shader, Object* object);
void shader_render(Shader* shader);
void set_uniform_mat4(Shader shader, const char* name, mat4 mat);
void set_uniform_float(Shader shader, const char* name, float val);
void set_uniform_vec3(Shader shader, const char* name, vec3 vec);
void set_uniform_mat4(Shader* shader, const char* name, mat4 mat);
void set_uniform_float(Shader* shader, const char* name, float val);
void set_uniform_vec3(Shader* shader, const char* name, vec3 vec);
#endif // SHADER_H

View file

@ -8,20 +8,6 @@
#include "objects/cube.h"
static void set_lighting_uniforms(Object* obj, Scene* scene)
{
Shader shader = obj->shader;
set_uniform_vec3(shader, "ambient_color", scene->ambient_light.color);
set_uniform_float(shader, "ambient_intens", scene->ambient_light.intensity);
set_uniform_vec3(shader, "point_pos", scene->point_light.position);
set_uniform_vec3(shader, "point_col", scene->point_light.color);
set_uniform_float(shader, "point_intens", scene->point_light.intensity);
set_uniform_vec3(shader, "cam_pos", scene->camera.object.position);
}
int create_scene(Scene* scene)
{
assert(scene);
@ -32,29 +18,13 @@ int create_scene(Scene* scene)
return 1;
}
scene->objects = create_dynamic_array(Object*);
scene->on_update = NULL;
scene->last_frame_start = glfwGetTime();
}
void destroy_scene(Scene scene)
{
for (size_t i = 0; i < scene.objects.size; i++)
{
Object* obj = *(Object**)dynamic_array_get(&scene.objects, i);
destroy_object(*obj);
}
destroy_dynamic_array(scene.objects);
}
void scene_add_object(Scene* scene, Object* object)
{
assert(scene);
object->scene = scene;
object->on_shader_use_scene = set_lighting_uniforms;
dynamic_array_push(&scene->objects, (void*)&object);
}
void scene_update_size(Scene* scene, int width, int height)
@ -63,6 +33,12 @@ void scene_update_size(Scene* scene, int width, int height)
set_camera_perspective(&scene->camera, 90.0f, (float)width / (float)height);
}
void scene_set_camera_uniforms(Scene* scene, Shader* shader)
{
set_uniform_mat4(shader, "view", get_camera_view(&scene->camera));
set_uniform_mat4(shader, "projection", scene->camera.projection);
}
void update_scene(Scene* scene)
{
double frametime = glfwGetTime() - scene->last_frame_start;
@ -76,10 +52,5 @@ void render_scene(Scene* scene)
assert(scene);
ctx_clear_screen(0.0f, 0.0f, 0.0f, 1.0f);
for (size_t i = 0; i < scene->objects.size; i++)
{
Object* obj = *(Object**)dynamic_array_get(&scene->objects, i);
update_object(obj);
render_object(obj, &scene->camera);
}
scene->on_render(scene);
}

View file

@ -11,21 +11,18 @@
typedef struct Scene
{
Camera camera;
DynamicArray objects;
AmbientLight ambient_light;
PointLight point_light;
void* child;
void(*on_update)(void*, double);
void(*on_render)(void*);
double last_frame_start;
} Scene;
int create_scene(Scene* scene);
void destroy_scene(Scene scene);
void scene_add_object(Scene* scene, Object* object);
void scene_update_size(Scene* scene, int width, int height);
void scene_set_camera_uniforms(Scene* scene, Shader* shader);
void update_scene(Scene* scene);
void render_scene(Scene* scene);

View file

@ -9,9 +9,73 @@
#include "objects/cube.h"
#include "application.h"
#include "renderer/object.h"
static const char* vertex_shader =
"#version 460 core\n"
""
"layout (location = 0) in vec3 pos;"
"layout (location = 1) in vec3 normal;"
""
"out vec3 frag_normal;"
"out vec3 frag_pos;"
""
"uniform mat4 model;"
"uniform mat4 view;"
"uniform mat4 projection;"
""
"void main() {"
" frag_normal = mat3(transpose(inverse(model))) * normal;"
" frag_pos = vec3(model * vec4(pos, 1.0));"
" gl_Position = projection * view * model * vec4(pos, 1.0);"
"}";
static const char* fragment_shader =
"#version 460 core\n"
""
"in vec3 frag_pos;"
"in vec3 frag_normal;"
""
"uniform vec3 ambient_color = vec3(1.0, 1.0, 1.0);"
"uniform float ambient_intens = 1.0f;"
""
"uniform vec3 point_pos = vec3(0.0, 0.0, 0.0);"
"uniform vec3 point_col = vec3(1.0, 1.0, 1.0);"
"uniform float point_intens = 1.0f;"
""
"uniform vec3 cam_pos = vec3(0.0, 0.0, 0.0);"
"float specular_strength = 0.5f;"
""
"uniform vec3 cube_color;"
""
"out vec4 FragColor;"
""
"void main() {"
" vec3 ambient = ambient_intens * ambient_color;"
""
" vec3 norm = normalize(frag_normal);"
" vec3 light_dir = normalize(point_pos - frag_pos);"
" float diff = max(dot(norm, light_dir), 0.0);"
" vec3 diffuse = diff * point_col;"
""
" vec3 view_dir = normalize(cam_pos - frag_pos);"
" vec3 reflect_dir = reflect(-light_dir, norm);"
""
" float spec = pow(max(dot(view_dir, reflect_dir), 0.0), 32);"
" vec3 specular = specular_strength * spec * point_col; "
""
" vec3 result = (ambient + diffuse + specular) * cube_color;"
" FragColor = vec4(result, 1.0);"
"}";
typedef struct SpinningCubes
{
Shader cube_shader;
DynamicArray objects;
AmbientLight ambient_light;
PointLight point_light;
struct {
double x, y;
} last_cursor_pos;
@ -23,6 +87,20 @@ typedef struct SpinningCubes
double time;
} SpinningCubes;
static void set_lighting_uniforms(Shader* shader, Scene* scene)
{
SpinningCubes* data = scene->child;
set_uniform_vec3(shader, "ambient_color", data->ambient_light.color);
set_uniform_float(shader, "ambient_intens", data->ambient_light.intensity);
set_uniform_vec3(shader, "point_pos", data->point_light.position);
set_uniform_vec3(shader, "point_col", data->point_light.color);
set_uniform_float(shader, "point_intens", data->point_light.intensity);
set_uniform_vec3(shader, "cam_pos", scene->camera.object.position);
}
static void init_spinning_cubes_data(SpinningCubes* scene)
{
assert(scene);
@ -31,6 +109,8 @@ static void init_spinning_cubes_data(SpinningCubes* scene)
scene->dragging = false;
scene->drag_speed = 0.01f;
scene->time = 0.0f;
scene->objects = create_dynamic_array(Object*);
}
static void get_arcball_vector(vec3 dest, double width, double height, double x, double y)
@ -113,23 +193,48 @@ static void mouse_moved_callback(GLFWwindow* window, double xpos, double ypos)
static void on_update(Scene* scene, double frametime)
{
SpinningCubes* data = scene->child;
for (int i = 0; i < data->objects.size; i++)
{
Object* obj = *(Object**)dynamic_array_get(&data->objects, i);
update_object(obj);
}
vec3 cam_pos = { 6.0f * sin(2.0f * data->time), 3.5f * cos(data->time), 6.0f * cos(2.0f * data->time)};
object_set_position(&scene->camera.object, cam_pos);
data->time += frametime;
glm_vec3_copy(scene->camera.object.position, scene->point_light.position);
glm_vec3_copy(scene->camera.object.position, data->point_light.position);
}
void create_spinning_cubes_scene(Window* window, Scene* scene)
static void on_render(Scene* scene)
{
SpinningCubes* data = scene->child;
bind_shader(&data->cube_shader);
set_lighting_uniforms(&data->cube_shader, scene);
scene_set_camera_uniforms(scene, &data->cube_shader);
for (int i = 0; i < data->objects.size; i++)
{
shader_add_object(&data->cube_shader, *(Object**)dynamic_array_get(&data->objects, i));
}
shader_render(&data->cube_shader);
}
int create_spinning_cubes_scene(Window* window, Scene* scene)
{
assert(scene);
create_scene(scene);
scene->on_update = on_update;
scene->on_render = on_render;
scene->child = malloc(sizeof(SpinningCubes));
init_spinning_cubes_data(scene->child);
SpinningCubes* data = scene->child;
for (int i = 0; i < 4; i++)
{
Cube* obj = (Cube*)malloc(sizeof(Cube));
@ -140,22 +245,31 @@ void create_spinning_cubes_scene(Window* window, Scene* scene)
0.0f,
((i < 2) ? -1 : 1) * 1.5
};
object_set_position(&obj->object, position);
scene_add_object(scene, &obj->object);
Object* raw_obj = &obj->object;
dynamic_array_push(&data->objects, (void*)&raw_obj);
}
if(create_shader(&data->cube_shader, vertex_shader, fragment_shader) != 0)
{
fprintf(stderr, "failed to create shader for cube\n");
return 1;
}
vec3 cam_pos = { 0.0f, 3.5f, 3.0 };
object_set_position(&scene->camera.object, cam_pos);
glm_vec3_zero(&scene->camera.look_at);
glm_vec3_one(data->ambient_light.color);
data->ambient_light.intensity = 0.1f;
glm_vec3_one(scene->ambient_light.color);
scene->ambient_light.intensity = 0.1f;
glm_vec3_one(scene->point_light.color);
scene->point_light.intensity = 1.0f;
glm_vec3_one(data->point_light.color);
data->point_light.intensity = 1.0f;
glfwSetMouseButtonCallback(window->window, mouse_button_callback);
glfwSetCursorPosCallback(window->window, mouse_moved_callback);
return 0;
}

View file

@ -4,6 +4,6 @@
#include "scene.h"
#include "renderer/window.h"
void create_spinning_cubes_scene(Window* window, Scene* scene);
int create_spinning_cubes_scene(Window* window, Scene* scene);
#endif // SCENE_SPINNING_CUBES_H

View file

@ -36,6 +36,14 @@ void* dynamic_array_get(DynamicArray* array, size_t i)
return (void*)((char*)array->data + (i * array->element_size));
}
void dynamic_array_clear(DynamicArray* array)
{
array->capacity = 5;
array->size = 0;
array->data = realloc(array->data, array->element_size * array->capacity);
}
void dynamic_array_push(DynamicArray* array, void* element)
{
assert(array->capacity > 0);

View file

@ -18,6 +18,7 @@ DynamicArray create_dynamic_array_from_size(size_t type_size);
void destroy_dynamic_array(DynamicArray array);
void* dynamic_array_get(DynamicArray* array, size_t i);
void dynamic_array_clear(DynamicArray* array);
void dynamic_array_push(DynamicArray* array, void* element);
void dynamic_array_pop(DynamicArray* array);