Compare commits

...

2 Commits

5 changed files with 145 additions and 58 deletions

View File

@ -7,7 +7,7 @@
#include <stddef.h> #include <stddef.h>
#include <string.h> #include <string.h>
internal u64 calculate_pixel_index(Buffer *buffer, u64 x, u64 y, u64 base_size); internal i64 calculate_pixel_index(Buffer *buffer, u64 x, u64 y, u64 base_size);
bool _init_buffer(Arena *arena, Buffer *buffer, u64 base_size) { bool _init_buffer(Arena *arena, Buffer *buffer, u64 base_size) {
if (!arena || !buffer || buffer->width == 0 || buffer->height == 0) { if (!arena || !buffer || buffer->width == 0 || buffer->height == 0) {
@ -21,12 +21,20 @@ bool _init_buffer(Arena *arena, Buffer *buffer, u64 base_size) {
} }
u8 *_get_pixel(Buffer *buffer, u64 x, u64 y, u64 base_size) { u8 *_get_pixel(Buffer *buffer, u64 x, u64 y, u64 base_size) {
u64 idx = calculate_pixel_index(buffer, x, y, base_size); i64 idx = calculate_pixel_index(buffer, x, y, base_size);
if (idx == -1) {
idx = 0;
}
return ((u8 *)(buffer->buf)) + idx; return ((u8 *)(buffer->buf)) + idx;
} }
void _set_pixel(Buffer *buffer, u64 x, u64 y, void *value, u64 base_size) { void _set_pixel(Buffer *buffer, u64 x, u64 y, void *value, u64 base_size) {
u64 idx = calculate_pixel_index(buffer, x, y, base_size); i64 idx = calculate_pixel_index(buffer, x, y, base_size);
if (idx == -1) {
return;
}
memcpy(((u8 *)(buffer->buf)) + idx, value, base_size); memcpy(((u8 *)(buffer->buf)) + idx, value, base_size);
return; return;
} }
@ -75,7 +83,11 @@ void save_image(const Image *img, const char *filename) {
write_p7_image(img->width, img->height, (u8 *)(img->buf), filename); write_p7_image(img->width, img->height, (u8 *)(img->buf), filename);
} }
internal u64 calculate_pixel_index(Buffer *buffer, u64 x, u64 y, internal i64 calculate_pixel_index(Buffer *buffer, u64 x, u64 y,
u64 base_size) { u64 base_size) {
if (x < 0 || y < 0 || x >= buffer->width || y >= buffer->height) {
return -1;
}
return (y * buffer->width + x) * base_size; return (y * buffer->width + x) * base_size;
} }

View File

@ -3,6 +3,7 @@
#include "img.h" #include "img.h"
#include "mem_arena.h" #include "mem_arena.h"
#include "pam.h" #include "pam.h"
#include "shader.h"
#include "typed_list.h" #include "typed_list.h"
#include "utils.h" #include "utils.h"
#include "vec.h" #include "vec.h"
@ -23,9 +24,10 @@ struct triangle_bbox {
}; };
internal void render_triangle(const Triangle *triangle, const Model *model, internal void render_triangle(const Triangle *triangle, const Model *model,
const Shader *shader, Render *render, ShaderID shader, Render *render,
RenderType render_type, Colour colour); 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], V3f normals[TRIANGLE_VERTICES],
V2f coordinates[TRIANGLE_VERTICES], Colour colour, V2f coordinates[TRIANGLE_VERTICES], Colour colour,
Image *texture, RenderType type); Image *texture, RenderType type);
@ -36,8 +38,6 @@ internal V3f get_barycentric_coords(f32 d00, f32 d01, f32 d11, f32 denom,
const V2i *ap); const V2i *ap);
internal V3f get_viewport_vertex(const V3f *vertex, const Image *img); 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) { Model load_obj_file(Arena *arena, const char *filename, const char *texture) {
if (!arena) { if (!arena) {
return INVALID_MODEL; return INVALID_MODEL;
@ -131,7 +131,7 @@ bool init_render(Arena *arena, Render *render, u64 width, u64 height) {
return true; 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) { RenderType render_type, Colour colour) {
Triangle triangle; Triangle triangle;
for (u64 i = 0; i < model->triangles->count; ++i) { 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, internal void render_triangle(const Triangle *triangle, const Model *model,
const Shader *shader, Render *render, ShaderID shader, Render *render,
RenderType render_type, Colour colour) { RenderType render_type, Colour colour) {
Image *img = &(render->img); Image *img = &(render->img);
V3f vertices[TRIANGLE_VERTICES] = { 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) { for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) {
vertices[i] = shader->vertex(&vertices[i], shader->model_view, vertices[i] =
shader->projection, &render->img); run_vertex_shader(shader, &vertices[i], (Buffer *)&render->img);
} }
if (render_type == RENDER_TYPE_WIREFRAME) { 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 || } else if (render_type == RENDER_TYPE_FILLED ||
render_type == RENDER_TYPE_SHADED) { render_type == RENDER_TYPE_SHADED) {
fill_triangle(render, vertices, normals, coordinates, colour, fill_triangle(render, shader, vertices, normals, coordinates, colour,
model->texture, render_type); 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], V3f normals[TRIANGLE_VERTICES],
V2f coordinates[TRIANGLE_VERTICES], Colour colour, V2f coordinates[TRIANGLE_VERTICES], Colour colour,
Image *texture, RenderType type) { Image *texture, RenderType type) {
@ -207,6 +208,8 @@ internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES],
V3f normal; V3f normal;
f32 tx_u, tx_v; f32 tx_u, tx_v;
u64 tx_x, tx_y; u64 tx_x, tx_y;
V2f tex_coords;
FragmentResult result;
f32 intensity = 1.0f; f32 intensity = 1.0f;
@ -222,8 +225,10 @@ internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES],
z += v0.z * coords.x + v1.z * coords.y + v2.z * coords.z; z += v0.z * coords.x + v1.z * coords.y + v2.z * coords.z;
zbuf = get_pixel(f32, &(render->depth), x, y); zbuf = get_pixel(f32, &(render->depth), x, y);
if (z > zbuf) { if (z <= zbuf) {
if (type == RENDER_TYPE_SHADED) { continue;
}
nx = normals[0].x * coords.x + normals[1].x * coords.y + nx = normals[0].x * coords.x + normals[1].x * coords.y +
normals[2].x * coords.z; normals[2].x * coords.z;
ny = normals[0].y * coords.x + normals[1].y * coords.y + ny = normals[0].y * coords.x + normals[1].y * coords.y +
@ -231,31 +236,21 @@ internal void fill_triangle(Render *render, V3f vertices[TRIANGLE_VERTICES],
nz = normals[0].z * coords.x + normals[1].z * coords.y + nz = normals[0].z * coords.x + normals[1].z * coords.y +
normals[2].z * coords.z; normals[2].z * coords.z;
normal = (V3f){nx, ny, nz}; 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 + tx_u = coordinates[0].u * coords.x + coordinates[1].u * coords.y +
coordinates[2].u * coords.z; coordinates[2].u * coords.z;
tx_v = coordinates[0].v * coords.x + coordinates[1].v * coords.y + tx_v = coordinates[0].v * coords.x + coordinates[1].v * coords.y +
coordinates[2].v * coords.z; coordinates[2].v * coords.z;
tx_x = tx_u * texture->width; tex_coords = (V2f){tx_u, tx_v};
tx_y = (1.0f - tx_v) * texture->height;
colour = get_pixel(Colour, texture, tx_x, tx_y); result =
run_fragment_shader(shader, normal, tex_coords, &colour, texture);
if (DISCARD_FRAGMENT(result)) {
continue;
} }
colour.r *= intensity;
colour.g *= intensity;
colour.b *= intensity;
set_pixel(depth, x, y, &z); set_pixel(depth, x, y, &z);
set_pixel(img, x, y, &colour); set_pixel(img, x, y, &result.colour);
}
} }
} }
} }

View File

@ -57,7 +57,7 @@ struct render {
Model load_obj_file(Arena *arena, const char *filename, const char *texture); Model load_obj_file(Arena *arena, const char *filename, const char *texture);
bool init_render(Arena *arena, Render *render, u64 width, u64 height); 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); RenderType render_type, Colour colour);
#endif // OBJ_H #endif // OBJ_H

62
src/shader.c Normal file
View 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);
}

View File

@ -1,19 +1,37 @@
#ifndef SHADER_H #ifndef SHADER_H
#define SHADER_H #define SHADER_H
#include "aliases.h"
#include "img.h" #include "img.h"
#include "vec.h" #include "vec.h"
typedef V3f(VertexShader)(const V3f *vertex, M4x4f *model_view, typedef struct shader_id ShaderID;
M4x4f *projection, const Image *img); struct shader_id {
typedef bool(FragmentShader)(Colour colour); u64 id;
typedef struct shader Shader;
struct shader {
VertexShader *vertex;
FragmentShader *fragment;
M4x4f *model_view;
M4x4f *projection;
}; };
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 #endif // SHADER_H