diff --git a/src/main.c b/src/main.c index 2555f7b..19fe93c 100644 --- a/src/main.c +++ b/src/main.c @@ -2,6 +2,7 @@ #include "mem_arena.h" #include "mem_utils.h" #include "obj.h" +#include "render.h" #include "shader.h" #include "shaders.h" #include diff --git a/src/model/obj.c b/src/model/obj.c new file mode 100644 index 0000000..ed153ed --- /dev/null +++ b/src/model/obj.c @@ -0,0 +1,87 @@ +#include "obj.h" +#include "mem_arena.h" +#include "pam.h" +#include "typed_list.h" +#include "vec.h" +#include + +Model load_obj_file(Arena *arena, const char *filename, const char *texture, + const char *normal_map) { + if (!arena) { + return INVALID_MODEL; + } + + FILE *fp = fopen(filename, "r"); + if (!fp) { + return INVALID_MODEL; + } + + Model model = (Model){ + .vertices = list_create(V3f, arena), + .normals = list_create(V3f, arena), + .texture_coordinates = list_create(V2f, arena), + .triangles = list_create(Triangle, arena), + }; + if (!(model.vertices) || !(model.normals) || !(model.texture_coordinates) || + !(model.triangles)) { + return INVALID_MODEL; + } + + char line[8192]; + char identifier[8]; + V3f vertex; + V3f normal; + V2f coord; + Triangle triangle; + f32 vx, vy, vz; + f32 nx, ny, nz; + f32 u, v; + u64 fp0, fp1, fp2; + u64 vn0, vn1, vn2; + u64 tx0, tx1, tx2; + while (fgets(line, 8191, fp) != NULL) { + sscanf(line, "%s", identifier); + if (strncmp(identifier, "v", 8) == 0) { + sscanf(line + 2, "%f %f %f", &vx, &vy, &vz); + vertex.x = vx; + vertex.y = vy; + vertex.z = vz; + list_append(V3f, arena, model.vertices, vertex); + } else if (strncmp(identifier, "vn", 8) == 0) { + sscanf(line + 2, "%f %f %f", &nx, &ny, &nz); + normal.x = nx; + normal.y = ny; + normal.z = nz; + list_append(V3f, arena, model.normals, normal); + } else if (strncmp(identifier, "vt", 8) == 0) { + sscanf(line + 2, "%f %f", &u, &v); + coord.u = u; + coord.v = v; + list_append(V2f, arena, model.texture_coordinates, coord); + } else if (strncmp(identifier, "f", 8) == 0) { + sscanf(line + 2, "%lu/%lu/%lu %lu/%lu/%lu %lu/%lu/%lu", &fp0, &tx0, &vn0, + &fp1, &tx1, &vn1, &fp2, &tx2, &vn2); + // OBJ indices start from 1 + triangle.p0 = fp0 - 1; + triangle.p1 = fp1 - 1; + triangle.p2 = fp2 - 1; + triangle.n0 = vn0 - 1; + triangle.n1 = vn1 - 1; + triangle.n2 = vn2 - 1; + triangle.tx0 = tx0 - 1; + triangle.tx1 = tx1 - 1; + triangle.tx2 = tx2 - 1; + list_append(Triangle, arena, model.triangles, triangle); + } + } + + if (texture) { + model.texture = load_p6_image(arena, texture); + } + + if (normal_map) { + model.normal = load_p6_image(arena, normal_map); + } + + return model; +} diff --git a/src/obj/obj.h b/src/model/obj.h similarity index 58% rename from src/obj/obj.h rename to src/model/obj.h index e5f59f0..a99143d 100644 --- a/src/obj/obj.h +++ b/src/model/obj.h @@ -4,8 +4,8 @@ #include "aliases.h" #include "img.h" #include "mem_arena.h" -#include "shader.h" #include "typed_list.h" +#include "vec.h" #define INVALID_MODEL ((Model){0}) #define IS_INVALID_MODEL(m) (m.vertices == NULL || m.triangles == NULL) @@ -23,21 +23,6 @@ struct triangle { u64 tx2; }; -typedef enum { - RENDER_TYPE_WIREFRAME, - RENDER_TYPE_FILLED, - RENDER_TYPE_SHADED, - - COUNT_RENDER_TYPES, -} RenderType; - -typedef enum { - PROJECTION_TYPE_ORTHOGRAPHIC, - PROJECTION_TYPE_PERSPECTIVE, - - COUNT_PROJECTION_TYPE, -} ProjectionType; - MAKE_LIST_TYPE(Triangle); typedef struct model Model; @@ -50,16 +35,7 @@ struct model { Image *normal; }; -typedef struct render Render; -struct render { - Image img; - Depth depth; -}; - Model load_obj_file(Arena *arena, const char *filename, const char *texture, const char *normal_map); -bool init_render(Arena *arena, Render *render, u64 width, u64 height); -void render_model(const Model *model, Render *render, ShaderID shader, - RenderType render_type, Colour colour); #endif // OBJ_H diff --git a/src/obj/obj.c b/src/model/render.c similarity index 72% rename from src/obj/obj.c rename to src/model/render.c index d8e2827..e14b5f1 100644 --- a/src/obj/obj.c +++ b/src/model/render.c @@ -1,17 +1,6 @@ -#include "obj.h" -#include "aliases.h" -#include "img.h" -#include "mem_arena.h" -#include "pam.h" -#include "shader.h" -#include "typed_list.h" +#include "render.h" #include "utils.h" -#include "vec.h" -#include #include -#include -#include -#include #define TRIANGLE_VERTICES 3 @@ -38,87 +27,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); -Model load_obj_file(Arena *arena, const char *filename, const char *texture, - const char *normal_map) { - if (!arena) { - return INVALID_MODEL; - } - - FILE *fp = fopen(filename, "r"); - if (!fp) { - return INVALID_MODEL; - } - - Model model = (Model){ - .vertices = list_create(V3f, arena), - .normals = list_create(V3f, arena), - .texture_coordinates = list_create(V2f, arena), - .triangles = list_create(Triangle, arena), - }; - if (!(model.vertices) || !(model.normals) || !(model.texture_coordinates) || - !(model.triangles)) { - return INVALID_MODEL; - } - - char line[8192]; - char identifier[8]; - V3f vertex; - V3f normal; - V2f coord; - Triangle triangle; - f32 vx, vy, vz; - f32 nx, ny, nz; - f32 u, v; - u64 fp0, fp1, fp2; - u64 vn0, vn1, vn2; - u64 tx0, tx1, tx2; - while (fgets(line, 8191, fp) != NULL) { - sscanf(line, "%s", identifier); - if (strncmp(identifier, "v", 8) == 0) { - sscanf(line + 2, "%f %f %f", &vx, &vy, &vz); - vertex.x = vx; - vertex.y = vy; - vertex.z = vz; - list_append(V3f, arena, model.vertices, vertex); - } else if (strncmp(identifier, "vn", 8) == 0) { - sscanf(line + 2, "%f %f %f", &nx, &ny, &nz); - normal.x = nx; - normal.y = ny; - normal.z = nz; - list_append(V3f, arena, model.normals, normal); - } else if (strncmp(identifier, "vt", 8) == 0) { - sscanf(line + 2, "%f %f", &u, &v); - coord.u = u; - coord.v = v; - list_append(V2f, arena, model.texture_coordinates, coord); - } else if (strncmp(identifier, "f", 8) == 0) { - sscanf(line + 2, "%lu/%lu/%lu %lu/%lu/%lu %lu/%lu/%lu", &fp0, &tx0, &vn0, - &fp1, &tx1, &vn1, &fp2, &tx2, &vn2); - // OBJ indices start from 1 - triangle.p0 = fp0 - 1; - triangle.p1 = fp1 - 1; - triangle.p2 = fp2 - 1; - triangle.n0 = vn0 - 1; - triangle.n1 = vn1 - 1; - triangle.n2 = vn2 - 1; - triangle.tx0 = tx0 - 1; - triangle.tx1 = tx1 - 1; - triangle.tx2 = tx2 - 1; - list_append(Triangle, arena, model.triangles, triangle); - } - } - - if (texture) { - model.texture = load_p6_image(arena, texture); - } - - if (normal_map) { - model.normal = load_p6_image(arena, normal_map); - } - - return model; -} - bool init_render(Arena *arena, Render *render, u64 width, u64 height) { render->img = (Image){.width = width, .height = height}; if (!init_buffer(arena, &(render->img))) { @@ -248,8 +156,7 @@ internal void fill_triangle(Render *render, ShaderID shader, coordinates[2].v * coords.z; tex_coords = (V2f){tx_u, tx_v}; - result = run_fragment_shader(shader, normal, tex_coords, &colour, - model->texture, model->normal); + result = run_fragment_shader(shader, normal, tex_coords, &colour, model); if (DISCARD_FRAGMENT(result)) { continue; } diff --git a/src/model/render.h b/src/model/render.h new file mode 100644 index 0000000..478bd8a --- /dev/null +++ b/src/model/render.h @@ -0,0 +1,35 @@ +#ifndef RENDER_H +#define RENDER_H + +#include "aliases.h" +#include "mem_arena.h" +#include "obj.h" +#include "shader.h" +#include + +typedef enum { + RENDER_TYPE_WIREFRAME, + RENDER_TYPE_FILLED, + RENDER_TYPE_SHADED, + + COUNT_RENDER_TYPES, +} RenderType; + +typedef enum { + PROJECTION_TYPE_ORTHOGRAPHIC, + PROJECTION_TYPE_PERSPECTIVE, + + COUNT_PROJECTION_TYPE, +} ProjectionType; + +typedef struct render Render; +struct render { + Image img; + Depth depth; +}; + +bool init_render(Arena *arena, Render *render, u64 width, u64 height); +void render_model(const Model *model, Render *render, ShaderID shader, + RenderType render_type, Colour colour); + +#endif // RENDER_H diff --git a/src/shader/shader.c b/src/shader/shader.c index f4fe42f..c6b162e 100644 --- a/src/shader/shader.c +++ b/src/shader/shader.c @@ -46,8 +46,7 @@ V3f run_vertex_shader(ShaderID shader, const V3f *vertex, } FragmentResult run_fragment_shader(ShaderID shader, V3f normal, V2f tex_coords, - const Colour *colour, const Image *texture, - const Image *normal_map) { + const Colour *colour, const Model *model) { if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !colour) { return DISCARDED_FRAGMENT; } @@ -59,6 +58,5 @@ FragmentResult run_fragment_shader(ShaderID shader, V3f normal, V2f tex_coords, return DISCARDED_FRAGMENT; } - return fragment_func(shader_obj, normal, tex_coords, colour, texture, - normal_map); + return fragment_func(shader_obj, normal, tex_coords, colour, model); } diff --git a/src/shader/shader.h b/src/shader/shader.h index 42a6e87..afea063 100644 --- a/src/shader/shader.h +++ b/src/shader/shader.h @@ -3,6 +3,7 @@ #include "aliases.h" #include "img.h" +#include "obj.h" #include "vec.h" typedef struct shader_id ShaderID; @@ -25,15 +26,13 @@ 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, - const Image *normal_map); + const Model *model); 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, - const Image *normal_map); + const Colour *colour, const Model *model); #endif // SHADER_H diff --git a/src/shader/shaders.c b/src/shader/shaders.c index bfb23ad..14a1102 100644 --- a/src/shader/shaders.c +++ b/src/shader/shaders.c @@ -1,5 +1,5 @@ #include "img.h" -#include "obj.h" +#include "render.h" #include "shader.h" #include "vec.h" @@ -31,23 +31,19 @@ internal V3f general_shader_vertex(void *shader, const V3f *vertex, internal FragmentResult phong_shader_fragment(void *shader, V3f normal, V2f tex_coords, const Colour *colour, - const Image *texture, - const Image *normal_map); + const Model *model); internal FragmentResult lit_textured_shader_fragment(void *shader, V3f normal, V2f tex_coords, const Colour *colour, - const Image *texture, - const Image *normal_map); + const Model *model); internal FragmentResult lit_coloured_shader_fragment(void *shader, V3f normal, V2f tex_coords, const Colour *colour, - const Image *texture, - const Image *normal_map); + const Model *model); internal FragmentResult albedo_shader_fragment(void *shader, V3f normal, V2f tex_coords, const Colour *colour, - const Image *texture, - const Image *normal_map); + const Model *model); internal M4x4f get_projection_matrix(ProjectionType projection_type); internal f32 get_intensity(const V3f *normal); @@ -95,14 +91,13 @@ internal V3f general_shader_vertex(void *shader, const V3f *vertex, internal FragmentResult phong_shader_fragment(void *shader, V3f normal, V2f tex_coords, const Colour *colour, - const Image *texture, - const Image *normal_map) { + const Model *model) { f32 intensity = get_intensity(&normal); - if (normal_map) { - u64 nm_x = tex_coords.u * normal_map->width; - u64 nm_y = (1.0f - tex_coords.v) * normal_map->height; + if (model->normal) { + u64 nm_x = tex_coords.u * model->normal->width; + u64 nm_y = (1.0f - tex_coords.v) * model->normal->height; - Colour pixel = get_pixel(Colour, normal_map, nm_x, nm_y); + Colour pixel = get_pixel(Colour, model->normal, nm_x, nm_y); V3f norm = {.x = pixel.r, .y = pixel.g, .z = pixel.b}; normalise_v3(norm); @@ -112,10 +107,10 @@ internal FragmentResult phong_shader_fragment(void *shader, V3f normal, } Colour output; - if (texture) { - u64 tx_x = tex_coords.u * texture->width; - u64 tx_y = (1.0f - tex_coords.v) * texture->height; - output = get_pixel(Colour, texture, tx_x, tx_y); + if (model->texture) { + u64 tx_x = tex_coords.u * model->texture->width; + u64 tx_y = (1.0f - tex_coords.v) * model->texture->height; + output = get_pixel(Colour, model->texture, tx_x, tx_y); } else { output = *colour; } @@ -130,18 +125,17 @@ internal FragmentResult phong_shader_fragment(void *shader, V3f normal, internal FragmentResult lit_textured_shader_fragment(void *shader, V3f normal, V2f tex_coords, const Colour *colour, - const Image *texture, - const Image *normal_map) { - if (!texture) { + const Model *model) { + if (!(model->texture)) { return DISCARDED_FRAGMENT; } f32 intensity = get_intensity(&normal); - u64 tx_x = tex_coords.u * texture->width; - u64 tx_y = (1.0f - tex_coords.v) * texture->height; + u64 tx_x = tex_coords.u * model->texture->width; + u64 tx_y = (1.0f - tex_coords.v) * model->texture->height; - Colour output = get_pixel(Colour, texture, tx_x, tx_y); + Colour output = get_pixel(Colour, model->texture, tx_x, tx_y); output.r *= intensity; output.g *= intensity; @@ -153,8 +147,7 @@ internal FragmentResult lit_textured_shader_fragment(void *shader, V3f normal, internal FragmentResult lit_coloured_shader_fragment(void *shader, V3f normal, V2f tex_coords, const Colour *colour, - const Image *texture, - const Image *normal_map) { + const Model *model) { f32 intensity = get_intensity(&normal); Colour output = *colour; @@ -168,8 +161,7 @@ internal FragmentResult lit_coloured_shader_fragment(void *shader, V3f normal, internal FragmentResult albedo_shader_fragment(void *shader, V3f normal, V2f tex_coords, const Colour *colour, - const Image *texture, - const Image *normal_map) { + const Model *model) { return (FragmentResult){.colour = *colour}; }