Implement shaders #1
							
								
								
									
										81
									
								
								src/obj.c
									
									
									
									
									
								
							
							
						
						
									
										81
									
								
								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); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										62
									
								
								src/shader.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								src/shader.c
									
									
									
									
									
										Normal file
									
								
							| @@ -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); | ||||
| } | ||||
							
								
								
									
										38
									
								
								src/shader.h
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user