Skip to content

Commit

Permalink
Updated 3D model loading
Browse files Browse the repository at this point in the history
  • Loading branch information
tanis2000 committed Nov 28, 2023
1 parent d2e3008 commit a206e73
Show file tree
Hide file tree
Showing 7 changed files with 954 additions and 116 deletions.
1 change: 1 addition & 0 deletions src/binocle/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/src/deps
${CMAKE_SOURCE_DIR}/src/deps/cute_path
${CMAKE_SOURCE_DIR}/src/deps/glew
${CMAKE_SOURCE_DIR}/src/deps/freetype
${CMAKE_SOURCE_DIR}/src/deps/miniaudio
Expand Down
45 changes: 45 additions & 0 deletions src/binocle/core/binocle_fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#include <physfs.h>
#include <SDL.h>

#define CUTE_PATH_IMPLEMENTATION
#include <cute_path/cute_path.h>

binocle_fs binocle_fs_new() {
binocle_fs res = {0};
return res;
Expand Down Expand Up @@ -175,4 +178,46 @@ bool binocle_fs_load_text_file(const char *filename, char **buffer, size_t *size
binocle_fs_close(file);

return true;
}

void binocle_fs_get_directory(const char *filename, char *path, int *length) {
*length = path_pop(filename, path, NULL);
}

void binocle_fs_path_without_extension(char* myStr, char extSep, char pathSep, char *retStr) {
char *lastExt, *lastPath;

// Error checks and allocate string.

if (myStr == NULL) return;
if (retStr == NULL) return;

// Make a copy and find the relevant characters.

strcpy (retStr, myStr);
lastExt = strrchr (retStr, extSep);
lastPath = (pathSep == 0) ? NULL : strrchr (retStr, pathSep);

// If it has an extension separator.

if (lastExt != NULL) {
// and it's to the right of the path separator.

if (lastPath != NULL) {
if (lastPath < lastExt) {
// then remove it.

*lastExt = '\0';
}
} else {
// Has extension separator with no path separator.

*lastExt = '\0';
}
}
}

void binocle_fs_get_filename(const char *full_path, char *filename, int *length) {
char path[CUTE_PATH_MAX_PATH];
*length = path_pop(full_path, path, filename);
}
18 changes: 18 additions & 0 deletions src/binocle/core/binocle_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,23 @@ void binocle_fs_close(binocle_fs_file file);
bool binocle_fs_read(binocle_fs_file file, void **buffer, size_t *size);
bool binocle_fs_load_binary_file(const char *filename, void **buffer, size_t *size);
bool binocle_fs_load_text_file(const char *filename, char **buffer, size_t *size);
/// \brief Gets the directory part of the filename+path given as input
/// \param filename the full path including the filename
/// \param path the path without the filename and with no trailing slash
/// \param length the length of the returned path
void binocle_fs_get_directory(const char *filename, char *path, int *length);

/// \brief Return the file name given a full path
/// \param full_path the full path
/// \param filename the filename extracted from the path
/// \param length the length of the filename;
void binocle_fs_get_filename(const char *full_path, char *filename, int *length);

/// \brief Returns the filename without the extension
/// \param myStr the full filename (it can include the path)
/// \param extSep the separator character, e.g. "."
/// \param pathSep the path separator, e.g. "/"
/// \param retStr the filename without extension (including path if provided)
void binocle_fs_path_without_extension(char* myStr, char extSep, char pathSep, char *retStr);

#endif //BINOCLE_FS_H
76 changes: 62 additions & 14 deletions src/binocle/core/binocle_model.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,35 @@
#include "backend/binocle_material.h"
#include "binocle_image.h"
#include "backend/binocle_vpct.h"
#include "cute_path/cute_path.h"


binocle_model binocle_model_load_obj(char *filename, char *mtl_filename) {
void binocle_model_file_reader_callback(void *ctx, const char *filename, int is_mtl, const char *obj_filename, char **buf, size_t *len) {
binocle_model_buffers *buffers = (binocle_model_buffers *)ctx;
if (is_mtl) {
*buf = buffers->mtl.buffer;
*len = buffers->mtl.buffer_length;
} else {
*buf = buffers->obj.buffer;
*len = buffers->obj.buffer_length;
}
if (!binocle_sdl_load_binary_file(filename, buf, len)) {
*len = 0;
binocle_log_error("OBJ loader: cannot open file %s", filename);
return;
}
}

void binocle_model_get_mtl_filename(const char *filename, char *mtl_filename, int *length) {
char name[CUTE_PATH_MAX_PATH];

binocle_fs_path_without_extension(filename, '.', '/', name);
sprintf(mtl_filename, "%s.mtl", name);
}

binocle_model binocle_model_load_obj(char *filename) {
binocle_model model = {0};
char *buffer = NULL;
size_t buffer_length = 0;
binocle_model_buffers buffers = {0};
tinyobj_attrib_t attrib;
tinyobj_shape_t *meshes = NULL;
size_t mesh_count = 0;
Expand All @@ -29,20 +52,20 @@ binocle_model binocle_model_load_obj(char *filename, char *mtl_filename) {

smooth_vertex_normals = kh_init(spatial_binocle_smooth_vertex_t);

if (!binocle_sdl_load_binary_file(filename, &buffer, &buffer_length)) {
binocle_log_error("Cannot open OBJ file %s", filename);
return model;
}

int res = tinyobj_parse_obj(&attrib, &meshes, &mesh_count, &materials, &material_count, buffer, buffer_length, flags);
int res = tinyobj_parse_obj(&attrib, &meshes, &mesh_count, &materials, &material_count, filename, binocle_model_file_reader_callback, &buffers, flags);

if (res != TINYOBJ_SUCCESS) {
binocle_log_warning("Cannot load model data for %s", filename);
} else {
binocle_log_info("Loaded model data for %s: %i meshes and %i materials", filename, mesh_count, material_count);
}

res = tinyobj_parse_mtl_file(&materials, &material_count, mtl_filename);
char mtl_filename[CUTE_PATH_MAX_PATH];
int mtl_filename_length = 0;

binocle_model_get_mtl_filename(filename, (char *) &mtl_filename, &mtl_filename_length);

res = tinyobj_parse_mtl_file(&materials, &material_count, mtl_filename, filename, binocle_model_file_reader_callback, &buffers);
if (res != TINYOBJ_SUCCESS) {
binocle_log_warning("Cannot load material data for %s", mtl_filename);
} else {
Expand All @@ -53,7 +76,7 @@ binocle_model binocle_model_load_obj(char *filename, char *mtl_filename) {
binocle_log_info("# of normals = %d", attrib.num_normals);
binocle_log_info("# of texcoords = %d", attrib.num_texcoords);

model.mesh_count = 1; //mesh_count;
model.mesh_count = mesh_count;
model.meshes = malloc(model.mesh_count * sizeof(binocle_mesh));
memset(model.meshes, 0, model.mesh_count * sizeof(binocle_model));
model.material_count = material_count;
Expand Down Expand Up @@ -283,18 +306,43 @@ binocle_model binocle_model_load_obj(char *filename, char *mtl_filename) {
for (int i = 0 ; i < material_count ; i++) {
binocle_material *mat = binocle_material_new();
model.materials[i] = mat;
// We use diffuse only atm
if (materials[i].diffuse_texname != NULL) {
sg_image image = binocle_image_load(materials[i].diffuse_texname);
model.materials[i]->albedo_texture = image;
// TODO: fix this now that we no longer have default shaders
//model.materials[i]->shader = &binocle_shader_defaults[BINOCLE_SHADER_DEFAULT_FLAT];
}

if (materials[i].bump_texname != NULL) {
sg_image image = binocle_image_load(materials[i].bump_texname);
model.materials[i]->normal_texture = image;
}

if (materials[i].ambient_texname != NULL) {
sg_image image = binocle_image_load(materials[i].ambient_texname);
model.materials[i]->ao_texture = image;
}

if (materials[i].metallic_texname != NULL) {
sg_image image = binocle_image_load(materials[i].metallic_texname);
model.materials[i]->metallic_texture = image;
}

if (materials[i].specular_highlight_texname != NULL) {
sg_image image = binocle_image_load(materials[i].specular_highlight_texname);
model.materials[i]->roughness_texture = image;
}
}

// Fix up the materials of each mesh.
// TODO: check that we are assigning the right material and not just the first one.
for (int i = 0 ; i < mesh_count ; i++) {
model.meshes[i].material = model.materials[model.mesh_materials[i]];
}

tinyobj_attrib_free(&attrib);
tinyobj_shapes_free(meshes, mesh_count);
tinyobj_materials_free(materials, material_count);
SDL_free(buffers.obj.buffer);
SDL_free(buffers.mtl.buffer);

binocle_log_info("Model %s loaded successfully", filename);

Expand Down
12 changes: 11 additions & 1 deletion src/binocle/core/binocle_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,22 @@ typedef struct binocle_model {
uint64_t *mesh_materials; // mesh materials
} binocle_model;

typedef struct binocle_model_buffer {
char *buffer;
size_t buffer_length;
} binocle_model_buffer;

typedef struct binocle_model_buffers {
binocle_model_buffer obj;
binocle_model_buffer mtl;
} binocle_model_buffers;

typedef uint64_t binocle_model_smooth_vertex_key_t;
#define binocle_model_smooth_vertex_hash_func(key) (binocle_model_smooth_vertex_key_t)(key)
#define binocle_model_smooth_vertex_equal(a, b) ((a) == (b))
KHASH_INIT(spatial_binocle_smooth_vertex_t, binocle_model_smooth_vertex_key_t, kmVec3, 1, binocle_model_smooth_vertex_hash_func, binocle_model_smooth_vertex_equal)

binocle_model binocle_model_load_obj(char *filename, char *mtl_filename);
binocle_model binocle_model_load_obj(char *filename);
void binocle_model_compute_normal(float N[3], float v0[3], float v1[3], float v2[3]);
void binocle_model_compute_smoothing_normals(tinyobj_attrib_t *attrib, tinyobj_shape_t *shape, khash_t(spatial_binocle_smooth_vertex_t) *smooth_vertex_normals);

Expand Down
Loading

0 comments on commit a206e73

Please sign in to comment.