aboutsummaryrefslogtreecommitdiff
path: root/examples/callback_api/main.cc
blob: a7a74225ad10f7a3457a46217d22dd007620f2aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//
// 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 <cassert>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <sstream>

typedef struct {
  std::vector<float> vertices;
  std::vector<float> normals;
  std::vector<float> texcoords;
  std::vector<int> v_indices;
  std::vector<int> vn_indices;
  std::vector<int> vt_indices;

  std::vector<tinyobj::material_t> materials;

} MyMesh;

void vertex_cb(void *user_data, float x, float y, float z, float w) {
  MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
  printf("v[%ld] = %f, %f, %f (w %f)\n", mesh->vertices.size() / 3, x, y, z, w);

  mesh->vertices.push_back(x);
  mesh->vertices.push_back(y);
  mesh->vertices.push_back(z);
  // Discard w
}

void normal_cb(void *user_data, float x, float y, float z) {
  MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
  printf("vn[%ld] = %f, %f, %f\n", mesh->normals.size() / 3, x, y, z);

  mesh->normals.push_back(x);
  mesh->normals.push_back(y);
  mesh->normals.push_back(z);
}

void texcoord_cb(void *user_data, float x, float y, float z) {
  MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);
  printf("vt[%ld] = %f, %f, %f\n", mesh->texcoords.size() / 3, x, y, z);

  mesh->texcoords.push_back(x);
  mesh->texcoords.push_back(y);
  mesh->texcoords.push_back(z);
}

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(whic means relative
  // index).
  // Also, the first index starts with 1, not 0.
  // See fixIndex() function in tiny_obj_loader.h for details.
  // Also, 0 is set for the index value which
  // does not exist in .obj
  MyMesh *mesh = reinterpret_cast<MyMesh *>(user_data);

  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 != 0) {
      mesh->v_indices.push_back(idx.vertex_index);
    }
    if (idx.normal_index != 0) {
      mesh->vn_indices.push_back(idx.normal_index);
    }
    if (idx.texcoord_index != 0) {
      mesh->vt_indices.push_back(idx.texcoord_index);
    }
  }
}

void usemtl_cb(void *user_data, const char *name, int material_idx) {
  MyMesh *mesh = reinterpret_cast<MyMesh *>(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());
  } 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<MyMesh *>(user_data);
  printf("mtllib. # of materials = %d\n", num_materials);

  for (int i = 0; i < num_materials; i++) {
    mesh->materials.push_back(materials[i]);
  }
}

void group_cb(void *user_data, const char **names, int num_names) {
  // MyMesh *mesh = reinterpret_cast<MyMesh*>(user_data);
  printf("group : name = \n");

  for (int i = 0; i < num_names; i++) {
    printf("  %s\n", names[i]);
  }
}

void object_cb(void *user_data, const char *name) {
  // MyMesh *mesh = reinterpret_cast<MyMesh*>(user_data);
  printf("object : name = %s\n", name);
}

int main(int argc, char **argv) {
  tinyobj::callback_t cb;
  cb.vertex_cb = vertex_cb;
  cb.normal_cb = normal_cb;
  cb.texcoord_cb = texcoord_cb;
  cb.index_cb = index_cb;
  cb.usemtl_cb = usemtl_cb;
  cb.mtllib_cb = mtllib_cb;
  cb.group_cb = group_cb;
  cb.object_cb = object_cb;

  MyMesh mesh;
  std::string err;
  std::string filename = "../../models/cornell_box.obj";
  if (argc > 1) {
    filename = std::string(argv[1]);
  }
  std::ifstream ifs(filename.c_str());

  if (ifs.fail()) {
    std::cerr << "file not found." << std::endl;
    return EXIT_FAILURE;
  }

  tinyobj::MaterialFileReader mtlReader("../../models/");

  bool ret = tinyobj::LoadObjWithCallback(ifs, cb, &mesh, &mtlReader, &err);

  if (!err.empty()) {
    std::cerr << err << std::endl;
  }

  if (!ret) {
    std::cerr << "Failed to parse .obj" << std::endl;
    return EXIT_FAILURE;
  }

  printf("# of vertices         = %ld\n", mesh.vertices.size() / 3);
  printf("# of normals          = %ld\n", mesh.normals.size() / 3);
  printf("# of texcoords        = %ld\n", mesh.texcoords.size() / 2);
  printf("# of vertex indices   = %ld\n", mesh.v_indices.size());
  printf("# of normal indices   = %ld\n", mesh.vn_indices.size());
  printf("# of texcoord indices   = %ld\n", mesh.vt_indices.size());
  printf("# of materials = %ld\n", mesh.materials.size());

  return EXIT_SUCCESS;
}