diff --git a/src/obj.c b/src/obj.c index d408f39..862f7b9 100644 --- a/src/obj.c +++ b/src/obj.c @@ -3,6 +3,7 @@ #include "img.h" #include "mem_arena.h" #include "pam.h" +#include "shader.h" #include "typed_list.h" #include "utils.h" #include "vec.h" @@ -23,9 +24,10 @@ struct triangle_bbox { }; internal void render_triangle(const Triangle *triangle, const Model *model, - const Shader *shader, Render *render, + ShaderID shader, Render *render, RenderType render_type, Colour colour); -internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES], +internal void fill_triangle(Render *render, ShaderID shader, + V3f vertices[TRIANGLE_VERTICES], V3f normals[TRIANGLE_VERTICES], V2f coordinates[TRIANGLE_VERTICES], Colour colour, Image *texture, RenderType type); @@ -36,8 +38,6 @@ internal V3f get_barycentric_coords(f32 d00, f32 d01, f32 d11, f32 denom, const V2i *ap); internal V3f get_viewport_vertex(const V3f *vertex, const Image *img); -V3f g_light_dir = {0.0f, 0.0f, 1.0f}; - Model load_obj_file(Arena *arena, const char *filename, const char *texture) { if (!arena) { return INVALID_MODEL; @@ -131,7 +131,7 @@ bool init_render(Arena *arena, Render *render, u64 width, u64 height) { return true; } -void render_model(const Model *model, Render *render, const Shader *shader, +void render_model(const Model *model, Render *render, ShaderID shader, RenderType render_type, Colour colour) { Triangle triangle; for (u64 i = 0; i < model->triangles->count; ++i) { @@ -141,7 +141,7 @@ void render_model(const Model *model, Render *render, const Shader *shader, } internal void render_triangle(const Triangle *triangle, const Model *model, - const Shader *shader, Render *render, + ShaderID shader, Render *render, RenderType render_type, Colour colour) { Image *img = &(render->img); V3f vertices[TRIANGLE_VERTICES] = { @@ -161,8 +161,8 @@ internal void render_triangle(const Triangle *triangle, const Model *model, }; for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) { - vertices[i] = shader->vertex(&vertices[i], shader->model_view, - shader->projection, &render->img); + vertices[i] = + run_vertex_shader(shader, &vertices[i], (Buffer *)&render->img); } if (render_type == RENDER_TYPE_WIREFRAME) { @@ -176,12 +176,13 @@ internal void render_triangle(const Triangle *triangle, const Model *model, } } else if (render_type == RENDER_TYPE_FILLED || render_type == RENDER_TYPE_SHADED) { - fill_triangle(render, vertices, normals, coordinates, colour, + fill_triangle(render, shader, vertices, normals, coordinates, colour, model->texture, render_type); } } -internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES], +internal void fill_triangle(Render *render, ShaderID shader, + V3f vertices[TRIANGLE_VERTICES], V3f normals[TRIANGLE_VERTICES], V2f coordinates[TRIANGLE_VERTICES], Colour colour, Image *texture, RenderType type) { @@ -207,6 +208,8 @@ internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES], V3f normal; f32 tx_u, tx_v; u64 tx_x, tx_y; + V2f tex_coords; + FragmentResult result; f32 intensity = 1.0f; @@ -222,40 +225,32 @@ internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES], z += v0.z * coords.x + v1.z * coords.y + v2.z * coords.z; zbuf = get_pixel(f32, &(render->depth), x, y); - if (z > zbuf) { - if (type == RENDER_TYPE_SHADED) { - nx = normals[0].x * coords.x + normals[1].x * coords.y + - normals[2].x * coords.z; - ny = normals[0].y * coords.x + normals[1].y * coords.y + - normals[2].y * coords.z; - nz = normals[0].z * coords.x + normals[1].z * coords.y + - normals[2].z * coords.z; - normal = (V3f){nx, ny, nz}; - intensity = dot_v3(normal, g_light_dir); - } - - if (intensity < 0.0f) { - intensity = 0.01f; - } - - if (texture) { - tx_u = coordinates[0].u * coords.x + coordinates[1].u * coords.y + - coordinates[2].u * coords.z; - tx_v = coordinates[0].v * coords.x + coordinates[1].v * coords.y + - coordinates[2].v * coords.z; - tx_x = tx_u * texture->width; - tx_y = (1.0f - tx_v) * texture->height; - - colour = get_pixel(Colour, texture, tx_x, tx_y); - } - - colour.r *= intensity; - colour.g *= intensity; - colour.b *= intensity; - - set_pixel(depth, x, y, &z); - set_pixel(img, x, y, &colour); + if (z <= zbuf) { + continue; } + + nx = normals[0].x * coords.x + normals[1].x * coords.y + + normals[2].x * coords.z; + ny = normals[0].y * coords.x + normals[1].y * coords.y + + normals[2].y * coords.z; + nz = normals[0].z * coords.x + normals[1].z * coords.y + + normals[2].z * coords.z; + normal = (V3f){nx, ny, nz}; + + tx_u = coordinates[0].u * coords.x + coordinates[1].u * coords.y + + coordinates[2].u * coords.z; + tx_v = coordinates[0].v * coords.x + coordinates[1].v * coords.y + + coordinates[2].v * coords.z; + tex_coords = (V2f){tx_u, tx_v}; + + result = + run_fragment_shader(shader, normal, tex_coords, &colour, texture); + if (DISCARD_FRAGMENT(result)) { + continue; + } + + set_pixel(depth, x, y, &z); + set_pixel(img, x, y, &result.colour); } } } diff --git a/src/obj.h b/src/obj.h index 7ac49bf..23f8c94 100644 --- a/src/obj.h +++ b/src/obj.h @@ -57,7 +57,7 @@ struct render { Model load_obj_file(Arena *arena, const char *filename, const char *texture); bool init_render(Arena *arena, Render *render, u64 width, u64 height); -void render_model(const Model *model, Render *render, const Shader *shader, +void render_model(const Model *model, Render *render, ShaderID shader, RenderType render_type, Colour colour); #endif // OBJ_H diff --git a/src/shader.c b/src/shader.c new file mode 100644 index 0000000..312220f --- /dev/null +++ b/src/shader.c @@ -0,0 +1,62 @@ +#include "shader.h" +#include "aliases.h" +#include "vec.h" + +#define MAX_SHADER_COUNT 2048 + +typedef struct shader_repo ShaderRepo; +struct shader_repo { + void *shaders[MAX_SHADER_COUNT]; + VertexShader *vertex_funcs[MAX_SHADER_COUNT]; + FragmentShader *fragment_funcs[MAX_SHADER_COUNT]; + u64 count; +}; + +internal ShaderRepo g_repository = {0}; + +ShaderID create_shader(void *shader, VertexShader *vertex, + FragmentShader *fragment) { + if (g_repository.count + 1 >= MAX_SHADER_COUNT) { + return INVALID_SHADER; + } + + ++(g_repository.count); + g_repository.shaders[g_repository.count] = shader; + g_repository.vertex_funcs[g_repository.count] = vertex; + g_repository.fragment_funcs[g_repository.count] = fragment; + + return (ShaderID){g_repository.count}; +} + +V3f run_vertex_shader(ShaderID shader, const V3f *vertex, + const Buffer *out_buf) { + if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !vertex || + !out_buf) { + return (V3f){0}; + } + + void *shader_obj = g_repository.shaders[shader.id]; + VertexShader *vertex_func = g_repository.vertex_funcs[shader.id]; + + if (!shader_obj || !vertex_func) { + return (V3f){0}; + } + + return vertex_func(shader_obj, vertex, out_buf); +} + +FragmentResult run_fragment_shader(ShaderID shader, V3f normal, V2f tex_coords, + const Colour *colour, const Image *texture) { + if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !colour) { + return DISCARDED_FRAGMENT; + } + + void *shader_obj = g_repository.shaders[shader.id]; + FragmentShader *fragment_func = g_repository.fragment_funcs[shader.id]; + + if (!shader_obj || !fragment_func) { + return DISCARDED_FRAGMENT; + } + + return fragment_func(shader_obj, normal, tex_coords, colour, texture); +} diff --git a/src/shader.h b/src/shader.h index 42817d8..ca73f49 100644 --- a/src/shader.h +++ b/src/shader.h @@ -1,19 +1,37 @@ #ifndef SHADER_H #define SHADER_H +#include "aliases.h" #include "img.h" #include "vec.h" -typedef V3f(VertexShader)(const V3f *vertex, M4x4f *model_view, - M4x4f *projection, const Image *img); -typedef bool(FragmentShader)(Colour colour); - -typedef struct shader Shader; -struct shader { - VertexShader *vertex; - FragmentShader *fragment; - M4x4f *model_view; - M4x4f *projection; +typedef struct shader_id ShaderID; +struct shader_id { + u64 id; }; +typedef struct fragment_result FragmentResult; +struct fragment_result { + Colour colour; + bool discard; +}; + +#define INVALID_SHADER ((ShaderID){0}) +#define IS_INVALID_SHADER(ID) (ID.id == 0) +#define DISCARDED_FRAGMENT ((FragmentResult){.discard = true}) +#define DISCARD_FRAGMENT(RESULT) (RESULT.discard) + +typedef V3f(VertexShader)(void *shader, const V3f *vertex, + const Buffer *out_buf); +typedef FragmentResult(FragmentShader)(void *shader, V3f normal, V2f tex_coords, + const Colour *colour, + const Image *texture); + +ShaderID create_shader(void *shader, VertexShader *vertex, + FragmentShader *fragment); +V3f run_vertex_shader(ShaderID shader, const V3f *vertex, + const Buffer *out_buf); +FragmentResult run_fragment_shader(ShaderID shader, V3f normal, V2f tex_coords, + const Colour *colour, const Image *texture); + #endif // SHADER_H