Compare commits

..

6 Commits

31 changed files with 112319 additions and 38515 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
.cache .cache
compile_commands.json compile_commands.json
/tiny tiny
*.pam *.pam
resources/*.png resources/*.png
.venv .venv
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 652 KiB

After

Width:  |  Height:  |  Size: 494 KiB

File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because one or more lines are too long
+98787 -24186
View File
File diff suppressed because it is too large Load Diff
+13010
View File
File diff suppressed because one or more lines are too long
-7
View File
@@ -1,7 +0,0 @@
#ifndef CONSTANTS_H
#define CONSTANTS_H
#define DEPTH_MAX 255
#define TRIANGLE_VERTICES 3
#endif // CONSTANTS_H
+8 -6
View File
@@ -12,8 +12,6 @@
TYPE *buf; \ TYPE *buf; \
} NAME } NAME
#define BUF_SIZE(BUF) sizeof(*((BUF)->buf))
typedef struct colour Colour; typedef struct colour Colour;
struct colour { struct colour {
u8 r; u8 r;
@@ -26,10 +24,14 @@ BUF_TYPE(void, Buffer);
BUF_TYPE(Colour, Image); BUF_TYPE(Colour, Image);
BUF_TYPE(f32, Depth); BUF_TYPE(f32, Depth);
#define init_buffer(ARENA, BUF) (_init_buffer(ARENA, (Buffer *)BUF, BUF_SIZE(BUF))) #define init_buffer(ARENA, BUF) \
#define get_pixel(TYPE, BUF, X, Y) (*((TYPE *)(_get_pixel((Buffer *)BUF, X, Y, BUF_SIZE(BUF))))) _init_buffer(ARENA, (Buffer *)BUF, sizeof(*((BUF)->buf)))
#define set_pixel(BUF, X, Y, VAL_PTR) (_set_pixel((Buffer *)BUF, X, Y, VAL_PTR, BUF_SIZE(BUF))) #define get_pixel(TYPE, BUF, X, Y) \
#define clear_buffer(BUF, VAL_PTR) (_clear_buffer((Buffer *)BUF, VAL_PTR, BUF_SIZE(BUF))) (*((TYPE *)(_get_pixel((Buffer *)BUF, X, Y, sizeof(*((BUF)->buf))))))
#define set_pixel(BUF, X, Y, VAL_PTR) \
_set_pixel((Buffer *)BUF, X, Y, VAL_PTR, sizeof(*((BUF)->buf)))
#define clear_buffer(BUF, VAL_PTR) \
_clear_buffer((Buffer *)BUF, VAL_PTR, sizeof(*((BUF)->buf)))
bool _init_buffer(Arena *arena, Buffer *buffer, u64 base_size); 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);
+62 -4
View File
@@ -1,6 +1,64 @@
#include "aliases.h" #include "img.h"
#include "tiny.h" #include "mem_arena.h"
#include "misc_utils.h"
#include "obj.h"
#include "render.h"
#include "shaders.h"
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
i32 main(i32 argc, char *argv[]) { #define IMAGE_DIMENSION 1200
return tiny_main(argc, argv); #define RESOURCE(NAME) "resources/" NAME
enum {
TINY_EXIT_SUCCESS,
TINY_EXIT_ARENA_INIT_FAILED,
TINY_EXIT_RENDER_INIT_FAILED,
TINY_EXIT_MODEL_LOAD_FAILED,
};
int main(void) {
Arena *arena = NULL;
if (!wapp_mem_arena_init(&arena, GB(10))) {
return TINY_EXIT_ARENA_INIT_FAILED;
}
Colour bg = {.r = 42, .g = 45, .b = 52, .a = 255};
Colour teal = {.r = 14, .g = 156, .b = 208, .a = 255};
Render render;
if (!init_render(arena, &render, IMAGE_DIMENSION, IMAGE_DIMENSION)) {
return TINY_EXIT_RENDER_INIT_FAILED;
}
Model obj = load_obj_file(arena, RESOURCE("head.obj"), RESOURCE("head.pnm"),
RESOURCE("head_nm.pnm"));
// Model obj =
// load_obj_file(arena, RESOURCE("polygon.obj"), RESOURCE("grid.pnm"),
// NULL);
if (IS_INVALID_MODEL(obj)) {
return TINY_EXIT_MODEL_LOAD_FAILED;
}
PhongMaterial material = {
.ambient = 0.3f,
.diffuse = 1.5f,
.specular = 2.0f,
// .ambient = 1.0f,
// .diffuse = 0.0f,
// .specular = 0.0f,
.shininess = 1.5f,
};
obj.material = material;
load_shaders();
clear_buffer(&(render.img), &bg);
render_model(&obj, &render, perspective_phong, RENDER_TYPE_SHADED, teal);
save_image(&(render.img), "result.pam");
wapp_mem_arena_destroy(&arena);
return TINY_EXIT_SUCCESS;
} }
+10 -10
View File
@@ -5,7 +5,8 @@
#include "vec.h" #include "vec.h"
#include <stdio.h> #include <stdio.h>
Model load_obj_file(Arena *arena, const char *filename, const char *diffuse, const char *tangent) { Model load_obj_file(Arena *arena, const char *filename, const char *texture,
const char *normal_map) {
if (!arena) { if (!arena) {
return INVALID_MODEL; return INVALID_MODEL;
} }
@@ -21,7 +22,8 @@ Model load_obj_file(Arena *arena, const char *filename, const char *diffuse, con
.texture_coordinates = list_create(V2f, arena), .texture_coordinates = list_create(V2f, arena),
.triangles = list_create(Triangle, arena), .triangles = list_create(Triangle, arena),
}; };
if (!(model.vertices) || !(model.normals) || !(model.texture_coordinates) || !(model.triangles)) { if (!(model.vertices) || !(model.normals) || !(model.texture_coordinates) ||
!(model.triangles)) {
return INVALID_MODEL; return INVALID_MODEL;
} }
@@ -57,10 +59,8 @@ Model load_obj_file(Arena *arena, const char *filename, const char *diffuse, con
coord.v = 1.0f - v; coord.v = 1.0f - v;
list_append(V2f, arena, model.texture_coordinates, coord); list_append(V2f, arena, model.texture_coordinates, coord);
} else if (strncmp(identifier, "f", 8) == 0) { } else if (strncmp(identifier, "f", 8) == 0) {
sscanf(line + 2, "%lu/%lu/%lu %lu/%lu/%lu %lu/%lu/%lu", sscanf(line + 2, "%lu/%lu/%lu %lu/%lu/%lu %lu/%lu/%lu", &fp0, &tx0, &vn0,
&fp0, &tx0, &vn0, &fp1, &tx1, &vn1, &fp2, &tx2, &vn2);
&fp1, &tx1, &vn1,
&fp2, &tx2, &vn2);
// OBJ indices start from 1 // OBJ indices start from 1
triangle.p0 = fp0 - 1; triangle.p0 = fp0 - 1;
triangle.p1 = fp1 - 1; triangle.p1 = fp1 - 1;
@@ -75,12 +75,12 @@ Model load_obj_file(Arena *arena, const char *filename, const char *diffuse, con
} }
} }
if (diffuse) { if (texture) {
model.texture = load_p6_image(arena, diffuse); model.texture = load_p6_image(arena, texture);
} }
if (tangent) { if (normal_map) {
model.normal = load_p6_image(arena, tangent); model.normal = load_p6_image(arena, normal_map);
} }
return model; return model;
+11 -17
View File
@@ -2,7 +2,6 @@
#define OBJ_H #define OBJ_H
#include "aliases.h" #include "aliases.h"
#include "constants.h"
#include "img.h" #include "img.h"
#include "mem_arena.h" #include "mem_arena.h"
#include "typed_list.h" #include "typed_list.h"
@@ -13,34 +12,27 @@
typedef struct triangle Triangle; typedef struct triangle Triangle;
struct triangle { struct triangle {
union {
u64 positions[TRIANGLE_VERTICES];
struct {
u64 p0; u64 p0;
u64 p1; u64 p1;
u64 p2; u64 p2;
};
};
union {
u64 normals[TRIANGLE_VERTICES];
struct {
u64 n0; u64 n0;
u64 n1; u64 n1;
u64 n2; u64 n2;
};
};
union {
u64 coordinates[TRIANGLE_VERTICES];
struct {
u64 tx0; u64 tx0;
u64 tx1; u64 tx1;
u64 tx2; u64 tx2;
}; };
};
};
MAKE_LIST_TYPE(Triangle); MAKE_LIST_TYPE(Triangle);
typedef struct phong_material PhongMaterial;
struct phong_material {
f32 specular;
f32 diffuse;
f32 ambient;
f32 shininess;
};
typedef struct point_light PointLight; typedef struct point_light PointLight;
struct point_light { struct point_light {
V3f diffuse_intensity; V3f diffuse_intensity;
@@ -56,8 +48,10 @@ struct model {
LIST_TYPE(Triangle) * triangles; LIST_TYPE(Triangle) * triangles;
Image *texture; Image *texture;
Image *normal; Image *normal;
PhongMaterial material;
}; };
Model load_obj_file(Arena *arena, const char *filename, const char *diffuse, const char *tangent); Model load_obj_file(Arena *arena, const char *filename, const char *texture,
const char *normal_map);
#endif // OBJ_H #endif // OBJ_H
+112 -68
View File
@@ -1,15 +1,11 @@
#include "render.h" #include "render.h"
#include "aliases.h" #include "aliases.h"
#include "constants.h"
#include "img.h"
#include "shader.h" #include "shader.h"
#include "typed_list.h"
#include "utils.h" #include "utils.h"
#include "vec.h" #include "vec.h"
#include <stdint.h>
#include <math.h> #include <math.h>
Render g_render_passes[COUNT_RENDER_PASS] = {0}; #define TRIANGLE_VERTICES 3
typedef struct triangle_bbox TriangleBBox; typedef struct triangle_bbox TriangleBBox;
struct triangle_bbox { struct triangle_bbox {
@@ -19,13 +15,18 @@ struct triangle_bbox {
u64 y1; u64 y1;
}; };
internal void render_triangle(const Triangle *triangle, const Model *model, ShaderID shader, internal void render_triangle(const Triangle *triangle, const Model *model,
Render *render, RenderType render_type, Colour colour); ShaderID shader, Render *render,
internal void fill_triangle(Render *render, ShaderID shader, VertexData vertices[TRIANGLE_VERTICES], RenderType render_type, Colour colour);
Colour colour, const Model *model, RenderType type); internal void fill_triangle(Render *render, ShaderID shader,
internal TriangleBBox get_triangle_bbox(const Image *img, V2f vertices[TRIANGLE_VERTICES]); V3f vertices[TRIANGLE_VERTICES],
internal V3f get_barycentric_coords(V2f a, V2f b, V2f c, V2f p); V3f normals[TRIANGLE_VERTICES],
internal V2f get_viewport_vertex(const V3f *vertex, const Image *img); V2f coordinates[TRIANGLE_VERTICES], Colour colour,
const Model *model, RenderType type);
internal TriangleBBox get_triangle_bbox(const Image *img,
V3f vertices[TRIANGLE_VERTICES]);
internal V3f get_barycentric_coords(V3f a, V3f b, V3f c, V3f p);
internal V3f get_viewport_vertex(const V3f *vertex, const Image *img);
bool init_render(Arena *arena, Render *render, u64 width, u64 height) { bool init_render(Arena *arena, Render *render, u64 width, u64 height) {
render->img = (Image){.width = width, .height = height}; render->img = (Image){.width = width, .height = height};
@@ -44,7 +45,8 @@ bool init_render(Arena *arena, Render *render, u64 width, u64 height) {
return true; return true;
} }
void render_model(const Model *model, Render *render, ShaderID shader, RenderType render_type, Colour colour) { void render_model(const Model *model, Render *render, ShaderID shader,
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) {
triangle = list_get(model->triangles, i); triangle = list_get(model->triangles, i);
@@ -52,92 +54,131 @@ void render_model(const Model *model, Render *render, ShaderID shader, RenderTyp
} }
} }
internal void render_triangle(const Triangle *triangle, const Model *model, ShaderID shader, internal void render_triangle(const Triangle *triangle, const Model *model,
Render *render, RenderType render_type, Colour colour) { ShaderID shader, Render *render,
RenderType render_type, Colour colour) {
Image *img = &(render->img); Image *img = &(render->img);
VertexData vertices[TRIANGLE_VERTICES]; V3f vertices[TRIANGLE_VERTICES] = {
for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) { list_get(model->vertices, triangle->p0),
vertices[i].position = list_get(model->vertices, triangle->positions[i]); list_get(model->vertices, triangle->p1),
vertices[i].normal = list_get(model->normals, triangle->normals[i]); list_get(model->vertices, triangle->p2),
vertices[i].uv = list_get(model->texture_coordinates, triangle->coordinates[i]); };
V3f normals[TRIANGLE_VERTICES] = {
list_get(model->normals, triangle->n0),
list_get(model->normals, triangle->n1),
list_get(model->normals, triangle->n2),
};
V2f coordinates[TRIANGLE_VERTICES] = {
list_get(model->texture_coordinates, triangle->tx0),
list_get(model->texture_coordinates, triangle->tx1),
list_get(model->texture_coordinates, triangle->tx2),
};
vertices[i] = run_vertex_shader(shader, &vertices[i], i, model); for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) {
vertices[i] =
run_vertex_shader(shader, &vertices[i], (Buffer *)&render->img);
} }
if (render_type == RENDER_TYPE_WIREFRAME) { if (render_type == RENDER_TYPE_WIREFRAME) {
// V3f v0, v1; V3f v0, v1;
// u64 x0, y0, x1, y1; u64 x0, y0, x1, y1;
// for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) { for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) {
// v0 = vertices[i]; v0 = vertices[i];
// v1 = vertices[(i + 1) % TRIANGLE_VERTICES]; v1 = vertices[(i + 1) % TRIANGLE_VERTICES];
//
// draw_line(img, (u64)v0.x, (u64)v0.y, (u64)v1.x, (u64)v1.y, colour); draw_line(img, (u64)v0.x, (u64)v0.y, (u64)v1.x, (u64)v1.y, colour);
// } }
} else if (render_type == RENDER_TYPE_FILLED || render_type == RENDER_TYPE_SHADED) { } else if (render_type == RENDER_TYPE_FILLED ||
fill_triangle(render, shader, vertices, colour, model, render_type); render_type == RENDER_TYPE_SHADED) {
fill_triangle(render, shader, vertices, normals, coordinates, colour, model,
render_type);
} }
} }
internal void fill_triangle(Render *render, ShaderID shader, VertexData vertices[TRIANGLE_VERTICES], internal void fill_triangle(Render *render, ShaderID shader,
Colour colour, const Model *model, RenderType type) { V3f vertices[TRIANGLE_VERTICES],
V3f normals[TRIANGLE_VERTICES],
V2f coordinates[TRIANGLE_VERTICES], Colour colour,
const Model *model, RenderType type) {
Image *img = &(render->img); Image *img = &(render->img);
Depth *depth = &(render->depth); Depth *depth = &(render->depth);
TriangleBBox bbox = get_triangle_bbox(img, vertices);
V2f vp_verts[TRIANGLE_VERTICES] = {0}; V3f vert0 = vertices[0];
for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) { V3f vert1 = vertices[1];
vp_verts[i] = get_viewport_vertex(&vertices[i].position, img); V3f vert2 = vertices[2];
} V3f point;
TriangleBBox bbox = get_triangle_bbox(img, vp_verts);
V2f point;
V3f coords; V3f coords;
f32 z; f32 z;
f32 zbuf; f32 zbuf;
V4f shader_colour; f32 px, py, pz;
Colour output_colour; V3f position;
f32 nx, ny, nz;
V3f normal;
f32 tx_u, tx_v;
u64 tx_x, tx_y;
V2f tex_coords;
FragmentData data = {0};
FragmentResult result; FragmentResult result;
f32 intensity = 1.0f; f32 intensity = 1.0f;
for (u64 y = bbox.y0; y <= bbox.y1; ++y) { for (u64 y = bbox.y0; y <= bbox.y1; ++y) {
for (u64 x = bbox.x0; x <= bbox.x1; ++x) { for (u64 x = bbox.x0; x <= bbox.x1; ++x) {
point = (V2f){x, y}; point = (V3f){x, y, 1.0f};
coords = get_barycentric_coords(vp_verts[0], vp_verts[1], vp_verts[2], point); coords = get_barycentric_coords(vert0, vert1, vert2, point);
if (coords.x < 0.0f || coords.y < 0.0f || coords.z < 0.0f) { if (coords.x < 0.0f || coords.y < 0.0f || coords.z < 0.0f) {
continue; continue;
} }
z = 0.0f; z = 0.0f;
z += vertices[0].position.z * coords.x + z += vert0.z * coords.x + vert1.z * coords.y + vert2.z * coords.z;
vertices[1].position.z * coords.y +
vertices[2].position.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) {
continue; continue;
} }
shader_colour = (V4f){.r = colour.r, .g = colour.g, .b = colour.b, .a = colour.a}; px = vertices[0].x * coords.x + vertices[1].x * coords.y +
result = run_fragment_shader(shader, &coords, &shader_colour, model); vertices[2].x * coords.z;
py = vertices[0].y * coords.x + vertices[1].y * coords.y +
vertices[2].y * coords.z;
pz = vertices[0].z * coords.x + vertices[1].z * coords.y +
vertices[2].z * coords.z;
position = (V3f){px, py, pz};
normalise_v3(position);
data.position = position;
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};
data.normal = normal;
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};
data.tex_coords = tex_coords;
result = run_fragment_shader(shader, &data, &colour, model);
if (DISCARD_FRAGMENT(result)) { if (DISCARD_FRAGMENT(result)) {
continue; continue;
} }
output_colour = (Colour){
.r = clamp(result.colour.r, 0, UINT8_MAX),
.g = clamp(result.colour.g, 0, UINT8_MAX),
.b = clamp(result.colour.b, 0, UINT8_MAX),
.a = clamp(result.colour.a, 0, UINT8_MAX),
};
set_pixel(depth, x, y, &z); set_pixel(depth, x, y, &z);
set_pixel(img, x, y, &output_colour); set_pixel(img, x, y, &result.colour);
} }
} }
} }
internal TriangleBBox get_triangle_bbox(const Image *img, V2f vertices[TRIANGLE_VERTICES]) { internal TriangleBBox get_triangle_bbox(const Image *img,
V3f vertices[TRIANGLE_VERTICES]) {
f32 x0 = min(vertices[0].x, min(vertices[1].x, vertices[2].x)); f32 x0 = min(vertices[0].x, min(vertices[1].x, vertices[2].x));
f32 x1 = max(vertices[0].x, max(vertices[1].x, vertices[2].x)); f32 x1 = max(vertices[0].x, max(vertices[1].x, vertices[2].x));
f32 y0 = min(vertices[0].y, min(vertices[1].y, vertices[2].y)); f32 y0 = min(vertices[0].y, min(vertices[1].y, vertices[2].y));
@@ -151,11 +192,16 @@ internal TriangleBBox get_triangle_bbox(const Image *img, V2f vertices[TRIANGLE_
}; };
} }
internal V3f get_barycentric_coords(V2f a, V2f b, V2f c, V2f p) { internal V3f get_barycentric_coords(V3f a, V3f b, V3f c, V3f p) {
V3f x_vec = V3(V3f, f32, c.x, b.x, a.x, a.x, a.x, p.x); V3f s[2];
V3f y_vec = V3(V3f, f32, c.y, b.y, a.y, a.y, a.y, p.y);
V3f u = cross_product(x_vec, y_vec); for (u64 i = 0; i < 2; ++i) {
s[i].x = c.elements[i] - a.elements[i];
s[i].y = b.elements[i] - a.elements[i];
s[i].z = a.elements[i] - p.elements[i];
}
V3f u = cross_product(s[0], s[1]);
if (fabsf(u.z) < 1e-2) { if (fabsf(u.z) < 1e-2) {
return (V3f){-1.0f, 1.0f, 1.0f}; return (V3f){-1.0f, 1.0f, 1.0f};
} }
@@ -163,10 +209,8 @@ internal V3f get_barycentric_coords(V2f a, V2f b, V2f c, V2f p) {
return (V3f){1.0f - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z}; return (V3f){1.0f - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z};
} }
internal V2f get_viewport_vertex(const V3f *vertex, const Image *img) { internal V3f get_viewport_vertex(const V3f *vertex, const Image *img) {
V3f output = *vertex; V4f vh = {.x = vertex->x, .y = 0.0f - vertex->y, .z = vertex->z, .w = 1.0f};
output.x = clamp(output.x, 0.0f, img->width); vh = mat4x4_mul_vec4(viewport(vh.x, vh.y, img->width, img->height), vh);
output.y = clamp(output.y, 0.0f, img->height); return project_vec4(vh);
return (V2f){output.x, output.y};
} }
+4 -11
View File
@@ -5,13 +5,14 @@
#include "mem_arena.h" #include "mem_arena.h"
#include "obj.h" #include "obj.h"
#include "shader.h" #include "shader.h"
#include <stdbool.h>
typedef enum { typedef enum {
RENDER_TYPE_WIREFRAME, RENDER_TYPE_WIREFRAME,
RENDER_TYPE_FILLED, RENDER_TYPE_FILLED,
RENDER_TYPE_SHADED, RENDER_TYPE_SHADED,
COUNT_RENDER_TYPE, COUNT_RENDER_TYPES,
} RenderType; } RenderType;
typedef enum { typedef enum {
@@ -27,16 +28,8 @@ struct render {
Depth depth; Depth depth;
}; };
enum render_pass {
RENDER_PASS_SHADOW,
RENDER_PASS_MAIN,
COUNT_RENDER_PASS,
};
extern Render g_render_passes[COUNT_RENDER_PASS];
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, ShaderID shader, RenderType render_type, Colour colour); void render_model(const Model *model, Render *render, ShaderID shader,
RenderType render_type, Colour colour);
#endif // RENDER_H #endif // RENDER_H
-135
View File
@@ -1,135 +0,0 @@
#include "main_shader.h"
#include "img.h"
#include "obj.h"
#include "render.h"
#include "shader.h"
#include "utils.h"
#include "vec.h"
VertexData general_shader_vertex(void *shader, const VertexData *vert, u8 index, const Model *model) {
Shader *shdr = (Shader *)shader;
V4f vh = V3_to_V4(vert->position);
vh.y = 0.0 - vh.y;
vh = mat4x4_mul_vec4(shdr->final, vh);
shdr->vertices[index].position = project_vec4(vh);
shdr->vertices[index].uv = vert->uv;
V4f hnorm = V3_to_V4(vert->normal);
hnorm = mat4x4_mul_vec4(shdr->proj_mv_inv_t, hnorm);
shdr->vertices[index].normal = project_vec4(hnorm);
normalise_v3(shdr->vertices[index].normal);
return shdr->vertices[index];
}
FragmentResult diffuse_shader_fragment(void *shader, const V3f *barycentric, const V4f *colour,
const Model *model) {
Shader *shdr = (Shader *)shader;
M3x3f pos_mat = {.rows = {shdr->vertices[0].position, shdr->vertices[1].position, shdr->vertices[2].position}};
pos_mat = mat3x3_transpose(pos_mat);
M3x3f normal_mat = {.rows = {shdr->vertices[0].normal, shdr->vertices[1].normal, shdr->vertices[2].normal}};
normal_mat = mat3x3_transpose(normal_mat);
M3x2f uvs = {shdr->vertices[0].uv, shdr->vertices[1].uv, shdr->vertices[2].uv};
M2x3f uv_mat = mat3x2_transpose(uvs);
V3f position = mat3x3_mul_vec3(pos_mat, (*barycentric));
V3f normal = mat3x3_mul_vec3(normal_mat, (*barycentric));
V2f uv = mat2x3_mul_vec3(uv_mat, (*barycentric));
V4f shadow_position_h = V3_to_V4(position);
shadow_position_h = mat4x4_mul_vec4(shdr->shadow_matrix, shadow_position_h);
V3f shadow_position = project_vec4(shadow_position_h);
// Calculate shadow
const Render *shadow_pass = &(g_render_passes[RENDER_PASS_SHADOW]);
f32 shadow_z = get_pixel(f32, &(shadow_pass->depth), shadow_position.x, shadow_position.y);
f32 shadow = 0.3f + 0.7f * (shadow_z < shadow_position.z + 10.0f);
#pragma region darboux_frame_tangent_normals
/**
* Based on the following section of the tinyrenderer tutorial
* https://github.com/ssloy/tinyrenderer/wiki/Lesson-6bis:-tangent-space-normal-mapping#starting-point-phong-shading
*/
if (model->normal) {
u64 nm_x = uv.u * model->normal->width;
u64 nm_y = uv.v * model->normal->height;
Colour pixel = get_pixel(Colour, model->normal, nm_x, nm_y);
V3f tangent = (V3f){
.x = pixel.r / 255.f * 2.f - 1.f,
.y = pixel.g / 255.f * 2.f - 1.f,
.z = pixel.b / 255.f * 2.f - 1.f,
};
V3f p0p1 = sub_v3(shdr->vertices[1].position, shdr->vertices[0].position);
V3f p0p2 = sub_v3(shdr->vertices[2].position, shdr->vertices[0].position);
M3x3f A = {.rows = {p0p1, p0p2, normal}};
M3x3f A_inv = mat3x3_inv(A);
V2f uv0 = shdr->vertices[0].uv;
V2f uv1 = shdr->vertices[1].uv;
V2f uv2 = shdr->vertices[2].uv;
V3f u_vec = {uv1.u - uv0.u, uv2.u - uv0.u, 0};
V3f v_vec = {uv1.v - uv0.v, uv2.v - uv0.v, 0};
V3f i = mat3x3_mul_vec3(A_inv, u_vec);
normalise_v3(i);
V3f j = mat3x3_mul_vec3(A_inv, v_vec);
normalise_v3(j);
M3x3f B = {.rows = {i, j, normal}};
B = mat3x3_transpose(B);
normal = mat3x3_mul_vec3(B, tangent);
normalise_v3(normal);
}
#pragma endregion darboux_frame_tangent_normals
V4f output;
if (model->texture) {
u64 tx_x = uv.u * model->texture->width;
u64 tx_y = uv.v * model->texture->height;
Colour tx = get_pixel(Colour, model->texture, tx_x, tx_y);
output = (V4f){.r = tx.r, .g = tx.g, .b = tx.b, .a = tx.a};
} else {
output = *colour;
}
f32 intensity = max(0.001f, dot_v3(normal, shdr->light_dir));
f32 r = clamp(intensity + shdr->ambient.r, 0.0f, 1.0f);
f32 g = clamp(intensity + shdr->ambient.g, 0.0f, 1.0f);
f32 b = clamp(intensity + shdr->ambient.b, 0.0f, 1.0f);
output.r *= r * shadow;
output.g *= g * shadow;
output.b *= b * shadow;
return (FragmentResult){.colour = output};
}
FragmentResult albedo_shader_fragment(void *shader, const V3f *barycentric, const V4f *colour,
const Model *model) {
Shader *shdr = (Shader *)shader;
M3x2f uvs = {shdr->vertices[0].uv, shdr->vertices[1].uv, shdr->vertices[2].uv};
M2x3f uv_mat = mat3x2_transpose(uvs);
V2f uv = mat2x3_mul_vec3(uv_mat, (*barycentric));
V4f output;
if (model->texture) {
u64 tx_x = uv.u * model->texture->width;
u64 tx_y = uv.v * model->texture->height;
Colour tx = get_pixel(Colour, model->texture, tx_x, tx_y);
output = (V4f){.r = tx.r, .g = tx.g, .b = tx.b, .a = tx.a};
} else {
output = *colour;
}
return (FragmentResult){.colour = output};
}
-18
View File
@@ -1,18 +0,0 @@
#ifndef MAIN_SHADER_H
#define MAIN_SHADER_H
#include "shader.h"
#include "vec.h"
typedef struct shader Shader;
struct shader {
#include "shader_base.inc"
M4x4f shadow_matrix;
};
VertexData general_shader_vertex(void *shader, const VertexData *vert, u8 index, const Model *model);
FragmentResult diffuse_shader_fragment(void *shader, const V3f *barycentric, const V4f *colour,
const Model *model);
FragmentResult albedo_shader_fragment(void *shader, const V3f *barycentric, const V4f *colour,
const Model *model);
#endif // !MAIN_SHADER_H
+13 -9
View File
@@ -1,5 +1,6 @@
#include "shader.h" #include "shader.h"
#include "aliases.h" #include "aliases.h"
#include "vec.h"
#define MAX_SHADER_COUNT 2048 #define MAX_SHADER_COUNT 2048
@@ -13,7 +14,8 @@ struct shader_repo {
internal ShaderRepo g_repository = {0}; internal ShaderRepo g_repository = {0};
ShaderID register_shader(void *shader, VertexShader *vertex, FragmentShader *fragment) { ShaderID register_shader(void *shader, VertexShader *vertex,
FragmentShader *fragment) {
if (g_repository.count + 1 >= MAX_SHADER_COUNT) { if (g_repository.count + 1 >= MAX_SHADER_COUNT) {
return INVALID_SHADER; return INVALID_SHADER;
} }
@@ -26,23 +28,25 @@ ShaderID register_shader(void *shader, VertexShader *vertex, FragmentShader *fra
return (ShaderID){g_repository.count}; return (ShaderID){g_repository.count};
} }
VertexData run_vertex_shader(ShaderID shader, const VertexData *vert, u8 index, const Model *model) { V3f run_vertex_shader(ShaderID shader, const V3f *vertex,
if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !vert || !model) { const Buffer *out_buf) {
return (VertexData){0}; if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !vertex ||
!out_buf) {
return (V3f){0};
} }
void *shader_obj = g_repository.shaders[shader.id]; void *shader_obj = g_repository.shaders[shader.id];
VertexShader *vertex_func = g_repository.vertex_funcs[shader.id]; VertexShader *vertex_func = g_repository.vertex_funcs[shader.id];
if (!shader_obj || !vertex_func) { if (!shader_obj || !vertex_func) {
return (VertexData){0}; return (V3f){0};
} }
return vertex_func(shader_obj, vert, index, model); return vertex_func(shader_obj, vertex, out_buf);
} }
FragmentResult run_fragment_shader(ShaderID shader, const V3f *barycentric, const V4f *colour, FragmentResult run_fragment_shader(ShaderID shader, const FragmentData *data,
const Model *model) { const Colour *colour, const Model *model) {
if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !colour) { if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !colour) {
return DISCARDED_FRAGMENT; return DISCARDED_FRAGMENT;
} }
@@ -54,5 +58,5 @@ FragmentResult run_fragment_shader(ShaderID shader, const V3f *barycentric, cons
return DISCARDED_FRAGMENT; return DISCARDED_FRAGMENT;
} }
return fragment_func(shader_obj, barycentric, colour, model); return fragment_func(shader_obj, data, colour, model);
} }
+19 -13
View File
@@ -2,6 +2,7 @@
#define SHADER_H #define SHADER_H
#include "aliases.h" #include "aliases.h"
#include "img.h"
#include "obj.h" #include "obj.h"
#include "vec.h" #include "vec.h"
@@ -10,30 +11,35 @@ struct shader_id {
u64 id; u64 id;
}; };
typedef struct vertex_data VertexData;
struct vertex_data {
V3f position;
V3f normal;
V2f uv;
};
typedef struct fragment_result FragmentResult; typedef struct fragment_result FragmentResult;
struct fragment_result { struct fragment_result {
V4f colour; Colour colour;
bool discard; bool discard;
}; };
typedef struct fragment_data FragmentData;
struct fragment_data {
V3f position;
V3f normal;
V2f tex_coords;
};
#define INVALID_SHADER ((ShaderID){0}) #define INVALID_SHADER ((ShaderID){0})
#define IS_INVALID_SHADER(ID) (ID.id == 0) #define IS_INVALID_SHADER(ID) (ID.id == 0)
#define DISCARDED_FRAGMENT ((FragmentResult){.discard = true}) #define DISCARDED_FRAGMENT ((FragmentResult){.discard = true})
#define DISCARD_FRAGMENT(RESULT) (RESULT.discard) #define DISCARD_FRAGMENT(RESULT) (RESULT.discard)
typedef VertexData(VertexShader)(void *shader, const VertexData *vert, u8 index, const Model *model); typedef V3f(VertexShader)(void *shader, const V3f *vertex,
typedef FragmentResult(FragmentShader)(void *shader, const V3f *barycentric, const V4f *colour, const Buffer *out_buf);
typedef FragmentResult(FragmentShader)(void *shader, const FragmentData *data,
const Colour *colour,
const Model *model); const Model *model);
ShaderID register_shader(void *shader, VertexShader *vertex, FragmentShader *fragment); ShaderID register_shader(void *shader, VertexShader *vertex,
VertexData run_vertex_shader(ShaderID shader, const VertexData *vert, u8 index, const Model *model); FragmentShader *fragment);
FragmentResult run_fragment_shader(ShaderID shader, const V3f *barycentric, const V4f *colour, const Model *model); V3f run_vertex_shader(ShaderID shader, const V3f *vertex,
const Buffer *out_buf);
FragmentResult run_fragment_shader(ShaderID shader, const FragmentData *data,
const Colour *colour, const Model *model);
#endif // SHADER_H #endif // SHADER_H
-8
View File
@@ -1,8 +0,0 @@
V3f light_dir;
V3f ambient;
M4x4f proj_mv;
M4x4f proj_mv_inv_t;
M4x4f viewport;
M4x4f final;
M4x4f final_inv;
VertexData vertices[TRIANGLE_VERTICES];
+181 -55
View File
@@ -1,86 +1,212 @@
#include "shaders.h"
#include "aliases.h" #include "aliases.h"
#include "shadow_shader.h" #include "img.h"
#include "main_shader.h" #include "obj.h"
#include "render.h" #include "render.h"
#include "shader.h" #include "shader.h"
#include "utils.h"
#include "vec.h" #include "vec.h"
#include <math.h>
ShaderID depth = {0}; typedef struct shader Shader;
ShaderID perspective_diffuse = {0}; struct shader {
M4x4f model_view;
M4x4f projection;
};
ShaderID perspective_phong = {0};
ShaderID perspective_albedo = {0}; ShaderID perspective_albedo = {0};
ShaderID orthographic_diffuse = {0}; ShaderID orthographic_phong = {0};
ShaderID orthographic_albedo = {0}; ShaderID orthographic_albedo = {0};
internal ShadowShader depth_shader = {0};
internal Shader perspective = {0}; internal Shader perspective = {0};
internal Shader orthographic = {0}; internal Shader orthographic = {0};
internal V3f g_ambient_light = {0.1f, 0.1f, 0.1f}; internal V3f g_ambient_light = {0.6f, 0.45f, 0.55f};
internal V3f g_eye = {0.2f, -0.1f, 0.5f}; internal PointLight g_directional_light = {
.diffuse_intensity = {0.9f, 1.0f, 1.0f},
.specular_intensity = {1.0f, 0.8f, 2.0f},
.position = {1.05f, 0.9f, 1.2f},
};
internal V3f g_eye = {0.2f, 0.1f, 0.75f};
internal V3f g_target = {0}; internal V3f g_target = {0};
internal V3f g_up = {0.0f, 1.0f, 0.0f}; internal V3f g_up = {0.0f, 1.0f, 0.0f};
internal V3f g_light_dir = {1.0f, -1.0f, 1.0f}; internal M4x4f g_cam_matrix = mat4x4_identity;
internal V3f general_shader_vertex(void *shader, const V3f *vertex,
const Buffer *out_buf);
internal FragmentResult phong_shader_fragment(void *shader,
const FragmentData *data,
const Colour *colour,
const Model *model);
internal FragmentResult albedo_shader_fragment(void *shader,
const FragmentData *data,
const Colour *colour,
const Model *model);
internal M4x4f get_projection_matrix(ProjectionType projection_type); internal M4x4f get_projection_matrix(ProjectionType projection_type);
internal f32 get_intensity(const V3f *normal);
void load_shaders(M4x4f vp) { void load_shaders(void) {
// Set up depth shader matrices
M4x4f depth_model_view = lookat(g_light_dir, g_target, g_up);
M4x4f depth_projection = projection(0.0f);
// Set up depth shader
depth_shader.proj_mv = mat4x4_mul(depth_projection, depth_model_view);
depth_shader.proj_mv_inv_t = mat4x4_inv(mat4x4_transpose(depth_shader.proj_mv));
depth_shader.viewport = vp;
depth_shader.final = mat4x4_mul(depth_shader.viewport, depth_shader.proj_mv);
depth_shader.light_dir = mat3x3_mul_vec3(depth_shader.proj_mv, g_light_dir);
normalise_v3(depth_shader.light_dir);
// Set up main shader matrices
M4x4f model_view = lookat(g_eye, g_target, g_up); M4x4f model_view = lookat(g_eye, g_target, g_up);
M4x4f orthographic_projection = get_projection_matrix(PROJECTION_TYPE_ORTHOGRAPHIC); M4x4f orthographic_projection =
M4x4f perspective_projection = get_projection_matrix(PROJECTION_TYPE_PERSPECTIVE); get_projection_matrix(PROJECTION_TYPE_ORTHOGRAPHIC);
M4x4f perspective_projection =
get_projection_matrix(PROJECTION_TYPE_PERSPECTIVE);
// M4x4f model_view = mat4x4_identity;
// M4x4f orthographic_projection = mat4x4_identity;
// M4x4f perspective_projection = mat4x4_identity;
// Set up perspective shader perspective.model_view = orthographic.model_view = model_view;
perspective.proj_mv = mat4x4_mul(perspective_projection, model_view); perspective.projection = perspective_projection;
perspective.proj_mv_inv_t = mat4x4_inv(mat4x4_transpose(perspective.proj_mv)); orthographic.projection = orthographic_projection;
perspective.viewport = vp;
perspective.final = mat4x4_mul(perspective.viewport, perspective.proj_mv);
perspective.final_inv = mat4x4_inv(perspective.final);
perspective.ambient = g_ambient_light;
perspective.light_dir = mat3x3_mul_vec3(perspective.proj_mv, g_light_dir);
normalise_v3(perspective.light_dir);
perspective.shadow_matrix = mat4x4_mul(depth_shader.final, perspective.final_inv);
// Set up orthographic shader perspective_phong = register_shader(&perspective, general_shader_vertex,
orthographic.proj_mv = mat4x4_mul(orthographic_projection, model_view); phong_shader_fragment);
orthographic.proj_mv_inv_t = mat4x4_inv(mat4x4_transpose(orthographic.proj_mv)); perspective_albedo = register_shader(&perspective, general_shader_vertex,
orthographic.viewport = vp; albedo_shader_fragment);
orthographic.final = mat4x4_mul(orthographic.viewport, orthographic.proj_mv); orthographic_phong = register_shader(&orthographic, general_shader_vertex,
orthographic.final_inv = mat4x4_inv(perspective.final); phong_shader_fragment);
orthographic.shadow_matrix = mat4x4_mul(depth_shader.final, orthographic.final_inv); orthographic_albedo = register_shader(&orthographic, general_shader_vertex,
orthographic.light_dir = mat3x3_mul_vec3(orthographic.proj_mv, g_light_dir); albedo_shader_fragment);
normalise_v3(orthographic.light_dir); }
orthographic.ambient = g_ambient_light;
// Register shaders internal V3f general_shader_vertex(void *shader, const V3f *vertex,
depth = register_shader(&depth_shader, shadow_shader_vertex, shadow_shader_fragment); const Buffer *out_buf) {
perspective_diffuse = register_shader(&perspective, general_shader_vertex, diffuse_shader_fragment); Shader *shader_ptr = (Shader *)shader;
perspective_albedo = register_shader(&perspective, general_shader_vertex, albedo_shader_fragment);
orthographic_diffuse = register_shader(&orthographic, general_shader_vertex, diffuse_shader_fragment); V4f vh = {.x = vertex->x, .y = vertex->y, .z = vertex->z, .w = 1.0f};
orthographic_albedo = register_shader(&orthographic, general_shader_vertex, albedo_shader_fragment); vh = mat4x4_mul_vec4(shader_ptr->projection,
mat4x4_mul_vec4(shader_ptr->model_view, vh));
vh.y = 0.0 - vh.y;
vh = mat4x4_mul_vec4(viewport(vh.x, vh.y, out_buf->width, out_buf->height),
vh);
V3f output = project_vec4(vh);
output.x = clamp(output.x, 0.0f, out_buf->width);
output.y = clamp(output.y, 0.0f, out_buf->height);
return output;
}
internal FragmentResult phong_shader_fragment(void *shader,
const FragmentData *data,
const Colour *colour,
const Model *model) {
Shader *shader_ptr = (Shader *)shader;
V4f hnorm;
V3f norm;
if (model->normal) {
u64 nm_x = data->tex_coords.u * model->normal->width;
u64 nm_y = data->tex_coords.v * model->normal->height;
Colour pixel = get_pixel(Colour, model->normal, nm_x, nm_y);
hnorm = (V4f){
.x = pixel.r,
.y = pixel.g,
.z = pixel.b,
.w = 1.0f,
};
} else {
hnorm = V3_to_V4(data->normal);
}
M4x4f matrix = mat4x4_mul(shader_ptr->projection, shader_ptr->model_view);
M4x4f transposed = mat4x4_transpose(matrix);
M4x4f inv_transpose = mat4x4_inv(transposed);
hnorm = mat4x4_mul_vec4(inv_transpose, hnorm);
norm = project_vec4(hnorm);
normalise_v3(norm);
Colour output;
if (model->texture) {
u64 tx_x = data->tex_coords.u * model->texture->width;
u64 tx_y = data->tex_coords.v * model->texture->height;
output = get_pixel(Colour, model->texture, tx_x, tx_y);
} else {
output = *colour;
}
V3f local_colour = {.r = output.r, .g = output.g, .b = output.b};
local_colour = num_div_v3(local_colour, 255.0f);
// Ambient term
V3f intensity = num_mul_v3(g_ambient_light, model->material.ambient);
V4f hdir = V3_to_V4(g_directional_light.position);
hdir = mat4x4_mul_vec4(matrix, hdir);
V3f light_pos = project_vec4(hdir);
normalise_v3(light_pos);
V3f light_dir = sub_v3(light_pos, data->position);
// Diffuse term
f32 l_dot_n = dot_v3(norm, light_dir);
if (l_dot_n <= 0.0f) {
goto RETURN_OUTPUT_COLOUR;
}
V3f diffuse = num_mul_v3(g_directional_light.diffuse_intensity,
model->material.diffuse * l_dot_n);
intensity = add_v3(intensity, diffuse);
// Specular term
V3f _2_l_dot_n_norm = num_mul_v3(norm, 2.0f * l_dot_n);
V3f reflected = sub_v3(_2_l_dot_n_norm, light_dir);
normalise_v3(reflected);
V3f v = sub_v3(g_eye, data->position);
normalise_v3(v);
f32 r_dot_v = dot_v3(reflected, v);
if (r_dot_v <= 0.0f) {
goto RETURN_OUTPUT_COLOUR;
}
V3f specular = num_mul_v3(g_directional_light.specular_intensity,
model->material.specular *
powf(r_dot_v, model->material.shininess));
intensity = add_v3(intensity, specular);
RETURN_OUTPUT_COLOUR:
intensity.r = clamp(intensity.r, 0.0f, 1.0f);
intensity.g = clamp(intensity.g, 0.0f, 1.0f);
intensity.b = clamp(intensity.b, 0.0f, 1.0f);
local_colour = mul_v3(local_colour, intensity);
output.r = 255.0f * local_colour.r;
output.g = 255.0f * local_colour.g;
output.b = 255.0f * local_colour.b;
return (FragmentResult){.colour = output};
}
internal FragmentResult albedo_shader_fragment(void *shader,
const FragmentData *data,
const Colour *colour,
const Model *model) {
return (FragmentResult){.colour = *colour};
} }
internal M4x4f get_projection_matrix(ProjectionType projection_type) { internal M4x4f get_projection_matrix(ProjectionType projection_type) {
if (projection_type == PROJECTION_TYPE_PERSPECTIVE) { if (projection_type == PROJECTION_TYPE_PERSPECTIVE) {
V3f cam = V3(V3f, f32, g_target.x, g_target.y, g_target.z, g_eye.x, g_eye.y, g_eye.z); // Calculate projection matrix
V3f cam = V3(V3f, f32, g_target.x, g_target.y, g_target.z, g_eye.x, g_eye.y,
g_eye.z);
normalise_v3(cam); normalise_v3(cam);
f32 coeff = -1.0f / magnitude_v3(cam) * 0.5f; f32 coeff = -1.0f / magnitude_v3(cam) * 0.5f;
return projection(coeff); return projection(coeff);
} }
return mat4x4_identity; return mat4x4_identity;
} }
internal f32 get_intensity(const V3f *normal) {
V3f light = g_directional_light.position;
normalise_v3(light);
f32 intensity = dot_v3((*normal), light);
if (intensity < 0.0f) {
intensity = 0.001f;
}
return intensity;
}
+3 -4
View File
@@ -3,12 +3,11 @@
#include "shader.h" #include "shader.h"
extern ShaderID depth; extern ShaderID perspective_phong;
extern ShaderID perspective_diffuse;
extern ShaderID perspective_albedo; extern ShaderID perspective_albedo;
extern ShaderID orthographic_diffuse; extern ShaderID orthographic_phong;
extern ShaderID orthographic_albedo; extern ShaderID orthographic_albedo;
void load_shaders(M4x4f vp); void load_shaders(void);
#endif // SHADERS_H #endif // SHADERS_H
-30
View File
@@ -1,30 +0,0 @@
#include "shadow_shader.h"
#include "constants.h"
#include "shader.h"
#include "utils.h"
VertexData shadow_shader_vertex(void *shader, const VertexData *vert, u8 index, const Model *model) {
ShadowShader *shdr = (ShadowShader *)shader;
V4f vh = V3_to_V4(vert->position);
vh.y = 0.0 - vh.y;
vh = mat4x4_mul_vec4(shdr->final, vh);
shdr->vertices[index].position = project_vec4(vh);
return shdr->vertices[index];
}
FragmentResult shadow_shader_fragment(void *shader, const V3f *barycentric, const V4f *colour,
const Model *model) {
ShadowShader *shdr = (ShadowShader *)shader;
M3x3f pos_mat = {.rows = {shdr->vertices[0].position, shdr->vertices[1].position, shdr->vertices[2].position}};
pos_mat = mat3x3_transpose(pos_mat);
V3f position = mat3x3_mul_vec3(pos_mat, (*barycentric));
f32 channel = clamp(position.z + DEPTH_MAX, 0.0f, DEPTH_MAX);
V4f output = {.r = channel, .g = channel, .b = channel, .a = 255};
return (FragmentResult){.colour = output};
}
-17
View File
@@ -1,17 +0,0 @@
#ifndef SHADOW_SHADER_H
#define SHADOW_SHADER_H
#include "constants.h"
#include "shader.h"
#include "vec.h"
typedef struct shadow_shader ShadowShader;
struct shadow_shader {
#include "shader_base.inc"
};
VertexData shadow_shader_vertex(void *shader, const VertexData *vert, u8 index, const Model *model);
FragmentResult shadow_shader_fragment(void *shader, const V3f *barycentric, const V4f *colour,
const Model *model);
#endif // !SHADOW_SHADER_H
-97
View File
@@ -1,97 +0,0 @@
#include "str.h"
#include "aliases.h"
#include "mem_arena.h"
#include <stddef.h>
#include <string.h>
#define CAPACITY_SCALAR 4
Str8 str8(Arena *arena, char *str) {
if (!str) {
return (Str8){0};
}
u64 length = strlen(str);
Str8 output = {
.str = str,
.length = length,
.capacity = length,
};
if (arena) {
output.capacity *= CAPACITY_SCALAR;
output.str = wapp_mem_arena_alloc(arena, output.capacity);
if (!output.str) {
return (Str8){0};
}
strncpy(output.str, str, output.length);
}
return output;
}
Str8 str8_copy(Arena *arena, const Str8 *str) {
if (!arena) {
return str8_lit(str->str);
}
char *tmp = wapp_mem_arena_alloc(arena, str->capacity);
if (!tmp) {
return str8_lit(str->str);
}
strncpy(tmp, str->str, str->length);
return (Str8){
.str = tmp,
.length = str->length,
.capacity = str->capacity,
};
}
i32 str8_concat(Arena *arena, Str8 *dst, char *src) {
if (!src || !dst) {
return STR_OP_FAILED;
}
u64 src_length = strlen(src);
if (src_length + dst->length > dst->capacity) {
if (!arena) {
return STR_OP_FAILED;
}
u64 capacity = dst->capacity * CAPACITY_SCALAR + src_length;
char *str = wapp_mem_arena_alloc(arena, capacity);
if (!str) {
return STR_OP_FAILED;
}
strncpy(str, dst->str, dst->length);
strncpy(str + dst->length, src, src_length);
dst->str = str;
dst->length = dst->length + src_length;
dst->capacity = capacity;
return STR_OP_SUCEEDED;
}
strncpy(dst->str + dst->length, src, src_length);
return STR_OP_SUCEEDED;
}
Str8 str8_substr(Arena *arena, const Str8 *str, u64 start, u64 count) {
if (start > str->length || start + count > str->length) {
return (Str8){0};
}
Str8 tmp = {
.str = str->str + start,
.length = count,
.capacity = count,
};
return str8_copy(arena, &tmp);
}
-26
View File
@@ -1,26 +0,0 @@
#ifndef STR_H
#define STR_H
#include "aliases.h"
#include "mem_arena.h"
enum {
STR_OP_SUCEEDED,
STR_OP_FAILED,
};
typedef struct str8 Str8;
struct str8 {
char *str;
u64 length;
u64 capacity;
};
#define str8_lit(STR) (str8(NULL, STR))
Str8 str8(Arena *arena, char *str);
Str8 str8_copy(Arena *arena, const Str8 *str);
i32 str8_concat(Arena *arena, Str8 *dst, char *src);
Str8 str8_substr(Arena *arena, const Str8 *str, u64 start, u64 count);
#endif // !STR_H
-116
View File
@@ -1,116 +0,0 @@
#include "img.h"
#include "mem_arena.h"
#include "misc_utils.h"
#include "obj.h"
#include "render.h"
#include "shaders.h"
#include "str.h"
#include "vec.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#define IMAGE_DIMENSION 1200
enum {
TINY_EXIT_SUCCESS,
TINY_EXIT_MISSING_ARGS,
TINY_EXIT_OBJ_NOT_EXIST,
TINY_EXIT_ARENA_INIT_FAILED,
TINY_EXIT_RENDER_INIT_FAILED,
TINY_EXIT_MODEL_LOAD_FAILED,
};
typedef struct tiny_args TinyArgs;
struct tiny_args {
Str8 obj;
Str8 diffuse;
Str8 tangent;
};
internal TinyArgs parse_args(Arena *arena, int argc, char *argv[]);
internal i32 tinyrenderer(Arena *arena, TinyArgs args);
internal bool file_exists(const Str8 *path);
i32 tiny_main(i32 argc, char *argv[]) {
Arena *arena = NULL;
if (!wapp_mem_arena_init(&arena, GB(10))) {
return TINY_EXIT_ARENA_INIT_FAILED;
}
TinyArgs args = parse_args(arena, argc, argv);
i32 output = tinyrenderer(arena, args);
wapp_mem_arena_destroy(&arena);
return output;
}
internal TinyArgs parse_args(Arena *arena, int argc, char *argv[]) {
if (argc < 2) {
exit(TINY_EXIT_MISSING_ARGS);
}
TinyArgs args = {
.obj = str8_lit(argv[1]),
};
if (!file_exists(&args.obj)) {
exit(TINY_EXIT_OBJ_NOT_EXIST);
}
u64 substr_end = args.obj.length - 4;
args.diffuse = str8_substr(arena, &args.obj, 0, substr_end);
str8_concat(arena, &args.diffuse, "_diffuse.pnm");
if (!file_exists(&args.diffuse)) {
args.diffuse = (Str8){0};
}
args.tangent = str8_substr(arena, &args.obj, 0, substr_end);
str8_concat(arena, &args.tangent, "_tangent.pnm");
if (!file_exists(&args.tangent)) {
args.tangent = (Str8){0};
}
return args;
}
internal i32 tinyrenderer(Arena *arena, TinyArgs args) {
Colour bg = {.r = 42, .g = 45, .b = 52, .a = 255};
Colour main_colour = {.r = 14, .g = 156, .b = 208, .a = 255};
Render *shadowbuffer = &(g_render_passes[RENDER_PASS_SHADOW]);
Render *framebuffer = &(g_render_passes[RENDER_PASS_MAIN]);
if (!init_render(arena, shadowbuffer, IMAGE_DIMENSION, IMAGE_DIMENSION) ||
!init_render(arena, framebuffer, IMAGE_DIMENSION, IMAGE_DIMENSION)) {
return TINY_EXIT_RENDER_INIT_FAILED;
}
const char *diffuse = args.diffuse.length > 0 ? args.diffuse.str : NULL;
const char *tangent = args.tangent.length > 0 ? args.tangent.str : NULL;
Model obj = load_obj_file(arena, args.obj.str, diffuse, tangent);
if (IS_INVALID_MODEL(obj)) {
return TINY_EXIT_MODEL_LOAD_FAILED;
}
load_shaders(viewport(0, 0, IMAGE_DIMENSION, IMAGE_DIMENSION));
clear_buffer(&(framebuffer->img), &bg);
render_model(&obj, shadowbuffer, depth, RENDER_TYPE_SHADED, main_colour);
render_model(&obj, framebuffer, perspective_diffuse, RENDER_TYPE_SHADED, main_colour);
save_image(&(framebuffer->img), "result.pam");
return TINY_EXIT_SUCCESS;
}
internal bool file_exists(const Str8 *path) {
struct stat st;
return stat(path->str, &st) == 0;
}
-8
View File
@@ -1,8 +0,0 @@
#ifndef TINY_H
#define TINY_H
#include "aliases.h"
i32 tiny_main(i32 argc, char *argv[]);
#endif // !TINY_H
+5 -37
View File
@@ -1,5 +1,7 @@
#include "vec.h" #include "vec.h"
#include "constants.h" #include <assert.h>
#define DEPTH_MAX 255
M4x4f lookat(V3f eye, V3f target, V3f up) { M4x4f lookat(V3f eye, V3f target, V3f up) {
V3f z = V3(V3f, f32, target.x, target.y, target.z, eye.x, eye.y, eye.z); V3f z = V3(V3f, f32, target.x, target.y, target.z, eye.x, eye.y, eye.z);
@@ -29,12 +31,14 @@ M4x4f lookat(V3f eye, V3f target, V3f up) {
} }
M4x4f projection(f32 coeff) { M4x4f projection(f32 coeff) {
// clang-format off
return (M4x4f){ return (M4x4f){
.row0 = {1.0f, 0.0f, 0.0f, 0.0f}, .row0 = {1.0f, 0.0f, 0.0f, 0.0f},
.row1 = {0.0f, 1.0f, 0.0f, 0.0f}, .row1 = {0.0f, 1.0f, 0.0f, 0.0f},
.row2 = {0.0f, 0.0f, 1.0f, 0.0f}, .row2 = {0.0f, 0.0f, 1.0f, 0.0f},
.row3 = {0.0f, 0.0f, coeff, 1.0f}, .row3 = {0.0f, 0.0f, coeff, 1.0f},
}; };
// clang-format on
} }
M4x4f viewport(f32 x, f32 y, u64 w, u64 h) { M4x4f viewport(f32 x, f32 y, u64 w, u64 h) {
@@ -53,42 +57,6 @@ M4x4f viewport(f32 x, f32 y, u64 w, u64 h) {
return output; return output;
} }
M3x3f mat3x3_inv(M3x3f matrix) {
M3x3f dest = {0};
float det;
float a = matrix.rows[0].elements[0], b = matrix.rows[0].elements[1],
c = matrix.rows[0].elements[2], d = matrix.rows[1].elements[0],
e = matrix.rows[1].elements[1], f = matrix.rows[1].elements[2],
g = matrix.rows[2].elements[0], h = matrix.rows[2].elements[1],
i = matrix.rows[2].elements[2];
dest.rows[0].elements[0] = e * i - f * h;
dest.rows[0].elements[1] = -(b * i - h * c);
dest.rows[0].elements[2] = b * f - e * c;
dest.rows[1].elements[0] = -(d * i - g * f);
dest.rows[1].elements[1] = a * i - c * g;
dest.rows[1].elements[2] = -(a * f - d * c);
dest.rows[2].elements[0] = d * h - g * e;
dest.rows[2].elements[1] = -(a * h - g * b);
dest.rows[2].elements[2] = a * e - b * d;
det = 1.0f / (a * dest.rows[0].elements[0] + b * dest.rows[1].elements[0] +
c * dest.rows[2].elements[0]);
dest.rows[0].elements[0] *= det;
dest.rows[0].elements[1] *= det;
dest.rows[0].elements[2] *= det;
dest.rows[1].elements[0] *= det;
dest.rows[1].elements[1] *= det;
dest.rows[1].elements[2] *= det;
dest.rows[2].elements[0] *= det;
dest.rows[2].elements[1] *= det;
dest.rows[2].elements[2] *= det;
return dest;
}
M4x4f mat4x4_inv(M4x4f matrix) { M4x4f mat4x4_inv(M4x4f matrix) {
f32 mat[4][4] = mat4x4_to_array(matrix); f32 mat[4][4] = mat4x4_to_array(matrix);
f32 dest[4][4] = {0}; f32 dest[4][4] = {0};
+15 -112
View File
@@ -5,6 +5,8 @@
#include "typed_list.h" #include "typed_list.h"
#include <math.h> #include <math.h>
#define V3_ELEM_COUNT 3
typedef struct i64x2 V2i; typedef struct i64x2 V2i;
struct i64x2 { struct i64x2 {
i64 x; i64 x;
@@ -17,10 +19,8 @@ struct u64x2 {
u64 y; u64 y;
}; };
typedef union f32x2 V2f; typedef struct f32x2 V2f;
union f32x2 { struct f32x2 {
f32 elements[2];
struct {
union { union {
f32 x; f32 x;
f32 u; f32 u;
@@ -30,11 +30,11 @@ union f32x2 {
f32 v; f32 v;
}; };
}; };
};
typedef union f32x3 V3f; typedef struct f32x3 V3f;
union f32x3 { struct f32x3 {
f32 elements[3]; union {
f32 elements[V3_ELEM_COUNT];
struct { struct {
union { union {
f32 x; f32 x;
@@ -50,28 +50,14 @@ union f32x3 {
}; };
}; };
}; };
};
typedef union f32x4 V4f; typedef struct f32x4 V4f;
union f32x4 { struct f32x4 {
f32 elements[4];
struct {
union {
f32 x; f32 x;
f32 r;
};
union {
f32 y; f32 y;
f32 g;
};
union {
f32 z; f32 z;
f32 b;
};
union {
f32 w; f32 w;
f32 a;
};
};
}; };
typedef struct u64x3 V3u; typedef struct u64x3 V3u;
@@ -81,45 +67,20 @@ struct u64x3 {
u64 z; u64 z;
}; };
typedef union f32_3x2 M3x2f; typedef struct f32_3x3 M3x3f;
union f32_3x2 { struct f32_3x3 {
V2f rows[3];
struct {
V2f row0;
V2f row1;
V2f row2;
};
};
typedef union f32_2x3 M2x3f;
union f32_2x3 {
V3f rows[2];
struct {
V3f row0;
V3f row1;
};
};
typedef union f32_3x3 M3x3f;
union f32_3x3 {
V3f rows[3];
struct {
V3f row0; V3f row0;
V3f row1; V3f row1;
V3f row2; V3f row2;
}; };
};
typedef union f32_4x4 M4x4f; typedef struct f32_4x4 M4x4f;
union f32_4x4 { struct f32_4x4 {
V4f rows[4];
struct {
V4f row0; V4f row0;
V4f row1; V4f row1;
V4f row2; V4f row2;
V4f row3; V4f row3;
}; };
};
MAKE_LIST_TYPE(V3f); MAKE_LIST_TYPE(V3f);
MAKE_LIST_TYPE(V2f); MAKE_LIST_TYPE(V2f);
@@ -135,35 +96,6 @@ MAKE_LIST_TYPE(V2f);
#define dot_v2(V1, V2) ((f32)V1.x * (f32)V2.x + (f32)V1.y * (f32)V2.y) #define dot_v2(V1, V2) ((f32)V1.x * (f32)V2.x + (f32)V1.y * (f32)V2.y)
#define add_v2(V1, V2) \
((V2f){ \
.x = V1.x + V2.x, \
.y = V1.y + V2.y, \
})
#define sub_v2(V1, V2) \
((V2f){ \
.x = V1.x - V2.x, \
.y = V1.y - V2.y, \
})
#define mul_v2(V1, V2) \
((V2f){ \
.x = V1.x * V2.x, \
.y = V1.y * V2.y, \
})
#define num_mul_v2(V, N) ((V2f){.x = (N) * V.x, .y = (N) * V.y})
#define magnitude_v2(V) (sqrtf(dot_v2(V, V)))
#define normalise_v2(V) \
do { \
f32 magnitude = magnitude_v2(V); \
V.x /= magnitude; \
V.y /= magnitude; \
} while (0)
#define dot_v3(V1, V2) \ #define dot_v3(V1, V2) \
((f32)V1.x * (f32)V2.x + (f32)V1.y * (f32)V2.y + (f32)V1.z * (f32)V2.z) ((f32)V1.x * (f32)V2.x + (f32)V1.y * (f32)V2.y + (f32)V1.z * (f32)V2.z)
@@ -209,32 +141,6 @@ MAKE_LIST_TYPE(V2f);
.z = V1.x * V2.y - V1.y * V2.x, \ .z = V1.x * V2.y - V1.y * V2.x, \
}) })
#define mat3x2_transpose(MAT) \
((M2x3f){ \
.row0 = {.x = MAT.row0.x, .y = MAT.row1.x, .z = MAT.row2.x}, \
.row1 = {.x = MAT.row0.y, .y = MAT.row1.y, .z = MAT.row2.y}, \
})
#define mat2x3_mul_vec3(MAT, V) \
((V2f){ \
.elements[0] = dot_v3(MAT.rows[0], V), \
.elements[1] = dot_v3(MAT.rows[1], V), \
})
#define mat3x3_transpose(MAT) \
((M3x3f){ \
.row0 = {.x = MAT.row0.x, .y = MAT.row1.x, .z = MAT.row2.x}, \
.row1 = {.x = MAT.row0.y, .y = MAT.row1.y, .z = MAT.row2.y}, \
.row2 = {.x = MAT.row0.z, .y = MAT.row1.z, .z = MAT.row2.z}, \
})
#define mat3x3_mul_vec3(MAT, V) \
((V3f){ \
.elements[0] = dot_v3(MAT.rows[0], V), \
.elements[1] = dot_v3(MAT.rows[1], V), \
.elements[2] = dot_v3(MAT.rows[2], V), \
})
#define mat4x4_identity \ #define mat4x4_identity \
((M4x4f){ \ ((M4x4f){ \
.row0 = {1.0f, 0.0f, 0.0f, 0.0f}, \ .row0 = {1.0f, 0.0f, 0.0f, 0.0f}, \
@@ -329,12 +235,9 @@ MAKE_LIST_TYPE(V2f);
#define project_vec4(V) ((V3f){.x = V.x / V.w, .y = V.y / V.w, .z = V.z / V.w}) #define project_vec4(V) ((V3f){.x = V.x / V.w, .y = V.y / V.w, .z = V.z / V.w})
#define mat_access(MAT, i, j) (MAT.rows[i].elements[j])
M4x4f lookat(V3f eye, V3f target, V3f up); M4x4f lookat(V3f eye, V3f target, V3f up);
M4x4f projection(f32 coeff); M4x4f projection(f32 coeff);
M4x4f viewport(f32 x, f32 y, u64 w, u64 h); M4x4f viewport(f32 x, f32 y, u64 w, u64 h);
M3x3f mat3x3_inv(M3x3f matrix);
M4x4f mat4x4_inv(M4x4f matrix); M4x4f mat4x4_inv(M4x4f matrix);
#endif // VEC_H #endif // VEC_H