diff --git a/examples/callback_api/main.cc b/examples/callback_api/main.cc index 4f492d0..44ec62f 100644 --- a/examples/callback_api/main.cc +++ b/examples/callback_api/main.cc @@ -1,29 +1,34 @@ +// +// An example of how to use callback API. +// This example is minimum and incomplete. Just showing the usage of callback +// API. +// You need to implement your own Mesh data struct constrution based on this +// example in practical. +// #define TINYOBJLOADER_IMPLEMENTATION #include "tiny_obj_loader.h" +#include #include #include -#include +#include #include #include -#include -typedef struct -{ +typedef struct { std::vector vertices; std::vector normals; std::vector texcoords; - std::vector v_indices; - std::vector vn_indices; - std::vector vt_indices; + std::vector v_indices; + std::vector vn_indices; + std::vector vt_indices; std::vector materials; } MyMesh; -void vertex_cb(void *user_data, float x, float y, float z) -{ - MyMesh *mesh = reinterpret_cast(user_data); +void vertex_cb(void *user_data, float x, float y, float z) { + MyMesh *mesh = reinterpret_cast(user_data); printf("v[%ld] = %f, %f, %f\n", mesh->vertices.size() / 3, x, y, z); mesh->vertices.push_back(x); @@ -31,9 +36,8 @@ void vertex_cb(void *user_data, float x, float y, float z) mesh->vertices.push_back(z); } -void normal_cb(void *user_data, float x, float y, float z) -{ - MyMesh *mesh = reinterpret_cast(user_data); +void normal_cb(void *user_data, float x, float y, float z) { + MyMesh *mesh = reinterpret_cast(user_data); printf("vn[%ld] = %f, %f, %f\n", mesh->normals.size() / 3, x, y, z); mesh->normals.push_back(x); @@ -41,49 +45,55 @@ void normal_cb(void *user_data, float x, float y, float z) mesh->normals.push_back(z); } -void texcoord_cb(void *user_data, float x, float y) -{ - MyMesh *mesh = reinterpret_cast(user_data); +void texcoord_cb(void *user_data, float x, float y) { + MyMesh *mesh = reinterpret_cast(user_data); printf("vt[%ld] = %f, %f\n", mesh->texcoords.size() / 2, x, y); mesh->texcoords.push_back(x); mesh->texcoords.push_back(y); } -void index_cb(void *user_data, int v_idx, int vn_idx, int vt_idx) -{ - // NOTE: the value of each index is raw value. +void index_cb(void *user_data, tinyobj::index_t *indices, int num_indices) { + // NOTE: the value of each index is raw value. // For example, the application must manually adjust the index with offset - // (e.g. v_indices.size()) when the value is negative(relative index). + // (e.g. v_indices.size()) when the value is negative(whic means relative + // index). + // Also, the first index starts with 1, not 0. // See fixIndex() function in tiny_obj_loader.h for details. - // Also, -2147483648(0x80000000) is set for the index value which does not exist in .obj - MyMesh *mesh = reinterpret_cast(user_data); - printf("idx[%ld] = %d, %d, %d\n", mesh->v_indices.size(), v_idx, vn_idx, vt_idx); + // Also, -2147483648(0x80000000 = -INT_MAX) is set for the index value which + // does not exist in .obj + MyMesh *mesh = reinterpret_cast(user_data); - if (v_idx != 0x80000000) { - mesh->v_indices.push_back(v_idx); - } - if (vn_idx != 0x80000000) { - mesh->vn_indices.push_back(vn_idx); - } - if (vt_idx != 0x80000000) { - mesh->vt_indices.push_back(vt_idx); + for (int i = 0; i < num_indices; i++) { + tinyobj::index_t idx = indices[i]; + printf("idx[%ld] = %d, %d, %d\n", mesh->v_indices.size(), idx.vertex_index, + idx.normal_index, idx.texcoord_index); + + if (idx.vertex_index != 0x80000000) { + mesh->v_indices.push_back(idx.vertex_index); + } + if (idx.normal_index != 0x80000000) { + mesh->vn_indices.push_back(idx.normal_index); + } + if (idx.texcoord_index != 0x80000000) { + mesh->vt_indices.push_back(idx.texcoord_index); + } } } -void usemtl_cb(void *user_data, const char* name, int material_idx) -{ - MyMesh *mesh = reinterpret_cast(user_data); +void usemtl_cb(void *user_data, const char *name, int material_idx) { + MyMesh *mesh = reinterpret_cast(user_data); if ((material_idx > -1) && (material_idx < mesh->materials.size())) { - printf("usemtl. material id = %d(name = %s)\n", material_idx, mesh->materials[material_idx].name.c_str()); + printf("usemtl. material id = %d(name = %s)\n", material_idx, + mesh->materials[material_idx].name.c_str()); } else { printf("usemtl. name = %s\n", name); } } -void mtllib_cb(void *user_data, const tinyobj::material_t *materials, int num_materials) -{ - MyMesh *mesh = reinterpret_cast(user_data); +void mtllib_cb(void *user_data, const tinyobj::material_t *materials, + int num_materials) { + MyMesh *mesh = reinterpret_cast(user_data); printf("mtllib. # of materials = %d\n", num_materials); for (int i = 0; i < num_materials; i++) { @@ -91,9 +101,8 @@ void mtllib_cb(void *user_data, const tinyobj::material_t *materials, int num_ma } } -void group_cb(void *user_data, const char **names, int num_names) -{ - //MyMesh *mesh = reinterpret_cast(user_data); +void group_cb(void *user_data, const char **names, int num_names) { + // MyMesh *mesh = reinterpret_cast(user_data); printf("group : name = \n"); for (int i = 0; i < num_names; i++) { @@ -101,16 +110,12 @@ void group_cb(void *user_data, const char **names, int num_names) } } -void object_cb(void *user_data, const char *name) -{ - //MyMesh *mesh = reinterpret_cast(user_data); +void object_cb(void *user_data, const char *name) { + // MyMesh *mesh = reinterpret_cast(user_data); printf("object : name = %s\n", name); - } -int -main(int argc, char** argv) -{ +int main(int argc, char **argv) { tinyobj::callback_t cb; cb.vertex_cb = vertex_cb; cb.normal_cb = normal_cb; @@ -131,7 +136,7 @@ main(int argc, char** argv) } tinyobj::MaterialFileReader mtlReader("../../models/"); - + bool ret = tinyobj::LoadObjWithCallback(&mesh, cb, &err, &ifs, &mtlReader); if (!err.empty()) { diff --git a/tiny_obj_loader.h b/tiny_obj_loader.h index 777ca70..4f79f42 100644 --- a/tiny_obj_loader.h +++ b/tiny_obj_loader.h @@ -151,11 +151,16 @@ typedef struct callback_t_ { void (*vertex_cb)(void *user_data, float x, float y, float z); void (*normal_cb)(void *user_data, float x, float y, float z); void (*texcoord_cb)(void *user_data, float x, float y); - // -2147483648 will be passed for undefined index - void (*index_cb)(void *user_data, int v_idx, int vn_idx, int vt_idx); - // `name` material name, `materialId` = the array index of material_t[]. -1 if + + // called per 'f' line. num_indices is the number of face indices(e.g. 3 for + // triangle, 4 for quad) + // -2147483648(-INT_MAX) will be passed for undefined index in index_t + // members. + void (*index_cb)(void *user_data, index_t *indices, int num_indices); + // `name` material name, `material_id` = the array index of material_t[]. -1 + // if // a material not found in .mtl - void (*usemtl_cb)(void *user_data, const char *name, int materialId); + void (*usemtl_cb)(void *user_data, const char *name, int material_id); // `materials` = parsed material data. void (*mtllib_cb)(void *user_data, const material_t *materials, int num_materials); @@ -216,9 +221,7 @@ bool LoadObj(attrib_t *attrib, std::vector *shapes, /// `callback.mtllib_cb`. /// Returns true when loading .obj/.mtl become success. /// Returns warning and error message into `err` -/// 'mtl_basepath' is optional, and used for base path for .mtl file. -/// 'triangulate' is optional, and used whether triangulate polygon face in .obj -/// or not. +/// See `examples/callback_api/` for how to use this function. bool LoadObjWithCallback(void *user_data, const callback_t &callback, std::string *err, std::istream *inStream, MaterialReader *readMatFn); @@ -1312,14 +1315,11 @@ bool LoadObjWithCallback(void *user_data, const callback_t &callback, // material std::map material_map; - int materialId = -1; // -1 = invalid + int material_id = -1; // -1 = invalid - int maxchars = 8192; // Alloc enough size. - std::vector buf(static_cast(maxchars)); // Alloc enough size. while (inStream->peek() != -1) { - inStream->getline(&buf[0], maxchars); - - std::string linebuf(&buf[0]); + std::string linebuf; + std::getline(*inStream, linebuf); // Trim newline '\r\n' or '\n' if (linebuf.size() > 0) { @@ -1383,15 +1383,24 @@ bool LoadObjWithCallback(void *user_data, const callback_t &callback, token += 2; token += strspn(token, " \t"); + std::vector indices; while (!IS_NEW_LINE(token[0])) { vertex_index vi = parseRawTriple(&token); - if (callback.index_cb) { - callback.index_cb(user_data, vi.v_idx, vi.vn_idx, vi.vt_idx); - } + + index_t idx; + idx.vertex_index = vi.v_idx; + idx.normal_index = vi.vn_idx; + idx.texcoord_index = vi.vt_idx; + + indices.push_back(idx); size_t n = strspn(token, " \t\r"); token += n; } + if (callback.index_cb && indices.size() > 0) { + callback.index_cb(user_data, &indices.at(0), indices.size()); + } + continue; } @@ -1412,12 +1421,12 @@ bool LoadObjWithCallback(void *user_data, const callback_t &callback, // { error!! material not found } } - if (newMaterialId != materialId) { - materialId = newMaterialId; + if (newMaterialId != material_id) { + material_id = newMaterialId; } if (callback.usemtl_cb) { - callback.usemtl_cb(user_data, namebuf, materialId); + callback.usemtl_cb(user_data, namebuf, material_id); } continue;