summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--assets/models/obj/cube/container.jpgbin0 -> 184939 bytes
-rw-r--r--assets/models/obj/cube/cube.mtl14
-rw-r--r--assets/models/obj/cube/cube.obj47
-rw-r--r--examples/demo/demo.c22
-rw-r--r--examples/obj_loading/ex_obj_loading.c25
-rw-r--r--src/core.h3
-rw-r--r--src/platform/file.c6
-rw-r--r--src/renderer/render.c78
-rw-r--r--src/renderer/render.h5
-rw-r--r--src/renderer/render_types.h74
-rw-r--r--src/resources/loaders.h3
-rw-r--r--src/resources/obj.c361
-rw-r--r--src/std/str.h7
-rw-r--r--xmake.lua18
14 files changed, 652 insertions, 11 deletions
diff --git a/assets/models/obj/cube/container.jpg b/assets/models/obj/cube/container.jpg
new file mode 100644
index 0000000..d07bee4
--- /dev/null
+++ b/assets/models/obj/cube/container.jpg
Binary files differ
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;
+}
diff --git a/src/core.h b/src/core.h
index 8a3d037..1b3e28b 100644
--- a/src/core.h
+++ b/src/core.h
@@ -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", &current_material.ambient_colour.x,
+ &current_material.ambient_colour.y, &current_material.ambient_colour.z);
+ } else if (strcmp(line_header, "Kd") == 0) {
+ // diffuse
+ sscanf(pch + offset, "%f %f %f", &current_material.diffuse.x, &current_material.diffuse.y,
+ &current_material.diffuse.z);
+ } else if (strcmp(line_header, "Ks") == 0) {
+ // specular
+ sscanf(pch + offset, "%f %f %f", &current_material.specular.x, &current_material.specular.y,
+ &current_material.specular.z);
+ } else if (strcmp(line_header, "Ns") == 0) {
+ // specular exponent
+ sscanf(pch + offset, "%f", &current_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(&current_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(&current_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;
+}
diff --git a/xmake.lua b/xmake.lua
index e6b77c2..450b97d 100644
--- a/xmake.lua
+++ b/xmake.lua
@@ -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)")