From 69b1487e3e063cbecba96706c550d417b2f24e37 Mon Sep 17 00:00:00 2001 From: omnisci3nce Date: Sat, 27 Apr 2024 18:15:56 +1000 Subject: getting us compiling on windows --- examples/main_loop/ex_main_loop.c | 3 +- src/core.c | 8 +- src/core.h | 4 +- src/platform/path.c | 6 +- src/renderer/archive/render.c | 413 +++++++++++++++++ src/renderer/archive/render.h | 46 ++ src/renderer/archive/render_backend.h | 39 ++ src/renderer/archive/render_types.h | 210 +++++++++ src/renderer/backends/backend_dx11.c | 4 +- src/renderer/backends/backend_dx11.h | 27 ++ src/renderer/cleanroom/ral.h | 86 ---- src/renderer/cleanroom/types.h | 130 +----- src/renderer/ral.h | 87 ++++ src/renderer/ral_types.h | 93 ++++ src/renderer/render.c | 395 +---------------- src/renderer/render.h | 41 +- src/renderer/render_backend.h | 39 -- src/renderer/render_types.h | 277 ++++-------- src/resources/gltf.c | 810 +++++++++++++++++----------------- src/resources/obj.c | 595 +++++++++++++------------ xmake.lua | 139 +++--- 21 files changed, 1840 insertions(+), 1612 deletions(-) create mode 100644 src/renderer/archive/render.c create mode 100644 src/renderer/archive/render.h create mode 100644 src/renderer/archive/render_backend.h create mode 100644 src/renderer/archive/render_types.h create mode 100644 src/renderer/backends/backend_dx11.h delete mode 100644 src/renderer/cleanroom/ral.h create mode 100644 src/renderer/ral.h create mode 100644 src/renderer/ral_types.h delete mode 100644 src/renderer/render_backend.h diff --git a/examples/main_loop/ex_main_loop.c b/examples/main_loop/ex_main_loop.c index 8819f7c..4e1f6a9 100644 --- a/examples/main_loop/ex_main_loop.c +++ b/examples/main_loop/ex_main_loop.c @@ -4,7 +4,6 @@ #include "core.h" #include "maths.h" #include "render.h" -#include "render_backend.h" int main() { core* core = core_bringup(); @@ -14,7 +13,7 @@ int main() { // Main loop while (!glfwWindowShouldClose(core->renderer.window)) { input_update(&core->input); - threadpool_process_results(&core->threadpool, 1); + // threadpool_process_results(&core->threadpool, 1); render_frame_begin(&core->renderer); diff --git a/src/core.c b/src/core.c index 0db8962..714505f 100644 --- a/src/core.c +++ b/src/core.c @@ -8,7 +8,7 @@ #include "log.h" #include "render.h" #include "render_types.h" -#include "threadpool.h" +// #include "threadpool.h" #define SCR_WIDTH 1000 #define SCR_HEIGHT 1000 @@ -21,10 +21,10 @@ core* core_bringup() { .scr_height = SCR_HEIGHT, .clear_colour = (vec3){ .08, .08, .1 } }; c->renderer.config = conf; - c->renderer.backend_state = NULL; + c->renderer.backend_context = NULL; - threadpool_create(&c->threadpool, 6, 256); - threadpool_set_ctx(&c->threadpool, c); // Gives the threadpool access to the core + // threadpool_create(&c->threadpool, 6, 256); + // threadpool_set_ctx(&c->threadpool, c); // Gives the threadpool access to the core // initialise all subsystems if (!renderer_init(&c->renderer)) { diff --git a/src/core.h b/src/core.h index be88c53..a122448 100644 --- a/src/core.h +++ b/src/core.h @@ -6,13 +6,13 @@ #include "screenspace.h" #include "terrain.h" #include "text.h" -#include "threadpool.h" +// #include "threadpool.h" typedef struct core { const char* app_name; // foundations renderer renderer; - threadpool threadpool; + // threadpool threadpool; // systems input_state input; text_system_state text; diff --git a/src/platform/path.c b/src/platform/path.c index 9572941..bee4e9c 100644 --- a/src/platform/path.c +++ b/src/platform/path.c @@ -1,12 +1,12 @@ #include "path.h" -#include #include #include #include "mem.h" #include "str.h" #if defined(CEL_PLATFORM_LINUX) || defined(CEL_PLATFORM_MAC) +#include path_opt path_parent(arena* a, const char* path) { // Duplicate the string because dirname doesnt like const literals char* path_copy = arena_alloc(a, strlen(path) + 1); @@ -17,4 +17,6 @@ path_opt path_parent(arena* a, const char* path) { #endif #ifdef CEL_PLATFORM_WINDOWS // TODO: path_opt path_parent(const char* path) -#endif \ No newline at end of file +#endif + +path_opt path_parent(arena* a, const char* path) {} \ No newline at end of file diff --git a/src/renderer/archive/render.c b/src/renderer/archive/render.c new file mode 100644 index 0000000..b1e2a46 --- /dev/null +++ b/src/renderer/archive/render.c @@ -0,0 +1,413 @@ +#include +#include +#include +#include "animation.h" +#include "maths_types.h" +#include "mem.h" +#include "transform_hierarchy.h" +#define STB_IMAGE_IMPLEMENTATION +#include + +#define STB_TRUETYPE_IMPLEMENTATION +#include + +#include "render.h" +#include "render_types.h" + +#include +#include + +#include "defines.h" +#include "log.h" +#include "maths.h" +#include "render_backend.h" + +// FIXME: get rid of these and store dynamic screen realestate +// in renderer +#define SCR_WIDTH 1000 +#define SCR_HEIGHT 1000 + +material DEFAULT_MATERIAL = { 0 }; + +bool renderer_init(renderer* ren) { + INFO("Renderer init"); + + // NOTE: all platforms use GLFW at the moment but thats subject to change + glfwInit(); + +#if defined(CEL_REND_BACKEND_OPENGL) + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); +#elif defined(CEL_REND_BACKEND_VULKAN) + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); +#endif + + // glfw window creation + GLFWwindow* window = glfwCreateWindow(ren->config.scr_width, ren->config.scr_height, + ren->config.window_name, NULL, NULL); + if (window == NULL) { + ERROR("Failed to create GLFW window\n"); + glfwTerminate(); + return false; + } + ren->window = window; + + glfwMakeContextCurrent(ren->window); + + DEBUG("init graphics api backend"); + if (!gfx_backend_init(ren)) { + FATAL("Couldnt load graphics api backend"); + return false; + } + + ren->blinn_phong = + shader_create_separate("assets/shaders/blinn_phong.vert", "assets/shaders/blinn_phong.frag"); + + ren->skinned = + shader_create_separate("assets/shaders/skinned.vert", "assets/shaders/blinn_phong.frag"); + + default_material_init(); + + return true; +} + +void renderer_shutdown(renderer* ren) {} + +void render_frame_begin(renderer* ren) { + vec3 color = ren->config.clear_colour; + clear_screen(color); +} +void render_frame_end(renderer* ren) { + // present frame + glfwSwapBuffers(ren->window); + glfwPollEvents(); +} + +void default_material_init() { + INFO("Load default material") + DEFAULT_MATERIAL.ambient_colour = (vec3){ 0.5, 0.5, 0.5 }; + DEFAULT_MATERIAL.diffuse = (vec3){ 0.8, 0.8, 0.8 }; + DEFAULT_MATERIAL.specular = (vec3){ 1.0, 1.0, 1.0 }; + DEFAULT_MATERIAL.diffuse_texture = texture_data_load("assets/textures/white1x1.png", false); + DEFAULT_MATERIAL.specular_texture = texture_data_load("assets/textures/black1x1.png", false); + DEFAULT_MATERIAL.spec_exponent = 32.0; + strcpy(DEFAULT_MATERIAL.name, "Default"); + texture_data_upload(&DEFAULT_MATERIAL.diffuse_texture); + texture_data_upload(&DEFAULT_MATERIAL.specular_texture); +} + +void model_destroy(model* model) { + TRACE("Freeing all data for model %s", model->name); + arena_free_all(&model->animation_data_arena); + arena_free_storage(&model->animation_data_arena); + mesh_darray_free(model->meshes); + material_darray_free(model->materials); + if (model->is_uploaded) { + // Delete gpu buffer data + for (u32 i = 0; i < mesh_darray_len(model->meshes); i++) { + // FIXME: dont leak Opengl + glDeleteBuffers(1, &model->meshes->data[i].vbo); + glDeleteVertexArrays(1, &model->meshes->data[i].vao); + } + } +} + +typedef struct draw_ctx { + model_darray* models; + renderer* ren; + camera* cam; + scene* scene; +} draw_ctx; +bool draw_scene_node(transform_node* node, void* ctx_data) { + if (!node || !node->parent) return true; + draw_ctx* ctx = ctx_data; + model* m = &ctx->models->data[node->model.raw]; + draw_model(ctx->ren, ctx->cam, m, &node->world_matrix_tf, ctx->scene); + return true; +} + +void draw_scene(arena* frame, model_darray* models, renderer* ren, camera* camera, + transform_hierarchy* tfh, scene* scene) { + draw_ctx* ctx = arena_alloc(frame, sizeof(draw_ctx)); + ctx->models = models; + ctx->ren = ren; + ctx->cam = camera; + ctx->scene = scene; + transform_hierarchy_dfs(transform_hierarchy_root_node(tfh), draw_scene_node, true, ctx); +} + +void draw_model(renderer* ren, camera* camera, model* model, mat4* model_tf, scene* scene) { + // TRACE("Drawing model: %s", model->name); + mat4 view; + mat4 proj; + camera_view_projection(camera, SCR_HEIGHT, SCR_WIDTH, &view, &proj); + + set_shader(ren->blinn_phong); + + // set camera uniform + uniform_vec3f(ren->blinn_phong.program_id, "viewPos", &camera->position); + // set light uniforms + dir_light_upload_uniforms(ren->blinn_phong, &scene->dir_light); + for (int i = 0; i < scene->n_point_lights; i++) { + point_light_upload_uniforms(ren->blinn_phong, &scene->point_lights[i], '0' + i); + } + + for (size_t i = 0; i < mesh_darray_len(model->meshes); i++) { + mesh* m = &model->meshes->data[i]; + if (vertex_darray_len(m->vertices) == 0) { + continue; + } + // TRACE("Drawing mesh %d", i); + material* mat = &model->materials->data[m->material_index]; + draw_mesh(ren, m, model_tf, mat, &view, &proj); + } +} + +void draw_mesh(renderer* ren, mesh* mesh, mat4* model_tf, material* mat, mat4* view, mat4* proj) { + shader lighting_shader = ren->blinn_phong; + + // bind buffer + bind_mesh_vertex_buffer(ren->backend_state, mesh); + + // bind textures + bind_texture(lighting_shader, &mat->diffuse_texture, 0); // bind to slot 0 + bind_texture(lighting_shader, &mat->specular_texture, 1); // bind to slot 1 + uniform_f32(lighting_shader.program_id, "material.shininess", 32.); + + // upload model, view, and projection matrices + uniform_mat4f(lighting_shader.program_id, "model", model_tf); + uniform_mat4f(lighting_shader.program_id, "view", view); + uniform_mat4f(lighting_shader.program_id, "projection", proj); + + // draw triangles + u32 num_vertices = vertex_darray_len(mesh->vertices); + draw_primitives(CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, 0, num_vertices); +} + +void draw_skinned_mesh(renderer* ren, mesh* mesh, transform tf, material* mat, mat4* view, + mat4* proj) { + shader lighting_shader = ren->skinned; + + // bind buffer + bind_mesh_vertex_buffer(ren->backend_state, mesh); + + // bind textures + bind_texture(lighting_shader, &mat->diffuse_texture, 0); // bind to slot 0 + bind_texture(lighting_shader, &mat->specular_texture, 1); // bind to slot 1 + + // Uniforms + uniform_f32(lighting_shader.program_id, "material.shininess", 32.); + mat4 trans = mat4_translation(tf.position); + mat4 rot = mat4_rotation(tf.rotation); + mat4 scale = mat4_scale(tf.scale); + mat4 model_tf = mat4_mult(trans, mat4_mult(rot, scale)); + uniform_mat4f(lighting_shader.program_id, "model", &model_tf); + uniform_mat4f(lighting_shader.program_id, "view", view); + uniform_mat4f(lighting_shader.program_id, "projection", proj); + + // bone transforms + size_t n_bones = mesh->bones->len; + + // for now assume correct ordering + mat4* bone_transforms = malloc(n_bones * sizeof(mat4)); + mat4 parent = mat4_ident(); + for (int bone_i = 0; bone_i < n_bones; bone_i++) { + joint j = mesh->bones->data[bone_i]; + transform tf = mesh->bones->data[bone_i].transform_components; + tf.position.y = -tf.position.y; + mat4 local = transform_to_mat(&tf); + mat4 inverse = j.inverse_bind_matrix; + inverse.data[13] = -inverse.data[13]; + mat4 intemediate = mat4_mult(local, inverse); + + bone_transforms[bone_i] = intemediate; + parent = bone_transforms[bone_i]; + } + + // premultiply the inverses + // for (int bone_i = 0; bone_i < n_bones; bone_i++) { + // joint j = mesh->bones->data[bone_i]; + // // bone_transforms[bone_i] = mat4_mult(bone_transforms[bone_i], j.inverse_bind_matrix); + // bone_transforms[bone_i] = mat4_mult(bone_transforms[bone_i], j.inverse_bind_matrix); + // } + + glUniformMatrix4fv(glGetUniformLocation(lighting_shader.program_id, "boneMatrices"), n_bones, + GL_FALSE, &bone_transforms->data[0]); + + free(bone_transforms); + + // draw triangles + u32 num_vertices = vertex_darray_len(mesh->vertices); + draw_primitives(CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, 0, num_vertices); +} + +void draw_skinned_model(renderer* ren, camera* cam, model* model, transform tf, scene* scene) { + mat4 view; + mat4 proj; + camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj); + + set_shader(ren->skinned); + + // set camera uniform + uniform_vec3f(ren->skinned.program_id, "viewPos", &cam->position); + // set light uniforms + dir_light_upload_uniforms(ren->skinned, &scene->dir_light); + for (int i = 0; i < scene->n_point_lights; i++) { + point_light_upload_uniforms(ren->skinned, &scene->point_lights[i], '0' + i); + } + + for (size_t i = 0; i < mesh_darray_len(model->meshes); i++) { + mesh* m = &model->meshes->data[i]; + if (vertex_darray_len(m->vertices) == 0) { + continue; + } + // material* mat = &model->materials->data[m->material_index]; + material* mat = &DEFAULT_MATERIAL; + draw_skinned_mesh(ren, m, tf, mat, &view, &proj); + } +} + +void model_upload_meshes(renderer* ren, model* model) { + INFO("Upload mesh vertex data to GPU for model %s", model->name); + + size_t num_meshes = mesh_darray_len(model->meshes); + u32 VBOs[num_meshes]; + u32 VAOs[num_meshes]; + glGenBuffers(num_meshes, VBOs); + glGenVertexArrays(num_meshes, VAOs); + + u64 total_verts = 0; + + TRACE("num meshes %d", num_meshes); + + // upload each mesh to the GPU + for (int mesh_i = 0; mesh_i < num_meshes; mesh_i++) { + mesh mesh = model->meshes->data[mesh_i]; + model->meshes->data[mesh_i].vao = VAOs[mesh_i]; + model->meshes->data[mesh_i].vbo = VBOs[mesh_i]; + // 3. bind buffers + glBindBuffer(GL_ARRAY_BUFFER, VBOs[mesh_i]); + + size_t num_vertices = vertex_darray_len(model->meshes->data[mesh_i].vertices); + // TRACE("Uploading vertex array data: %d verts", num_vertices); + total_verts += num_vertices; + + size_t static_vertex_size = 2 * sizeof(vec3) + sizeof(vec2); + size_t skinned_vertex_size = 2 * sizeof(vec3) + sizeof(vec2) + 4 * sizeof(u32) + sizeof(vec4); + size_t vertex_size = mesh.is_skinned ? skinned_vertex_size : static_vertex_size; + + // TRACE("sizeof(vertex) -> %ld, vertex_size -> %ld\n", sizeof(vertex), vertex_size); + if (mesh.is_skinned) { + assert(vertex_size == (12 + 12 + 8 + 16 + 16)); + } else { + assert(vertex_size == sizeof(vertex)); + assert(vertex_size == 8 * sizeof(float)); + } + + size_t buffer_size = vertex_size * num_vertices; + u8* bytes = malloc(buffer_size); + + for (int i = 0; i < num_vertices; i++) { + u8* p = bytes + vertex_size * i; + memcpy(p, &mesh.vertices->data[i], static_vertex_size); + if (mesh.is_skinned) { + u8* bone_data_offset = p + static_vertex_size; + memcpy(bone_data_offset, &mesh.vertex_bone_data->data[i], sizeof(vertex_bone_data)); + } + } + + // 4. upload data + glBufferData(GL_ARRAY_BUFFER, buffer_size, bytes, GL_STATIC_DRAW); + + // 5. cont. set mesh vertex layout + glBindVertexArray(model->meshes->data[mesh_i].vao); + // position attribute + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertex_size, (void*)0); + glEnableVertexAttribArray(0); + // normal vector attribute + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertex_size, (void*)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + // tex coords + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertex_size, (void*)(6 * sizeof(float))); + glEnableVertexAttribArray(2); + + // skinning (optional) + if (mesh.is_skinned) { + glEnableVertexAttribArray(3); + glVertexAttribIPointer(3, 4, GL_INT, vertex_size, (void*)(8 * sizeof(float))); + + glEnableVertexAttribArray(4); + glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, vertex_size, (void*)(12 * sizeof(float))); + } + } + + INFO("Uploaded %d submeshes with a total of %d vertices\n", num_meshes, total_verts); + + // 6. reset buffer + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +texture texture_data_load(const char* path, bool invert_y) { + TRACE("Load texture %s", path); + + // load the file data + // texture loading + int width, height, num_channels; + stbi_set_flip_vertically_on_load(invert_y); + +#pragma GCC diagnostic ignored "-Wpointer-sign" + char* data = stbi_load(path, &width, &height, &num_channels, 0); // STBI_rgb_alpha); + if (data) { + DEBUG("loaded texture: %s", path); + } else { + WARN("failed to load texture"); + } + + unsigned int channel_type; + if (num_channels == 4) { + channel_type = GL_RGBA; + } else { + channel_type = GL_RGB; + } + + return (texture){ .texture_id = 0, + .width = width, + .height = height, + .channel_count = num_channels, + .channel_type = channel_type, + .name = "TODO: Texture names", + .image_data = data }; +} + +void dir_light_upload_uniforms(shader shader, directional_light* light) { + uniform_vec3f(shader.program_id, "dirLight.direction", &light->direction); + uniform_vec3f(shader.program_id, "dirLight.ambient", &light->ambient); + uniform_vec3f(shader.program_id, "dirLight.diffuse", &light->diffuse); + uniform_vec3f(shader.program_id, "dirLight.specular", &light->specular); +} + +void point_light_upload_uniforms(shader shader, point_light* light, char index) { + char position_str[] = "pointLights[x].position"; + position_str[12] = (char)index; + char ambient_str[] = "pointLights[x].ambient"; + ambient_str[12] = (char)index; + char diffuse_str[] = "pointLights[x].diffuse"; + diffuse_str[12] = (char)index; + char specular_str[] = "pointLights[x].specular"; + specular_str[12] = (char)index; + char constant_str[] = "pointLights[x].constant"; + constant_str[12] = (char)index; + char linear_str[] = "pointLights[x].linear"; + linear_str[12] = (char)index; + char quadratic_str[] = "pointLights[x].quadratic"; + quadratic_str[12] = (char)index; + uniform_vec3f(shader.program_id, position_str, &light->position); + uniform_vec3f(shader.program_id, ambient_str, &light->ambient); + uniform_vec3f(shader.program_id, diffuse_str, &light->diffuse); + uniform_vec3f(shader.program_id, specular_str, &light->specular); + uniform_f32(shader.program_id, constant_str, light->constant); + uniform_f32(shader.program_id, linear_str, light->linear); + uniform_f32(shader.program_id, quadratic_str, light->quadratic); +} \ No newline at end of file diff --git a/src/renderer/archive/render.h b/src/renderer/archive/render.h new file mode 100644 index 0000000..31cf3b0 --- /dev/null +++ b/src/renderer/archive/render.h @@ -0,0 +1,46 @@ +/** + * @file render.h + * @author your name (you@domain.com) + * @brief Renderer frontend + * @version 0.1 + * @date 2024-03-21 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once + +#include "camera.h" +#include "loaders.h" +#include "render_types.h" +#include "transform_hierarchy.h" + +// --- Lifecycle +/** @brief initialise the render system frontend */ +bool renderer_init(renderer* ren); +/** @brief shutdown the render system frontend */ +void renderer_shutdown(renderer* ren); + +void renderer_on_resize(renderer* ren); + +struct render_packet; + +// --- Frame + +void render_frame_begin(renderer* ren); +void render_frame_end(renderer* ren); +void render_frame_draw(renderer* ren); + +// --- models meshes +void model_upload_meshes(renderer* ren, model* model); +void draw_model(renderer* ren, camera* camera, model* model, mat4* tf, scene* scene); +void draw_mesh(renderer* ren, mesh* mesh, mat4* tf, material* mat, mat4* view, mat4* proj); +void draw_scene(arena* frame, model_darray* models, renderer* ren, camera* camera, + transform_hierarchy* tfh, scene* scene); + +void draw_skinned_model(renderer* ren, camera* cam, model* model, transform tf, scene* scene); + +void model_destroy(model* model); + +// --- +texture texture_data_load(const char* path, bool invert_y); // #frontend diff --git a/src/renderer/archive/render_backend.h b/src/renderer/archive/render_backend.h new file mode 100644 index 0000000..da30bcc --- /dev/null +++ b/src/renderer/archive/render_backend.h @@ -0,0 +1,39 @@ +/** + * @brief Renderer backend + */ +#pragma once + +#include "camera.h" +#include "maths_types.h" +#include "render_types.h" + +/// --- Lifecycle + +/** @brief Initialise the graphics API backend */ +bool gfx_backend_init(renderer* ren); +void gfx_backend_shutdown(renderer* ren); + +void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model, texture* tex); +void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, vec4 ambient_colour, + i32 mode); + +void clear_screen(vec3 colour); + +void texture_data_upload(texture* tex); +void bind_texture(shader s, texture* tex, u32 slot); +void bind_mesh_vertex_buffer(void* backend, mesh* mesh); +void draw_primitives(cel_primitive_topology primitive, u32 start_index, u32 count); + +shader shader_create_separate(const char* vert_shader, const char* frag_shader); +void set_shader(shader s); + +// --- Uniforms + +/** @brief upload a vec3 of f32 to a uniform */ +void uniform_vec3f(u32 program_id, const char* uniform_name, vec3* value); +/** @brief upload a single f32 to a uniform */ +void uniform_f32(u32 program_id, const char* uniform_name, f32 value); +/** @brief upload a integer to a uniform */ +void uniform_i32(u32 program_id, const char* uniform_name, i32 value); +/** @brief upload a mat4 of f32 to a uniform */ +void uniform_mat4f(u32 program_id, const char* uniform_name, mat4* value); \ No newline at end of file diff --git a/src/renderer/archive/render_types.h b/src/renderer/archive/render_types.h new file mode 100644 index 0000000..13a6651 --- /dev/null +++ b/src/renderer/archive/render_types.h @@ -0,0 +1,210 @@ +// /** +// * @file render_types.h +// * @author Omniscient +// * @brief Type definitions for the majority of data required by the renderer system +// * @date 2024-02-24 +// * +// */ +// #pragma once + +#include "animation.h" +#include "darray.h" +#include "maths.h" +#include "maths_types.h" +#include "str.h" + +struct GLFWwindow; + +#define MAX_MATERIAL_NAME_LEN 256 +#define MAX_TEXTURE_NAME_LEN 256 + +// #ifndef RESOURCE_HANDLE_DEFS +// // CORE_DEFINE_HANDLE(model_handle); +// #define ABSENT_MODEL_HANDLE 999999999 +// // CORE_DEFINE_HANDLE(texture_handle); +// #define RESOURCE_HANDLE_DEFS +// #endif + +/* @brief Opaque wrapper around a shader program */ +typedef struct shader { + u32 program_id; +} shader; + +/** @brief configuration passed to the renderer at init time */ +typedef struct renderer_config { + char window_name[256]; + u32 scr_width, scr_height; + vec3 clear_colour; /** colour that the screen gets cleared to every frame */ +} renderer_config; + +// typedef struct frame_stats { +// u64 last_time; +// } frame_stats; + +typedef struct renderer { + struct GLFWwindow *window; /** Currently all platforms use GLFW*/ + void *backend_state; /** Graphics API-specific state */ + renderer_config config; + // shaders + shader blinn_phong; + shader skinned; +} renderer; + +// // --- Lighting & Materials + +typedef struct texture { + u32 texture_id; + char name[MAX_TEXTURE_NAME_LEN]; + void *image_data; + void *backend_data; + u32 width; + u32 height; + u8 channel_count; + u32 channel_type; +} texture; + +typedef struct blinn_phong_material { + char name[MAX_MATERIAL_NAME_LEN]; + texture diffuse_texture; + char diffuse_tex_path[256]; + texture specular_texture; + char specular_tex_path[256]; + vec3 ambient_colour; + vec3 diffuse; + vec3 specular; + f32 spec_exponent; + bool is_loaded; + bool is_uploaded; +} blinn_phong_material; +typedef blinn_phong_material material; // when we start using PBR, this will no longer be the +// case + +// // the default blinn-phong material. MUST be initialised with the function below +// extern material DEFAULT_MATERIAL; +// void default_material_init(); + +#ifndef TYPED_MATERIAL_ARRAY +KITC_DECL_TYPED_ARRAY(material) // creates "material_darray" +#define TYPED_MATERIAL_ARRAY +#endif + +#ifndef TYPED_ANIMATION_CLIP_ARRAY +KITC_DECL_TYPED_ARRAY(animation_clip) // creates "material_darray" +#define TYPED_ANIMATION_CLIP_ARRAY +#endif + +// // lights +// typedef struct point_light { +// vec3 position; +// f32 constant, linear, quadratic; +// vec3 ambient; +// vec3 diffuse; +// vec3 specular; +// } point_light; + +// typedef struct directional_light { +// vec3 direction; +// vec3 ambient; +// vec3 diffuse; +// vec3 specular; +// } directional_light; + +// void point_light_upload_uniforms(shader shader, point_light *light, char index); +// void dir_light_upload_uniforms(shader shader, directional_light *light); + +// // --- Models & Meshes + +// /** @brief Vertex format for a static mesh */ +typedef struct vertex { + vec3 position; + vec3 normal; + vec2 uv; +} vertex; + +typedef struct vertex_bone_data { + vec4u joints; /** @brief 4 indices of joints that influence vectors position */ + vec4 weights; /** @brief weight (0,1) of each joint */ +} vertex_bone_data; + +#include "animation.h" +#ifndef TYPED_VERTEX_ARRAY +KITC_DECL_TYPED_ARRAY(vertex) // creates "vertex_darray" +KITC_DECL_TYPED_ARRAY(vertex_bone_data) // creates "skinned_vertex_darray" +KITC_DECL_TYPED_ARRAY(joint) +#define TYPED_VERTEX_ARRAY +#endif + +typedef struct mesh { + vertex_darray *vertices; + vertex_bone_data_darray *vertex_bone_data; // only used if model needs it + joint_darray *bones; + bool is_skinned; + u32 vertex_size; /** size in bytes of each vertex including necessary padding */ + bool has_indices; + u32 *indices; + u32 indices_len; + size_t material_index; + u32 vbo, vao; /** OpenGL data. TODO: dont leak OpenGL details */ +} mesh; + +// #ifndef TYPED_MESH_ARRAY +// KITC_DECL_TYPED_ARRAY(mesh) // creates "mesh_darray" +// #define TYPED_MESH_ARRAY +// #endif + +typedef struct model { + str8 name; + mesh_darray *meshes; + aabb_3d bbox; + material_darray *materials; + animation_clip_darray *animations; + arena animation_data_arena; + bool is_loaded; + bool is_uploaded; +} model; + +// #ifndef TYPED_MODEL_ARRAY +// KITC_DECL_TYPED_ARRAY(model) // creates "model_darray" +// #define TYPED_MODEL_ARRAY +// #endif + +// // --- Scene + +// // NOTE: This struct won't stay like this for a long time. It's somewhat temporary +// // in order to get a basic scene working without putting burden on the caller of +// // draw_model() +// typedef struct scene { +// directional_light dir_light; +// point_light point_lights[4]; +// size_t n_point_lights; +// } scene; + +// // --- Graphics API related + +// // typedef enum cel_primitive_topology { +// // CEL_PRIMITIVE_TOPOLOGY_POINT, +// // CEL_PRIMITIVE_TOPOLOGY_LINE, +// // CEL_PRIMITIVE_TOPOLOGY_LINE_STRIP, +// // CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, +// // CEL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, +// // CEL_PRIMITIVE_TOPOLOGY_COUNT +// // } cel_primitive_topology; + +// // typedef enum gpu_texture_type { +// // TEXTURE_TYPE_2D, +// // TEXTURE_TYPE_3D, +// // TEXTURE_TYPE_2D_ARRAY, +// // TEXTURE_TYPE_CUBE_MAP, +// // TEXTURE_TYPE_COUNT +// // } gpu_texture_type; + +// // typedef enum gpu_texture_format { +// // TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM, +// // TEXTURE_FORMAT_DEPTH_DEFAULT, +// // TEXTURE_FORMAT_COUNT +// // } gpu_texture_format; + +// // typedef enum pipeline_kind { +// // GRAPHICS, +// // COMPUTE, +// // } pipeline_kind; \ No newline at end of file diff --git a/src/renderer/backends/backend_dx11.c b/src/renderer/backends/backend_dx11.c index d991f03..7e48853 100644 --- a/src/renderer/backends/backend_dx11.c +++ b/src/renderer/backends/backend_dx11.c @@ -1,3 +1,5 @@ -#if CEL_REND_BACKEND_DX11 +#if defined(CEL_REND_BACKEND_DX11) +#include +#include #endif \ No newline at end of file diff --git a/src/renderer/backends/backend_dx11.h b/src/renderer/backends/backend_dx11.h new file mode 100644 index 0000000..163ca97 --- /dev/null +++ b/src/renderer/backends/backend_dx11.h @@ -0,0 +1,27 @@ +#pragma once +#include "ral.h" + +#define GPU_SWAPCHAIN_IMG_COUNT 2 + +typedef struct gpu_swapchain { +} gpu_swapchain; +typedef struct gpu_device { + // VkPhysicalDevice physical_device; + // VkDevice logical_device; + // VkPhysicalDeviceProperties properties; + // VkPhysicalDeviceFeatures features; + // VkPhysicalDeviceMemoryProperties memory; + // VkCommandPool pool; +} gpu_device; +typedef struct gpu_pipeline { +} gpu_pipeline; + +typedef struct gpu_renderpass { + // VkRenderPass vk_handle; + // VkFramebuffer framebuffers[GPU_SWAPCHAIN_IMG_COUNT]; + // u32 +} gpu_renderpass; + +typedef struct gpu_cmd_encoder { + // VkCommandBuffer cmd_buffer; +} gpu_cmd_encoder; \ No newline at end of file diff --git a/src/renderer/cleanroom/ral.h b/src/renderer/cleanroom/ral.h deleted file mode 100644 index 15eb027..0000000 --- a/src/renderer/cleanroom/ral.h +++ /dev/null @@ -1,86 +0,0 @@ -/** - * @file ral.h - * @author your name (you@domain.com) - * @brief Render Abstraction Layer - * @details API that a graphics backend *must* implement - * @version 0.1 - * @date 2024-03-31 - * - * @copyright Copyright (c) 2024 - * - */ -#pragma once - -#include "cleanroom/types.h" -#include "defines.h" - -// Forward declare structs -typedef struct gpu_swapchain gpu_swapchain; -typedef struct gpu_device gpu_device; -typedef struct gpu_pipeline gpu_pipeline; -typedef struct gpu_renderpass gpu_renderpass; -typedef struct gpu_cmd_encoder gpu_cmd_encoder; // Recording -typedef struct gpu_cmd_buffer gpu_cmd_buffer; // Ready for submission - -enum pipeline_kind { - GRAPHICS, - COMPUTE, -} pipeline_kind; - -typedef struct shader_desc { - const char* debug_name; - str8 filepath; // where it came from - str8 glsl; // contents -} shader_desc; - -struct pipeline_desc { - shader_desc vs; /** @brief Vertex shader stage */ - shader_desc fs; /** @brief Fragment shader stage */ -}; - -// lifecycle functions -gpu_device* gpu_device_create(); -void gpu_device_destroy(); - -gpu_renderpass* gpu_renderpass_create(); -void gpu_renderpass_destroy(gpu_renderpass* pass); - -gpu_pipeline* gpu_pipeline_create(enum pipeline_kind kind, struct pipeline_desc description); -void gpu_pipeline_destroy(gpu_pipeline* pipeline); - -void gpu_cmd_encoder_begin(); -void gpu_cmd_encoder_begin_render(); -void gpu_cmd_encoder_begin_compute(); - -/* Actual commands that we can encode */ -void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_offset, - buffer_handle dst, u64 dst_offset, u64 copy_size); -void encode_clear_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); -void encode_set_pipeline(gpu_cmd_encoder* encoder, gpu_pipeline* pipeline); -// render pass -void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); -void encode_set_index_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); -void encode_set_bind_group(); -void encode_draw(gpu_cmd_encoder* encoder); -void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count); - -// FUTURE: compute passes - -/** @brief Finish recording and return a command buffer that can be submitted to a queue */ -gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder); - -void gpu_queue_submit(gpu_cmd_buffer* buffer); - -// Buffers -void gpu_buffer_create(u64 size); -void gpu_buffer_destroy(buffer_handle buffer); -void gpu_buffer_upload(); -void gpu_buffer_bind(buffer_handle buffer); - -// Textures -void gpu_texture_create(); -void gpu_texture_destroy(); -void gpu_texture_upload(); - -// Samplers -void gpu_sampler_create(); \ No newline at end of file diff --git a/src/renderer/cleanroom/types.h b/src/renderer/cleanroom/types.h index 7a6cfbd..0a28b1c 100644 --- a/src/renderer/cleanroom/types.h +++ b/src/renderer/cleanroom/types.h @@ -3,22 +3,11 @@ #include "defines.h" #include "maths_types.h" #include "str.h" +#include "render_types.h" -CORE_DEFINE_HANDLE(buffer_handle); -CORE_DEFINE_HANDLE(texture_handle); -CORE_DEFINE_HANDLE(sampler_handle); -CORE_DEFINE_HANDLE(shader_handle); -CORE_DEFINE_HANDLE(model_handle); +// typedef struct transform_hierarchy { +// } transform_hierarchy; -typedef struct transform_hierarchy { -} transform_hierarchy; - -/** @brief Texture Description - used by texture creation functions */ -typedef struct texture_desc { - // gpu_texture_type tex_type; - // gpu_texture_format format; - // u32x2 extents; -} texture_desc; /* - render_types.h @@ -27,102 +16,10 @@ typedef struct texture_desc { - render.h ? */ -// gpu types -typedef enum gpu_primitive_topology { - CEL_PRIMITIVE_TOPOLOGY_POINT, - CEL_PRIMITIVE_TOPOLOGY_LINE, - CEL_PRIMITIVE_TOPOLOGY_LINE_STRIP, - CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, - CEL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, - CEL_PRIMITIVE_TOPOLOGY_COUNT -} cel_primitive_topology; - -typedef enum gpu_texture_type { - CEL_TEXTURE_TYPE_2D, - CEL_TEXTURE_TYPE_3D, - CEL_TEXTURE_TYPE_2D_ARRAY, - CEL_TEXTURE_TYPE_CUBE_MAP, - CEL_TEXTURE_TYPE_COUNT -} gpu_texture_type; - -typedef enum gpu_texture_format { - CEL_TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM, - CEL_TEXTURE_FORMAT_DEPTH_DEFAULT, - CEL_TEXTURE_FORMAT_COUNT -} gpu_texture_format; - /* render_types */ typedef struct model pbr_material; typedef struct model bp_material; // blinn-phong -#include "maths_types.h" - -typedef enum vertex_format { - VERTEX_STATIC_3D, - VERTEX_SPRITE, - VERTEX_SKINNED, - VERTEX_COUNT -} vertex_format; - -typedef union vertex { - struct { - vec3 position; - vec4 colour; - vec2 tex_coords; - vec3 normal; - } static_3d; /** @brief standard vertex format for static geometry in 3D */ - - struct { - vec2 position; - vec4 colour; - vec2 tex_coords; - } sprite; /** @brief vertex format for 2D sprites or quads */ - - struct { - vec3 position; - vec4 colour; - vec2 tex_coords; - vec3 normal; - vec4i bone_ids; // Integer vector for bone IDs - vec4 bone_weights; // Weight of each bone's influence - } skinned_3d; /** @brief vertex format for skeletal (animated) geometry in 3D */ -} vertex; - -KITC_DECL_TYPED_ARRAY(vertex) -KITC_DECL_TYPED_ARRAY(u32) - -typedef struct geometry_data { - vertex_format format; - vertex_darray vertices; - bool has_indices; - u32_darray indices; - vec3 colour; /** Optional: set vertex colours */ -} geometry_data; - -void geo_set_vertex_colours(geometry_data* geo, vec4 colour); - -typedef struct mesh { - buffer_handle vertex_buffer; - buffer_handle index_buffer; - u32 index_count; - bool has_indices; - geometry_data* vertices; // NULL means it has been freed -} mesh; - -/* Hot reloading: -C side - reload_model(): - - load model from disk using existing loader - - remove from transform graph so it isnt tried to be drawn - - - -*/ - -// TODO: move to some sort of render layer (not inside the abstraction layer) -typedef struct model { - str8 debug_name; - mesh* meshes; - u32 mesh_count; -} model; // ? How to tie together materials and shaders @@ -149,27 +46,6 @@ typedef struct model { /* --- Renderer layer */ /* render.h */ -typedef struct renderer { - void* backend_context; -} renderer; - -bool renderer_init(renderer* ren); -void renderer_shutdown(renderer* ren); - -// frontend -- these can be called from say a loop in an example, or via FFI -texture_handle texture_create(const char* debug_name, texture_desc description, const u8* data); - -// Frontend Resources -void texture_data_upload(texture_handle texture); -buffer_handle buffer_create(const char* debug_name, u64 size); -bool buffer_destroy(buffer_handle buffer); -sampler_handle sampler_create(); - -void shader_hot_reload(const char* filepath); - -// models and meshes are implemented **in terms of the above** -mesh mesh_create(geometry_data* geometry); -model_handle model_load(const char* debug_name, const char* filepath); // Drawing diff --git a/src/renderer/ral.h b/src/renderer/ral.h new file mode 100644 index 0000000..fd83e76 --- /dev/null +++ b/src/renderer/ral.h @@ -0,0 +1,87 @@ +/** + * @file ral.h + * @author your name (you@domain.com) + * @brief Render Abstraction Layer + * @details API that a graphics backend *must* implement + * @version 0.1 + * @date 2024-03-31 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once + +#include "ral_types.h" +#include "defines.h" +#include "str.h" + +// Forward declare structs +typedef struct gpu_swapchain gpu_swapchain; +typedef struct gpu_device gpu_device; +typedef struct gpu_pipeline gpu_pipeline; +typedef struct gpu_renderpass gpu_renderpass; +typedef struct gpu_cmd_encoder gpu_cmd_encoder; // Recording +typedef struct gpu_cmd_buffer gpu_cmd_buffer; // Ready for submission + +enum pipeline_kind { + GRAPHICS, + COMPUTE, +}; + +typedef struct shader_desc { + const char* debug_name; + str8 filepath; // where it came from + str8 glsl; // contents +} shader_desc; + +struct pipeline_desc { + shader_desc vs; /** @brief Vertex shader stage */ + shader_desc fs; /** @brief Fragment shader stage */ +}; + +// lifecycle functions +gpu_device* gpu_device_create(); +void gpu_device_destroy(); + +gpu_renderpass* gpu_renderpass_create(); +void gpu_renderpass_destroy(gpu_renderpass* pass); + +gpu_pipeline* gpu_pipeline_create(enum pipeline_kind kind, struct pipeline_desc description); +void gpu_pipeline_destroy(gpu_pipeline* pipeline); + +void gpu_cmd_encoder_begin(); +void gpu_cmd_encoder_begin_render(); +void gpu_cmd_encoder_begin_compute(); + +/* Actual commands that we can encode */ +void encode_buffer_copy(gpu_cmd_encoder* encoder, buffer_handle src, u64 src_offset, + buffer_handle dst, u64 dst_offset, u64 copy_size); +void encode_clear_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); +void encode_set_pipeline(gpu_cmd_encoder* encoder, gpu_pipeline* pipeline); +// render pass +void encode_set_vertex_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); +void encode_set_index_buffer(gpu_cmd_encoder* encoder, buffer_handle buf); +void encode_set_bind_group(); +void encode_draw(gpu_cmd_encoder* encoder); +void encode_draw_indexed(gpu_cmd_encoder* encoder, u64 index_count); + +// FUTURE: compute passes + +/** @brief Finish recording and return a command buffer that can be submitted to a queue */ +gpu_cmd_buffer gpu_cmd_encoder_finish(gpu_cmd_encoder* encoder); + +void gpu_queue_submit(gpu_cmd_buffer* buffer); + +// Buffers +void gpu_buffer_create(u64 size); +void gpu_buffer_destroy(buffer_handle buffer); +void gpu_buffer_upload(); +void gpu_buffer_bind(buffer_handle buffer); + +// Textures +void gpu_texture_create(); +void gpu_texture_destroy(); +void gpu_texture_upload(); + +// Samplers +void gpu_sampler_create(); \ No newline at end of file diff --git a/src/renderer/ral_types.h b/src/renderer/ral_types.h new file mode 100644 index 0000000..9b1ef62 --- /dev/null +++ b/src/renderer/ral_types.h @@ -0,0 +1,93 @@ +/** + * @file ral_types.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-04-27 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once + +#include "defines.h" +#include "maths_types.h" +#include "darray.h" + +#ifndef RENDERER_TYPED_HANDLES +CORE_DEFINE_HANDLE(buffer_handle); +CORE_DEFINE_HANDLE(texture_handle); +CORE_DEFINE_HANDLE(sampler_handle); +CORE_DEFINE_HANDLE(shader_handle); +CORE_DEFINE_HANDLE(model_handle); +#define ABSENT_MODEL_HANDLE 999999999 +#define RENDERER_TYPED_HANDLES +#endif + +// gpu types +typedef enum gpu_primitive_topology { + CEL_PRIMITIVE_TOPOLOGY_POINT, + CEL_PRIMITIVE_TOPOLOGY_LINE, + CEL_PRIMITIVE_TOPOLOGY_LINE_STRIP, + CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, + CEL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, + CEL_PRIMITIVE_TOPOLOGY_COUNT +} cel_primitive_topology; + +typedef enum gpu_texture_type { + CEL_TEXTURE_TYPE_2D, + CEL_TEXTURE_TYPE_3D, + CEL_TEXTURE_TYPE_2D_ARRAY, + CEL_TEXTURE_TYPE_CUBE_MAP, + CEL_TEXTURE_TYPE_COUNT +} gpu_texture_type; + +typedef enum gpu_texture_format { + CEL_TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM, + CEL_TEXTURE_FORMAT_DEPTH_DEFAULT, + CEL_TEXTURE_FORMAT_COUNT +} gpu_texture_format; + +/** @brief Texture Description - used by texture creation functions */ +typedef struct texture_desc { + // gpu_texture_type tex_type; + // gpu_texture_format format; + // u32x2 extents; +} texture_desc; + +typedef enum vertex_format { + VERTEX_STATIC_3D, + VERTEX_SPRITE, + VERTEX_SKINNED, + VERTEX_COUNT +} vertex_format; + +typedef union vertex { + struct { + vec3 position; + vec4 colour; + vec2 tex_coords; + vec3 normal; + } static_3d; /** @brief standard vertex format for static geometry in 3D */ + + struct { + vec2 position; + vec4 colour; + vec2 tex_coords; + } sprite; /** @brief vertex format for 2D sprites or quads */ + + struct { + vec3 position; + vec4 colour; + vec2 tex_coords; + vec3 normal; + vec4i bone_ids; // Integer vector for bone IDs + vec4 bone_weights; // Weight of each bone's influence + } skinned_3d; /** @brief vertex format for skeletal (animated) geometry in 3D */ +} vertex; + +#ifndef TYPED_VERTEX_ARRAY +KITC_DECL_TYPED_ARRAY(vertex) +KITC_DECL_TYPED_ARRAY(u32) +#define TYPED_VERTEX_ARRAY +#endif \ No newline at end of file diff --git a/src/renderer/render.c b/src/renderer/render.c index b1e2a46..8cd7421 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -1,36 +1,9 @@ -#include -#include -#include -#include "animation.h" -#include "maths_types.h" -#include "mem.h" -#include "transform_hierarchy.h" -#define STB_IMAGE_IMPLEMENTATION -#include - -#define STB_TRUETYPE_IMPLEMENTATION -#include - -#include "render.h" -#include "render_types.h" - -#include #include - -#include "defines.h" -#include "log.h" -#include "maths.h" -#include "render_backend.h" - -// FIXME: get rid of these and store dynamic screen realestate -// in renderer -#define SCR_WIDTH 1000 -#define SCR_HEIGHT 1000 - -material DEFAULT_MATERIAL = { 0 }; +#include "render.h" +#include "camera.h" bool renderer_init(renderer* ren) { - INFO("Renderer init"); + // INFO("Renderer init"); // NOTE: all platforms use GLFW at the moment but thats subject to change glfwInit(); @@ -48,7 +21,7 @@ bool renderer_init(renderer* ren) { GLFWwindow* window = glfwCreateWindow(ren->config.scr_width, ren->config.scr_height, ren->config.window_name, NULL, NULL); if (window == NULL) { - ERROR("Failed to create GLFW window\n"); + // ERROR("Failed to create GLFW window\n"); glfwTerminate(); return false; } @@ -56,358 +29,26 @@ bool renderer_init(renderer* ren) { glfwMakeContextCurrent(ren->window); - DEBUG("init graphics api backend"); - if (!gfx_backend_init(ren)) { - FATAL("Couldnt load graphics api backend"); - return false; - } + // DEBUG("init graphics api backend"); + // if (!gfx_backend_init(ren)) { + // FATAL("Couldnt load graphics api backend"); + // return false; + // } - ren->blinn_phong = - shader_create_separate("assets/shaders/blinn_phong.vert", "assets/shaders/blinn_phong.frag"); + // ren->blinn_phong = + // shader_create_separate("assets/shaders/blinn_phong.vert", "assets/shaders/blinn_phong.frag"); - ren->skinned = - shader_create_separate("assets/shaders/skinned.vert", "assets/shaders/blinn_phong.frag"); + // ren->skinned = + // shader_create_separate("assets/shaders/skinned.vert", "assets/shaders/blinn_phong.frag"); - default_material_init(); + // default_material_init(); return true; } - void renderer_shutdown(renderer* ren) {} -void render_frame_begin(renderer* ren) { - vec3 color = ren->config.clear_colour; - clear_screen(color); -} -void render_frame_end(renderer* ren) { - // present frame - glfwSwapBuffers(ren->window); - glfwPollEvents(); -} - -void default_material_init() { - INFO("Load default material") - DEFAULT_MATERIAL.ambient_colour = (vec3){ 0.5, 0.5, 0.5 }; - DEFAULT_MATERIAL.diffuse = (vec3){ 0.8, 0.8, 0.8 }; - DEFAULT_MATERIAL.specular = (vec3){ 1.0, 1.0, 1.0 }; - DEFAULT_MATERIAL.diffuse_texture = texture_data_load("assets/textures/white1x1.png", false); - DEFAULT_MATERIAL.specular_texture = texture_data_load("assets/textures/black1x1.png", false); - DEFAULT_MATERIAL.spec_exponent = 32.0; - strcpy(DEFAULT_MATERIAL.name, "Default"); - texture_data_upload(&DEFAULT_MATERIAL.diffuse_texture); - texture_data_upload(&DEFAULT_MATERIAL.specular_texture); -} - -void model_destroy(model* model) { - TRACE("Freeing all data for model %s", model->name); - arena_free_all(&model->animation_data_arena); - arena_free_storage(&model->animation_data_arena); - mesh_darray_free(model->meshes); - material_darray_free(model->materials); - if (model->is_uploaded) { - // Delete gpu buffer data - for (u32 i = 0; i < mesh_darray_len(model->meshes); i++) { - // FIXME: dont leak Opengl - glDeleteBuffers(1, &model->meshes->data[i].vbo); - glDeleteVertexArrays(1, &model->meshes->data[i].vao); - } - } -} - -typedef struct draw_ctx { - model_darray* models; - renderer* ren; - camera* cam; - scene* scene; -} draw_ctx; -bool draw_scene_node(transform_node* node, void* ctx_data) { - if (!node || !node->parent) return true; - draw_ctx* ctx = ctx_data; - model* m = &ctx->models->data[node->model.raw]; - draw_model(ctx->ren, ctx->cam, m, &node->world_matrix_tf, ctx->scene); - return true; -} - -void draw_scene(arena* frame, model_darray* models, renderer* ren, camera* camera, - transform_hierarchy* tfh, scene* scene) { - draw_ctx* ctx = arena_alloc(frame, sizeof(draw_ctx)); - ctx->models = models; - ctx->ren = ren; - ctx->cam = camera; - ctx->scene = scene; - transform_hierarchy_dfs(transform_hierarchy_root_node(tfh), draw_scene_node, true, ctx); -} - -void draw_model(renderer* ren, camera* camera, model* model, mat4* model_tf, scene* scene) { - // TRACE("Drawing model: %s", model->name); - mat4 view; - mat4 proj; - camera_view_projection(camera, SCR_HEIGHT, SCR_WIDTH, &view, &proj); - - set_shader(ren->blinn_phong); - - // set camera uniform - uniform_vec3f(ren->blinn_phong.program_id, "viewPos", &camera->position); - // set light uniforms - dir_light_upload_uniforms(ren->blinn_phong, &scene->dir_light); - for (int i = 0; i < scene->n_point_lights; i++) { - point_light_upload_uniforms(ren->blinn_phong, &scene->point_lights[i], '0' + i); - } - - for (size_t i = 0; i < mesh_darray_len(model->meshes); i++) { - mesh* m = &model->meshes->data[i]; - if (vertex_darray_len(m->vertices) == 0) { - continue; - } - // TRACE("Drawing mesh %d", i); - material* mat = &model->materials->data[m->material_index]; - draw_mesh(ren, m, model_tf, mat, &view, &proj); - } -} - -void draw_mesh(renderer* ren, mesh* mesh, mat4* model_tf, material* mat, mat4* view, mat4* proj) { - shader lighting_shader = ren->blinn_phong; - - // bind buffer - bind_mesh_vertex_buffer(ren->backend_state, mesh); - - // bind textures - bind_texture(lighting_shader, &mat->diffuse_texture, 0); // bind to slot 0 - bind_texture(lighting_shader, &mat->specular_texture, 1); // bind to slot 1 - uniform_f32(lighting_shader.program_id, "material.shininess", 32.); - - // upload model, view, and projection matrices - uniform_mat4f(lighting_shader.program_id, "model", model_tf); - uniform_mat4f(lighting_shader.program_id, "view", view); - uniform_mat4f(lighting_shader.program_id, "projection", proj); - - // draw triangles - u32 num_vertices = vertex_darray_len(mesh->vertices); - draw_primitives(CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, 0, num_vertices); -} - -void draw_skinned_mesh(renderer* ren, mesh* mesh, transform tf, material* mat, mat4* view, - mat4* proj) { - shader lighting_shader = ren->skinned; - - // bind buffer - bind_mesh_vertex_buffer(ren->backend_state, mesh); - - // bind textures - bind_texture(lighting_shader, &mat->diffuse_texture, 0); // bind to slot 0 - bind_texture(lighting_shader, &mat->specular_texture, 1); // bind to slot 1 - - // Uniforms - uniform_f32(lighting_shader.program_id, "material.shininess", 32.); - mat4 trans = mat4_translation(tf.position); - mat4 rot = mat4_rotation(tf.rotation); - mat4 scale = mat4_scale(tf.scale); - mat4 model_tf = mat4_mult(trans, mat4_mult(rot, scale)); - uniform_mat4f(lighting_shader.program_id, "model", &model_tf); - uniform_mat4f(lighting_shader.program_id, "view", view); - uniform_mat4f(lighting_shader.program_id, "projection", proj); - - // bone transforms - size_t n_bones = mesh->bones->len; - - // for now assume correct ordering - mat4* bone_transforms = malloc(n_bones * sizeof(mat4)); - mat4 parent = mat4_ident(); - for (int bone_i = 0; bone_i < n_bones; bone_i++) { - joint j = mesh->bones->data[bone_i]; - transform tf = mesh->bones->data[bone_i].transform_components; - tf.position.y = -tf.position.y; - mat4 local = transform_to_mat(&tf); - mat4 inverse = j.inverse_bind_matrix; - inverse.data[13] = -inverse.data[13]; - mat4 intemediate = mat4_mult(local, inverse); - - bone_transforms[bone_i] = intemediate; - parent = bone_transforms[bone_i]; - } - - // premultiply the inverses - // for (int bone_i = 0; bone_i < n_bones; bone_i++) { - // joint j = mesh->bones->data[bone_i]; - // // bone_transforms[bone_i] = mat4_mult(bone_transforms[bone_i], j.inverse_bind_matrix); - // bone_transforms[bone_i] = mat4_mult(bone_transforms[bone_i], j.inverse_bind_matrix); - // } - - glUniformMatrix4fv(glGetUniformLocation(lighting_shader.program_id, "boneMatrices"), n_bones, - GL_FALSE, &bone_transforms->data[0]); - - free(bone_transforms); - - // draw triangles - u32 num_vertices = vertex_darray_len(mesh->vertices); - draw_primitives(CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, 0, num_vertices); -} - -void draw_skinned_model(renderer* ren, camera* cam, model* model, transform tf, scene* scene) { - mat4 view; - mat4 proj; - camera_view_projection(cam, SCR_HEIGHT, SCR_WIDTH, &view, &proj); - - set_shader(ren->skinned); - - // set camera uniform - uniform_vec3f(ren->skinned.program_id, "viewPos", &cam->position); - // set light uniforms - dir_light_upload_uniforms(ren->skinned, &scene->dir_light); - for (int i = 0; i < scene->n_point_lights; i++) { - point_light_upload_uniforms(ren->skinned, &scene->point_lights[i], '0' + i); - } - - for (size_t i = 0; i < mesh_darray_len(model->meshes); i++) { - mesh* m = &model->meshes->data[i]; - if (vertex_darray_len(m->vertices) == 0) { - continue; - } - // material* mat = &model->materials->data[m->material_index]; - material* mat = &DEFAULT_MATERIAL; - draw_skinned_mesh(ren, m, tf, mat, &view, &proj); - } -} - -void model_upload_meshes(renderer* ren, model* model) { - INFO("Upload mesh vertex data to GPU for model %s", model->name); - - size_t num_meshes = mesh_darray_len(model->meshes); - u32 VBOs[num_meshes]; - u32 VAOs[num_meshes]; - glGenBuffers(num_meshes, VBOs); - glGenVertexArrays(num_meshes, VAOs); - - u64 total_verts = 0; - - TRACE("num meshes %d", num_meshes); - - // upload each mesh to the GPU - for (int mesh_i = 0; mesh_i < num_meshes; mesh_i++) { - mesh mesh = model->meshes->data[mesh_i]; - model->meshes->data[mesh_i].vao = VAOs[mesh_i]; - model->meshes->data[mesh_i].vbo = VBOs[mesh_i]; - // 3. bind buffers - glBindBuffer(GL_ARRAY_BUFFER, VBOs[mesh_i]); - - size_t num_vertices = vertex_darray_len(model->meshes->data[mesh_i].vertices); - // TRACE("Uploading vertex array data: %d verts", num_vertices); - total_verts += num_vertices; - - size_t static_vertex_size = 2 * sizeof(vec3) + sizeof(vec2); - size_t skinned_vertex_size = 2 * sizeof(vec3) + sizeof(vec2) + 4 * sizeof(u32) + sizeof(vec4); - size_t vertex_size = mesh.is_skinned ? skinned_vertex_size : static_vertex_size; - - // TRACE("sizeof(vertex) -> %ld, vertex_size -> %ld\n", sizeof(vertex), vertex_size); - if (mesh.is_skinned) { - assert(vertex_size == (12 + 12 + 8 + 16 + 16)); - } else { - assert(vertex_size == sizeof(vertex)); - assert(vertex_size == 8 * sizeof(float)); - } - - size_t buffer_size = vertex_size * num_vertices; - u8* bytes = malloc(buffer_size); - - for (int i = 0; i < num_vertices; i++) { - u8* p = bytes + vertex_size * i; - memcpy(p, &mesh.vertices->data[i], static_vertex_size); - if (mesh.is_skinned) { - u8* bone_data_offset = p + static_vertex_size; - memcpy(bone_data_offset, &mesh.vertex_bone_data->data[i], sizeof(vertex_bone_data)); - } - } - - // 4. upload data - glBufferData(GL_ARRAY_BUFFER, buffer_size, bytes, GL_STATIC_DRAW); - - // 5. cont. set mesh vertex layout - glBindVertexArray(model->meshes->data[mesh_i].vao); - // position attribute - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, vertex_size, (void*)0); - glEnableVertexAttribArray(0); - // normal vector attribute - glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertex_size, (void*)(3 * sizeof(float))); - glEnableVertexAttribArray(1); - // tex coords - glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertex_size, (void*)(6 * sizeof(float))); - glEnableVertexAttribArray(2); - - // skinning (optional) - if (mesh.is_skinned) { - glEnableVertexAttribArray(3); - glVertexAttribIPointer(3, 4, GL_INT, vertex_size, (void*)(8 * sizeof(float))); - - glEnableVertexAttribArray(4); - glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, vertex_size, (void*)(12 * sizeof(float))); - } - } - - INFO("Uploaded %d submeshes with a total of %d vertices\n", num_meshes, total_verts); - - // 6. reset buffer - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -texture texture_data_load(const char* path, bool invert_y) { - TRACE("Load texture %s", path); - - // load the file data - // texture loading - int width, height, num_channels; - stbi_set_flip_vertically_on_load(invert_y); - -#pragma GCC diagnostic ignored "-Wpointer-sign" - char* data = stbi_load(path, &width, &height, &num_channels, 0); // STBI_rgb_alpha); - if (data) { - DEBUG("loaded texture: %s", path); - } else { - WARN("failed to load texture"); - } - - unsigned int channel_type; - if (num_channels == 4) { - channel_type = GL_RGBA; - } else { - channel_type = GL_RGB; - } - - return (texture){ .texture_id = 0, - .width = width, - .height = height, - .channel_count = num_channels, - .channel_type = channel_type, - .name = "TODO: Texture names", - .image_data = data }; -} - -void dir_light_upload_uniforms(shader shader, directional_light* light) { - uniform_vec3f(shader.program_id, "dirLight.direction", &light->direction); - uniform_vec3f(shader.program_id, "dirLight.ambient", &light->ambient); - uniform_vec3f(shader.program_id, "dirLight.diffuse", &light->diffuse); - uniform_vec3f(shader.program_id, "dirLight.specular", &light->specular); -} +void render_frame_begin(renderer* ren) {} +void render_frame_end(renderer* ren) {} +void render_frame_draw(renderer* ren) {} -void point_light_upload_uniforms(shader shader, point_light* light, char index) { - char position_str[] = "pointLights[x].position"; - position_str[12] = (char)index; - char ambient_str[] = "pointLights[x].ambient"; - ambient_str[12] = (char)index; - char diffuse_str[] = "pointLights[x].diffuse"; - diffuse_str[12] = (char)index; - char specular_str[] = "pointLights[x].specular"; - specular_str[12] = (char)index; - char constant_str[] = "pointLights[x].constant"; - constant_str[12] = (char)index; - char linear_str[] = "pointLights[x].linear"; - linear_str[12] = (char)index; - char quadratic_str[] = "pointLights[x].quadratic"; - quadratic_str[12] = (char)index; - uniform_vec3f(shader.program_id, position_str, &light->position); - uniform_vec3f(shader.program_id, ambient_str, &light->ambient); - uniform_vec3f(shader.program_id, diffuse_str, &light->diffuse); - uniform_vec3f(shader.program_id, specular_str, &light->specular); - uniform_f32(shader.program_id, constant_str, light->constant); - uniform_f32(shader.program_id, linear_str, light->linear); - uniform_f32(shader.program_id, quadratic_str, light->quadratic); -} \ No newline at end of file +void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model, texture* tex) {} \ No newline at end of file diff --git a/src/renderer/render.h b/src/renderer/render.h index 31cf3b0..0aeeac2 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -10,37 +10,34 @@ */ #pragma once -#include "camera.h" -#include "loaders.h" #include "render_types.h" -#include "transform_hierarchy.h" +#include "ral_types.h" -// --- Lifecycle -/** @brief initialise the render system frontend */ bool renderer_init(renderer* ren); -/** @brief shutdown the render system frontend */ void renderer_shutdown(renderer* ren); -void renderer_on_resize(renderer* ren); - -struct render_packet; - -// --- Frame - void render_frame_begin(renderer* ren); void render_frame_end(renderer* ren); void render_frame_draw(renderer* ren); -// --- models meshes -void model_upload_meshes(renderer* ren, model* model); -void draw_model(renderer* ren, camera* camera, model* model, mat4* tf, scene* scene); -void draw_mesh(renderer* ren, mesh* mesh, mat4* tf, material* mat, mat4* view, mat4* proj); -void draw_scene(arena* frame, model_darray* models, renderer* ren, camera* camera, - transform_hierarchy* tfh, scene* scene); +// ! TEMP +typedef struct camera camera; +void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model, texture* tex); + +// frontend -- these can be called from say a loop in an example, or via FFI +texture_handle texture_create(const char* debug_name, texture_desc description, const u8* data); + +// Frontend Resources +// TODO: void texture_data_upload(texture_handle texture); +void texture_data_upload(texture* tex); +texture texture_data_load(const char* path, bool invert_y); +buffer_handle buffer_create(const char* debug_name, u64 size); +bool buffer_destroy(buffer_handle buffer); +sampler_handle sampler_create(); -void draw_skinned_model(renderer* ren, camera* cam, model* model, transform tf, scene* scene); +void shader_hot_reload(const char* filepath); -void model_destroy(model* model); +// models and meshes are implemented **in terms of the above** +mesh mesh_create(geometry_data* geometry); -// --- -texture texture_data_load(const char* path, bool invert_y); // #frontend +model_handle model_load(const char* debug_name, const char* filepath); \ No newline at end of file diff --git a/src/renderer/render_backend.h b/src/renderer/render_backend.h deleted file mode 100644 index da30bcc..0000000 --- a/src/renderer/render_backend.h +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @brief Renderer backend - */ -#pragma once - -#include "camera.h" -#include "maths_types.h" -#include "render_types.h" - -/// --- Lifecycle - -/** @brief Initialise the graphics API backend */ -bool gfx_backend_init(renderer* ren); -void gfx_backend_shutdown(renderer* ren); - -void gfx_backend_draw_frame(renderer* ren, camera* camera, mat4 model, texture* tex); -void gfx_backend_update_global_state(mat4 projection, mat4 view, vec3 view_pos, vec4 ambient_colour, - i32 mode); - -void clear_screen(vec3 colour); - -void texture_data_upload(texture* tex); -void bind_texture(shader s, texture* tex, u32 slot); -void bind_mesh_vertex_buffer(void* backend, mesh* mesh); -void draw_primitives(cel_primitive_topology primitive, u32 start_index, u32 count); - -shader shader_create_separate(const char* vert_shader, const char* frag_shader); -void set_shader(shader s); - -// --- Uniforms - -/** @brief upload a vec3 of f32 to a uniform */ -void uniform_vec3f(u32 program_id, const char* uniform_name, vec3* value); -/** @brief upload a single f32 to a uniform */ -void uniform_f32(u32 program_id, const char* uniform_name, f32 value); -/** @brief upload a integer to a uniform */ -void uniform_i32(u32 program_id, const char* uniform_name, i32 value); -/** @brief upload a mat4 of f32 to a uniform */ -void uniform_mat4f(u32 program_id, const char* uniform_name, mat4* value); \ No newline at end of file diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index 3bce88f..bc9692f 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -1,60 +1,71 @@ -// /** -// * @file render_types.h -// * @author Omniscient -// * @brief Type definitions for the majority of data required by the renderer system -// * @date 2024-02-24 -// * -// */ -// #pragma once +/** + * @file render_types.h + * @author your name (you@domain.com) + * @brief + * @version 0.1 + * @date 2024-04-27 + * + * @copyright Copyright (c) 2024 + * + */ +#pragma once + +#include "ral_types.h" +#include "ral.h" +#if defined(CEL_PLATFORM_WINDOWS) +#include "backend_dx11.h" +#endif -#include "animation.h" -#include "darray.h" -#include "maths.h" -#include "maths_types.h" -#include "str.h" - -// struct GLFWwindow; - -// #define MAX_MATERIAL_NAME_LEN 256 -// #define MAX_TEXTURE_NAME_LEN 256 - -// #ifndef RESOURCE_HANDLE_DEFS -// // CORE_DEFINE_HANDLE(model_handle); -// #define ABSENT_MODEL_HANDLE 999999999 -// // CORE_DEFINE_HANDLE(texture_handle); -// #define RESOURCE_HANDLE_DEFS -// #endif - -// /* @brief Opaque wrapper around a shader program */ -// typedef struct shader { -// u32 program_id; -// } shader; - -// /** @brief configuration passed to the renderer at init time */ -// typedef struct renderer_config { -// char window_name[256]; -// u32 scr_width, scr_height; -// vec3 clear_colour; /** colour that the screen gets cleared to every frame */ -// } renderer_config; - -// typedef struct frame_stats { -// u64 last_time; -// } frame_stats; +struct GLFWwindow; + +/** @brief configuration passed to the renderer at init time */ +typedef struct renderer_config { + char window_name[256]; + u32 scr_width, scr_height; + vec3 clear_colour; /** colour that the screen gets cleared to every frame */ +} renderer_config; typedef struct renderer { - struct GLFWwindow *window; /** Currently all platforms use GLFW*/ - void *backend_state; /** Graphics API-specific state */ + struct GLFWwindow* window; + void* backend_context; renderer_config config; - // shaders - shader blinn_phong; - shader skinned; + gpu_device* device; + gpu_pipeline* static_opaque_pipeline; } renderer; -// // --- Lighting & Materials +typedef struct geometry_data { + vertex_format format; + vertex_darray* vertices; // TODO: make it not a pointe + bool has_indices; + u32_darray indices; + vec3 colour; /** Optional: set vertex colours */ +} geometry_data; + +void geo_set_vertex_colours(geometry_data* geo, vec4 colour); + +typedef struct mesh { + buffer_handle vertex_buffer; + buffer_handle index_buffer; + u32 index_count; + bool has_indices; + geometry_data* vertices; // NULL means it has been freed +} mesh; + +/* Hot reloading: +C side - reload_model(): + - load model from disk using existing loader + - remove from transform graph so it isnt tried to be drawn +*/ + +typedef struct model { + str8 name; + mesh* meshes; + u32 mesh_count; +} model; typedef struct texture { u32 texture_id; - char name[MAX_TEXTURE_NAME_LEN]; + char name[256]; void *image_data; void *backend_data; u32 width; @@ -63,148 +74,42 @@ typedef struct texture { u32 channel_type; } texture; -// typedef struct blinn_phong_material { -// char name[MAX_MATERIAL_NAME_LEN]; -// texture diffuse_texture; -// char diffuse_tex_path[256]; -// texture specular_texture; -// char specular_tex_path[256]; -// vec3 ambient_colour; -// vec3 diffuse; -// vec3 specular; -// f32 spec_exponent; -// bool is_loaded; -// bool is_uploaded; -// } blinn_phong_material; -// typedef blinn_phong_material material; // when we start using PBR, this will no longer be the -// case - -// // the default blinn-phong material. MUST be initialised with the function below -// extern material DEFAULT_MATERIAL; -// void default_material_init(); +typedef struct blinn_phong_material { + char name[256]; + texture diffuse_texture; + char diffuse_tex_path[256]; + texture specular_texture; + char specular_tex_path[256]; + vec3 ambient_colour; + vec3 diffuse; + vec3 specular; + f32 spec_exponent; + bool is_loaded; + bool is_uploaded; +} blinn_phong_material; +typedef blinn_phong_material material; -#ifndef TYPED_MATERIAL_ARRAY -KITC_DECL_TYPED_ARRAY(material) // creates "material_darray" -#define TYPED_MATERIAL_ARRAY -#endif +// the default blinn-phong material. MUST be initialised with the function below +extern material DEFAULT_MATERIAL; +void default_material_init(); -#ifndef TYPED_ANIMATION_CLIP_ARRAY -KITC_DECL_TYPED_ARRAY(animation_clip) // creates "material_darray" -#define TYPED_ANIMATION_CLIP_ARRAY +#ifndef TYPED_MESH_ARRAY +KITC_DECL_TYPED_ARRAY(mesh) +#define TYPED_MESH_ARRAY #endif -// // lights -// typedef struct point_light { -// vec3 position; -// f32 constant, linear, quadratic; -// vec3 ambient; -// vec3 diffuse; -// vec3 specular; -// } point_light; - -// typedef struct directional_light { -// vec3 direction; -// vec3 ambient; -// vec3 diffuse; -// vec3 specular; -// } directional_light; - -// void point_light_upload_uniforms(shader shader, point_light *light, char index); -// void dir_light_upload_uniforms(shader shader, directional_light *light); - -// // --- Models & Meshes - -// /** @brief Vertex format for a static mesh */ -// typedef struct vertex { -// vec3 position; -// vec3 normal; -// vec2 uv; -// } vertex; - -typedef struct vertex_bone_data { - vec4u joints; /** @brief 4 indices of joints that influence vectors position */ - vec4 weights; /** @brief weight (0,1) of each joint */ -} vertex_bone_data; - -#include "animation.h" -#ifndef TYPED_VERTEX_ARRAY -KITC_DECL_TYPED_ARRAY(vertex) // creates "vertex_darray" -KITC_DECL_TYPED_ARRAY(vertex_bone_data) // creates "skinned_vertex_darray" -KITC_DECL_TYPED_ARRAY(joint) -#define TYPED_VERTEX_ARRAY +#ifndef TYPED_MODEL_ARRAY +KITC_DECL_TYPED_ARRAY(model) +#define TYPED_MODEL_ARRAY #endif -typedef struct mesh { - vertex_darray *vertices; - vertex_bone_data_darray *vertex_bone_data; // only used if model needs it - joint_darray *bones; - bool is_skinned; - u32 vertex_size; /** size in bytes of each vertex including necessary padding */ - bool has_indices; - u32 *indices; - u32 indices_len; - size_t material_index; - u32 vbo, vao; /** OpenGL data. TODO: dont leak OpenGL details */ -} mesh; - -// #ifndef TYPED_MESH_ARRAY -// KITC_DECL_TYPED_ARRAY(mesh) // creates "mesh_darray" -// #define TYPED_MESH_ARRAY -// #endif - -typedef struct model { - str8 name; - mesh_darray *meshes; - aabb_3d bbox; - material_darray *materials; - animation_clip_darray *animations; - arena animation_data_arena; - bool is_loaded; - bool is_uploaded; -} model; +#ifndef TYPED_MATERIAL_ARRAY +KITC_DECL_TYPED_ARRAY(material) +#define TYPED_MATERIAL_ARRAY +#endif -// #ifndef TYPED_MODEL_ARRAY -// KITC_DECL_TYPED_ARRAY(model) // creates "model_darray" -// #define TYPED_MODEL_ARRAY -// #endif - -// // --- Scene - -// // NOTE: This struct won't stay like this for a long time. It's somewhat temporary -// // in order to get a basic scene working without putting burden on the caller of -// // draw_model() -// typedef struct scene { -// directional_light dir_light; -// point_light point_lights[4]; -// size_t n_point_lights; -// } scene; - -// // --- Graphics API related - -// // typedef enum cel_primitive_topology { -// // CEL_PRIMITIVE_TOPOLOGY_POINT, -// // CEL_PRIMITIVE_TOPOLOGY_LINE, -// // CEL_PRIMITIVE_TOPOLOGY_LINE_STRIP, -// // CEL_PRIMITIVE_TOPOLOGY_TRIANGLE, -// // CEL_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, -// // CEL_PRIMITIVE_TOPOLOGY_COUNT -// // } cel_primitive_topology; - -// // typedef enum gpu_texture_type { -// // TEXTURE_TYPE_2D, -// // TEXTURE_TYPE_3D, -// // TEXTURE_TYPE_2D_ARRAY, -// // TEXTURE_TYPE_CUBE_MAP, -// // TEXTURE_TYPE_COUNT -// // } gpu_texture_type; - -// // typedef enum gpu_texture_format { -// // TEXTURE_FORMAT_8_8_8_8_RGBA_UNORM, -// // TEXTURE_FORMAT_DEPTH_DEFAULT, -// // TEXTURE_FORMAT_COUNT -// // } gpu_texture_format; - -// // typedef enum pipeline_kind { -// // GRAPHICS, -// // COMPUTE, -// // } pipeline_kind; \ No newline at end of file +#ifndef TYPED_ANIMATION_CLIP_ARRAY +#include "animation.h" +KITC_DECL_TYPED_ARRAY(animation_clip) +#define TYPED_ANIMATION_CLIP_ARRAY +#endif \ No newline at end of file diff --git a/src/resources/gltf.c b/src/resources/gltf.c index 81992d1..022bf95 100644 --- a/src/resources/gltf.c +++ b/src/resources/gltf.c @@ -12,7 +12,7 @@ #include "mem.h" #include "path.h" #include "render.h" -#include "render_backend.h" +// #include "render_backend.h" #include "render_types.h" #include "str.h" @@ -26,7 +26,6 @@ typedef struct face face; KITC_DECL_TYPED_ARRAY(vec3) KITC_DECL_TYPED_ARRAY(vec2) -KITC_DECL_TYPED_ARRAY(u32) KITC_DECL_TYPED_ARRAY(vec4u) KITC_DECL_TYPED_ARRAY(vec4) KITC_DECL_TYPED_ARRAY(face) @@ -49,7 +48,7 @@ model_handle model_load_gltf(struct core *core, const char *path, bool invert_te model model = { 0 }; model.name = str8_cstr_view(path); model.meshes = mesh_darray_new(1); - model.materials = material_darray_new(1); + // model.materials = material_darray_new(1); bool success = model_load_gltf_str(file_string, path, relative_path.path, &model, invert_texture_y); @@ -79,403 +78,414 @@ void assert_path_type_matches_component_type(cgltf_animation_path_type target_pa bool model_load_gltf_str(const char *file_string, const char *filepath, str8 relative_path, model *out_model, bool invert_textures_y) { - TRACE("Load GLTF from string"); - - // Setup temps - vec3_darray *tmp_positions = vec3_darray_new(1000); - vec3_darray *tmp_normals = vec3_darray_new(1000); - vec2_darray *tmp_uvs = vec2_darray_new(1000); - vec4u_darray *tmp_joint_indices = vec4u_darray_new(1000); - vec4_darray *tmp_weights = vec4_darray_new(1000); - joint_darray *tmp_joints = joint_darray_new(256); - vertex_bone_data_darray *tmp_vertex_bone_data = vertex_bone_data_darray_new(1000); - - cgltf_options options = { 0 }; - cgltf_data *data = NULL; - cgltf_result result = cgltf_parse_file(&options, filepath, &data); - if (result != cgltf_result_success) { - WARN("gltf load failed"); - // TODO: cleanup arrays(allocate all from arena ?) - return false; - } - - cgltf_load_buffers(&options, data, filepath); - DEBUG("loaded buffers"); - - // --- Skin - size_t num_skins = data->skins_count; - bool is_skinned = false; - if (num_skins == 1) { - is_skinned = true; - } else if (num_skins > 1) { - WARN("GLTF files with more than 1 skin are not supported"); - return false; - } - - if (is_skinned) { - cgltf_skin *gltf_skin = data->skins; - DEBUG("loading skin %s", gltf_skin->name); - size_t num_joints = gltf_skin->joints_count; - DEBUG("# Joints %d", num_joints); - - cgltf_accessor *gltf_inverse_bind_matrices = gltf_skin->inverse_bind_matrices; - - // for each one we'll spit out a joint - for (size_t i = 0; i < num_joints; i++) { - cgltf_node *joint_node = gltf_skin->joints[i]; - - joint joint_i = { .name = "testjoint" }; - if (joint_node->children_count > 0 && !joint_node->has_translation && - !joint_node->has_rotation) { - WARN("joint Node with index %d is the root node", i); - joint_i.transform_components = TRANSFORM_DEFAULT; - } else { - TRACE("Storing joint transform"); - joint_i.transform_components = TRANSFORM_DEFAULT; - if (joint_node->has_translation) { - memcpy(&joint_i.transform_components.position, &joint_node->translation, 3 * sizeof(f32)); - } - if (joint_node->has_rotation) { - memcpy(&joint_i.transform_components.rotation, &joint_node->rotation, 4 * sizeof(f32)); - } - // TODO: support scaling as vec instead of float - } - joint_i.local_transform = transform_to_mat(&joint_i.transform_components); - cgltf_accessor_read_float(gltf_inverse_bind_matrices, i, &joint_i.inverse_bind_matrix.data[0], - 16); - joint_darray_push(tmp_joints, joint_i); - } - } - - // --- Materials - TRACE("Num materials %d", data->materials_count); - size_t num_materials = data->materials_count; - for (size_t m = 0; m < num_materials; m++) { - cgltf_material gltf_material = data->materials[m]; - material our_material = DEFAULT_MATERIAL; - - strcpy(our_material.name, gltf_material.name); - - cgltf_pbr_metallic_roughness pbr = gltf_material.pbr_metallic_roughness; - if (gltf_material.has_pbr_metallic_roughness) { - // we will use base color texture like blinn phong - cgltf_texture_view diff_tex_view = pbr.base_color_texture; - - char diffuse_map_path[1024]; - snprintf(diffuse_map_path, sizeof(diffuse_map_path), "%s/%s", relative_path.buf, - diff_tex_view.texture->image->uri); - - strcpy(our_material.diffuse_tex_path, diffuse_map_path); - texture diffuse_texture = texture_data_load(our_material.diffuse_tex_path, false); - texture_data_upload(&diffuse_texture); - our_material.diffuse_texture = diffuse_texture; - - cgltf_texture_view specular_tex_view = pbr.metallic_roughness_texture; - - char specular_map_path[1024]; - snprintf(specular_map_path, sizeof(specular_map_path), "%s/%s", relative_path.buf, - specular_tex_view.texture->image->uri); - - strcpy(our_material.specular_tex_path, specular_map_path); - texture specular_texture = texture_data_load(our_material.specular_tex_path, false); - texture_data_upload(&specular_texture); - our_material.specular_texture = specular_texture; - } - - material_darray_push(out_model->materials, our_material); - } - - // --- Meshes - TRACE("Num meshes %d", data->meshes_count); - size_t num_meshes = data->meshes_count; - for (size_t m = 0; m < num_meshes; m++) { - cgltf_primitive primitive = data->meshes[m].primitives[0]; - DEBUG("Found %d attributes", primitive.attributes_count); - // DEBUG("Number of this primitive %d", primitive.) - - for (int a = 0; a < data->meshes[m].primitives[0].attributes_count; a++) { - cgltf_attribute attribute = data->meshes[m].primitives[0].attributes[a]; - if (attribute.type == cgltf_attribute_type_position) { - TRACE("Load positions from accessor"); - - cgltf_accessor *accessor = attribute.data; - assert(accessor->component_type == cgltf_component_type_r_32f); - // CASSERT_MSG(accessor->type == cgltf_type_vec3, "Vertex positions should be a vec3"); - - TRACE("Loading %d vec3 components", accessor->count); - - for (cgltf_size v = 0; v < accessor->count; ++v) { - vec3 pos; - cgltf_accessor_read_float(accessor, v, &pos.x, 3); - vec3_darray_push(tmp_positions, pos); - } - - } else if (attribute.type == cgltf_attribute_type_normal) { - TRACE("Load normals from accessor"); - - cgltf_accessor *accessor = attribute.data; - assert(accessor->component_type == cgltf_component_type_r_32f); - // CASSERT_MSG(accessor->type == cgltf_type_vec3, "Normal vectors should be a vec3"); - - for (cgltf_size v = 0; v < accessor->count; ++v) { - vec3 pos; - cgltf_accessor_read_float(accessor, v, &pos.x, 3); - vec3_darray_push(tmp_normals, pos); - } - - } else if (attribute.type == cgltf_attribute_type_texcoord) { - TRACE("Load texture coordinates from accessor"); - cgltf_accessor *accessor = attribute.data; - assert(accessor->component_type == cgltf_component_type_r_32f); - // CASSERT_MSG(accessor->type == cgltf_type_vec2, "Texture coordinates should be a vec2"); - - for (cgltf_size v = 0; v < accessor->count; ++v) { - vec2 tex; - bool success = cgltf_accessor_read_float(accessor, v, &tex.x, 2); - if (!success) { - ERROR("Error loading tex coord"); - } - vec2_darray_push(tmp_uvs, tex); - } - } else if (attribute.type == cgltf_attribute_type_joints) { - TRACE("Load joint indices from accessor"); - cgltf_accessor *accessor = attribute.data; - assert(accessor->component_type == cgltf_component_type_r_16u); - assert(accessor->type == cgltf_type_vec4); - vec4u joint_indices; - vec4 joints_as_floats; - for (cgltf_size v = 0; v < accessor->count; ++v) { - cgltf_accessor_read_float(accessor, v, &joints_as_floats.x, 4); - joint_indices.x = (u32)joints_as_floats.x; - joint_indices.y = (u32)joints_as_floats.y; - joint_indices.z = (u32)joints_as_floats.z; - joint_indices.w = (u32)joints_as_floats.w; - printf("Joints affecting vertex %d : %d %d %d %d\n", v, joint_indices.x, joint_indices.y, - joint_indices.z, joint_indices.w); - vec4u_darray_push(tmp_joint_indices, joint_indices); - } - - } else if (attribute.type == cgltf_attribute_type_weights) { - TRACE("Load joint weights from accessor"); - cgltf_accessor *accessor = attribute.data; - assert(accessor->component_type == cgltf_component_type_r_32f); - assert(accessor->type == cgltf_type_vec4); - - for (cgltf_size v = 0; v < accessor->count; ++v) { - vec4 weights; - cgltf_accessor_read_float(accessor, v, &weights.x, 4); - printf("Weights affecting vertex %d : %f %f %f %f\n", v, weights.x, weights.y, weights.z, - weights.w); - vec4_darray_push(tmp_weights, weights); - } - } else { - WARN("Unhandled cgltf_attribute_type: %s. skipping..", attribute.name); - } - } - - mesh mesh = { 0 }; - mesh.vertices = vertex_darray_new(10); - mesh.vertex_bone_data = vertex_bone_data_darray_new(1); - - if (primitive.material != NULL) { - for (int i = 0; i < material_darray_len(out_model->materials); i++) { - printf("%s vs %s \n", primitive.material->name, out_model->materials->data[i].name); - if (strcmp(primitive.material->name, out_model->materials->data[i].name) == 0) { - TRACE("Found material"); - mesh.material_index = i; - break; - } - } - } - - if (is_skinned) { - mesh.is_skinned = true; - // mesh.vertex_bone_data = vertex_bone_data_darray_new(tmp_joint_indices->len); - mesh.bones = joint_darray_new(tmp_joints->len); - for (int i = 0; i < tmp_joint_indices->len; i++) { - vertex_bone_data data; - data.joints = tmp_joint_indices->data[i]; - data.weights = tmp_weights->data[i]; - vertex_bone_data_darray_push(tmp_vertex_bone_data, - data); // Push the temp data that aligns with raw vertices - } - for (int i = 0; i < tmp_joints->len; i++) { - joint data = tmp_joints->data[i]; - joint_darray_push(mesh.bones, data); - } - } - - cgltf_accessor *indices = primitive.indices; - if (primitive.indices > 0) { - WARN("indices!"); - mesh.has_indices = true; - - mesh.indices = malloc(indices->count * sizeof(u32)); - mesh.indices_len = indices->count; - - // store indices - for (cgltf_size i = 0; i < indices->count; ++i) { - cgltf_uint ei; - cgltf_accessor_read_uint(indices, i, &ei, 1); - mesh.indices[i] = ei; - } - - // fetch and store vertices for each index - for (cgltf_size i = 0; i < indices->count; ++i) { - vertex vert; - cgltf_uint index = mesh.indices[i]; - vert.position = tmp_positions->data[index]; - vert.normal = tmp_normals->data[index]; - vert.uv = tmp_uvs->data[index]; - vertex_darray_push(mesh.vertices, vert); - - if (is_skinned) { - vertex_bone_data vbd = tmp_vertex_bone_data->data[index]; // create a copy - vertex_bone_data_darray_push(mesh.vertex_bone_data, vbd); - } - // for each vertex do the bone data - } - } else { - mesh.has_indices = false; - return false; // TODO - } - - mesh_darray_push(out_model->meshes, mesh); - - // clear data for each mesh - vec3_darray_clear(tmp_positions); - vec3_darray_clear(tmp_normals); - vec2_darray_free(tmp_uvs); - vec4u_darray_clear(tmp_joint_indices); - vec4_darray_clear(tmp_weights); - joint_darray_clear(tmp_joints); - } - - for (int i = 0; i < out_model->meshes->len; i++) { - u32 mat_idx = out_model->meshes->data[i].material_index; - printf("Mesh %d Mat index %d Mat name %s\n", i, mat_idx, - out_model->materials->data[mat_idx].name); - } - - // Animations - TRACE("Num animations %d", data->animations_count); - size_t num_animations = data->animations_count; - if (num_animations > 0) { -// Create an arena for all animation related data -#define ANIMATION_STORAGE_ARENA_SIZE (1024 * 1024 * 1024) - char *animation_backing_storage = malloc(ANIMATION_STORAGE_ARENA_SIZE); - // We'll store data on this arena so we can easily free it all at once later - out_model->animation_data_arena = - arena_create(animation_backing_storage, ANIMATION_STORAGE_ARENA_SIZE); - arena *arena = &out_model->animation_data_arena; - - if (!out_model->animations) { - out_model->animations = animation_clip_darray_new(num_animations); - } - - for (int anim_idx = 0; anim_idx < data->animations_count; anim_idx++) { - cgltf_animation animation = data->animations[anim_idx]; - animation_clip clip = { 0 }; - - for (size_t c = 0; c < animation.channels_count; c++) { - cgltf_animation_channel channel = animation.channels[c]; - - animation_sampler *sampler = arena_alloc(arena, sizeof(animation_sampler)); - - animation_sampler **target_property; - keyframe_kind data_type; - - switch (channel.target_path) { - case cgltf_animation_path_type_rotation: - target_property = &clip.rotation; - data_type = KEYFRAME_ROTATION; - break; - case cgltf_animation_path_type_translation: - target_property = &clip.translation; - data_type = KEYFRAME_TRANSLATION; - break; - case cgltf_animation_path_type_scale: - target_property = &clip.scale; - data_type = KEYFRAME_SCALE; - break; - case cgltf_animation_path_type_weights: - target_property = &clip.weights; - data_type = KEYFRAME_WEIGHTS; - WARN("Morph target weights arent supported yet"); - return false; - default: - WARN("unsupported animation type"); - return false; - } - *target_property = sampler; - - sampler->current_index = 0; - printf("1 %d index\n", sampler->current_index); - sampler->animation.interpolation = INTERPOLATION_LINEAR; - - // keyframe times - size_t n_frames = channel.sampler->input->count; - assert(channel.sampler->input->component_type == cgltf_component_type_r_32f); - // FIXME: CASSERT_MSG function "Expected animation sampler input component to be type f32 - // (keyframe times)"); - f32 *times = arena_alloc(arena, n_frames * sizeof(f32)); - sampler->animation.n_timestamps = n_frames; - sampler->animation.timestamps = times; - cgltf_accessor_unpack_floats(channel.sampler->input, times, n_frames); - - assert_path_type_matches_component_type(channel.target_path, channel.sampler->output); - - // keyframe values - size_t n_values = channel.sampler->output->count; - assert(n_frames == n_values); - - keyframes keyframes = { 0 }; - keyframes.kind = KEYFRAME_ROTATION; - keyframes.count = n_values; - keyframes.values = arena_alloc(arena, n_values * sizeof(keyframe)); - for (cgltf_size v = 0; v < channel.sampler->output->count; ++v) { - switch (data_type) { - case KEYFRAME_ROTATION: { - quat rot; - cgltf_accessor_read_float(channel.sampler->output, v, &rot.x, 4); - // printf("Quat %f %f %f %f\n", rot.x, rot.y, rot.z, rot.w); - keyframes.values[v].rotation = rot; - break; - } - case KEYFRAME_TRANSLATION: { - vec3 trans; - cgltf_accessor_read_float(channel.sampler->output, v, &trans.x, 3); - keyframes.values[v].translation = trans; - break; - } - case KEYFRAME_SCALE: { - vec3 scale; - cgltf_accessor_read_float(channel.sampler->output, v, &scale.x, 3); - keyframes.values[v].scale = scale; - break; - } - case KEYFRAME_WEIGHTS: { - // TODO - break; - } - } - } - sampler->animation.values = keyframes; - - sampler->min = channel.sampler->input->min[0]; - sampler->max = channel.sampler->input->max[0]; - - // clip.rotation = sampler; - // printf("%d timestamps\n", sampler->animation.n_timestamps); - // printf("%d index\n", sampler->current_index); - } - - WARN("stuff %ld", clip.rotation->animation.n_timestamps); - animation_clip_darray_push(out_model->animations, clip); - } - } - - return true; + return false; + // TRACE("Load GLTF from string"); + + // // Setup temps + // vec3_darray *tmp_positions = vec3_darray_new(1000); + // vec3_darray *tmp_normals = vec3_darray_new(1000); + // vec2_darray *tmp_uvs = vec2_darray_new(1000); + // vec4u_darray *tmp_joint_indices = vec4u_darray_new(1000); + // vec4_darray *tmp_weights = vec4_darray_new(1000); + // // FIXME + // // joint_darray *tmp_joints = joint_darray_new(256); + // // vertex_bone_data_darray *tmp_vertex_bone_data = vertex_bone_data_darray_new(1000); + + // cgltf_options options = { 0 }; + // cgltf_data *data = NULL; + // cgltf_result result = cgltf_parse_file(&options, filepath, &data); + // if (result != cgltf_result_success) { + // WARN("gltf load failed"); + // // TODO: cleanup arrays(allocate all from arena ?) + // return false; + // } + + // cgltf_load_buffers(&options, data, filepath); + // DEBUG("loaded buffers"); + + // // --- Skin + // size_t num_skins = data->skins_count; + // bool is_skinned = false; + // if (num_skins == 1) { + // is_skinned = true; + // } else if (num_skins > 1) { + // WARN("GLTF files with more than 1 skin are not supported"); + // return false; + // } + + // if (is_skinned) { + // cgltf_skin *gltf_skin = data->skins; + // DEBUG("loading skin %s", gltf_skin->name); + // size_t num_joints = gltf_skin->joints_count; + // DEBUG("# Joints %d", num_joints); + + // cgltf_accessor *gltf_inverse_bind_matrices = gltf_skin->inverse_bind_matrices; + + // // for each one we'll spit out a joint + // for (size_t i = 0; i < num_joints; i++) { + // cgltf_node *joint_node = gltf_skin->joints[i]; + + // joint joint_i = { .name = "testjoint" }; + // if (joint_node->children_count > 0 && !joint_node->has_translation && + // !joint_node->has_rotation) { + // WARN("joint Node with index %d is the root node", i); + // joint_i.transform_components = TRANSFORM_DEFAULT; + // } else { + // TRACE("Storing joint transform"); + // joint_i.transform_components = TRANSFORM_DEFAULT; + // if (joint_node->has_translation) { + // memcpy(&joint_i.transform_components.position, &joint_node->translation, 3 * + // sizeof(f32)); + // } + // if (joint_node->has_rotation) { + // memcpy(&joint_i.transform_components.rotation, &joint_node->rotation, 4 * + // sizeof(f32)); + // } + // // TODO: support scaling as vec instead of float + // } + // joint_i.local_transform = transform_to_mat(&joint_i.transform_components); + // cgltf_accessor_read_float(gltf_inverse_bind_matrices, i, + // &joint_i.inverse_bind_matrix.data[0], + // 16); + // // joint_darray_push(tmp_joints, joint_i); + // } + // } + + // // --- Materials + // TRACE("Num materials %d", data->materials_count); + // size_t num_materials = data->materials_count; + // for (size_t m = 0; m < num_materials; m++) { + // cgltf_material gltf_material = data->materials[m]; + // material our_material = DEFAULT_MATERIAL; + + // strcpy(our_material.name, gltf_material.name); + + // cgltf_pbr_metallic_roughness pbr = gltf_material.pbr_metallic_roughness; + // if (gltf_material.has_pbr_metallic_roughness) { + // // we will use base color texture like blinn phong + // cgltf_texture_view diff_tex_view = pbr.base_color_texture; + + // char diffuse_map_path[1024]; + // snprintf(diffuse_map_path, sizeof(diffuse_map_path), "%s/%s", relative_path.buf, + // diff_tex_view.texture->image->uri); + + // strcpy(our_material.diffuse_tex_path, diffuse_map_path); + // texture diffuse_texture = texture_data_load(our_material.diffuse_tex_path, false); + // texture_data_upload(&diffuse_texture); + // our_material.diffuse_texture = diffuse_texture; + + // cgltf_texture_view specular_tex_view = pbr.metallic_roughness_texture; + + // char specular_map_path[1024]; + // snprintf(specular_map_path, sizeof(specular_map_path), "%s/%s", relative_path.buf, + // specular_tex_view.texture->image->uri); + + // strcpy(our_material.specular_tex_path, specular_map_path); + // texture specular_texture = texture_data_load(our_material.specular_tex_path, false); + // texture_data_upload(&specular_texture); + // our_material.specular_texture = specular_texture; + // } + + // // material_darray_push(out_model->materials, our_material); + // } + + // // --- Meshes + // TRACE("Num meshes %d", data->meshes_count); + // size_t num_meshes = data->meshes_count; + // for (size_t m = 0; m < num_meshes; m++) { + // cgltf_primitive primitive = data->meshes[m].primitives[0]; + // DEBUG("Found %d attributes", primitive.attributes_count); + // // DEBUG("Number of this primitive %d", primitive.) + + // for (int a = 0; a < data->meshes[m].primitives[0].attributes_count; a++) { + // cgltf_attribute attribute = data->meshes[m].primitives[0].attributes[a]; + // if (attribute.type == cgltf_attribute_type_position) { + // TRACE("Load positions from accessor"); + + // cgltf_accessor *accessor = attribute.data; + // assert(accessor->component_type == cgltf_component_type_r_32f); + // // CASSERT_MSG(accessor->type == cgltf_type_vec3, "Vertex positions should be a vec3"); + + // TRACE("Loading %d vec3 components", accessor->count); + + // for (cgltf_size v = 0; v < accessor->count; ++v) { + // vec3 pos; + // cgltf_accessor_read_float(accessor, v, &pos.x, 3); + // vec3_darray_push(tmp_positions, pos); + // } + + // } else if (attribute.type == cgltf_attribute_type_normal) { + // TRACE("Load normals from accessor"); + + // cgltf_accessor *accessor = attribute.data; + // assert(accessor->component_type == cgltf_component_type_r_32f); + // // CASSERT_MSG(accessor->type == cgltf_type_vec3, "Normal vectors should be a vec3"); + + // for (cgltf_size v = 0; v < accessor->count; ++v) { + // vec3 pos; + // cgltf_accessor_read_float(accessor, v, &pos.x, 3); + // vec3_darray_push(tmp_normals, pos); + // } + + // } else if (attribute.type == cgltf_attribute_type_texcoord) { + // TRACE("Load texture coordinates from accessor"); + // cgltf_accessor *accessor = attribute.data; + // assert(accessor->component_type == cgltf_component_type_r_32f); + // // CASSERT_MSG(accessor->type == cgltf_type_vec2, "Texture coordinates should be a + // vec2"); + + // for (cgltf_size v = 0; v < accessor->count; ++v) { + // vec2 tex; + // bool success = cgltf_accessor_read_float(accessor, v, &tex.x, 2); + // if (!success) { + // ERROR("Error loading tex coord"); + // } + // vec2_darray_push(tmp_uvs, tex); + // } + // } else if (attribute.type == cgltf_attribute_type_joints) { + // TRACE("Load joint indices from accessor"); + // cgltf_accessor *accessor = attribute.data; + // assert(accessor->component_type == cgltf_component_type_r_16u); + // assert(accessor->type == cgltf_type_vec4); + // vec4u joint_indices; + // vec4 joints_as_floats; + // for (cgltf_size v = 0; v < accessor->count; ++v) { + // cgltf_accessor_read_float(accessor, v, &joints_as_floats.x, 4); + // joint_indices.x = (u32)joints_as_floats.x; + // joint_indices.y = (u32)joints_as_floats.y; + // joint_indices.z = (u32)joints_as_floats.z; + // joint_indices.w = (u32)joints_as_floats.w; + // printf("Joints affecting vertex %d : %d %d %d %d\n", v, joint_indices.x, + // joint_indices.y, + // joint_indices.z, joint_indices.w); + // vec4u_darray_push(tmp_joint_indices, joint_indices); + // } + + // } else if (attribute.type == cgltf_attribute_type_weights) { + // TRACE("Load joint weights from accessor"); + // cgltf_accessor *accessor = attribute.data; + // assert(accessor->component_type == cgltf_component_type_r_32f); + // assert(accessor->type == cgltf_type_vec4); + + // for (cgltf_size v = 0; v < accessor->count; ++v) { + // vec4 weights; + // cgltf_accessor_read_float(accessor, v, &weights.x, 4); + // printf("Weights affecting vertex %d : %f %f %f %f\n", v, weights.x, weights.y, + // weights.z, + // weights.w); + // vec4_darray_push(tmp_weights, weights); + // } + // } else { + // WARN("Unhandled cgltf_attribute_type: %s. skipping..", attribute.name); + // } + // } + + // mesh mesh = { 0 }; + // mesh.vertices = vertex_darray_new(10); + // // mesh.vertex_bone_data = vertex_bone_data_darray_new(1); + + // if (primitive.material != NULL) { + // // for (int i = 0; i < material_darray_len(out_model->materials); i++) { + // // printf("%s vs %s \n", primitive.material->name, out_model->materials->data[i].name); + // // if (strcmp(primitive.material->name, out_model->materials->data[i].name) == 0) { + // // TRACE("Found material"); + // // mesh.material_index = i; + // // break; + // // } + // // } + // } + + // // FIXME + // // if (is_skinned) { + // // mesh.is_skinned = true; + // // // mesh.vertex_bone_data = vertex_bone_data_darray_new(tmp_joint_indices->len); + // // mesh.bones = joint_darray_new(tmp_joints->len); + // // for (int i = 0; i < tmp_joint_indices->len; i++) { + // // vertex_bone_data data; + // // data.joints = tmp_joint_indices->data[i]; + // // data.weights = tmp_weights->data[i]; + // // vertex_bone_data_darray_push(tmp_vertex_bone_data, + // // data); // Push the temp data that aligns with raw + // vertices + // // } + // // for (int i = 0; i < tmp_joints->len; i++) { + // // joint data = tmp_joints->data[i]; + // // joint_darray_push(mesh.bones, data); + // // } + // // } + + // cgltf_accessor *indices = primitive.indices; + // if (primitive.indices > 0) { + // WARN("indices!"); + // mesh.has_indices = true; + + // mesh.indices = malloc(indices->count * sizeof(u32)); + // mesh.indices_len = indices->count; + + // // store indices + // for (cgltf_size i = 0; i < indices->count; ++i) { + // cgltf_uint ei; + // cgltf_accessor_read_uint(indices, i, &ei, 1); + // mesh.indices[i] = ei; + // } + + // // fetch and store vertices for each index + // for (cgltf_size i = 0; i < indices->count; ++i) { + // vertex vert; + // cgltf_uint index = mesh.indices[i]; + // vert.position = tmp_positions->data[index]; + // vert.normal = tmp_normals->data[index]; + // vert.uv = tmp_uvs->data[index]; + // vertex_darray_push(mesh.vertices, vert); + + // if (is_skinned) { + // vertex_bone_data vbd = tmp_vertex_bone_data->data[index]; // create a copy + // vertex_bone_data_darray_push(mesh.vertex_bone_data, vbd); + // } + // // for each vertex do the bone data + // } + // } else { + // mesh.has_indices = false; + // return false; // TODO + // } + + // mesh_darray_push(out_model->meshes, mesh); + + // // clear data for each mesh + // vec3_darray_clear(tmp_positions); + // vec3_darray_clear(tmp_normals); + // vec2_darray_free(tmp_uvs); + // vec4u_darray_clear(tmp_joint_indices); + // vec4_darray_clear(tmp_weights); + // joint_darray_clear(tmp_joints); + // } + + // for (int i = 0; i < out_model->meshes->len; i++) { + // u32 mat_idx = out_model->meshes->data[i].material_index; + // printf("Mesh %d Mat index %d Mat name %s\n", i, mat_idx, + // out_model->materials->data[mat_idx].name); + // } + + // // Animations + // TRACE("Num animations %d", data->animations_count); + // size_t num_animations = data->animations_count; + // if (num_animations > 0) { + // // Create an arena for all animation related data + // #define ANIMATION_STORAGE_ARENA_SIZE (1024 * 1024 * 1024) + // char *animation_backing_storage = malloc(ANIMATION_STORAGE_ARENA_SIZE); + // // We'll store data on this arena so we can easily free it all at once later + // out_model->animation_data_arena = + // arena_create(animation_backing_storage, ANIMATION_STORAGE_ARENA_SIZE); + // arena *arena = &out_model->animation_data_arena; + + // if (!out_model->animations) { + // out_model->animations = animation_clip_darray_new(num_animations); + // } + + // for (int anim_idx = 0; anim_idx < data->animations_count; anim_idx++) { + // cgltf_animation animation = data->animations[anim_idx]; + // animation_clip clip = { 0 }; + + // for (size_t c = 0; c < animation.channels_count; c++) { + // cgltf_animation_channel channel = animation.channels[c]; + + // animation_sampler *sampler = arena_alloc(arena, sizeof(animation_sampler)); + + // animation_sampler **target_property; + // keyframe_kind data_type; + + // switch (channel.target_path) { + // case cgltf_animation_path_type_rotation: + // target_property = &clip.rotation; + // data_type = KEYFRAME_ROTATION; + // break; + // case cgltf_animation_path_type_translation: + // target_property = &clip.translation; + // data_type = KEYFRAME_TRANSLATION; + // break; + // case cgltf_animation_path_type_scale: + // target_property = &clip.scale; + // data_type = KEYFRAME_SCALE; + // break; + // case cgltf_animation_path_type_weights: + // target_property = &clip.weights; + // data_type = KEYFRAME_WEIGHTS; + // WARN("Morph target weights arent supported yet"); + // return false; + // default: + // WARN("unsupported animation type"); + // return false; + // } + // *target_property = sampler; + + // sampler->current_index = 0; + // printf("1 %d index\n", sampler->current_index); + // sampler->animation.interpolation = INTERPOLATION_LINEAR; + + // // keyframe times + // size_t n_frames = channel.sampler->input->count; + // assert(channel.sampler->input->component_type == cgltf_component_type_r_32f); + // // FIXME: CASSERT_MSG function "Expected animation sampler input component to be type + // f32 + // // (keyframe times)"); + // f32 *times = arena_alloc(arena, n_frames * sizeof(f32)); + // sampler->animation.n_timestamps = n_frames; + // sampler->animation.timestamps = times; + // cgltf_accessor_unpack_floats(channel.sampler->input, times, n_frames); + + // assert_path_type_matches_component_type(channel.target_path, channel.sampler->output); + + // // keyframe values + // size_t n_values = channel.sampler->output->count; + // assert(n_frames == n_values); + + // keyframes keyframes = { 0 }; + // keyframes.kind = KEYFRAME_ROTATION; + // keyframes.count = n_values; + // keyframes.values = arena_alloc(arena, n_values * sizeof(keyframe)); + // for (cgltf_size v = 0; v < channel.sampler->output->count; ++v) { + // switch (data_type) { + // case KEYFRAME_ROTATION: { + // quat rot; + // cgltf_accessor_read_float(channel.sampler->output, v, &rot.x, 4); + // // printf("Quat %f %f %f %f\n", rot.x, rot.y, rot.z, rot.w); + // keyframes.values[v].rotation = rot; + // break; + // } + // case KEYFRAME_TRANSLATION: { + // vec3 trans; + // cgltf_accessor_read_float(channel.sampler->output, v, &trans.x, 3); + // keyframes.values[v].translation = trans; + // break; + // } + // case KEYFRAME_SCALE: { + // vec3 scale; + // cgltf_accessor_read_float(channel.sampler->output, v, &scale.x, 3); + // keyframes.values[v].scale = scale; + // break; + // } + // case KEYFRAME_WEIGHTS: { + // // TODO + // break; + // } + // } + // } + // sampler->animation.values = keyframes; + + // sampler->min = channel.sampler->input->min[0]; + // sampler->max = channel.sampler->input->max[0]; + + // // clip.rotation = sampler; + // // printf("%d timestamps\n", sampler->animation.n_timestamps); + // // printf("%d index\n", sampler->current_index); + // } + + // WARN("stuff %ld", clip.rotation->animation.n_timestamps); + // animation_clip_darray_push(out_model->animations, clip); + // } + // } + + // return true; } /* diff --git a/src/resources/obj.c b/src/resources/obj.c index ea73ffa..888e16e 100644 --- a/src/resources/obj.c +++ b/src/resources/obj.c @@ -18,7 +18,7 @@ #include "mem.h" #include "path.h" #include "render.h" -#include "render_backend.h" +// #include "render_backend.h" #include "render_types.h" #include "str.h" @@ -55,7 +55,7 @@ model_handle model_load_obj(core *core, const char *path, bool invert_textures_y model model = { 0 }; model.name = str8_cstr_view(path); model.meshes = mesh_darray_new(1); - model.materials = material_darray_new(1); + // model.materials = material_darray_new(1); bool success = model_load_obj_str(file_string, relative_path.path, &model, invert_textures_y); @@ -76,151 +76,157 @@ bool model_load_obj_str(const char *file_string, str8 relative_path, model *out_ bool invert_textures_y) { TRACE("Load OBJ from string"); - // Setup temps - vec3_darray *tmp_positions = vec3_darray_new(1000); - vec3_darray *tmp_normals = vec3_darray_new(1000); - vec2_darray *tmp_uvs = vec2_darray_new(1000); - face_darray *tmp_faces = face_darray_new(1000); - // TODO: In the future I'd like these temporary arrays to be allocated from an arena provided - // by the function one level up, model_load_obj. That way we can just `return false;` anywhere in - // this code to indicate an error, and be sure that all that memory will be cleaned up without - // having to call vec3_darray_free in every single error case before returning. - - // Other state - bool object_set = false; - bool material_loaded = false; - char current_material_name[64]; - - char *pch; - char *rest = file_string; - pch = strtok_r((char *)file_string, "\n", &rest); - - int line_num = 0; - char last_char_type = 'a'; - - while (pch != NULL) { - line_num++; - char line_header[128]; - int offset = 0; - - // skip whitespace - char *p = pch; - - skip_space(pch); - - if (*p == '\0') { - /* the string is empty */ - } else { - // read the first word of the line - int res = sscanf(pch, "%s %n", line_header, &offset); - /* printf("header: %s, offset : %d res: %d\n",line_header, offset, res); */ - if (res != 1) { - break; - } - - if (strcmp(line_header, "o") == 0 || strcmp(line_header, "g") == 0) { - // if we're currently parsing one - if (!object_set) { - object_set = true; - } else { - create_submesh(out_model->meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, - out_model->materials, material_loaded, current_material_name); - object_set = false; - } - } else if (strcmp(line_header, "v") == 0) { - // special logic: if we went from faces back to vertices trigger a mesh output. - // PS: I hate OBJ - if (last_char_type == 'f') { - create_submesh(out_model->meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, - out_model->materials, material_loaded, current_material_name); - object_set = false; - } - - last_char_type = 'v'; - vec3 vertex; - sscanf(pch + offset, "%f %f %f", &vertex.x, &vertex.y, &vertex.z); - - vec3_darray_push(tmp_positions, vertex); - } else if (strcmp(line_header, "vt") == 0) { - last_char_type = 't'; - vec2 uv; - char copy[1024]; - memcpy(copy, pch + offset, strlen(pch + offset) + 1); - char *p = pch + offset; - while (isspace((unsigned char)*p)) ++p; - - // I can't remember what is going on here - memset(copy, 0, 1024); - memcpy(copy, pch + offset, strlen(pch + offset) + 1); - int res = sscanf(copy, "%f %f", &uv.x, &uv.y); - memset(copy, 0, 1024); - memcpy(copy, pch + offset, strlen(pch + offset) + 1); - if (res != 1) { - // da frick? some .obj files have 3 uvs instead of 2 - f32 dummy; - int res2 = sscanf(copy, "%f %f %f", &uv.x, &uv.y, &dummy); - } - - if (invert_textures_y) { - uv.y = -uv.y; // flip Y axis to be consistent with how other PNGs are being handled - // `texture_load` will flip it again - } - vec2_darray_push(tmp_uvs, uv); - } else if (strcmp(line_header, "vn") == 0) { - last_char_type = 'n'; - vec3 normal; - sscanf(pch + offset, "%f %f %f", &normal.x, &normal.y, &normal.z); - vec3_darray_push(tmp_normals, normal); - } else if (strcmp(line_header, "f") == 0) { - last_char_type = 'f'; - struct face f; - sscanf(pch + offset, "%d/%d/%d %d/%d/%d %d/%d/%d", &f.vertex_indices[0], &f.uv_indices[0], - &f.normal_indices[0], &f.vertex_indices[1], &f.uv_indices[1], &f.normal_indices[1], - &f.vertex_indices[2], &f.uv_indices[2], &f.normal_indices[2]); - // printf("f %d/%d/%d %d/%d/%d %d/%d/%d\n", f.vertex_indices[0], f.uv_indices[0], - // f.normal_indices[0], - // f.vertex_indices[1], f.uv_indices[1], f.normal_indices[1], - // f.vertex_indices[2], f.uv_indices[2], f.normal_indices[2]); - face_darray_push(tmp_faces, f); - } else if (strcmp(line_header, "mtllib") == 0) { - char filename[1024]; - sscanf(pch + offset, "%s", filename); - char mtllib_path[1024]; - snprintf(mtllib_path, sizeof(mtllib_path), "%s/%s", relative_path.buf, filename); - if (!load_material_lib(mtllib_path, relative_path, out_model->materials)) { - ERROR("couldnt load material lib"); - return false; - } - } else if (strcmp(line_header, "usemtl") == 0) { - material_loaded = true; - sscanf(pch + offset, "%s", current_material_name); - } - } - - pch = strtok_r(NULL, "\n", &rest); - } - - // last mesh or if one wasnt created with 'o' directive - if (face_darray_len(tmp_faces) > 0) { - TRACE("Last leftover mesh"); - create_submesh(out_model->meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, - out_model->materials, material_loaded, current_material_name); - } - - // Free data - free((char *)file_string); - vec3_darray_free(tmp_positions); - vec3_darray_free(tmp_normals); - vec2_darray_free(tmp_uvs); - face_darray_free(tmp_faces); - TRACE("Freed temporary OBJ loading data"); - - if (mesh_darray_len(out_model->meshes) > 256) { - printf("num meshes: %ld\n", mesh_darray_len(out_model->meshes)); - } - - // TODO: bounding box calculation for each mesh - // TODO: bounding box calculation for model + // // Setup temps + // vec3_darray *tmp_positions = vec3_darray_new(1000); + // vec3_darray *tmp_normals = vec3_darray_new(1000); + // vec2_darray *tmp_uvs = vec2_darray_new(1000); + // face_darray *tmp_faces = face_darray_new(1000); + // // TODO: In the future I'd like these temporary arrays to be allocated from an arena provided + // // by the function one level up, model_load_obj. That way we can just `return false;` anywhere + // in + // // this code to indicate an error, and be sure that all that memory will be cleaned up without + // // having to call vec3_darray_free in every single error case before returning. + + // // Other state + // bool object_set = false; + // bool material_loaded = false; + // char current_material_name[64]; + + // char *pch; + // char *rest = file_string; + // pch = strtok_r((char *)file_string, "\n", &rest); + + // int line_num = 0; + // char last_char_type = 'a'; + + // while (pch != NULL) { + // line_num++; + // char line_header[128]; + // int offset = 0; + + // // skip whitespace + // char *p = pch; + + // skip_space(pch); + + // if (*p == '\0') { + // /* the string is empty */ + // } else { + // // read the first word of the line + // int res = sscanf(pch, "%s %n", line_header, &offset); + // /* printf("header: %s, offset : %d res: %d\n",line_header, offset, res); */ + // if (res != 1) { + // break; + // } + + // if (strcmp(line_header, "o") == 0 || strcmp(line_header, "g") == 0) { + // // if we're currently parsing one + // if (!object_set) { + // object_set = true; + // } else { + // create_submesh(out_model->meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, + // NULL, // out_model->materials, + // material_loaded, current_material_name); + // object_set = false; + // } + // } else if (strcmp(line_header, "v") == 0) { + // // special logic: if we went from faces back to vertices trigger a mesh output. + // // PS: I hate OBJ + // if (last_char_type == 'f') { + // create_submesh(out_model->meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, + // NULL, // FIXME: out_model->materials, + // material_loaded, current_material_name); + // object_set = false; + // } + + // last_char_type = 'v'; + // vec3 vertex; + // sscanf(pch + offset, "%f %f %f", &vertex.x, &vertex.y, &vertex.z); + + // vec3_darray_push(tmp_positions, vertex); + // } else if (strcmp(line_header, "vt") == 0) { + // last_char_type = 't'; + // vec2 uv; + // char copy[1024]; + // memcpy(copy, pch + offset, strlen(pch + offset) + 1); + // char *p = pch + offset; + // while (isspace((unsigned char)*p)) ++p; + + // // I can't remember what is going on here + // memset(copy, 0, 1024); + // memcpy(copy, pch + offset, strlen(pch + offset) + 1); + // int res = sscanf(copy, "%f %f", &uv.x, &uv.y); + // memset(copy, 0, 1024); + // memcpy(copy, pch + offset, strlen(pch + offset) + 1); + // if (res != 1) { + // // da frick? some .obj files have 3 uvs instead of 2 + // f32 dummy; + // int res2 = sscanf(copy, "%f %f %f", &uv.x, &uv.y, &dummy); + // } + + // if (invert_textures_y) { + // uv.y = -uv.y; // flip Y axis to be consistent with how other PNGs are being handled + // // `texture_load` will flip it again + // } + // vec2_darray_push(tmp_uvs, uv); + // } else if (strcmp(line_header, "vn") == 0) { + // last_char_type = 'n'; + // vec3 normal; + // sscanf(pch + offset, "%f %f %f", &normal.x, &normal.y, &normal.z); + // vec3_darray_push(tmp_normals, normal); + // } else if (strcmp(line_header, "f") == 0) { + // last_char_type = 'f'; + // struct face f; + // sscanf(pch + offset, "%d/%d/%d %d/%d/%d %d/%d/%d", &f.vertex_indices[0], + // &f.uv_indices[0], + // &f.normal_indices[0], &f.vertex_indices[1], &f.uv_indices[1], + // &f.normal_indices[1], &f.vertex_indices[2], &f.uv_indices[2], + // &f.normal_indices[2]); + // // printf("f %d/%d/%d %d/%d/%d %d/%d/%d\n", f.vertex_indices[0], f.uv_indices[0], + // // f.normal_indices[0], + // // f.vertex_indices[1], f.uv_indices[1], f.normal_indices[1], + // // f.vertex_indices[2], f.uv_indices[2], f.normal_indices[2]); + // face_darray_push(tmp_faces, f); + // } else if (strcmp(line_header, "mtllib") == 0) { + // char filename[1024]; + // sscanf(pch + offset, "%s", filename); + // char mtllib_path[1024]; + // snprintf(mtllib_path, sizeof(mtllib_path), "%s/%s", relative_path.buf, filename); + // if (!load_material_lib(mtllib_path, relative_path, out_model->materials)) { + // ERROR("couldnt load material lib"); + // return false; + // } + // } else if (strcmp(line_header, "usemtl") == 0) { + // material_loaded = true; + // sscanf(pch + offset, "%s", current_material_name); + // } + // } + + // pch = strtok_r(NULL, "\n", &rest); + // } + + // // last mesh or if one wasnt created with 'o' directive + // if (face_darray_len(tmp_faces) > 0) { + // TRACE("Last leftover mesh"); + // create_submesh(out_model->meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, + // NULL, // TODO: out_model->materials, + // material_loaded, current_material_name); + // } + + // // Free data + // free((char *)file_string); + // vec3_darray_free(tmp_positions); + // vec3_darray_free(tmp_normals); + // vec2_darray_free(tmp_uvs); + // face_darray_free(tmp_faces); + // TRACE("Freed temporary OBJ loading data"); + + // if (mesh_darray_len(out_model->meshes) > 256) { + // printf("num meshes: %ld\n", mesh_darray_len(out_model->meshes)); + // } + + // // TODO: bounding box calculation for each mesh + // // TODO: bounding box calculation for model return true; } @@ -232,158 +238,159 @@ bool model_load_obj_str(const char *file_string, str8 relative_path, model *out_ void create_submesh(mesh_darray *meshes, vec3_darray *tmp_positions, vec3_darray *tmp_normals, vec2_darray *tmp_uvs, face_darray *tmp_faces, material_darray *materials, bool material_loaded, char current_material_name[256]) { - size_t num_verts = face_darray_len(tmp_faces) * 3; - vertex_darray *out_vertices = vertex_darray_new(num_verts); - - face_darray_iter face_iter = face_darray_iter_new(tmp_faces); - struct face *f; - - while ((f = face_darray_iter_next(&face_iter))) { - for (int j = 0; j < 3; j++) { - vertex vert = { 0 }; - vert.position = tmp_positions->data[f->vertex_indices[j] - 1]; - if (vec3_darray_len(tmp_normals) == 0) { - vert.normal = vec3_create(0.0, 0.0, 0.0); - } else { - vert.normal = tmp_normals->data[f->normal_indices[j] - 1]; - } - vert.uv = tmp_uvs->data[f->uv_indices[j] - 1]; - vertex_darray_push(out_vertices, vert); - } - } - - DEBUG("Loaded submesh\n vertices: %zu\n uvs: %zu\n normals: %zu\n faces: %zu", - vec3_darray_len(tmp_positions), vec2_darray_len(tmp_uvs), vec3_darray_len(tmp_normals), - face_darray_len(tmp_faces)); - - // Clear current object faces - face_darray_clear(tmp_faces); - - mesh m = { .vertices = out_vertices }; - if (material_loaded) { - // linear scan to find material - bool found = false; - DEBUG("Num of materials : %ld", material_darray_len(materials)); - material_darray_iter mat_iter = material_darray_iter_new(materials); - blinn_phong_material *cur_material; - while ((cur_material = material_darray_iter_next(&mat_iter))) { - if (strcmp(cur_material->name, current_material_name) == 0) { - DEBUG("Found match"); - m.material_index = mat_iter.current_idx - 1; - found = true; - break; - } - } - - if (!found) { - // TODO: default material - m.material_index = 0; - DEBUG("Set default material"); - } - } - mesh_darray_push(meshes, m); + // size_t num_verts = face_darray_len(tmp_faces) * 3; + // vertex_darray *out_vertices = vertex_darray_new(num_verts); + + // face_darray_iter face_iter = face_darray_iter_new(tmp_faces); + // struct face *f; + + // while ((f = face_darray_iter_next(&face_iter))) { + // for (int j = 0; j < 3; j++) { + // vertex vert = { 0 }; + // vert.position = tmp_positions->data[f->vertex_indices[j] - 1]; + // if (vec3_darray_len(tmp_normals) == 0) { + // vert.normal = vec3_create(0.0, 0.0, 0.0); + // } else { + // vert.normal = tmp_normals->data[f->normal_indices[j] - 1]; + // } + // vert.uv = tmp_uvs->data[f->uv_indices[j] - 1]; + // vertex_darray_push(out_vertices, vert); + // } + // } + + // DEBUG("Loaded submesh\n vertices: %zu\n uvs: %zu\n normals: %zu\n faces: %zu", + // vec3_darray_len(tmp_positions), vec2_darray_len(tmp_uvs), vec3_darray_len(tmp_normals), + // face_darray_len(tmp_faces)); + + // // Clear current object faces + // face_darray_clear(tmp_faces); + + // mesh m = { .vertices = out_vertices }; + // if (material_loaded) { + // // linear scan to find material + // bool found = false; + // DEBUG("Num of materials : %ld", material_darray_len(materials)); + // material_darray_iter mat_iter = material_darray_iter_new(materials); + // blinn_phong_material *cur_material; + // while ((cur_material = material_darray_iter_next(&mat_iter))) { + // if (strcmp(cur_material->name, current_material_name) == 0) { + // DEBUG("Found match"); + // m.material_index = mat_iter.current_idx - 1; + // found = true; + // break; + // } + // } + + // if (!found) { + // // TODO: default material + // m.material_index = 0; + // DEBUG("Set default material"); + // } + // } + // mesh_darray_push(meshes, m); } bool load_material_lib(const char *path, str8 relative_path, material_darray *materials) { TRACE("BEGIN load material lib at %s", path); - const char *file_string = string_from_file(path); - if (file_string == NULL) { - ERROR("couldnt load %s", path); - return false; - } - - char *pch; - char *saveptr; - pch = strtok_r((char *)file_string, "\n", &saveptr); - - material current_material = DEFAULT_MATERIAL; - - bool material_set = false; - - while (pch != NULL) { - char line_header[128]; - int offset = 0; - // read the first word of the line - int res = sscanf(pch, "%s %n", line_header, &offset); - if (res != 1) { - break; - } - - // When we see "newmtl", start a new material, or flush the previous one - if (strcmp(line_header, "newmtl") == 0) { - if (material_set) { - // a material was being parsed, so flush that one and start a new one - material_darray_push(materials, current_material); - DEBUG("pushed material with name %s", current_material.name); - WARN("Reset current material"); - current_material = DEFAULT_MATERIAL; - } else { - material_set = true; - } - // scan the new material name - char material_name[64]; - sscanf(pch + offset, "%s", current_material.name); - DEBUG("material name %s\n", current_material.name); - // current_material.name = material_name; - } else if (strcmp(line_header, "Ka") == 0) { - // ambient - sscanf(pch + offset, "%f %f %f", ¤t_material.ambient_colour.x, - ¤t_material.ambient_colour.y, ¤t_material.ambient_colour.z); - } else if (strcmp(line_header, "Kd") == 0) { - // diffuse - sscanf(pch + offset, "%f %f %f", ¤t_material.diffuse.x, ¤t_material.diffuse.y, - ¤t_material.diffuse.z); - } else if (strcmp(line_header, "Ks") == 0) { - // specular - sscanf(pch + offset, "%f %f %f", ¤t_material.specular.x, ¤t_material.specular.y, - ¤t_material.specular.z); - } else if (strcmp(line_header, "Ns") == 0) { - // specular exponent - sscanf(pch + offset, "%f", ¤t_material.spec_exponent); - } else if (strcmp(line_header, "map_Kd") == 0) { - char diffuse_map_filename[1024]; - sscanf(pch + offset, "%s", diffuse_map_filename); - char diffuse_map_path[1024]; - snprintf(diffuse_map_path, sizeof(diffuse_map_path), "%s/%s", relative_path.buf, - diffuse_map_filename); - printf("load from %s\n", diffuse_map_path); - - // -------------- - texture diffuse_texture = texture_data_load(diffuse_map_path, true); - current_material.diffuse_texture = diffuse_texture; - strcpy(current_material.diffuse_tex_path, diffuse_map_path); - texture_data_upload(¤t_material.diffuse_texture); - // -------------- - } else if (strcmp(line_header, "map_Ks") == 0) { - // char specular_map_path[1024] = "assets/"; - // sscanf(pch + offset, "%s", specular_map_path + 7); - char specular_map_filename[1024]; - sscanf(pch + offset, "%s", specular_map_filename); - char specular_map_path[1024]; - snprintf(specular_map_path, sizeof(specular_map_path), "%s/%s", relative_path.buf, - specular_map_filename); - printf("load from %s\n", specular_map_path); - // -------------- - texture specular_texture = texture_data_load(specular_map_path, true); - current_material.specular_texture = specular_texture; - strcpy(current_material.specular_tex_path, specular_map_path); - texture_data_upload(¤t_material.specular_texture); - // -------------- - } else if (strcmp(line_header, "map_Bump") == 0) { - // TODO - } - - pch = strtok_r(NULL, "\n", &saveptr); - } - - TRACE("end load material lib"); - - // last mesh or if one wasnt created with 'o' directive - // TRACE("Last leftover material"); - material_darray_push(materials, current_material); - - INFO("Loaded %ld materials", material_darray_len(materials)); + // const char *file_string = string_from_file(path); + // if (file_string == NULL) { + // ERROR("couldnt load %s", path); + // return false; + // } + + // char *pch; + // char *saveptr; + // pch = strtok_r((char *)file_string, "\n", &saveptr); + + // material current_material = DEFAULT_MATERIAL; + + // bool material_set = false; + + // while (pch != NULL) { + // char line_header[128]; + // int offset = 0; + // // read the first word of the line + // int res = sscanf(pch, "%s %n", line_header, &offset); + // if (res != 1) { + // break; + // } + + // // When we see "newmtl", start a new material, or flush the previous one + // if (strcmp(line_header, "newmtl") == 0) { + // if (material_set) { + // // a material was being parsed, so flush that one and start a new one + // material_darray_push(materials, current_material); + // DEBUG("pushed material with name %s", current_material.name); + // WARN("Reset current material"); + // current_material = DEFAULT_MATERIAL; + // } else { + // material_set = true; + // } + // // scan the new material name + // char material_name[64]; + // sscanf(pch + offset, "%s", current_material.name); + // DEBUG("material name %s\n", current_material.name); + // // current_material.name = material_name; + // } else if (strcmp(line_header, "Ka") == 0) { + // // ambient + // sscanf(pch + offset, "%f %f %f", ¤t_material.ambient_colour.x, + // ¤t_material.ambient_colour.y, ¤t_material.ambient_colour.z); + // } else if (strcmp(line_header, "Kd") == 0) { + // // diffuse + // sscanf(pch + offset, "%f %f %f", ¤t_material.diffuse.x, ¤t_material.diffuse.y, + // ¤t_material.diffuse.z); + // } else if (strcmp(line_header, "Ks") == 0) { + // // specular + // sscanf(pch + offset, "%f %f %f", ¤t_material.specular.x, + // ¤t_material.specular.y, + // ¤t_material.specular.z); + // } else if (strcmp(line_header, "Ns") == 0) { + // // specular exponent + // sscanf(pch + offset, "%f", ¤t_material.spec_exponent); + // } else if (strcmp(line_header, "map_Kd") == 0) { + // char diffuse_map_filename[1024]; + // sscanf(pch + offset, "%s", diffuse_map_filename); + // char diffuse_map_path[1024]; + // snprintf(diffuse_map_path, sizeof(diffuse_map_path), "%s/%s", relative_path.buf, + // diffuse_map_filename); + // printf("load from %s\n", diffuse_map_path); + + // // -------------- + // texture diffuse_texture = texture_data_load(diffuse_map_path, true); + // current_material.diffuse_texture = diffuse_texture; + // strcpy(current_material.diffuse_tex_path, diffuse_map_path); + // texture_data_upload(¤t_material.diffuse_texture); + // // -------------- + // } else if (strcmp(line_header, "map_Ks") == 0) { + // // char specular_map_path[1024] = "assets/"; + // // sscanf(pch + offset, "%s", specular_map_path + 7); + // char specular_map_filename[1024]; + // sscanf(pch + offset, "%s", specular_map_filename); + // char specular_map_path[1024]; + // snprintf(specular_map_path, sizeof(specular_map_path), "%s/%s", relative_path.buf, + // specular_map_filename); + // printf("load from %s\n", specular_map_path); + // // -------------- + // texture specular_texture = texture_data_load(specular_map_path, true); + // current_material.specular_texture = specular_texture; + // strcpy(current_material.specular_tex_path, specular_map_path); + // texture_data_upload(¤t_material.specular_texture); + // // -------------- + // } else if (strcmp(line_header, "map_Bump") == 0) { + // // TODO + // } + + // pch = strtok_r(NULL, "\n", &saveptr); + // } + + // TRACE("end load material lib"); + + // // last mesh or if one wasnt created with 'o' directive + // // TRACE("Last leftover material"); + // material_darray_push(materials, current_material); + + // INFO("Loaded %ld materials", material_darray_len(materials)); TRACE("END load material lib"); return true; } diff --git a/xmake.lua b/xmake.lua index a5e6239..0fc042c 100644 --- a/xmake.lua +++ b/xmake.lua @@ -1,6 +1,6 @@ set_project("celeritas") set_version("0.1.0") -set_config("cc", "gcc") +set_config("cc", "clang") add_rules("mode.debug", "mode.release") -- we have two modes: debug & release @@ -25,7 +25,7 @@ if is_plat("linux") then elseif is_plat("windows") then add_defines("CEL_PLATFORM_WINDOWS") add_syslinks("user32", "gdi32", "kernel32", "shell32") - add_links("pthreadVC2-w64") + -- add_links("pthreadVC2-w64") elseif is_plat("macosx") then add_defines("CEL_PLATFORM_MAC") add_frameworks("Cocoa", "IOKit", "CoreVideo", "OpenGL") @@ -54,11 +54,10 @@ add_requires("local_glfw") local core_sources = { "deps/glad/src/glad.c", "src/*.c", - "src/logos/*.c", + -- "src/logos/*.c", "src/platform/*.c", "src/renderer/*.c", "src/renderer/backends/*.c", - "src/renderer/cleanroom/*.c", "src/resources/*.c", "src/std/*.c", "src/std/containers/*.c", @@ -96,12 +95,12 @@ target("core_config") add_includedirs("deps/stb_image_write", {public = true}) add_includedirs("deps/stb_truetype", {public = true}) add_includedirs("src/", {public = true}) - add_includedirs("src/logos/", {public = true}) + -- add_includedirs("src/logos/", {public = true}) add_includedirs("src/maths/", {public = true}) add_includedirs("src/platform/", {public = true}) add_includedirs("src/renderer/", {public = true}) add_includedirs("src/renderer/backends/", {public = true}) - add_includedirs("src/renderer/cleanroom/", {public = true}) + -- add_includedirs("src/renderer/cleanroom/", {public = true}) add_includedirs("src/resources/", {public = true}) add_includedirs("src/std/", {public = true}) add_includedirs("src/std/containers", {public = true}) @@ -133,75 +132,75 @@ target("core_shared") if is_plat("windows") then add_links("msvcrt", "legacy_stdio_definitions") -- for release builds add_links("msvcrtd", "legacy_stdio_definitions") -- for debug builds - add_links("pthreadVC2-w64") + -- add_links("pthreadVC2-w64") end target("main_loop") - set_kind("binary") - set_group("examples") - add_deps("core_shared") - add_files("examples/main_loop/ex_main_loop.c") - set_rundir("$(projectdir)") - -target("std") - set_kind("binary") - set_group("examples") - add_deps("core_static") - add_files("examples/standard_lib/ex_std.c") - set_rundir("$(projectdir)") - -target("obj") - set_kind("binary") - set_group("examples") - add_deps("core_static") - add_files("examples/obj_loading/ex_obj_loading.c") - set_rundir("$(projectdir)") - -target("input") - set_kind("binary") - set_group("examples") - add_deps("core_static") - add_files("examples/input/ex_input.c") - set_rundir("$(projectdir)") - -target("gltf") - set_kind("binary") - set_group("examples") - add_deps("core_static") - add_files("examples/gltf_loading/ex_gltf_loading.c") - set_rundir("$(projectdir)") - -target("transforms") - set_kind("binary") - set_group("examples") - add_deps("core_shared") - add_files("examples/transforms/ex_transforms.c") - set_rundir("$(projectdir)") - -target("animation") - set_kind("binary") - set_group("examples") - add_deps("core_shared") - add_files("examples/property_animation/ex_property_animation.c") - set_rundir("$(projectdir)") - -target("skinned") - set_kind("binary") - set_group("examples") - add_deps("core_shared") - add_files("examples/skinned_animation/ex_skinned_animation.c") - set_rundir("$(projectdir)") - -target("input") set_kind("binary") set_group("examples") add_deps("core_static") - add_files("examples/input/ex_input.c") + add_files("examples/main_loop/ex_main_loop.c") set_rundir("$(projectdir)") -target("demo") - set_kind("binary") - set_group("examples") - add_deps("core_static") - add_files("examples/demo/demo.c") - set_rundir("$(projectdir)") +-- target("std") +-- set_kind("binary") +-- set_group("examples") +-- add_deps("core_static") +-- add_files("examples/standard_lib/ex_std.c") +-- set_rundir("$(projectdir)") + +-- target("obj") +-- set_kind("binary") +-- set_group("examples") +-- add_deps("core_static") +-- add_files("examples/obj_loading/ex_obj_loading.c") +-- set_rundir("$(projectdir)") + +-- target("input") +-- set_kind("binary") +-- set_group("examples") +-- add_deps("core_static") +-- add_files("examples/input/ex_input.c") +-- set_rundir("$(projectdir)") + +-- target("gltf") +-- set_kind("binary") +-- set_group("examples") +-- add_deps("core_static") +-- add_files("examples/gltf_loading/ex_gltf_loading.c") +-- set_rundir("$(projectdir)") + +-- target("transforms") +-- set_kind("binary") +-- set_group("examples") +-- add_deps("core_shared") +-- add_files("examples/transforms/ex_transforms.c") +-- set_rundir("$(projectdir)") + +-- target("animation") +-- set_kind("binary") +-- set_group("examples") +-- add_deps("core_shared") +-- add_files("examples/property_animation/ex_property_animation.c") +-- set_rundir("$(projectdir)") + +-- target("skinned") +-- set_kind("binary") +-- set_group("examples") +-- add_deps("core_shared") +-- add_files("examples/skinned_animation/ex_skinned_animation.c") +-- set_rundir("$(projectdir)") + +-- target("input") +-- set_kind("binary") +-- set_group("examples") +-- add_deps("core_static") +-- add_files("examples/input/ex_input.c") +-- set_rundir("$(projectdir)") + +-- target("demo") +-- set_kind("binary") +-- set_group("examples") +-- add_deps("core_static") +-- add_files("examples/demo/demo.c") +-- set_rundir("$(projectdir)") -- cgit v1.2.3-70-g09d2