diff options
-rw-r--r-- | assets/models/obj/cube/container.jpg | bin | 0 -> 184939 bytes | |||
-rw-r--r-- | assets/models/obj/cube/cube.mtl | 14 | ||||
-rw-r--r-- | assets/models/obj/cube/cube.obj | 47 | ||||
-rw-r--r-- | examples/demo/demo.c | 22 | ||||
-rw-r--r-- | examples/obj_loading/ex_obj_loading.c | 25 | ||||
-rw-r--r-- | src/core.h | 3 | ||||
-rw-r--r-- | src/platform/file.c | 6 | ||||
-rw-r--r-- | src/renderer/render.c | 78 | ||||
-rw-r--r-- | src/renderer/render.h | 5 | ||||
-rw-r--r-- | src/renderer/render_types.h | 74 | ||||
-rw-r--r-- | src/resources/loaders.h | 3 | ||||
-rw-r--r-- | src/resources/obj.c | 361 | ||||
-rw-r--r-- | src/std/str.h | 7 | ||||
-rw-r--r-- | xmake.lua | 18 |
14 files changed, 652 insertions, 11 deletions
diff --git a/assets/models/obj/cube/container.jpg b/assets/models/obj/cube/container.jpg Binary files differnew file mode 100644 index 0000000..d07bee4 --- /dev/null +++ b/assets/models/obj/cube/container.jpg diff --git a/assets/models/obj/cube/cube.mtl b/assets/models/obj/cube/cube.mtl new file mode 100644 index 0000000..83a0e8c --- /dev/null +++ b/assets/models/obj/cube/cube.mtl @@ -0,0 +1,14 @@ +# Blender MTL File: 'None' +# Material Count: 1 + +newmtl Scene_-_Root +Ns 225.000000 +Ka 1.000000 1.000000 1.000000 +Kd 0.800000 0.800000 0.800000 +Ks 0.500000 0.500000 0.500000 +Ke 0.0 0.0 0.0 +Ni 1.450000 +d 1.000000 +illum 2 +map_Kd container.jpg + diff --git a/assets/models/obj/cube/cube.obj b/assets/models/obj/cube/cube.obj new file mode 100644 index 0000000..db3bda6 --- /dev/null +++ b/assets/models/obj/cube/cube.obj @@ -0,0 +1,47 @@ +# cube.obj +# + +mtllib cube.mtl +o cube + +v -0.500000 -0.500000 0.500000 +v 0.500000 -0.500000 0.500000 +v -0.500000 0.500000 0.500000 +v 0.500000 0.500000 0.500000 +v -0.500000 0.500000 -0.500000 +v 0.500000 0.500000 -0.500000 +v -0.500000 -0.500000 -0.500000 +v 0.500000 -0.500000 -0.500000 + +vt 0.000000 0.000000 +vt 1.000000 0.000000 +vt 0.000000 1.000000 +vt 1.000000 1.000000 + +vn 0.000000 0.000000 1.000000 +vn 0.000000 1.000000 0.000000 +vn 0.000000 0.000000 -1.000000 +vn 0.000000 -1.000000 0.000000 +vn 1.000000 0.000000 0.000000 +vn -1.000000 0.000000 0.000000 + +g cube +usemtl cube +s 1 +f 1/1/1 2/2/1 3/3/1 +f 3/3/1 2/2/1 4/4/1 +s 2 +f 3/1/2 4/2/2 5/3/2 +f 5/3/2 4/2/2 6/4/2 +s 3 +f 5/4/3 6/3/3 7/2/3 +f 7/2/3 6/3/3 8/1/3 +s 4 +f 7/1/4 8/2/4 1/3/4 +f 1/3/4 8/2/4 2/4/4 +s 5 +f 2/1/5 8/2/5 4/3/5 +f 4/3/5 8/2/5 6/4/5 +s 6 +f 7/1/6 1/2/6 5/3/6 +f 5/3/6 1/2/6 3/4/6
\ No newline at end of file diff --git a/examples/demo/demo.c b/examples/demo/demo.c new file mode 100644 index 0000000..3b2354a --- /dev/null +++ b/examples/demo/demo.c @@ -0,0 +1,22 @@ +#include <glfw3.h> + +#include "core.h" +#include "render.h" + +int main() { + core* core = core_bringup(); + + // Main loop + while (!glfwWindowShouldClose(core->renderer.window)) { + input_update(&core->input); + threadpool_process_results(&core->threadpool, 1); + + render_frame_begin(&core->renderer); + + // insert work here + + render_frame_end(&core->renderer); + } + + return 0; +} diff --git a/examples/obj_loading/ex_obj_loading.c b/examples/obj_loading/ex_obj_loading.c new file mode 100644 index 0000000..87aeb2d --- /dev/null +++ b/examples/obj_loading/ex_obj_loading.c @@ -0,0 +1,25 @@ +#include <glfw3.h> + +#include "core.h" +#include "render.h" + +int main() { + core* core = core_bringup(); + + // Set up our scene + model_handle cube = model_load_obj(core, "assets/models/obj/cube/cube.obj", true); + + // Main loop + while (!glfwWindowShouldClose(core->renderer.window)) { + input_update(&core->input); + threadpool_process_results(&core->threadpool, 1); + + render_frame_begin(&core->renderer); + + // insert work here + + render_frame_end(&core->renderer); + } + + return 0; +} @@ -13,10 +13,11 @@ typedef struct core { input_state input; text_system_state text; screenspace_state screenspace; + model_darray* models; } core; // --- Lifecycle core* core_bringup(); void core_shutdown(core* core); -void core_input_update(core* core);
\ No newline at end of file +void core_input_update(core* core); diff --git a/src/platform/file.c b/src/platform/file.c index 44aa9d0..4eeee46 100644 --- a/src/platform/file.c +++ b/src/platform/file.c @@ -12,6 +12,7 @@ const char *string_from_file(const char *path) { FILE *f = fopen(path, "rb"); + printf("Hello\n"); if (f == NULL) { ERROR("Error reading file: %s. errno: %d", path, errno); return NULL; @@ -20,6 +21,7 @@ const char *string_from_file(const char *path) { ERROR("Error reading file: %s. errno: %d", path, errno); return NULL; } + printf("Hello2\n"); fseek(f, 0, SEEK_END); long fsize = ftell(f); rewind(f); @@ -29,6 +31,8 @@ const char *string_from_file(const char *path) { fclose(f); string[fsize] = '\0'; + printf("Hello3\n"); + printf("Hello %s\n", string); return string; } @@ -60,4 +64,4 @@ str8_opt str8_from_file(arena *a, str8 path) { result.has_value = true; return result; -}
\ No newline at end of file +} diff --git a/src/renderer/render.c b/src/renderer/render.c index 4e9ad89..f12954f 100644 --- a/src/renderer/render.c +++ b/src/renderer/render.c @@ -1,10 +1,19 @@ +#define STB_IMAGE_IMPLEMENTATION +#include <stb_image.h> + +#define STB_TRUETYPE_IMPLEMENTATION +#include <stb_truetype.h> + #include "render.h" +#include <glad/glad.h> #include <glfw3.h> #include "log.h" #include "render_backend.h" +material DEFAULT_MATERIAL = { 0 }; + bool renderer_init(renderer* ren) { INFO("Renderer init"); @@ -39,4 +48,71 @@ void render_frame_end(renderer* ren) { // present frame glfwSwapBuffers(ren->window); glfwPollEvents(); -}
\ No newline at end of file +} + +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); +} + +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); + 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 texture_data_upload(texture* tex) { + TRACE("Upload texture data"); + u32 texture_id; + glGenTextures(1, &texture_id); + glBindTexture(GL_TEXTURE_2D, texture_id); + tex->texture_id = texture_id; + + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, + GL_REPEAT); // set texture wrapping to GL_REPEAT (default wrapping method) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + // set texture filtering parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex->width, tex->height, 0, tex->channel_type, + GL_UNSIGNED_BYTE, tex->image_data); + glGenerateMipmap(GL_TEXTURE_2D); + DEBUG("Freeing texture image data after uploading to GPU"); + // stbi_image_free(tex->image_data); // data is on gpu now so we dont need it around +} diff --git a/src/renderer/render.h b/src/renderer/render.h index c89c364..d1de515 100644 --- a/src/renderer/render.h +++ b/src/renderer/render.h @@ -1,6 +1,7 @@ #pragma once #include "render_types.h" +#include "loaders.h" // --- Lifecycle /** @brief initialise the render system frontend */ @@ -13,4 +14,6 @@ void renderer_shutdown(renderer* ren); void render_frame_begin(renderer* ren); void render_frame_end(renderer* ren); -// ---
\ No newline at end of file +// --- +texture texture_data_load(const char* path, bool invert_y); // #frontend +void texture_data_upload(texture* tex); // #backend diff --git a/src/renderer/render_types.h b/src/renderer/render_types.h index e24fc24..45851fe 100644 --- a/src/renderer/render_types.h +++ b/src/renderer/render_types.h @@ -13,7 +13,11 @@ struct GLFWwindow; +#define MAX_MATERIAL_NAME_LEN 256 +#define MAX_TEXTURE_NAME_LEN 256 + #ifndef RESOURCE_HANDLE_DEFS +CORE_DEFINE_HANDLE(model_handle); CORE_DEFINE_HANDLE(texture_handle); #define RESOURCE_HANDLE_DEFS #endif @@ -36,6 +40,42 @@ typedef struct renderer { renderer_config config; } renderer; +// --- Lighting & Materials + +typedef struct texture { + u32 texture_id; + char name[MAX_TEXTURE_NAME_LEN]; + void *image_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 + /** @brief Vertex format for a static mesh */ typedef struct vertex { vec3 position; @@ -57,7 +97,7 @@ typedef struct mesh { u32 *indices; u32 indices_len; size_t material_index; - u32 vbo, vao; /** OpenGL data */ + u32 vbo, vao; /** OpenGL data. TODO: dont leak OpenGL details */ } mesh; #ifndef TYPED_MESH_ARRAY @@ -67,9 +107,39 @@ KITC_DECL_TYPED_ARRAY(mesh) // creates "mesh_darray" typedef struct model { str8 name; + mesh_darray meshes; + aabb_3d bbox; + material_darray *materials; + bool is_loaded; + bool is_uploaded; } model; #ifndef TYPED_MODEL_ARRAY KITC_DECL_TYPED_ARRAY(model) // creates "model_darray" #define TYPED_MODEL_ARRAY -#endif
\ No newline at end of file +#endif + +// --- 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; diff --git a/src/resources/loaders.h b/src/resources/loaders.h index ba38ec4..8904655 100644 --- a/src/resources/loaders.h +++ b/src/resources/loaders.h @@ -3,7 +3,6 @@ #include "defines.h" struct core; -typedef u32 model_handle; model_handle model_load_obj(struct core *core, const char *path, bool invert_texture_y); -model_handle model_load_gltf(struct core *core, const char *path, bool invert_texture_y);
\ No newline at end of file +model_handle model_load_gltf(struct core *core, const char *path, bool invert_texture_y); diff --git a/src/resources/obj.c b/src/resources/obj.c index b646f58..05aa96e 100644 --- a/src/resources/obj.c +++ b/src/resources/obj.c @@ -1 +1,360 @@ -// TODO: Port code from old repo
\ No newline at end of file +/** + * @file obj.c + * @brief Wavefront OBJ loader. + * @copyright Copyright (c) 2024 + */ +#include <ctype.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "core.h" +#include "darray.h" +#include "log.h" +#include "maths.h" +#include "render.h" +#include "render_types.h" + +struct face { + u32 vertex_indices[3]; + u32 normal_indices[3]; + u32 uv_indices[3]; +}; +typedef struct face face; + +KITC_DECL_TYPED_ARRAY(vec3) +KITC_DECL_TYPED_ARRAY(vec2) +KITC_DECL_TYPED_ARRAY(face) + +// Forward declarations +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]); +bool load_material_lib(const char *path, material_darray *materials); +bool model_load_obj_str(const char *file_string, model *out_model, bool invert_textures_y); + +model_handle model_load_obj(core *core, const char *path, bool invert_textures_y) { + printf("Path %s\n", path); + const char *file_string = string_from_file(path); + printf("Loaded file %s\n", file_string); + model model; + + bool success = model_load_obj_str(file_string, &model, invert_textures_y); + + if (!success) { + exit(-1); // FIXME: Return some sort of result type? + } + + u32 index = model_darray_len(core->models); + model_darray_push(core->models, model); + return (model_handle){ .raw = index }; +} + +bool model_load_obj_str(const char *file_string, model *out_model, 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); + + mesh_darray *meshes = mesh_darray_new(1); + material_darray *materials = material_darray_new(1); + + // 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(meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, 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(meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, 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 path[1024] = "assets/"; + sscanf(pch + offset, "%s", path + 7); + if (!load_material_lib(path, materials)) { + ERROR("couldnt load material lib"); + } + } 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(meshes, tmp_positions, tmp_normals, tmp_uvs, tmp_faces, 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"); + + memset(out_model, 0, sizeof(model)); + if (mesh_darray_len(meshes) > 256) { + printf("num meshes: %ld\n", mesh_darray_len(meshes)); + } + for (int i = 0; i < mesh_darray_len(meshes); i++) { + mesh_darray_push(&out_model->meshes, ((mesh *)meshes->data)[i]); + // TODO: bounding box calculation for each mesh + } + // TODO: bounding box calculation for model + + for (int i = 0; i < material_darray_len(materials); i++) { + material_darray_push(&out_model->materials, ((material *)materials->data)[i]); + } + + return true; +} + +/** + * @brief Takes the current positions, normals, uvs arrays and constructs the vertex array + * from those indices. + */ +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))) { + printf("Material name %s vs %s \n", cur_material->name, current_material_name); + 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, 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_path[1024] = "assets/"; + sscanf(pch + offset, "%s", diffuse_map_path + 7); + 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); + // -------------- + 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); + } + + // 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/src/std/str.h b/src/std/str.h index 735b88e..9d30cba 100644 --- a/src/std/str.h +++ b/src/std/str.h @@ -70,4 +70,9 @@ str8 str8_concat(arena* a, str8 left, str8 right); static inline bool str8_is_null_term(str8 a) { return a.buf[a.len] == 0; // This doesn't seem safe. YOLO -}
\ No newline at end of file +} + +// TODO: move or delete this and replace with handling using our internal type +static void skip_space(char *p) { + while (isspace((unsigned char)*p)) ++p; +} @@ -60,6 +60,7 @@ target("core_config") add_includedirs("src/platform/", {public = true}) add_includedirs("src/renderer/", {public = true}) add_includedirs("src/renderer/backends/", {public = true}) + add_includedirs("src/resources/", {public = true}) add_includedirs("src/std/", {public = true}) add_includedirs("src/std/containers", {public = true}) add_includedirs("src/systems/", {public = true}) @@ -69,6 +70,7 @@ target("core_config") add_files("src/platform/*.c") add_files("src/renderer/*.c") add_files("src/renderer/backends/*.c") + add_files("src/resources/*.c") add_files("src/std/*.c") add_files("src/std/containers/*.c") add_files("src/systems/*.c") @@ -94,4 +96,18 @@ target("std") set_group("examples") add_deps("core_static") add_files("examples/standard_lib/ex_std.c") - set_rundir("$(projectdir)")
\ No newline at end of file + set_rundir("$(projectdir)") + +target("obj_loading") + set_kind("binary") + set_group("examples") + add_deps("core_static") + add_files("examples/obj_loading/ex_obj_loading.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)") |