diff --git a/src/main.c b/src/main.c index 1e50d3a..9dcb087 100644 --- a/src/main.c +++ b/src/main.c @@ -4,30 +4,82 @@ #include "obj.h" #include "render.h" #include "shaders.h" +#include "str.h" #include +#include +#include #include +#include #include #define IMAGE_DIMENSION 1200 -#define RESOURCE(NAME) "resources/" NAME 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, }; -int tinyrenderer(void); +typedef struct tiny_args TinyArgs; +struct tiny_args { + Str8 obj; + Str8 diffuse; + Str8 nm_tangent; +}; -int main(void) { return tinyrenderer(); } +internal TinyArgs parse_args(Arena *arena, int argc, char *argv[]); +internal i32 tinyrenderer(Arena *arena, TinyArgs args); +internal bool file_exists(const Str8 *path); -int tinyrenderer(void) { +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); + } + + const Str8 basename = str8_substr(&args.obj, 0, args.obj.length - 4); + + args.diffuse = str8_copy(arena, &basename); + str8_concat(arena, &args.diffuse, "_diffuse.pnm"); + if (!file_exists(&args.diffuse)) { + args.diffuse = (Str8){0}; + } + + args.nm_tangent = str8_copy(arena, &basename); + str8_concat(arena, &args.nm_tangent, "_nm_tangent.pnm"); + if (!file_exists(&args.nm_tangent)) { + args.nm_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; @@ -35,8 +87,9 @@ int tinyrenderer(void) { return TINY_EXIT_RENDER_INIT_FAILED; } - Model obj = load_obj_file(arena, RESOURCE("head.obj"), RESOURCE("head.pnm"), - RESOURCE("head_nm_tangent.pnm")); + Model obj = load_obj_file( + arena, args.obj.str, args.diffuse.length > 0 ? args.diffuse.str : NULL, + args.nm_tangent.length > 0 ? args.nm_tangent.str : NULL); if (IS_INVALID_MODEL(obj)) { return TINY_EXIT_MODEL_LOAD_FAILED; } @@ -48,7 +101,10 @@ int tinyrenderer(void) { main_colour); save_image(&(render.img), "result.pam"); - wapp_mem_arena_destroy(&arena); - return TINY_EXIT_SUCCESS; } + +internal bool file_exists(const Str8 *path) { + struct stat st; + return stat(path->str, &st) == 0; +} diff --git a/src/str/str.c b/src/str/str.c new file mode 100644 index 0000000..d82e77d --- /dev/null +++ b/src/str/str.c @@ -0,0 +1,98 @@ +#include "str.h" +#include "aliases.h" +#include "mem_arena.h" +#include +#include + +#define CAPACITY_SCALAR 8 + +internal Arena *get_temp_arena(void); +internal void destroy_temp_arena(Arena *arena); + +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; +} + +const Str8 str8_substr(const Str8 *str, u64 start, u64 count) { + if (start > str->length || start + count > str->length) { + return (Str8){0}; + } + + return (Str8){ + .str = str->str + start, + .length = count, + .capacity = count, + }; +} diff --git a/src/str/str.h b/src/str/str.h new file mode 100644 index 0000000..771bdc2 --- /dev/null +++ b/src/str/str.h @@ -0,0 +1,26 @@ +#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); +const Str8 str8_substr(const Str8 *str, u64 start, u64 count); + +#endif // !STR_H