Compare commits
25 Commits
95895750e8
...
main
Author | SHA1 | Date | |
---|---|---|---|
4526c514e9 | |||
bf3a3ea02b | |||
669064e4a7 | |||
2ffd44f1a5 | |||
11dee52090 | |||
53e535774d | |||
2f086fe548 | |||
db42dd3d9e | |||
b0cebb67f8 | |||
bca5dafabf | |||
0aacccdf67 | |||
7a17d129a1 | |||
7f2c4cdd0a | |||
56fbde696f | |||
88e9d3550a | |||
66ca20ee5b | |||
ef0c29de02 | |||
87f6b2b87a | |||
390ab7c3b4 | |||
72ab9f6aa2 | |||
15a471f911 | |||
ab8343e749 | |||
09e9f611f8 | |||
fb1b8457d6 | |||
ab71bbc438 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,6 @@
|
|||||||
.cache
|
.cache
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
tiny
|
/tiny
|
||||||
*.pam
|
*.pam
|
||||||
resources/*.png
|
resources/*.png
|
||||||
.venv
|
.venv
|
||||||
|
BIN
output.png
BIN
output.png
Binary file not shown.
Before Width: | Height: | Size: 564 KiB After Width: | Height: | Size: 652 KiB |
31134
resources/head.obj
31134
resources/head.obj
File diff suppressed because it is too large
Load Diff
115
src/main.c
115
src/main.c
@@ -1,113 +1,6 @@
|
|||||||
#include "img.h"
|
#include "aliases.h"
|
||||||
#include "mem_arena.h"
|
#include "tiny.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
|
i32 main(i32 argc, char *argv[]) {
|
||||||
|
return tiny_main(argc, argv);
|
||||||
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 main(int 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 render;
|
|
||||||
if (!init_render(arena, &render, 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(&(render.img), &bg);
|
|
||||||
|
|
||||||
// render_model(&obj, &render, depth, RENDER_TYPE_SHADED, main_colour);
|
|
||||||
render_model(&obj, &render, perspective_diffuse, RENDER_TYPE_SHADED, main_colour);
|
|
||||||
save_image(&(render.img), "result.pam");
|
|
||||||
|
|
||||||
return TINY_EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool file_exists(const Str8 *path) {
|
|
||||||
struct stat st;
|
|
||||||
return stat(path->str, &st) == 0;
|
|
||||||
}
|
}
|
||||||
|
@@ -5,8 +5,7 @@
|
|||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
Model load_obj_file(Arena *arena, const char *filename, const char *diffuse,
|
Model load_obj_file(Arena *arena, const char *filename, const char *diffuse, const char *tangent) {
|
||||||
const char *tangent) {
|
|
||||||
if (!arena) {
|
if (!arena) {
|
||||||
return INVALID_MODEL;
|
return INVALID_MODEL;
|
||||||
}
|
}
|
||||||
@@ -22,8 +21,7 @@ Model load_obj_file(Arena *arena, const char *filename, const char *diffuse,
|
|||||||
.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) ||
|
if (!(model.vertices) || !(model.normals) || !(model.texture_coordinates) || !(model.triangles)) {
|
||||||
!(model.triangles)) {
|
|
||||||
return INVALID_MODEL;
|
return INVALID_MODEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -58,7 +58,6 @@ struct model {
|
|||||||
Image *normal;
|
Image *normal;
|
||||||
};
|
};
|
||||||
|
|
||||||
Model load_obj_file(Arena *arena, const char *filename, const char *diffuse,
|
Model load_obj_file(Arena *arena, const char *filename, const char *diffuse, const char *tangent);
|
||||||
const char *tangent);
|
|
||||||
|
|
||||||
#endif // OBJ_H
|
#endif // OBJ_H
|
||||||
|
@@ -6,8 +6,11 @@
|
|||||||
#include "typed_list.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};
|
||||||
|
|
||||||
typedef struct triangle_bbox TriangleBBox;
|
typedef struct triangle_bbox TriangleBBox;
|
||||||
struct triangle_bbox {
|
struct triangle_bbox {
|
||||||
u64 x0;
|
u64 x0;
|
||||||
@@ -16,14 +19,11 @@ struct triangle_bbox {
|
|||||||
u64 y1;
|
u64 y1;
|
||||||
};
|
};
|
||||||
|
|
||||||
internal void render_triangle(const Triangle *triangle, const Model *model,
|
internal void render_triangle(const Triangle *triangle, const Model *model, ShaderID shader,
|
||||||
ShaderID shader, Render *render,
|
Render *render, RenderType render_type, Colour colour);
|
||||||
RenderType render_type, Colour colour);
|
internal void fill_triangle(Render *render, ShaderID shader, VertexData vertices[TRIANGLE_VERTICES],
|
||||||
internal void fill_triangle(Render *render, ShaderID shader,
|
|
||||||
VertexData vertices[TRIANGLE_VERTICES],
|
|
||||||
Colour colour, const Model *model, RenderType type);
|
Colour colour, const Model *model, RenderType type);
|
||||||
internal TriangleBBox get_triangle_bbox(const Image *img,
|
internal TriangleBBox get_triangle_bbox(const Image *img, V2f vertices[TRIANGLE_VERTICES]);
|
||||||
V2f vertices[TRIANGLE_VERTICES]);
|
|
||||||
internal V3f get_barycentric_coords(V2f a, V2f b, V2f c, V2f p);
|
internal V3f get_barycentric_coords(V2f a, V2f b, V2f c, V2f p);
|
||||||
internal V2f get_viewport_vertex(const V3f *vertex, const Image *img);
|
internal V2f get_viewport_vertex(const V3f *vertex, const Image *img);
|
||||||
|
|
||||||
@@ -44,8 +44,7 @@ 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,
|
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) {
|
||||||
triangle = list_get(model->triangles, i);
|
triangle = list_get(model->triangles, i);
|
||||||
@@ -53,9 +52,8 @@ void render_model(const Model *model, Render *render, ShaderID shader,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void render_triangle(const Triangle *triangle, const Model *model,
|
internal void render_triangle(const Triangle *triangle, const Model *model, ShaderID shader,
|
||||||
ShaderID shader, Render *render,
|
Render *render, RenderType render_type, Colour colour) {
|
||||||
RenderType render_type, Colour colour) {
|
|
||||||
Image *img = &(render->img);
|
Image *img = &(render->img);
|
||||||
VertexData vertices[TRIANGLE_VERTICES];
|
VertexData vertices[TRIANGLE_VERTICES];
|
||||||
for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) {
|
for (u64 i = 0; i < TRIANGLE_VERTICES; ++i) {
|
||||||
@@ -80,10 +78,8 @@ internal void render_triangle(const Triangle *triangle, const Model *model,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void fill_triangle(Render *render, ShaderID shader,
|
internal void fill_triangle(Render *render, ShaderID shader, VertexData vertices[TRIANGLE_VERTICES],
|
||||||
VertexData vertices[TRIANGLE_VERTICES],
|
Colour colour, const Model *model, RenderType type) {
|
||||||
Colour colour, const Model *model,
|
|
||||||
RenderType type) {
|
|
||||||
Image *img = &(render->img);
|
Image *img = &(render->img);
|
||||||
Depth *depth = &(render->depth);
|
Depth *depth = &(render->depth);
|
||||||
|
|
||||||
@@ -98,6 +94,8 @@ internal void fill_triangle(Render *render, ShaderID shader,
|
|||||||
V3f coords;
|
V3f coords;
|
||||||
f32 z;
|
f32 z;
|
||||||
f32 zbuf;
|
f32 zbuf;
|
||||||
|
V4f shader_colour;
|
||||||
|
Colour output_colour;
|
||||||
FragmentResult result;
|
FragmentResult result;
|
||||||
|
|
||||||
f32 intensity = 1.0f;
|
f32 intensity = 1.0f;
|
||||||
@@ -120,19 +118,26 @@ internal void fill_triangle(Render *render, ShaderID shader,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = run_fragment_shader(shader, &coords, &colour, model);
|
shader_colour = (V4f){.r = colour.r, .g = colour.g, .b = colour.b, .a = colour.a};
|
||||||
|
result = run_fragment_shader(shader, &coords, &shader_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, &result.colour);
|
set_pixel(img, x, y, &output_colour);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal TriangleBBox get_triangle_bbox(const Image *img,
|
internal TriangleBBox get_triangle_bbox(const Image *img, V2f vertices[TRIANGLE_VERTICES]) {
|
||||||
V2f 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));
|
||||||
|
@@ -5,14 +5,13 @@
|
|||||||
#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_TYPES,
|
COUNT_RENDER_TYPE,
|
||||||
} RenderType;
|
} RenderType;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -28,8 +27,16 @@ 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,
|
void render_model(const Model *model, Render *render, ShaderID shader, RenderType render_type, Colour colour);
|
||||||
RenderType render_type, Colour colour);
|
|
||||||
|
|
||||||
#endif // RENDER_H
|
#endif // RENDER_H
|
||||||
|
@@ -1,11 +1,12 @@
|
|||||||
#include "main_shader.h"
|
#include "main_shader.h"
|
||||||
|
#include "img.h"
|
||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
|
#include "render.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
|
|
||||||
VertexData general_shader_vertex(void *shader, const VertexData *vert, u8 index,
|
VertexData general_shader_vertex(void *shader, const VertexData *vert, u8 index, const Model *model) {
|
||||||
const Model *model) {
|
|
||||||
Shader *shdr = (Shader *)shader;
|
Shader *shdr = (Shader *)shader;
|
||||||
|
|
||||||
V4f vh = V3_to_V4(vert->position);
|
V4f vh = V3_to_V4(vert->position);
|
||||||
@@ -15,17 +16,15 @@ VertexData general_shader_vertex(void *shader, const VertexData *vert, u8 index,
|
|||||||
shdr->vertices[index].position = project_vec4(vh);
|
shdr->vertices[index].position = project_vec4(vh);
|
||||||
shdr->vertices[index].uv = vert->uv;
|
shdr->vertices[index].uv = vert->uv;
|
||||||
|
|
||||||
M4x4f inv_transpose = mat4x4_inv(mat4x4_transpose(shdr->proj_mv));
|
|
||||||
V4f hnorm = V3_to_V4(vert->normal);
|
V4f hnorm = V3_to_V4(vert->normal);
|
||||||
hnorm = mat4x4_mul_vec4(inv_transpose, hnorm);
|
hnorm = mat4x4_mul_vec4(shdr->proj_mv_inv_t, hnorm);
|
||||||
shdr->vertices[index].normal = project_vec4(hnorm);
|
shdr->vertices[index].normal = project_vec4(hnorm);
|
||||||
normalise_v3(shdr->vertices[index].normal);
|
normalise_v3(shdr->vertices[index].normal);
|
||||||
|
|
||||||
return shdr->vertices[index];
|
return shdr->vertices[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
FragmentResult diffuse_shader_fragment(void *shader, const V3f *barycentric,
|
FragmentResult diffuse_shader_fragment(void *shader, const V3f *barycentric, const V4f *colour,
|
||||||
const Colour *colour,
|
|
||||||
const Model *model) {
|
const Model *model) {
|
||||||
Shader *shdr = (Shader *)shader;
|
Shader *shdr = (Shader *)shader;
|
||||||
|
|
||||||
@@ -40,6 +39,15 @@ FragmentResult diffuse_shader_fragment(void *shader, const V3f *barycentric,
|
|||||||
V3f normal = mat3x3_mul_vec3(normal_mat, (*barycentric));
|
V3f normal = mat3x3_mul_vec3(normal_mat, (*barycentric));
|
||||||
V2f uv = mat2x3_mul_vec3(uv_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
|
#pragma region darboux_frame_tangent_normals
|
||||||
/**
|
/**
|
||||||
* Based on the following section of the tinyrenderer tutorial
|
* Based on the following section of the tinyrenderer tutorial
|
||||||
@@ -83,11 +91,12 @@ FragmentResult diffuse_shader_fragment(void *shader, const V3f *barycentric,
|
|||||||
}
|
}
|
||||||
#pragma endregion darboux_frame_tangent_normals
|
#pragma endregion darboux_frame_tangent_normals
|
||||||
|
|
||||||
Colour output;
|
V4f output;
|
||||||
if (model->texture) {
|
if (model->texture) {
|
||||||
u64 tx_x = uv.u * model->texture->width;
|
u64 tx_x = uv.u * model->texture->width;
|
||||||
u64 tx_y = uv.v * model->texture->height;
|
u64 tx_y = uv.v * model->texture->height;
|
||||||
output = get_pixel(Colour, model->texture, tx_x, tx_y);
|
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 {
|
} else {
|
||||||
output = *colour;
|
output = *colour;
|
||||||
}
|
}
|
||||||
@@ -97,30 +106,27 @@ FragmentResult diffuse_shader_fragment(void *shader, const V3f *barycentric,
|
|||||||
f32 g = clamp(intensity + shdr->ambient.g, 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);
|
f32 b = clamp(intensity + shdr->ambient.b, 0.0f, 1.0f);
|
||||||
|
|
||||||
output.r *= r;
|
output.r *= r * shadow;
|
||||||
output.g *= g;
|
output.g *= g * shadow;
|
||||||
output.b *= b;
|
output.b *= b * shadow;
|
||||||
|
|
||||||
return (FragmentResult){.colour = output};
|
return (FragmentResult){.colour = output};
|
||||||
}
|
}
|
||||||
|
|
||||||
FragmentResult albedo_shader_fragment(void *shader, const V3f *barycentric,
|
FragmentResult albedo_shader_fragment(void *shader, const V3f *barycentric, const V4f *colour,
|
||||||
const Colour *colour,
|
|
||||||
const Model *model) {
|
const Model *model) {
|
||||||
Shader *shdr = (Shader *)shader;
|
Shader *shdr = (Shader *)shader;
|
||||||
|
|
||||||
// clang-format off
|
|
||||||
M3x2f uvs = {shdr->vertices[0].uv, shdr->vertices[1].uv, shdr->vertices[2].uv};
|
M3x2f uvs = {shdr->vertices[0].uv, shdr->vertices[1].uv, shdr->vertices[2].uv};
|
||||||
M2x3f uv_mat = mat3x2_transpose(uvs);
|
M2x3f uv_mat = mat3x2_transpose(uvs);
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
V2f uv = mat2x3_mul_vec3(uv_mat, (*barycentric));
|
V2f uv = mat2x3_mul_vec3(uv_mat, (*barycentric));
|
||||||
|
|
||||||
Colour output;
|
V4f output;
|
||||||
if (model->texture) {
|
if (model->texture) {
|
||||||
u64 tx_x = uv.u * model->texture->width;
|
u64 tx_x = uv.u * model->texture->width;
|
||||||
u64 tx_y = uv.v * model->texture->height;
|
u64 tx_y = uv.v * model->texture->height;
|
||||||
output = get_pixel(Colour, model->texture, tx_x, tx_y);
|
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 {
|
} else {
|
||||||
output = *colour;
|
output = *colour;
|
||||||
}
|
}
|
||||||
|
@@ -7,13 +7,12 @@
|
|||||||
typedef struct shader Shader;
|
typedef struct shader Shader;
|
||||||
struct shader {
|
struct shader {
|
||||||
#include "shader_base.inc"
|
#include "shader_base.inc"
|
||||||
|
M4x4f shadow_matrix;
|
||||||
};
|
};
|
||||||
|
|
||||||
VertexData general_shader_vertex(void *shader, const VertexData *vert, u8 index,
|
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);
|
const Model *model);
|
||||||
FragmentResult diffuse_shader_fragment(void *shader, const V3f *barycentric,
|
FragmentResult albedo_shader_fragment(void *shader, const V3f *barycentric, const V4f *colour,
|
||||||
const Colour *colour,
|
|
||||||
const Model *model);
|
const Model *model);
|
||||||
FragmentResult albedo_shader_fragment(void *shader, const V3f *barycentric,
|
|
||||||
const Colour *colour, const Model *model);
|
|
||||||
#endif // !MAIN_SHADER_H
|
#endif // !MAIN_SHADER_H
|
||||||
|
@@ -13,8 +13,7 @@ struct shader_repo {
|
|||||||
|
|
||||||
internal ShaderRepo g_repository = {0};
|
internal ShaderRepo g_repository = {0};
|
||||||
|
|
||||||
ShaderID register_shader(void *shader, VertexShader *vertex,
|
ShaderID register_shader(void *shader, VertexShader *vertex, FragmentShader *fragment) {
|
||||||
FragmentShader *fragment) {
|
|
||||||
if (g_repository.count + 1 >= MAX_SHADER_COUNT) {
|
if (g_repository.count + 1 >= MAX_SHADER_COUNT) {
|
||||||
return INVALID_SHADER;
|
return INVALID_SHADER;
|
||||||
}
|
}
|
||||||
@@ -27,10 +26,8 @@ ShaderID register_shader(void *shader, VertexShader *vertex,
|
|||||||
return (ShaderID){g_repository.count};
|
return (ShaderID){g_repository.count};
|
||||||
}
|
}
|
||||||
|
|
||||||
VertexData run_vertex_shader(ShaderID shader, const VertexData *vert, u8 index,
|
VertexData run_vertex_shader(ShaderID shader, const VertexData *vert, u8 index, const Model *model) {
|
||||||
const Model *model) {
|
if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !vert || !model) {
|
||||||
if (IS_INVALID_SHADER(shader) || shader.id > g_repository.count || !vert ||
|
|
||||||
!model) {
|
|
||||||
return (VertexData){0};
|
return (VertexData){0};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,8 +41,8 @@ VertexData run_vertex_shader(ShaderID shader, const VertexData *vert, u8 index,
|
|||||||
return vertex_func(shader_obj, vert, index, model);
|
return vertex_func(shader_obj, vert, index, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
FragmentResult run_fragment_shader(ShaderID shader, const V3f *barycentric,
|
FragmentResult run_fragment_shader(ShaderID shader, const V3f *barycentric, const V4f *colour,
|
||||||
const Colour *colour, const Model *model) {
|
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;
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
#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"
|
||||||
|
|
||||||
@@ -20,7 +19,7 @@ struct vertex_data {
|
|||||||
|
|
||||||
typedef struct fragment_result FragmentResult;
|
typedef struct fragment_result FragmentResult;
|
||||||
struct fragment_result {
|
struct fragment_result {
|
||||||
Colour colour;
|
V4f colour;
|
||||||
bool discard;
|
bool discard;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -29,17 +28,12 @@ struct fragment_result {
|
|||||||
#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,
|
typedef VertexData(VertexShader)(void *shader, const VertexData *vert, u8 index, const Model *model);
|
||||||
const Model *model);
|
typedef FragmentResult(FragmentShader)(void *shader, const V3f *barycentric, const V4f *colour,
|
||||||
typedef FragmentResult(FragmentShader)(void *shader, const V3f *barycentric,
|
|
||||||
const Colour *colour,
|
|
||||||
const Model *model);
|
const Model *model);
|
||||||
|
|
||||||
ShaderID register_shader(void *shader, VertexShader *vertex,
|
ShaderID register_shader(void *shader, VertexShader *vertex, FragmentShader *fragment);
|
||||||
FragmentShader *fragment);
|
VertexData run_vertex_shader(ShaderID shader, const VertexData *vert, u8 index, const Model *model);
|
||||||
VertexData run_vertex_shader(ShaderID shader, const VertexData *vert, u8 index,
|
FragmentResult run_fragment_shader(ShaderID shader, const V3f *barycentric, const V4f *colour, const Model *model);
|
||||||
const Model *model);
|
|
||||||
FragmentResult run_fragment_shader(ShaderID shader, const V3f *barycentric,
|
|
||||||
const Colour *colour, const Model *model);
|
|
||||||
|
|
||||||
#endif // SHADER_H
|
#endif // SHADER_H
|
||||||
|
@@ -4,4 +4,5 @@ M4x4f proj_mv;
|
|||||||
M4x4f proj_mv_inv_t;
|
M4x4f proj_mv_inv_t;
|
||||||
M4x4f viewport;
|
M4x4f viewport;
|
||||||
M4x4f final;
|
M4x4f final;
|
||||||
|
M4x4f final_inv;
|
||||||
VertexData vertices[TRIANGLE_VERTICES];
|
VertexData vertices[TRIANGLE_VERTICES];
|
||||||
|
@@ -1,20 +1,20 @@
|
|||||||
#include "shaders.h"
|
#include "shaders.h"
|
||||||
#include "aliases.h"
|
#include "aliases.h"
|
||||||
#include "depth_shader.h"
|
#include "shadow_shader.h"
|
||||||
#include "main_shader.h"
|
#include "main_shader.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "vec.h"
|
#include "vec.h"
|
||||||
|
|
||||||
|
ShaderID depth = {0};
|
||||||
ShaderID perspective_diffuse = {0};
|
ShaderID perspective_diffuse = {0};
|
||||||
ShaderID perspective_albedo = {0};
|
ShaderID perspective_albedo = {0};
|
||||||
ShaderID orthographic_diffuse = {0};
|
ShaderID orthographic_diffuse = {0};
|
||||||
ShaderID orthographic_albedo = {0};
|
ShaderID orthographic_albedo = {0};
|
||||||
ShaderID depth = {0};
|
|
||||||
|
|
||||||
|
internal ShadowShader depth_shader = {0};
|
||||||
internal Shader perspective = {0};
|
internal Shader perspective = {0};
|
||||||
internal Shader orthographic = {0};
|
internal Shader orthographic = {0};
|
||||||
internal DepthShader depth_shader = {0};
|
|
||||||
|
|
||||||
internal V3f g_ambient_light = {0.1f, 0.1f, 0.1f};
|
internal V3f g_ambient_light = {0.1f, 0.1f, 0.1f};
|
||||||
internal V3f g_eye = {0.2f, -0.1f, 0.5f};
|
internal V3f g_eye = {0.2f, -0.1f, 0.5f};
|
||||||
@@ -25,6 +25,19 @@ internal V3f g_light_dir = {1.0f, -1.0f, 1.0f};
|
|||||||
internal M4x4f get_projection_matrix(ProjectionType projection_type);
|
internal M4x4f get_projection_matrix(ProjectionType projection_type);
|
||||||
|
|
||||||
void load_shaders(M4x4f vp) {
|
void load_shaders(M4x4f vp) {
|
||||||
|
// 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 = get_projection_matrix(PROJECTION_TYPE_ORTHOGRAPHIC);
|
||||||
M4x4f perspective_projection = get_projection_matrix(PROJECTION_TYPE_PERSPECTIVE);
|
M4x4f perspective_projection = get_projection_matrix(PROJECTION_TYPE_PERSPECTIVE);
|
||||||
@@ -34,36 +47,29 @@ void load_shaders(M4x4f vp) {
|
|||||||
perspective.proj_mv_inv_t = mat4x4_inv(mat4x4_transpose(perspective.proj_mv));
|
perspective.proj_mv_inv_t = mat4x4_inv(mat4x4_transpose(perspective.proj_mv));
|
||||||
perspective.viewport = vp;
|
perspective.viewport = vp;
|
||||||
perspective.final = mat4x4_mul(perspective.viewport, perspective.proj_mv);
|
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);
|
perspective.light_dir = mat3x3_mul_vec3(perspective.proj_mv, g_light_dir);
|
||||||
normalise_v3(perspective.light_dir);
|
normalise_v3(perspective.light_dir);
|
||||||
perspective.ambient = g_ambient_light;
|
perspective.shadow_matrix = mat4x4_mul(depth_shader.final, perspective.final_inv);
|
||||||
|
|
||||||
// Set up orthographic shader
|
// Set up orthographic shader
|
||||||
orthographic.proj_mv = mat4x4_mul(orthographic_projection, model_view);
|
orthographic.proj_mv = mat4x4_mul(orthographic_projection, model_view);
|
||||||
orthographic.proj_mv_inv_t = mat4x4_inv(mat4x4_transpose(orthographic.proj_mv));
|
orthographic.proj_mv_inv_t = mat4x4_inv(mat4x4_transpose(orthographic.proj_mv));
|
||||||
orthographic.viewport = vp;
|
orthographic.viewport = vp;
|
||||||
orthographic.final = mat4x4_mul(orthographic.viewport, orthographic.proj_mv);
|
orthographic.final = mat4x4_mul(orthographic.viewport, orthographic.proj_mv);
|
||||||
|
orthographic.final_inv = mat4x4_inv(perspective.final);
|
||||||
|
orthographic.shadow_matrix = mat4x4_mul(depth_shader.final, orthographic.final_inv);
|
||||||
orthographic.light_dir = mat3x3_mul_vec3(orthographic.proj_mv, g_light_dir);
|
orthographic.light_dir = mat3x3_mul_vec3(orthographic.proj_mv, g_light_dir);
|
||||||
normalise_v3(orthographic.light_dir);
|
normalise_v3(orthographic.light_dir);
|
||||||
orthographic.ambient = g_ambient_light;
|
orthographic.ambient = g_ambient_light;
|
||||||
|
|
||||||
// Set up depth shader
|
|
||||||
M4x4f depth_model_view = lookat(g_light_dir, g_target, g_up);
|
|
||||||
M4x4f depth_projection = projection(0.0f);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
// Register shaders
|
// Register shaders
|
||||||
|
depth = register_shader(&depth_shader, shadow_shader_vertex, shadow_shader_fragment);
|
||||||
perspective_diffuse = register_shader(&perspective, general_shader_vertex, diffuse_shader_fragment);
|
perspective_diffuse = register_shader(&perspective, general_shader_vertex, diffuse_shader_fragment);
|
||||||
perspective_albedo = register_shader(&perspective, general_shader_vertex, albedo_shader_fragment);
|
perspective_albedo = register_shader(&perspective, general_shader_vertex, albedo_shader_fragment);
|
||||||
orthographic_diffuse = register_shader(&orthographic, general_shader_vertex, diffuse_shader_fragment);
|
orthographic_diffuse = register_shader(&orthographic, general_shader_vertex, diffuse_shader_fragment);
|
||||||
orthographic_albedo = register_shader(&orthographic, general_shader_vertex, albedo_shader_fragment);
|
orthographic_albedo = register_shader(&orthographic, general_shader_vertex, albedo_shader_fragment);
|
||||||
depth = register_shader(&depth_shader, depth_shader_vertex, depth_shader_fragment);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal M4x4f get_projection_matrix(ProjectionType projection_type) {
|
internal M4x4f get_projection_matrix(ProjectionType projection_type) {
|
||||||
|
@@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
|
||||||
|
extern ShaderID depth;
|
||||||
extern ShaderID perspective_diffuse;
|
extern ShaderID perspective_diffuse;
|
||||||
extern ShaderID perspective_albedo;
|
extern ShaderID perspective_albedo;
|
||||||
extern ShaderID orthographic_diffuse;
|
extern ShaderID orthographic_diffuse;
|
||||||
extern ShaderID orthographic_albedo;
|
extern ShaderID orthographic_albedo;
|
||||||
extern ShaderID depth;
|
|
||||||
|
|
||||||
void load_shaders(M4x4f vp);
|
void load_shaders(M4x4f vp);
|
||||||
|
|
||||||
|
30
src/shader/shadow_shader.c
Normal file
30
src/shader/shadow_shader.c
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#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
src/shader/shadow_shader.h
Normal file
17
src/shader/shadow_shader.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#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
|
@@ -6,9 +6,6 @@
|
|||||||
|
|
||||||
#define CAPACITY_SCALAR 4
|
#define CAPACITY_SCALAR 4
|
||||||
|
|
||||||
internal Arena *get_temp_arena(void);
|
|
||||||
internal void destroy_temp_arena(Arena *arena);
|
|
||||||
|
|
||||||
Str8 str8(Arena *arena, char *str) {
|
Str8 str8(Arena *arena, char *str) {
|
||||||
if (!str) {
|
if (!str) {
|
||||||
return (Str8){0};
|
return (Str8){0};
|
||||||
|
116
src/tiny/tiny.c
Normal file
116
src/tiny/tiny.c
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#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
src/tiny/tiny.h
Normal file
8
src/tiny/tiny.h
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#ifndef TINY_H
|
||||||
|
#define TINY_H
|
||||||
|
|
||||||
|
#include "aliases.h"
|
||||||
|
|
||||||
|
i32 tiny_main(i32 argc, char *argv[]);
|
||||||
|
|
||||||
|
#endif // !TINY_H
|
@@ -29,14 +29,12 @@ 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) {
|
||||||
|
@@ -55,10 +55,22 @@ typedef union f32x4 V4f;
|
|||||||
union f32x4 {
|
union f32x4 {
|
||||||
f32 elements[4];
|
f32 elements[4];
|
||||||
struct {
|
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;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -123,6 +135,35 @@ 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)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user