64#ifndef TINY_OBJ_LOADER_H_
65#define TINY_OBJ_LOADER_H_
74#if __cplusplus > 199711L
75#define TINYOBJ_OVERRIDE override
77#define TINYOBJ_OVERRIDE
81#pragma clang diagnostic push
82#if __has_warning("-Wzero-as-null-pointer-constant")
83#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
86#pragma clang diagnostic ignored "-Wpadded"
145#ifdef TINYOBJLOADER_USE_DOUBLE
245#ifdef TINY_OBJ_LOADER_PYTHON_BINDING
247 std::array<double, 3> GetDiffuse() {
248 std::array<double, 3> values;
249 values[0] = double(
diffuse[0]);
250 values[1] = double(
diffuse[1]);
251 values[2] = double(
diffuse[2]);
256 std::array<double, 3> GetSpecular() {
257 std::array<double, 3> values;
265 std::array<double, 3> GetTransmittance() {
266 std::array<double, 3> values;
274 std::array<double, 3> GetEmission() {
275 std::array<double, 3> values;
283 std::array<double, 3> GetAmbient() {
284 std::array<double, 3> values;
285 values[0] = double(
ambient[0]);
286 values[1] = double(
ambient[1]);
287 values[2] = double(
ambient[2]);
292 void SetDiffuse(std::array<double, 3> &a) {
298 void SetAmbient(std::array<double, 3> &a) {
304 void SetSpecular(std::array<double, 3> &a) {
310 void SetTransmittance(std::array<double, 3> &a) {
316 std::string GetCustomParameter(
const std::string &key) {
317 std::map<std::string, std::string>::const_iterator it =
323 return std::string();
359 std::vector<unsigned int>
442 void (*
usemtl_cb)(
void *user_data,
const char *name,
int material_id);
447 void (*
group_cb)(
void *user_data,
const char **names,
int num_names);
468 std::vector<material_t> *materials,
469 std::map<std::string, int> *matMap, std::string *warn,
470 std::string *err) = 0;
480 : m_mtlBaseDir(mtl_basedir) {}
483 std::vector<material_t> *materials,
484 std::map<std::string, int> *matMap, std::string *warn,
488 std::string m_mtlBaseDir;
497 : m_inStream(inStream) {}
500 std::vector<material_t> *materials,
501 std::map<std::string, int> *matMap, std::string *warn,
505 std::istream &m_inStream;
565 bool Valid()
const {
return valid_; }
569 const std::vector<shape_t> &
GetShapes()
const {
return shapes_; }
571 const std::vector<material_t> &
GetMaterials()
const {
return materials_; }
576 const std::string &
Warning()
const {
return warning_; }
581 const std::string &
Error()
const {
return error_; }
587 std::vector<shape_t> shapes_;
588 std::vector<material_t> materials_;
590 std::string warning_;
608bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
609 std::vector<material_t> *materials, std::string *warn,
610 std::string *err,
const char *filename,
611 const char *mtl_basedir = NULL,
bool triangulate =
true,
612 bool default_vcols_fallback =
true);
620bool LoadObjWithCallback(std::istream &inStream,
const callback_t &callback,
621 void *user_data = NULL,
622 MaterialReader *readMatFn = NULL,
623 std::string *warn = NULL, std::string *err = NULL);
630 std::vector<material_t> *materials, std::string *warn,
631 std::string *err, std::istream *inStream,
633 bool default_vcols_fallback =
true);
636void LoadMtl(std::map<std::string, int> *material_map,
637 std::vector<material_t> *materials, std::istream *inStream,
638 std::string *warning, std::string *err);
649 const char *linebuf);
657#ifdef TINYOBJLOADER_IMPLEMENTATION
670#ifdef TINYOBJLOADER_USE_MAPBOX_EARCUT
672#ifdef TINYOBJLOADER_DONOT_INCLUDE_MAPBOX_EARCUT
677#pragma clang diagnostic push
678#pragma clang diagnostic ignored "-Weverything"
683#include "mapbox/earcut.hpp"
686#pragma clang diagnostic pop
697struct vertex_index_t {
698 int v_idx, vt_idx, vn_idx;
699 vertex_index_t() : v_idx(-1), vt_idx(-1), vn_idx(-1) {}
700 explicit vertex_index_t(
int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {}
701 vertex_index_t(
int vidx,
int vtidx,
int vnidx)
702 : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {}
711 std::vector<vertex_index_t> vertex_indices;
713 face_t() : smoothing_group_id(0), pad_(0) {}
721 std::vector<vertex_index_t> vertex_indices;
729 std::vector<vertex_index_t> vertex_indices;
733 tag_sizes() : num_ints(0), num_reals(0), num_strings(0) {}
740 std::vector<real_t> v;
741 std::vector<real_t> vn;
742 std::vector<real_t> vt;
748 std::vector<face_t> faceGroup;
749 std::vector<__line_t> lineGroup;
750 std::vector<__points_t> pointsGroup;
758 bool IsEmpty()
const {
759 return faceGroup.empty() && lineGroup.empty() && pointsGroup.empty();
767static std::istream &safeGetline(std::istream &is, std::string &t) {
776 std::istream::sentry se(is,
true);
777 std::streambuf *sb = is.rdbuf();
781 int c = sb->sbumpc();
786 if (sb->sgetc() ==
'\n') sb->sbumpc();
790 if (t.empty()) is.setstate(std::ios::eofbit);
793 t +=
static_cast<char>(c);
801#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
803 (static_cast<unsigned int>((x) - '0') < static_cast<unsigned int>(10))
804#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
807static inline std::string toString(
const T &t) {
808 std::stringstream ss;
813struct warning_context {
819static inline bool fixIndex(
int idx,
int n,
int *ret,
bool allow_zero,
820 const warning_context &context) {
834 "A zero value index found (will have a value of -1 for normal and "
835 "tex indices. Line " +
836 toString(context.line_number) +
").\n";
854static inline std::string parseString(
const char **token) {
856 (*token) += strspn((*token),
" \t");
857 size_t e = strcspn((*token),
" \t\r");
858 s = std::string((*token), &(*token)[e]);
863static inline int parseInt(
const char **token) {
864 (*token) += strspn((*token),
" \t");
865 int i = atoi((*token));
866 (*token) += strcspn((*token),
" \t\r");
897static bool tryParseDouble(
const char *s,
const char *s_end,
double *result) {
902 double mantissa = 0.0;
916 char const *curr = s;
921 bool end_not_reached =
false;
922 bool leading_decimal_dots =
false;
929 if (*curr ==
'+' || *curr ==
'-') {
932 if ((curr != s_end) && (*curr ==
'.')) {
934 leading_decimal_dots =
true;
936 }
else if (IS_DIGIT(*curr)) {
937 }
else if (*curr ==
'.') {
939 leading_decimal_dots =
true;
945 end_not_reached = (curr != s_end);
946 if (!leading_decimal_dots) {
947 while (end_not_reached && IS_DIGIT(*curr)) {
949 mantissa +=
static_cast<int>(*curr - 0x30);
952 end_not_reached = (curr != s_end);
956 if (read == 0)
goto fail;
960 if (!end_not_reached)
goto assemble;
966 end_not_reached = (curr != s_end);
967 while (end_not_reached && IS_DIGIT(*curr)) {
968 static const double pow_lut[] = {
969 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001,
971 const int lut_entries =
sizeof pow_lut /
sizeof pow_lut[0];
974 mantissa +=
static_cast<int>(*curr - 0x30) *
975 (read < lut_entries ? pow_lut[read] : std::pow(10.0, -read));
978 end_not_reached = (curr != s_end);
980 }
else if (*curr ==
'e' || *curr ==
'E') {
985 if (!end_not_reached)
goto assemble;
988 if (*curr ==
'e' || *curr ==
'E') {
991 end_not_reached = (curr != s_end);
992 if (end_not_reached && (*curr ==
'+' || *curr ==
'-')) {
995 }
else if (IS_DIGIT(*curr)) {
1002 end_not_reached = (curr != s_end);
1003 while (end_not_reached && IS_DIGIT(*curr)) {
1007 (2147483647 / 10)) {
1012 exponent +=
static_cast<int>(*curr - 0x30);
1015 end_not_reached = (curr != s_end);
1017 exponent *= (exp_sign ==
'+' ? 1 : -1);
1018 if (read == 0)
goto fail;
1022 *result = (sign ==
'+' ? 1 : -1) *
1023 (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent)
1030static inline real_t parseReal(
const char **token,
double default_value = 0.0) {
1031 (*token) += strspn((*token),
" \t");
1032 const char *end = (*token) + strcspn((*token),
" \t\r");
1033 double val = default_value;
1034 tryParseDouble((*token), end, &val);
1040static inline bool parseReal(
const char **token,
real_t *out) {
1041 (*token) += strspn((*token),
" \t");
1042 const char *end = (*token) + strcspn((*token),
" \t\r");
1044 bool ret = tryParseDouble((*token), end, &val);
1053static inline void parseReal2(
real_t *x,
real_t *y,
const char **token,
1054 const double default_x = 0.0,
1055 const double default_y = 0.0) {
1056 (*x) = parseReal(token, default_x);
1057 (*y) = parseReal(token, default_y);
1061 const char **token,
const double default_x = 0.0,
1062 const double default_y = 0.0,
1063 const double default_z = 0.0) {
1064 (*x) = parseReal(token, default_x);
1065 (*y) = parseReal(token, default_y);
1066 (*z) = parseReal(token, default_z);
1071 const char **token,
const double default_x = 0.0,
1072 const double default_y = 0.0,
1073 const double default_z = 0.0,
1074 const double default_w = 1.0) {
1075 (*x) = parseReal(token, default_x);
1076 (*y) = parseReal(token, default_y);
1077 (*z) = parseReal(token, default_z);
1078 (*w) = parseReal(token, default_w);
1088 const double default_x = 0.0,
1089 const double default_y = 0.0,
1090 const double default_z = 0.0) {
1092 (*x) = parseReal(token, default_x);
1093 (*y) = parseReal(token, default_y);
1094 (*z) = parseReal(token, default_z);
1097 bool has_r = parseReal(token, r);
1100 (*r) = (*g) = (*b) = 1.0;
1104 bool has_g = parseReal(token, g);
1111 bool has_b = parseReal(token, b);
1114 (*r) = (*g) = (*b) = 1.0;
1121static inline bool parseOnOff(
const char **token,
bool default_value =
true) {
1122 (*token) += strspn((*token),
" \t");
1123 const char *end = (*token) + strcspn((*token),
" \t\r");
1125 bool ret = default_value;
1126 if ((0 == strncmp((*token),
"on", 2))) {
1128 }
else if ((0 == strncmp((*token),
"off", 3))) {
1138 (*token) += strspn((*token),
" \t");
1139 const char *end = (*token) + strcspn((*token),
" \t\r");
1142 if ((0 == strncmp((*token),
"cube_top", strlen(
"cube_top")))) {
1144 }
else if ((0 == strncmp((*token),
"cube_bottom", strlen(
"cube_bottom")))) {
1146 }
else if ((0 == strncmp((*token),
"cube_left", strlen(
"cube_left")))) {
1148 }
else if ((0 == strncmp((*token),
"cube_right", strlen(
"cube_right")))) {
1150 }
else if ((0 == strncmp((*token),
"cube_front", strlen(
"cube_front")))) {
1152 }
else if ((0 == strncmp((*token),
"cube_back", strlen(
"cube_back")))) {
1154 }
else if ((0 == strncmp((*token),
"sphere", strlen(
"sphere")))) {
1162static tag_sizes parseTagTriple(
const char **token) {
1165 (*token) += strspn((*token),
" \t");
1166 ts.num_ints = atoi((*token));
1167 (*token) += strcspn((*token),
"/ \t\r");
1168 if ((*token)[0] !=
'/') {
1174 (*token) += strspn((*token),
" \t");
1175 ts.num_reals = atoi((*token));
1176 (*token) += strcspn((*token),
"/ \t\r");
1177 if ((*token)[0] !=
'/') {
1182 ts.num_strings = parseInt(token);
1188static bool parseTriple(
const char **token,
int vsize,
int vnsize,
int vtsize,
1189 vertex_index_t *ret,
const warning_context &context) {
1194 vertex_index_t vi(-1);
1196 if (!fixIndex(atoi((*token)), vsize, &vi.v_idx,
false, context)) {
1200 (*token) += strcspn((*token),
"/ \t\r");
1201 if ((*token)[0] !=
'/') {
1208 if ((*token)[0] ==
'/') {
1210 if (!fixIndex(atoi((*token)), vnsize, &vi.vn_idx,
true, context)) {
1213 (*token) += strcspn((*token),
"/ \t\r");
1219 if (!fixIndex(atoi((*token)), vtsize, &vi.vt_idx,
true, context)) {
1223 (*token) += strcspn((*token),
"/ \t\r");
1224 if ((*token)[0] !=
'/') {
1231 if (!fixIndex(atoi((*token)), vnsize, &vi.vn_idx,
true, context)) {
1234 (*token) += strcspn((*token),
"/ \t\r");
1242static vertex_index_t parseRawTriple(
const char **token) {
1243 vertex_index_t vi(
static_cast<int>(0));
1245 vi.v_idx = atoi((*token));
1246 (*token) += strcspn((*token),
"/ \t\r");
1247 if ((*token)[0] !=
'/') {
1253 if ((*token)[0] ==
'/') {
1255 vi.vn_idx = atoi((*token));
1256 (*token) += strcspn((*token),
"/ \t\r");
1261 vi.vt_idx = atoi((*token));
1262 (*token) += strcspn((*token),
"/ \t\r");
1263 if ((*token)[0] !=
'/') {
1269 vi.vn_idx = atoi((*token));
1270 (*token) += strcspn((*token),
"/ \t\r");
1275 const char *linebuf) {
1277 bool found_texname =
false;
1278 std::string texture_name;
1280 const char *token = linebuf;
1282 while (!IS_NEW_LINE((*token))) {
1283 token += strspn(token,
" \t");
1284 if ((0 == strncmp(token,
"-blendu", 7)) && IS_SPACE((token[7]))) {
1286 texopt->blendu = parseOnOff(&token,
true);
1287 }
else if ((0 == strncmp(token,
"-blendv", 7)) && IS_SPACE((token[7]))) {
1289 texopt->blendv = parseOnOff(&token,
true);
1290 }
else if ((0 == strncmp(token,
"-clamp", 6)) && IS_SPACE((token[6]))) {
1292 texopt->clamp = parseOnOff(&token,
true);
1293 }
else if ((0 == strncmp(token,
"-boost", 6)) && IS_SPACE((token[6]))) {
1295 texopt->sharpness = parseReal(&token, 1.0);
1296 }
else if ((0 == strncmp(token,
"-bm", 3)) && IS_SPACE((token[3]))) {
1298 texopt->bump_multiplier = parseReal(&token, 1.0);
1299 }
else if ((0 == strncmp(token,
"-o", 2)) && IS_SPACE((token[2]))) {
1301 parseReal3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]),
1302 &(texopt->origin_offset[2]), &token);
1303 }
else if ((0 == strncmp(token,
"-s", 2)) && IS_SPACE((token[2]))) {
1305 parseReal3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]),
1306 &token, 1.0, 1.0, 1.0);
1307 }
else if ((0 == strncmp(token,
"-t", 2)) && IS_SPACE((token[2]))) {
1309 parseReal3(&(texopt->turbulence[0]), &(texopt->turbulence[1]),
1310 &(texopt->turbulence[2]), &token);
1311 }
else if ((0 == strncmp(token,
"-type", 5)) && IS_SPACE((token[5]))) {
1314 }
else if ((0 == strncmp(token,
"-texres", 7)) && IS_SPACE((token[7]))) {
1317 texopt->texture_resolution = parseInt(&token);
1318 }
else if ((0 == strncmp(token,
"-imfchan", 8)) && IS_SPACE((token[8]))) {
1320 token += strspn(token,
" \t");
1321 const char *end = token + strcspn(token,
" \t\r");
1322 if ((end - token) == 1) {
1323 texopt->imfchan = (*token);
1326 }
else if ((0 == strncmp(token,
"-mm", 3)) && IS_SPACE((token[3]))) {
1328 parseReal2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0);
1329 }
else if ((0 == strncmp(token,
"-colorspace", 11)) &&
1330 IS_SPACE((token[11]))) {
1332 texopt->colorspace = parseString(&token);
1336 size_t len = strcspn(token,
" \t\r");
1337 texture_name = std::string(token, token + len);
1340 token += strspn(token,
" \t");
1344 texture_name = std::string(token);
1345 token += texture_name.length();
1348 found_texname =
true;
1352 if (found_texname) {
1353 (*texname) = texture_name;
1362 texopt->imfchan =
'l';
1364 texopt->imfchan =
'm';
1366 texopt->bump_multiplier =
static_cast<real_t>(1.0);
1367 texopt->clamp =
false;
1368 texopt->blendu =
true;
1369 texopt->blendv =
true;
1370 texopt->sharpness =
static_cast<real_t>(1.0);
1371 texopt->brightness =
static_cast<real_t>(0.0);
1372 texopt->contrast =
static_cast<real_t>(1.0);
1373 texopt->origin_offset[0] =
static_cast<real_t>(0.0);
1374 texopt->origin_offset[1] =
static_cast<real_t>(0.0);
1375 texopt->origin_offset[2] =
static_cast<real_t>(0.0);
1376 texopt->scale[0] =
static_cast<real_t>(1.0);
1377 texopt->scale[1] =
static_cast<real_t>(1.0);
1378 texopt->scale[2] =
static_cast<real_t>(1.0);
1379 texopt->turbulence[0] =
static_cast<real_t>(0.0);
1380 texopt->turbulence[1] =
static_cast<real_t>(0.0);
1381 texopt->turbulence[2] =
static_cast<real_t>(0.0);
1382 texopt->texture_resolution = -1;
1386static void InitMaterial(
material_t *material) {
1387 InitTexOpt(&material->ambient_texopt,
false);
1388 InitTexOpt(&material->diffuse_texopt,
false);
1389 InitTexOpt(&material->specular_texopt,
false);
1390 InitTexOpt(&material->specular_highlight_texopt,
false);
1391 InitTexOpt(&material->bump_texopt,
true);
1392 InitTexOpt(&material->displacement_texopt,
false);
1393 InitTexOpt(&material->alpha_texopt,
false);
1394 InitTexOpt(&material->reflection_texopt,
false);
1395 InitTexOpt(&material->roughness_texopt,
false);
1396 InitTexOpt(&material->metallic_texopt,
false);
1397 InitTexOpt(&material->sheen_texopt,
false);
1398 InitTexOpt(&material->emissive_texopt,
false);
1399 InitTexOpt(&material->normal_texopt,
1401 material->name =
"";
1402 material->ambient_texname =
"";
1403 material->diffuse_texname =
"";
1404 material->specular_texname =
"";
1405 material->specular_highlight_texname =
"";
1406 material->bump_texname =
"";
1407 material->displacement_texname =
"";
1408 material->reflection_texname =
"";
1409 material->alpha_texname =
"";
1410 for (
int i = 0; i < 3; i++) {
1411 material->ambient[i] =
static_cast<real_t>(0.0);
1412 material->diffuse[i] =
static_cast<real_t>(0.0);
1413 material->specular[i] =
static_cast<real_t>(0.0);
1414 material->transmittance[i] =
static_cast<real_t>(0.0);
1415 material->emission[i] =
static_cast<real_t>(0.0);
1417 material->illum = 0;
1418 material->dissolve =
static_cast<real_t>(1.0);
1419 material->shininess =
static_cast<real_t>(1.0);
1420 material->ior =
static_cast<real_t>(1.0);
1422 material->roughness =
static_cast<real_t>(0.0);
1423 material->metallic =
static_cast<real_t>(0.0);
1424 material->sheen =
static_cast<real_t>(0.0);
1425 material->clearcoat_thickness =
static_cast<real_t>(0.0);
1426 material->clearcoat_roughness =
static_cast<real_t>(0.0);
1427 material->anisotropy_rotation =
static_cast<real_t>(0.0);
1428 material->anisotropy =
static_cast<real_t>(0.0);
1429 material->roughness_texname =
"";
1430 material->metallic_texname =
"";
1431 material->sheen_texname =
"";
1432 material->emissive_texname =
"";
1433 material->normal_texname =
"";
1435 material->unknown_parameter.clear();
1439template <
typename T>
1440static int pnpoly(
int nvert, T *vertx, T *verty, T testx, T testy) {
1442 for (i = 0, j = nvert - 1; i < nvert; j = i++) {
1443 if (((verty[i] > testy) != (verty[j] > testy)) &&
1445 (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) +
1452struct TinyObjPoint {
1454 TinyObjPoint() : x(0), y(0), z(0) {}
1455 TinyObjPoint(real_t x_, real_t y_, real_t z_) : x(x_), y(y_), z(z_) {}
1458inline TinyObjPoint cross(
const TinyObjPoint &v1,
const TinyObjPoint &v2) {
1459 return TinyObjPoint(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z,
1460 v1.x * v2.y - v1.y * v2.x);
1463inline real_t dot(
const TinyObjPoint &v1,
const TinyObjPoint &v2) {
1464 return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z);
1467inline real_t GetLength(TinyObjPoint &e) {
1468 return std::sqrt(e.x * e.x + e.y * e.y + e.z * e.z);
1471inline TinyObjPoint Normalize(TinyObjPoint e) {
1473 return TinyObjPoint(e.x * inv_length, e.y * inv_length, e.z * inv_length);
1476inline TinyObjPoint WorldToLocal(
const TinyObjPoint &a,
const TinyObjPoint &u,
1477 const TinyObjPoint &v,
const TinyObjPoint &w) {
1478 return TinyObjPoint(dot(a, u), dot(a, v), dot(a, w));
1482static bool exportGroupsToShape(
shape_t *shape,
const PrimGroup &prim_group,
1483 const std::vector<tag_t> &tags,
1484 const int material_id,
const std::string &name,
1485 bool triangulate,
const std::vector<real_t> &v,
1486 std::string *warn) {
1487 if (prim_group.IsEmpty()) {
1494 if (!prim_group.faceGroup.empty()) {
1496 for (
size_t i = 0; i < prim_group.faceGroup.size(); i++) {
1497 const face_t &face = prim_group.faceGroup[i];
1499 size_t npolys = face.vertex_indices.size();
1504 (*warn) +=
"Degenerated face found\n.";
1509 if (triangulate && npolys != 3) {
1511 vertex_index_t i0 = face.vertex_indices[0];
1512 vertex_index_t i1 = face.vertex_indices[1];
1513 vertex_index_t i2 = face.vertex_indices[2];
1514 vertex_index_t i3 = face.vertex_indices[3];
1516 size_t vi0 = size_t(i0.v_idx);
1517 size_t vi1 = size_t(i1.v_idx);
1518 size_t vi2 = size_t(i2.v_idx);
1519 size_t vi3 = size_t(i3.v_idx);
1521 if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) ||
1522 ((3 * vi2 + 2) >= v.size()) || ((3 * vi3 + 2) >= v.size())) {
1526 (*warn) +=
"Face with invalid vertex index found.\n";
1531 real_t v0x = v[vi0 * 3 + 0];
1532 real_t v0y = v[vi0 * 3 + 1];
1533 real_t v0z = v[vi0 * 3 + 2];
1534 real_t v1x = v[vi1 * 3 + 0];
1535 real_t v1y = v[vi1 * 3 + 1];
1536 real_t v1z = v[vi1 * 3 + 2];
1537 real_t v2x = v[vi2 * 3 + 0];
1538 real_t v2y = v[vi2 * 3 + 1];
1539 real_t v2z = v[vi2 * 3 + 2];
1540 real_t v3x = v[vi3 * 3 + 0];
1541 real_t v3y = v[vi3 * 3 + 1];
1542 real_t v3z = v[vi3 * 3 + 2];
1569 real_t sqr02 = e02x * e02x + e02y * e02y + e02z * e02z;
1570 real_t sqr13 = e13x * e13x + e13y * e13y + e13z * e13z;
1572 index_t idx0, idx1, idx2, idx3;
1575 idx0.normal_index = i0.vn_idx;
1576 idx0.texcoord_index = i0.vt_idx;
1577 idx1.vertex_index = i1.v_idx;
1578 idx1.normal_index = i1.vn_idx;
1579 idx1.texcoord_index = i1.vt_idx;
1580 idx2.vertex_index = i2.v_idx;
1581 idx2.normal_index = i2.vn_idx;
1582 idx2.texcoord_index = i2.vt_idx;
1583 idx3.vertex_index = i3.v_idx;
1584 idx3.normal_index = i3.vn_idx;
1585 idx3.texcoord_index = i3.vt_idx;
1587 if (sqr02 < sqr13) {
1589 shape->mesh.indices.push_back(idx0);
1590 shape->mesh.indices.push_back(idx1);
1591 shape->mesh.indices.push_back(idx2);
1593 shape->mesh.indices.push_back(idx0);
1594 shape->mesh.indices.push_back(idx2);
1595 shape->mesh.indices.push_back(idx3);
1598 shape->mesh.indices.push_back(idx0);
1599 shape->mesh.indices.push_back(idx1);
1600 shape->mesh.indices.push_back(idx3);
1602 shape->mesh.indices.push_back(idx1);
1603 shape->mesh.indices.push_back(idx2);
1604 shape->mesh.indices.push_back(idx3);
1608 shape->mesh.num_face_vertices.push_back(3);
1609 shape->mesh.num_face_vertices.push_back(3);
1611 shape->mesh.material_ids.push_back(material_id);
1612 shape->mesh.material_ids.push_back(material_id);
1614 shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);
1615 shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);
1618#ifdef TINYOBJLOADER_USE_MAPBOX_EARCUT
1619 vertex_index_t i0 = face.vertex_indices[0];
1620 vertex_index_t i0_2 = i0;
1625 for (
size_t k = 0; k < npolys; ++k) {
1626 i0 = face.vertex_indices[k % npolys];
1627 size_t vi0 = size_t(i0.v_idx);
1629 size_t j = (k + 1) % npolys;
1630 i0_2 = face.vertex_indices[j];
1631 size_t vi0_2 = size_t(i0_2.v_idx);
1633 real_t v0x = v[vi0 * 3 + 0];
1634 real_t v0y = v[vi0 * 3 + 1];
1635 real_t v0z = v[vi0 * 3 + 2];
1637 real_t v0x_2 = v[vi0_2 * 3 + 0];
1638 real_t v0y_2 = v[vi0_2 * 3 + 1];
1639 real_t v0z_2 = v[vi0_2 * 3 + 2];
1641 const TinyObjPoint point1(v0x, v0y, v0z);
1642 const TinyObjPoint point2(v0x_2, v0y_2, v0z_2);
1644 TinyObjPoint a(point1.x - point2.x, point1.y - point2.y,
1645 point1.z - point2.z);
1646 TinyObjPoint b(point1.x + point2.x, point1.y + point2.y,
1647 point1.z + point2.z);
1653 real_t length_n = GetLength(n);
1655 if (length_n <= 0) {
1664 TinyObjPoint axis_w, axis_v, axis_u;
1667 if (std::fabs(axis_w.x) >
real_t(0.9999999)) {
1668 a = TinyObjPoint(0, 1, 0);
1670 a = TinyObjPoint(1, 0, 0);
1672 axis_v = Normalize(cross(axis_w, a));
1673 axis_u = cross(axis_w, axis_v);
1674 using Point = std::array<real_t, 2>;
1678 std::vector<std::vector<Point> > polygon;
1680 std::vector<Point> polyline;
1687 for (
size_t k = 0; k < npolys; k++) {
1688 i0 = face.vertex_indices[k];
1689 size_t vi0 = size_t(i0.v_idx);
1691 assert(((3 * vi0 + 2) < v.size()));
1693 real_t v0x = v[vi0 * 3 + 0];
1694 real_t v0y = v[vi0 * 3 + 1];
1695 real_t v0z = v[vi0 * 3 + 2];
1697 TinyObjPoint polypoint(v0x, v0y, v0z);
1698 TinyObjPoint loc = WorldToLocal(polypoint, axis_u, axis_v, axis_w);
1700 polyline.push_back({loc.x, loc.y});
1703 polygon.push_back(polyline);
1704 std::vector<uint32_t> indices = mapbox::earcut<uint32_t>(polygon);
1707 assert(indices.size() % 3 == 0);
1710 for (
size_t k = 0; k < indices.size() / 3; k++) {
1713 idx0.
vertex_index = face.vertex_indices[indices[3 * k + 0]].v_idx;
1715 face.vertex_indices[indices[3 * k + 0]].vn_idx;
1716 idx0.texcoord_index =
1717 face.vertex_indices[indices[3 * k + 0]].vt_idx;
1718 idx1.vertex_index = face.vertex_indices[indices[3 * k + 1]].v_idx;
1720 face.vertex_indices[indices[3 * k + 1]].vn_idx;
1721 idx1.texcoord_index =
1722 face.vertex_indices[indices[3 * k + 1]].vt_idx;
1723 idx2.vertex_index = face.vertex_indices[indices[3 * k + 2]].v_idx;
1725 face.vertex_indices[indices[3 * k + 2]].vn_idx;
1726 idx2.texcoord_index =
1727 face.vertex_indices[indices[3 * k + 2]].vt_idx;
1729 shape->mesh.indices.push_back(idx0);
1730 shape->mesh.indices.push_back(idx1);
1731 shape->mesh.indices.push_back(idx2);
1733 shape->mesh.num_face_vertices.push_back(3);
1734 shape->mesh.material_ids.push_back(material_id);
1735 shape->mesh.smoothing_group_ids.push_back(
1736 face.smoothing_group_id);
1741 vertex_index_t i0 = face.vertex_indices[0];
1742 vertex_index_t i1(-1);
1743 vertex_index_t i2 = face.vertex_indices[1];
1746 size_t axes[2] = {1, 2};
1747 for (
size_t k = 0; k < npolys; ++k) {
1748 i0 = face.vertex_indices[(k + 0) % npolys];
1749 i1 = face.vertex_indices[(k + 1) % npolys];
1750 i2 = face.vertex_indices[(k + 2) % npolys];
1751 size_t vi0 = size_t(i0.v_idx);
1752 size_t vi1 = size_t(i1.v_idx);
1753 size_t vi2 = size_t(i2.v_idx);
1755 if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) ||
1756 ((3 * vi2 + 2) >= v.size())) {
1761 real_t v0x = v[vi0 * 3 + 0];
1762 real_t v0y = v[vi0 * 3 + 1];
1763 real_t v0z = v[vi0 * 3 + 2];
1764 real_t v1x = v[vi1 * 3 + 0];
1765 real_t v1y = v[vi1 * 3 + 1];
1766 real_t v1z = v[vi1 * 3 + 2];
1767 real_t v2x = v[vi2 * 3 + 0];
1768 real_t v2y = v[vi2 * 3 + 1];
1769 real_t v2z = v[vi2 * 3 + 2];
1776 real_t cx = std::fabs(e0y * e1z - e0z * e1y);
1777 real_t cy = std::fabs(e0z * e1x - e0x * e1z);
1778 real_t cz = std::fabs(e0x * e1y - e0y * e1x);
1779 const real_t epsilon = std::numeric_limits<real_t>::epsilon();
1782 if (cx > epsilon || cy > epsilon || cz > epsilon) {
1785 if (cx > cy && cx > cz) {
1790 if (cz > cx && cz > cy) {
1799 face_t remainingFace = face;
1800 size_t guess_vert = 0;
1801 vertex_index_t ind[3];
1807 size_t remainingIterations = face.vertex_indices.size();
1808 size_t previousRemainingVertices =
1809 remainingFace.vertex_indices.size();
1811 while (remainingFace.vertex_indices.size() > 3 &&
1812 remainingIterations > 0) {
1816 npolys = remainingFace.vertex_indices.size();
1817 if (guess_vert >= npolys) {
1818 guess_vert -= npolys;
1821 if (previousRemainingVertices != npolys) {
1823 previousRemainingVertices = npolys;
1824 remainingIterations = npolys;
1828 remainingIterations--;
1831 for (
size_t k = 0; k < 3; k++) {
1832 ind[k] = remainingFace.vertex_indices[(guess_vert + k) % npolys];
1833 size_t vi = size_t(ind[k].v_idx);
1834 if (((vi * 3 + axes[0]) >= v.size()) ||
1835 ((vi * 3 + axes[1]) >= v.size())) {
1837 vx[k] =
static_cast<real_t>(0.0);
1838 vy[k] =
static_cast<real_t>(0.0);
1840 vx[k] = v[vi * 3 + axes[0]];
1841 vy[k] = v[vi * 3 + axes[1]];
1848 real_t e0x = vx[1] - vx[0];
1849 real_t e0y = vy[1] - vy[0];
1850 real_t e1x = vx[2] - vx[1];
1851 real_t e1y = vy[2] - vy[1];
1852 real_t cross = e0x * e1y - e0y * e1x;
1858 (vx[0] * vy[1] - vy[0] * vx[1]) *
static_cast<real_t>(0.5);
1861 if (cross * area <
static_cast<real_t>(0.0)) {
1869 bool overlap =
false;
1870 for (
size_t otherVert = 3; otherVert < npolys; ++otherVert) {
1871 size_t idx = (guess_vert + otherVert) % npolys;
1873 if (idx >= remainingFace.vertex_indices.size()) {
1879 size_t ovi = size_t(remainingFace.vertex_indices[idx].v_idx);
1881 if (((ovi * 3 + axes[0]) >= v.size()) ||
1882 ((ovi * 3 + axes[1]) >= v.size())) {
1887 real_t tx = v[ovi * 3 + axes[0]];
1888 real_t ty = v[ovi * 3 + axes[1]];
1889 if (pnpoly(3, vx, vy, tx, ty)) {
1906 idx0.normal_index = ind[0].vn_idx;
1907 idx0.texcoord_index = ind[0].vt_idx;
1908 idx1.vertex_index = ind[1].v_idx;
1909 idx1.normal_index = ind[1].vn_idx;
1910 idx1.texcoord_index = ind[1].vt_idx;
1911 idx2.vertex_index = ind[2].v_idx;
1912 idx2.normal_index = ind[2].vn_idx;
1913 idx2.texcoord_index = ind[2].vt_idx;
1915 shape->mesh.indices.push_back(idx0);
1916 shape->mesh.indices.push_back(idx1);
1917 shape->mesh.indices.push_back(idx2);
1919 shape->mesh.num_face_vertices.push_back(3);
1920 shape->mesh.material_ids.push_back(material_id);
1921 shape->mesh.smoothing_group_ids.push_back(
1922 face.smoothing_group_id);
1926 size_t removed_vert_index = (guess_vert + 1) % npolys;
1927 while (removed_vert_index + 1 < npolys) {
1928 remainingFace.vertex_indices[removed_vert_index] =
1929 remainingFace.vertex_indices[removed_vert_index + 1];
1930 removed_vert_index += 1;
1932 remainingFace.vertex_indices.pop_back();
1937 if (remainingFace.vertex_indices.size() == 3) {
1938 i0 = remainingFace.vertex_indices[0];
1939 i1 = remainingFace.vertex_indices[1];
1940 i2 = remainingFace.vertex_indices[2];
1944 idx0.normal_index = i0.vn_idx;
1945 idx0.texcoord_index = i0.vt_idx;
1946 idx1.vertex_index = i1.v_idx;
1947 idx1.normal_index = i1.vn_idx;
1948 idx1.texcoord_index = i1.vt_idx;
1949 idx2.vertex_index = i2.v_idx;
1950 idx2.normal_index = i2.vn_idx;
1951 idx2.texcoord_index = i2.vt_idx;
1953 shape->mesh.indices.push_back(idx0);
1954 shape->mesh.indices.push_back(idx1);
1955 shape->mesh.indices.push_back(idx2);
1957 shape->mesh.num_face_vertices.push_back(3);
1958 shape->mesh.material_ids.push_back(material_id);
1959 shape->mesh.smoothing_group_ids.push_back(
1960 face.smoothing_group_id);
1966 for (
size_t k = 0; k < npolys; k++) {
1969 idx.normal_index = face.vertex_indices[k].vn_idx;
1970 idx.texcoord_index = face.vertex_indices[k].vt_idx;
1971 shape->mesh.indices.push_back(idx);
1974 shape->mesh.num_face_vertices.push_back(
1975 static_cast<unsigned int>(npolys));
1976 shape->mesh.material_ids.push_back(material_id);
1977 shape->mesh.smoothing_group_ids.push_back(
1978 face.smoothing_group_id);
1982 shape->mesh.tags = tags;
1986 if (!prim_group.lineGroup.empty()) {
1988 for (
size_t i = 0; i < prim_group.lineGroup.size(); i++) {
1989 for (
size_t j = 0; j < prim_group.lineGroup[i].vertex_indices.size();
1991 const vertex_index_t &vi = prim_group.lineGroup[i].vertex_indices[j];
1995 idx.normal_index = vi.vn_idx;
1996 idx.texcoord_index = vi.vt_idx;
1998 shape->lines.indices.push_back(idx);
2001 shape->lines.num_line_vertices.push_back(
2002 int(prim_group.lineGroup[i].vertex_indices.size()));
2007 if (!prim_group.pointsGroup.empty()) {
2009 for (
size_t i = 0; i < prim_group.pointsGroup.size(); i++) {
2010 for (
size_t j = 0; j < prim_group.pointsGroup[i].vertex_indices.size();
2012 const vertex_index_t &vi = prim_group.pointsGroup[i].vertex_indices[j];
2016 idx.normal_index = vi.vn_idx;
2017 idx.texcoord_index = vi.vt_idx;
2019 shape->points.indices.push_back(idx);
2029static void SplitString(
const std::string &s,
char delim,
char escape,
2030 std::vector<std::string> &elems) {
2033 bool escaping =
false;
2034 for (
size_t i = 0; i < s.size(); ++i) {
2038 }
else if (ch == escape) {
2041 }
else if (ch == delim) {
2042 if (!token.empty()) {
2043 elems.push_back(token);
2051 elems.push_back(token);
2054static std::string JoinPath(
const std::string &dir,
2055 const std::string &filename) {
2060 char lastChar = *dir.rbegin();
2061 if (lastChar !=
'/') {
2062 return dir + std::string(
"/") + filename;
2064 return dir + filename;
2069void LoadMtl(std::map<std::string, int> *material_map,
2070 std::vector<material_t> *materials, std::istream *inStream,
2071 std::string *warning, std::string *err) {
2076 InitMaterial(&material);
2080 bool has_tr =
false;
2084 bool has_kd =
false;
2086 std::stringstream warn_ss;
2089 std::string linebuf;
2090 while (inStream->peek() != -1) {
2091 safeGetline(*inStream, linebuf);
2095 if (linebuf.size() > 0) {
2096 linebuf = linebuf.substr(0, linebuf.find_last_not_of(
" \t") + 1);
2100 if (linebuf.size() > 0) {
2101 if (linebuf[linebuf.size() - 1] ==
'\n')
2102 linebuf.erase(linebuf.size() - 1);
2104 if (linebuf.size() > 0) {
2105 if (linebuf[linebuf.size() - 1] ==
'\r')
2106 linebuf.erase(linebuf.size() - 1);
2110 if (linebuf.empty()) {
2115 const char *token = linebuf.c_str();
2116 token += strspn(token,
" \t");
2119 if (token[0] ==
'\0')
continue;
2121 if (token[0] ==
'#')
continue;
2124 if ((0 == strncmp(token,
"newmtl", 6)) && IS_SPACE((token[6]))) {
2126 if (!material.name.empty()) {
2127 material_map->insert(std::pair<std::string, int>(
2128 material.name,
static_cast<int>(materials->size())));
2129 materials->push_back(material);
2133 InitMaterial(&material);
2142 std::string namebuf = parseString(&token);
2144 if (namebuf.empty()) {
2146 (*warning) +=
"empty material name in `newmtl`\n";
2149 material.name = namebuf;
2155 if (token[0] ==
'K' && token[1] ==
'a' && IS_SPACE((token[2]))) {
2158 parseReal3(&r, &g, &b, &token);
2159 material.ambient[0] = r;
2160 material.ambient[1] = g;
2161 material.ambient[2] = b;
2166 if (token[0] ==
'K' && token[1] ==
'd' && IS_SPACE((token[2]))) {
2169 parseReal3(&r, &g, &b, &token);
2170 material.diffuse[0] = r;
2171 material.diffuse[1] = g;
2172 material.diffuse[2] = b;
2178 if (token[0] ==
'K' && token[1] ==
's' && IS_SPACE((token[2]))) {
2181 parseReal3(&r, &g, &b, &token);
2182 material.specular[0] = r;
2183 material.specular[1] = g;
2184 material.specular[2] = b;
2189 if ((token[0] ==
'K' && token[1] ==
't' && IS_SPACE((token[2]))) ||
2190 (token[0] ==
'T' && token[1] ==
'f' && IS_SPACE((token[2])))) {
2193 parseReal3(&r, &g, &b, &token);
2194 material.transmittance[0] = r;
2195 material.transmittance[1] = g;
2196 material.transmittance[2] = b;
2201 if (token[0] ==
'N' && token[1] ==
'i' && IS_SPACE((token[2]))) {
2203 material.ior = parseReal(&token);
2208 if (token[0] ==
'K' && token[1] ==
'e' && IS_SPACE(token[2])) {
2211 parseReal3(&r, &g, &b, &token);
2212 material.emission[0] = r;
2213 material.emission[1] = g;
2214 material.emission[2] = b;
2219 if (token[0] ==
'N' && token[1] ==
's' && IS_SPACE(token[2])) {
2221 material.shininess = parseReal(&token);
2226 if (0 == strncmp(token,
"illum", 5) && IS_SPACE(token[5])) {
2228 material.illum = parseInt(&token);
2233 if ((token[0] ==
'd' && IS_SPACE(token[1]))) {
2235 material.dissolve = parseReal(&token);
2238 warn_ss <<
"Both `d` and `Tr` parameters defined for \""
2240 <<
"\". Use the value of `d` for dissolve (line " << line_no
2246 if (token[0] ==
'T' && token[1] ==
'r' && IS_SPACE(token[2])) {
2250 warn_ss <<
"Both `d` and `Tr` parameters defined for \""
2252 <<
"\". Use the value of `d` for dissolve (line " << line_no
2258 material.dissolve =
static_cast<real_t>(1.0) - parseReal(&token);
2265 if (token[0] ==
'P' && token[1] ==
'r' && IS_SPACE(token[2])) {
2267 material.roughness = parseReal(&token);
2272 if (token[0] ==
'P' && token[1] ==
'm' && IS_SPACE(token[2])) {
2274 material.metallic = parseReal(&token);
2279 if (token[0] ==
'P' && token[1] ==
's' && IS_SPACE(token[2])) {
2281 material.sheen = parseReal(&token);
2286 if (token[0] ==
'P' && token[1] ==
'c' && IS_SPACE(token[2])) {
2288 material.clearcoat_thickness = parseReal(&token);
2293 if ((0 == strncmp(token,
"Pcr", 3)) && IS_SPACE(token[3])) {
2295 material.clearcoat_roughness = parseReal(&token);
2300 if ((0 == strncmp(token,
"aniso", 5)) && IS_SPACE(token[5])) {
2302 material.anisotropy = parseReal(&token);
2307 if ((0 == strncmp(token,
"anisor", 6)) && IS_SPACE(token[6])) {
2309 material.anisotropy_rotation = parseReal(&token);
2314 if ((0 == strncmp(token,
"map_Ka", 6)) && IS_SPACE(token[6])) {
2317 &(material.ambient_texopt), token);
2322 if ((0 == strncmp(token,
"map_Kd", 6)) && IS_SPACE(token[6])) {
2325 &(material.diffuse_texopt), token);
2330 material.diffuse[0] =
static_cast<real_t>(0.6);
2331 material.diffuse[1] =
static_cast<real_t>(0.6);
2332 material.diffuse[2] =
static_cast<real_t>(0.6);
2339 if ((0 == strncmp(token,
"map_Ks", 6)) && IS_SPACE(token[6])) {
2342 &(material.specular_texopt), token);
2347 if ((0 == strncmp(token,
"map_Ns", 6)) && IS_SPACE(token[6])) {
2350 &(material.specular_highlight_texopt), token);
2355 if (((0 == strncmp(token,
"map_bump", 8)) ||
2356 (0 == strncmp(token,
"map_Bump", 8))) &&
2357 IS_SPACE(token[8])) {
2360 &(material.bump_texopt), token);
2365 if ((0 == strncmp(token,
"bump", 4)) && IS_SPACE(token[4])) {
2368 &(material.bump_texopt), token);
2373 if ((0 == strncmp(token,
"map_d", 5)) && IS_SPACE(token[5])) {
2375 material.alpha_texname = token;
2377 &(material.alpha_texopt), token);
2382 if (((0 == strncmp(token,
"map_disp", 8)) ||
2383 (0 == strncmp(token,
"map_Disp", 8))) &&
2384 IS_SPACE(token[8])) {
2387 &(material.displacement_texopt), token);
2392 if ((0 == strncmp(token,
"disp", 4)) && IS_SPACE(token[4])) {
2395 &(material.displacement_texopt), token);
2400 if ((0 == strncmp(token,
"refl", 4)) && IS_SPACE(token[4])) {
2403 &(material.reflection_texopt), token);
2408 if ((0 == strncmp(token,
"map_Pr", 6)) && IS_SPACE(token[6])) {
2411 &(material.roughness_texopt), token);
2416 if ((0 == strncmp(token,
"map_Pm", 6)) && IS_SPACE(token[6])) {
2419 &(material.metallic_texopt), token);
2424 if ((0 == strncmp(token,
"map_Ps", 6)) && IS_SPACE(token[6])) {
2427 &(material.sheen_texopt), token);
2432 if ((0 == strncmp(token,
"map_Ke", 6)) && IS_SPACE(token[6])) {
2435 &(material.emissive_texopt), token);
2440 if ((0 == strncmp(token,
"norm", 4)) && IS_SPACE(token[4])) {
2443 &(material.normal_texopt), token);
2448 const char *_space = strchr(token,
' ');
2450 _space = strchr(token,
'\t');
2453 std::ptrdiff_t len = _space - token;
2454 std::string key(token,
static_cast<size_t>(len));
2455 std::string value = _space + 1;
2456 material.unknown_parameter.insert(
2457 std::pair<std::string, std::string>(key, value));
2461 material_map->insert(std::pair<std::string, int>(
2462 material.name,
static_cast<int>(materials->size())));
2463 materials->push_back(material);
2466 (*warning) = warn_ss.str();
2471 std::vector<material_t> *materials,
2472 std::map<std::string, int> *matMap,
2473 std::string *warn, std::string *err) {
2474 if (!m_mtlBaseDir.empty()) {
2482 std::vector<std::string> paths;
2483 std::istringstream f(m_mtlBaseDir);
2486 while (getline(f, s, sep)) {
2490 for (
size_t i = 0; i < paths.size(); i++) {
2491 std::string filepath = JoinPath(paths[i], matId);
2493 std::ifstream matIStream(filepath.c_str());
2495 LoadMtl(matMap, materials, &matIStream, warn, err);
2501 std::stringstream ss;
2502 ss <<
"Material file [ " << matId
2503 <<
" ] not found in a path : " << m_mtlBaseDir <<
"\n";
2505 (*warn) += ss.str();
2510 std::string filepath = matId;
2511 std::ifstream matIStream(filepath.c_str());
2513 LoadMtl(matMap, materials, &matIStream, warn, err);
2518 std::stringstream ss;
2519 ss <<
"Material file [ " << filepath
2520 <<
" ] not found in a path : " << m_mtlBaseDir <<
"\n";
2522 (*warn) += ss.str();
2530 std::vector<material_t> *materials,
2531 std::map<std::string, int> *matMap,
2532 std::string *warn, std::string *err) {
2536 std::stringstream ss;
2537 ss <<
"Material stream in error state. \n";
2539 (*warn) += ss.str();
2544 LoadMtl(matMap, materials, &m_inStream, warn, err);
2550 std::vector<material_t> *materials, std::string *warn,
2551 std::string *err,
const char *filename,
const char *mtl_basedir,
2552 bool triangulate,
bool default_vcols_fallback) {
2553 attrib->vertices.clear();
2554 attrib->normals.clear();
2555 attrib->texcoords.clear();
2556 attrib->colors.clear();
2559 std::stringstream errss;
2561 std::ifstream ifs(filename);
2563 errss <<
"Cannot open file [" << filename <<
"]\n";
2565 (*err) = errss.str();
2570 std::string baseDir = mtl_basedir ? mtl_basedir :
"";
2571 if (!baseDir.empty()) {
2573 const char dirsep =
'/';
2575 const char dirsep =
'\\';
2577 if (baseDir[baseDir.length() - 1] != dirsep) baseDir += dirsep;
2581 return LoadObj(attrib, shapes, materials, warn, err, &ifs, &matFileReader,
2582 triangulate, default_vcols_fallback);
2586 std::vector<material_t> *materials, std::string *warn,
2587 std::string *err, std::istream *inStream,
2589 bool default_vcols_fallback) {
2590 std::stringstream errss;
2592 std::vector<real_t> v;
2593 std::vector<real_t> vertex_weights;
2594 std::vector<real_t> vn;
2595 std::vector<real_t> vt;
2596 std::vector<real_t> vc;
2597 std::vector<skin_weight_t> vw;
2598 std::vector<tag_t> tags;
2599 PrimGroup prim_group;
2603 std::set<std::string> material_filenames;
2604 std::map<std::string, int> material_map;
2608 unsigned int current_smoothing_id =
2611 int greatest_v_idx = -1;
2612 int greatest_vn_idx = -1;
2613 int greatest_vt_idx = -1;
2617 bool found_all_colors =
true;
2619 size_t line_num = 0;
2620 std::string linebuf;
2621 while (inStream->peek() != -1) {
2622 safeGetline(*inStream, linebuf);
2627 if (linebuf.size() > 0) {
2628 if (linebuf[linebuf.size() - 1] ==
'\n')
2629 linebuf.erase(linebuf.size() - 1);
2631 if (linebuf.size() > 0) {
2632 if (linebuf[linebuf.size() - 1] ==
'\r')
2633 linebuf.erase(linebuf.size() - 1);
2637 if (linebuf.empty()) {
2642 const char *token = linebuf.c_str();
2643 token += strspn(token,
" \t");
2646 if (token[0] ==
'\0')
continue;
2648 if (token[0] ==
'#')
continue;
2651 if (token[0] ==
'v' && IS_SPACE((token[1]))) {
2656 int num_components = parseVertexWithColor(&x, &y, &z, &r, &g, &b, &token);
2657 found_all_colors &= (num_components == 6);
2663 vertex_weights.push_back(
2666 if ((num_components == 6) || default_vcols_fallback) {
2676 if (token[0] ==
'v' && token[1] ==
'n' && IS_SPACE((token[2]))) {
2679 parseReal3(&x, &y, &z, &token);
2687 if (token[0] ==
'v' && token[1] ==
't' && IS_SPACE((token[2]))) {
2690 parseReal2(&x, &y, &token);
2697 if (token[0] ==
'v' && token[1] ==
'w' && IS_SPACE((token[2]))) {
2706 vid = parseInt(&token);
2712 while (!IS_NEW_LINE(token[0]) && token[0] !=
'#') {
2716 parseReal2(&j, &w, &token, -1.0);
2718 if (j <
static_cast<real_t>(0)) {
2720 std::stringstream ss;
2721 ss <<
"Failed parse `vw' line. joint_id is negative. "
2723 << line_num <<
".)\n";
2734 sw.weightValues.push_back(jw);
2736 size_t n = strspn(token,
" \t\r");
2743 warning_context context;
2744 context.warn = warn;
2745 context.line_number = line_num;
2748 if (token[0] ==
'l' && IS_SPACE((token[1]))) {
2753 while (!IS_NEW_LINE(token[0]) && token[0] !=
'#') {
2755 if (!parseTriple(&token,
static_cast<int>(v.size() / 3),
2756 static_cast<int>(vn.size() / 3),
2757 static_cast<int>(vt.size() / 2), &vi, context)) {
2760 "Failed to parse `l' line (e.g. a zero value for vertex index. "
2762 toString(line_num) +
").\n";
2767 line.vertex_indices.push_back(vi);
2769 size_t n = strspn(token,
" \t\r");
2773 prim_group.lineGroup.push_back(line);
2779 if (token[0] ==
'p' && IS_SPACE((token[1]))) {
2784 while (!IS_NEW_LINE(token[0]) && token[0] !=
'#') {
2786 if (!parseTriple(&token,
static_cast<int>(v.size() / 3),
2787 static_cast<int>(vn.size() / 3),
2788 static_cast<int>(vt.size() / 2), &vi, context)) {
2791 "Failed to parse `p' line (e.g. a zero value for vertex index. "
2793 toString(line_num) +
").\n";
2798 pts.vertex_indices.push_back(vi);
2800 size_t n = strspn(token,
" \t\r");
2804 prim_group.pointsGroup.push_back(pts);
2810 if (token[0] ==
'f' && IS_SPACE((token[1]))) {
2812 token += strspn(token,
" \t");
2816 face.smoothing_group_id = current_smoothing_id;
2817 face.vertex_indices.reserve(3);
2819 while (!IS_NEW_LINE(token[0]) && token[0] !=
'#') {
2821 if (!parseTriple(&token,
static_cast<int>(v.size() / 3),
2822 static_cast<int>(vn.size() / 3),
2823 static_cast<int>(vt.size() / 2), &vi, context)) {
2826 "Failed to parse `f' line (e.g. a zero value for vertex index "
2827 "or invalid relative vertex index). Line " +
2828 toString(line_num) +
").\n";
2833 greatest_v_idx = greatest_v_idx > vi.v_idx ? greatest_v_idx : vi.v_idx;
2835 greatest_vn_idx > vi.vn_idx ? greatest_vn_idx : vi.vn_idx;
2837 greatest_vt_idx > vi.vt_idx ? greatest_vt_idx : vi.vt_idx;
2839 face.vertex_indices.push_back(vi);
2840 size_t n = strspn(token,
" \t\r");
2845 prim_group.faceGroup.push_back(face);
2851 if ((0 == strncmp(token,
"usemtl", 6))) {
2853 std::string namebuf = parseString(&token);
2855 int newMaterialId = -1;
2856 std::map<std::string, int>::const_iterator it =
2857 material_map.find(namebuf);
2858 if (it != material_map.end()) {
2859 newMaterialId = it->second;
2863 (*warn) +=
"material [ '" + namebuf +
"' ] not found in .mtl\n";
2867 if (newMaterialId != material) {
2871 exportGroupsToShape(&shape, prim_group, tags, material, name,
2872 triangulate, v, warn);
2873 prim_group.faceGroup.clear();
2874 material = newMaterialId;
2881 if ((0 == strncmp(token,
"mtllib", 6)) && IS_SPACE((token[6]))) {
2885 std::vector<std::string> filenames;
2886 SplitString(std::string(token),
' ',
'\\', filenames);
2888 if (filenames.empty()) {
2890 std::stringstream ss;
2891 ss <<
"Looks like empty filename for mtllib. Use default "
2893 << line_num <<
".)\n";
2895 (*warn) += ss.str();
2899 for (
size_t s = 0; s < filenames.size(); s++) {
2900 if (material_filenames.count(filenames[s]) > 0) {
2905 std::string warn_mtl;
2906 std::string err_mtl;
2907 bool ok = (*readMatFn)(filenames[s].c_str(), materials,
2908 &material_map, &warn_mtl, &err_mtl);
2909 if (warn && (!warn_mtl.empty())) {
2910 (*warn) += warn_mtl;
2913 if (err && (!err_mtl.empty())) {
2919 material_filenames.insert(filenames[s]);
2927 "Failed to load material file(s). Use default "
2938 if (token[0] ==
'g' && IS_SPACE((token[1]))) {
2940 bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
2941 triangulate, v, warn);
2944 if (shape.mesh.indices.size() > 0) {
2945 shapes->push_back(shape);
2953 std::vector<std::string> names;
2955 while (!IS_NEW_LINE(token[0]) && token[0] !=
'#') {
2956 std::string str = parseString(&token);
2957 names.push_back(str);
2958 token += strspn(token,
" \t\r");
2963 if (names.size() < 2) {
2966 std::stringstream ss;
2967 ss <<
"Empty group name. line: " << line_num <<
"\n";
2968 (*warn) += ss.str();
2972 std::stringstream ss;
2979 for (
size_t i = 2; i < names.size(); i++) {
2980 ss <<
" " << names[i];
2990 if (token[0] ==
'o' && IS_SPACE((token[1]))) {
2992 bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
2993 triangulate, v, warn);
2996 if (shape.mesh.indices.size() > 0 || shape.lines.indices.size() > 0 ||
2997 shape.points.indices.size() > 0) {
2998 shapes->push_back(shape);
3007 std::stringstream ss;
3014 if (token[0] ==
't' && IS_SPACE(token[1])) {
3015 const int max_tag_nums = 8192;
3020 tag.
name = parseString(&token);
3022 tag_sizes ts = parseTagTriple(&token);
3024 if (ts.num_ints < 0) {
3027 if (ts.num_ints > max_tag_nums) {
3028 ts.num_ints = max_tag_nums;
3031 if (ts.num_reals < 0) {
3034 if (ts.num_reals > max_tag_nums) {
3035 ts.num_reals = max_tag_nums;
3038 if (ts.num_strings < 0) {
3041 if (ts.num_strings > max_tag_nums) {
3042 ts.num_strings = max_tag_nums;
3045 tag.intValues.resize(
static_cast<size_t>(ts.num_ints));
3047 for (
size_t i = 0; i < static_cast<size_t>(ts.num_ints); ++i) {
3048 tag.intValues[i] = parseInt(&token);
3051 tag.floatValues.resize(
static_cast<size_t>(ts.num_reals));
3052 for (
size_t i = 0; i < static_cast<size_t>(ts.num_reals); ++i) {
3053 tag.floatValues[i] = parseReal(&token);
3056 tag.stringValues.resize(
static_cast<size_t>(ts.num_strings));
3057 for (
size_t i = 0; i < static_cast<size_t>(ts.num_strings); ++i) {
3058 tag.stringValues[i] = parseString(&token);
3061 tags.push_back(tag);
3066 if (token[0] ==
's' && IS_SPACE(token[1])) {
3071 token += strspn(token,
" \t");
3073 if (token[0] ==
'\0') {
3077 if (token[0] ==
'\r' || token[1] ==
'\n') {
3081 if (strlen(token) >= 3 && token[0] ==
'o' && token[1] ==
'f' &&
3083 current_smoothing_id = 0;
3086 int smGroupId = parseInt(&token);
3087 if (smGroupId < 0) {
3090 current_smoothing_id = 0;
3092 current_smoothing_id =
static_cast<unsigned int>(smGroupId);
3103 if (!found_all_colors && !default_vcols_fallback) {
3107 if (greatest_v_idx >=
static_cast<int>(v.size() / 3)) {
3109 std::stringstream ss;
3110 ss <<
"Vertex indices out of bounds (line " << line_num <<
".)\n\n";
3111 (*warn) += ss.str();
3114 if (greatest_vn_idx >=
static_cast<int>(vn.size() / 3)) {
3116 std::stringstream ss;
3117 ss <<
"Vertex normal indices out of bounds (line " << line_num
3119 (*warn) += ss.str();
3122 if (greatest_vt_idx >=
static_cast<int>(vt.size() / 2)) {
3124 std::stringstream ss;
3125 ss <<
"Vertex texcoord indices out of bounds (line " << line_num
3127 (*warn) += ss.str();
3131 bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
3132 triangulate, v, warn);
3137 if (ret || shape.mesh.indices
3139 shapes->push_back(shape);
3144 (*err) += errss.str();
3147 attrib->vertices.swap(v);
3148 attrib->vertex_weights.swap(vertex_weights);
3149 attrib->normals.swap(vn);
3150 attrib->texcoords.swap(vt);
3151 attrib->texcoord_ws.swap(vt);
3152 attrib->colors.swap(vc);
3153 attrib->skin_weights.swap(vw);
3158bool LoadObjWithCallback(std::istream &inStream,
const callback_t &callback,
3162 std::string *err ) {
3163 std::stringstream errss;
3166 std::set<std::string> material_filenames;
3167 std::map<std::string, int> material_map;
3168 int material_id = -1;
3170 std::vector<index_t> indices;
3171 std::vector<material_t> materials;
3172 std::vector<std::string> names;
3174 std::vector<const char *> names_out;
3176 std::string linebuf;
3177 while (inStream.peek() != -1) {
3178 safeGetline(inStream, linebuf);
3181 if (linebuf.size() > 0) {
3182 if (linebuf[linebuf.size() - 1] ==
'\n')
3183 linebuf.erase(linebuf.size() - 1);
3185 if (linebuf.size() > 0) {
3186 if (linebuf[linebuf.size() - 1] ==
'\r')
3187 linebuf.erase(linebuf.size() - 1);
3191 if (linebuf.empty()) {
3196 const char *token = linebuf.c_str();
3197 token += strspn(token,
" \t");
3200 if (token[0] ==
'\0')
continue;
3202 if (token[0] ==
'#')
continue;
3205 if (token[0] ==
'v' && IS_SPACE((token[1]))) {
3210 int num_components = parseVertexWithColor(&x, &y, &z, &r, &g, &b, &token);
3211 if (callback.vertex_cb) {
3212 callback.vertex_cb(user_data, x, y, z, r);
3214 if (callback.vertex_color_cb) {
3215 bool found_color = (num_components == 6);
3216 callback.vertex_color_cb(user_data, x, y, z, r, g, b, found_color);
3222 if (token[0] ==
'v' && token[1] ==
'n' && IS_SPACE((token[2]))) {
3225 parseReal3(&x, &y, &z, &token);
3226 if (callback.normal_cb) {
3227 callback.normal_cb(user_data, x, y, z);
3233 if (token[0] ==
'v' && token[1] ==
't' && IS_SPACE((token[2]))) {
3236 parseReal3(&x, &y, &z, &token);
3237 if (callback.texcoord_cb) {
3238 callback.texcoord_cb(user_data, x, y, z);
3244 if (token[0] ==
'f' && IS_SPACE((token[1]))) {
3246 token += strspn(token,
" \t");
3249 while (!IS_NEW_LINE(token[0]) && token[0] !=
'#') {
3250 vertex_index_t vi = parseRawTriple(&token);
3254 idx.normal_index = vi.vn_idx;
3255 idx.texcoord_index = vi.vt_idx;
3257 indices.push_back(idx);
3258 size_t n = strspn(token,
" \t\r");
3262 if (callback.index_cb && indices.size() > 0) {
3263 callback.index_cb(user_data, &indices.at(0),
3264 static_cast<int>(indices.size()));
3271 if ((0 == strncmp(token,
"usemtl", 6)) && IS_SPACE((token[6]))) {
3273 std::stringstream ss;
3275 std::string namebuf = ss.str();
3277 int newMaterialId = -1;
3278 std::map<std::string, int>::const_iterator it =
3279 material_map.find(namebuf);
3280 if (it != material_map.end()) {
3281 newMaterialId = it->second;
3284 if (warn && (!callback.usemtl_cb)) {
3285 (*warn) +=
"material [ " + namebuf +
" ] not found in .mtl\n";
3289 if (newMaterialId != material_id) {
3290 material_id = newMaterialId;
3293 if (callback.usemtl_cb) {
3294 callback.usemtl_cb(user_data, namebuf.c_str(), material_id);
3301 if ((0 == strncmp(token,
"mtllib", 6)) && IS_SPACE((token[6]))) {
3305 std::vector<std::string> filenames;
3306 SplitString(std::string(token),
' ',
'\\', filenames);
3308 if (filenames.empty()) {
3311 "Looks like empty filename for mtllib. Use default "
3316 for (
size_t s = 0; s < filenames.size(); s++) {
3317 if (material_filenames.count(filenames[s]) > 0) {
3322 std::string warn_mtl;
3323 std::string err_mtl;
3324 bool ok = (*readMatFn)(filenames[s].c_str(), &materials,
3325 &material_map, &warn_mtl, &err_mtl);
3327 if (warn && (!warn_mtl.empty())) {
3328 (*warn) += warn_mtl;
3331 if (err && (!err_mtl.empty())) {
3337 material_filenames.insert(filenames[s]);
3345 "Failed to load material file(s). Use default "
3349 if (callback.mtllib_cb) {
3350 callback.mtllib_cb(user_data, &materials.at(0),
3351 static_cast<int>(materials.size()));
3361 if (token[0] ==
'g' && IS_SPACE((token[1]))) {
3364 while (!IS_NEW_LINE(token[0]) && token[0] !=
'#') {
3365 std::string str = parseString(&token);
3366 names.push_back(str);
3367 token += strspn(token,
" \t\r");
3370 assert(names.size() > 0);
3372 if (callback.group_cb) {
3373 if (names.size() > 1) {
3375 names_out.resize(names.size() - 1);
3376 for (
size_t j = 0; j < names_out.size(); j++) {
3377 names_out[j] = names[j + 1].c_str();
3379 callback.group_cb(user_data, &names_out.at(0),
3380 static_cast<int>(names_out.size()));
3383 callback.group_cb(user_data, NULL, 0);
3391 if (token[0] ==
'o' && IS_SPACE((token[1]))) {
3395 std::stringstream ss;
3397 std::string object_name = ss.str();
3399 if (callback.object_cb) {
3400 callback.object_cb(user_data, object_name.c_str());
3407 if (token[0] ==
't' && IS_SPACE(token[1])) {
3411 std::stringstream ss;
3413 tag.
name = ss.str();
3415 token += tag.name.size() + 1;
3417 tag_sizes ts = parseTagTriple(&token);
3419 tag.intValues.resize(
static_cast<size_t>(ts.num_ints));
3421 for (
size_t i = 0; i < static_cast<size_t>(ts.num_ints); ++i) {
3422 tag.intValues[i] = atoi(token);
3423 token += strcspn(token,
"/ \t\r") + 1;
3426 tag.floatValues.resize(
static_cast<size_t>(ts.num_reals));
3427 for (
size_t i = 0; i < static_cast<size_t>(ts.num_reals); ++i) {
3428 tag.floatValues[i] = parseReal(&token);
3429 token += strcspn(token,
"/ \t\r") + 1;
3432 tag.stringValues.resize(
static_cast<size_t>(ts.num_strings));
3433 for (
size_t i = 0; i < static_cast<size_t>(ts.num_strings); ++i) {
3434 std::stringstream ss;
3436 tag.stringValues[i] = ss.str();
3437 token += tag.stringValues[i].size() + 1;
3440 tags.push_back(tag);
3448 (*err) += errss.str();
3456 std::string mtl_search_path;
3458 if (config.mtl_search_path.empty()) {
3463 size_t pos = filename.find_last_of(
"/\\");
3464 if (pos != std::string::npos) {
3465 mtl_search_path = filename.substr(0, pos);
3468 mtl_search_path = config.mtl_search_path;
3471 valid_ =
LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_,
3472 filename.c_str(), mtl_search_path.c_str(),
3473 config.triangulate, config.vertex_color);
3479 const std::string &mtl_text,
3481 std::stringbuf obj_buf(obj_text);
3482 std::stringbuf mtl_buf(mtl_text);
3484 std::istream obj_ifs(&obj_buf);
3485 std::istream mtl_ifs(&mtl_buf);
3487 MaterialStreamReader mtl_ss(mtl_ifs);
3489 valid_ =
LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_,
3490 &obj_ifs, &mtl_ss, config.triangulate, config.vertex_color);
3496#pragma clang diagnostic pop
Definition tiny_obj_loader.h:476
virtual bool operator()(const std::string &matId, std::vector< material_t > *materials, std::map< std::string, int > *matMap, std::string *warn, std::string *err) TINYOBJ_OVERRIDE
MaterialFileReader(const std::string &mtl_basedir)
Definition tiny_obj_loader.h:479
virtual ~MaterialFileReader() TINYOBJ_OVERRIDE
Definition tiny_obj_loader.h:481
Definition tiny_obj_loader.h:462
virtual bool operator()(const std::string &matId, std::vector< material_t > *materials, std::map< std::string, int > *matMap, std::string *warn, std::string *err)=0
MaterialReader()
Definition tiny_obj_loader.h:464
virtual ~MaterialReader()
virtual ~MaterialStreamReader() TINYOBJ_OVERRIDE
Definition tiny_obj_loader.h:498
MaterialStreamReader(std::istream &inStream)
Definition tiny_obj_loader.h:496
virtual bool operator()(const std::string &matId, std::vector< material_t > *materials, std::map< std::string, int > *matMap, std::string *warn, std::string *err) TINYOBJ_OVERRIDE
bool ParseFromFile(const std::string &filename, const ObjReaderConfig &config=ObjReaderConfig())
const attrib_t & GetAttrib() const
Definition tiny_obj_loader.h:567
ObjReader()
Definition tiny_obj_loader.h:539
const std::string & Warning() const
Definition tiny_obj_loader.h:576
const std::string & Error() const
Definition tiny_obj_loader.h:581
const std::vector< material_t > & GetMaterials() const
Definition tiny_obj_loader.h:571
bool ParseFromString(const std::string &obj_text, const std::string &mtl_text, const ObjReaderConfig &config=ObjReaderConfig())
bool Valid() const
Definition tiny_obj_loader.h:565
const std::vector< shape_t > & GetShapes() const
Definition tiny_obj_loader.h:569
Definition tiny_obj_loader.h:71
texture_type_t
Definition tiny_obj_loader.h:153
@ TEXTURE_TYPE_CUBE_LEFT
Definition tiny_obj_loader.h:160
@ TEXTURE_TYPE_CUBE_FRONT
Definition tiny_obj_loader.h:158
@ TEXTURE_TYPE_CUBE_BOTTOM
Definition tiny_obj_loader.h:157
@ TEXTURE_TYPE_NONE
Definition tiny_obj_loader.h:154
@ TEXTURE_TYPE_SPHERE
Definition tiny_obj_loader.h:155
@ TEXTURE_TYPE_CUBE_RIGHT
Definition tiny_obj_loader.h:161
@ TEXTURE_TYPE_CUBE_TOP
Definition tiny_obj_loader.h:156
@ TEXTURE_TYPE_CUBE_BACK
Definition tiny_obj_loader.h:159
void LoadMtl(std::map< std::string, int > *material_map, std::vector< material_t > *materials, std::istream *inStream, std::string *warning, std::string *err)
Loads materials into std::map.
bool LoadObj(attrib_t *attrib, std::vector< shape_t > *shapes, std::vector< material_t > *materials, std::string *warn, std::string *err, std::istream *inStream, MaterialReader *readMatFn=NULL, bool triangulate=true, bool default_vcols_fallback=true)
==>>========= Legacy v1 API =============================================
float real_t
Definition tiny_obj_loader.h:150
bool ParseTextureNameAndOption(std::string *texname, texture_option_t *texopt, const char *linebuf)
Definition tiny_obj_loader.h:509
std::string triangulation_method
Definition tiny_obj_loader.h:515
bool triangulate
Definition tiny_obj_loader.h:510
ObjReaderConfig()
Definition tiny_obj_loader.h:530
bool vertex_color
Definition tiny_obj_loader.h:521
std::string mtl_search_path
Definition tiny_obj_loader.h:528
Definition tiny_obj_loader.h:391
const std::vector< real_t > & GetVertices() const
Definition tiny_obj_loader.h:419
attrib_t()
Definition tiny_obj_loader.h:414
std::vector< real_t > vertices
Definition tiny_obj_loader.h:392
std::vector< real_t > texcoord_ws
Definition tiny_obj_loader.h:401
const std::vector< real_t > & GetVertexWeights() const
Definition tiny_obj_loader.h:421
std::vector< skin_weight_t > skin_weights
Definition tiny_obj_loader.h:412
std::vector< real_t > vertex_weights
Definition tiny_obj_loader.h:395
std::vector< real_t > colors
Definition tiny_obj_loader.h:402
std::vector< real_t > texcoords
Definition tiny_obj_loader.h:397
std::vector< real_t > normals
Definition tiny_obj_loader.h:396
Definition tiny_obj_loader.h:424
void(* mtllib_cb)(void *user_data, const material_t *materials, int num_materials)
Definition tiny_obj_loader.h:444
void(* vertex_color_cb)(void *user_data, real_t x, real_t y, real_t z, real_t r, real_t g, real_t b, bool has_color)
Definition tiny_obj_loader.h:427
void(* index_cb)(void *user_data, index_t *indices, int num_indices)
Definition tiny_obj_loader.h:438
callback_t()
Definition tiny_obj_loader.h:450
void(* vertex_cb)(void *user_data, real_t x, real_t y, real_t z, real_t w)
Definition tiny_obj_loader.h:426
void(* object_cb)(void *user_data, const char *name)
Definition tiny_obj_loader.h:448
void(* group_cb)(void *user_data, const char **names, int num_names)
Definition tiny_obj_loader.h:447
void(* texcoord_cb)(void *user_data, real_t x, real_t y, real_t z)
Definition tiny_obj_loader.h:433
void(* normal_cb)(void *user_data, real_t x, real_t y, real_t z)
Definition tiny_obj_loader.h:429
void(* usemtl_cb)(void *user_data, const char *name, int material_id)
Definition tiny_obj_loader.h:442
Definition tiny_obj_loader.h:351
int vertex_index
Definition tiny_obj_loader.h:352
int texcoord_index
Definition tiny_obj_loader.h:354
int normal_index
Definition tiny_obj_loader.h:353
Definition tiny_obj_loader.h:337
int joint_id
Definition tiny_obj_loader.h:338
real_t weight
Definition tiny_obj_loader.h:339
Definition tiny_obj_loader.h:373
std::vector< int > num_line_vertices
Definition tiny_obj_loader.h:376
std::vector< index_t > indices
Definition tiny_obj_loader.h:375
Definition tiny_obj_loader.h:185
std::string sheen_texname
Definition tiny_obj_loader.h:231
real_t clearcoat_roughness
Definition tiny_obj_loader.h:225
real_t anisotropy
Definition tiny_obj_loader.h:226
real_t metallic
Definition tiny_obj_loader.h:222
std::string reflection_texname
Definition tiny_obj_loader.h:208
texture_option_t diffuse_texopt
Definition tiny_obj_loader.h:211
std::map< std::string, std::string > unknown_parameter
Definition tiny_obj_loader.h:243
std::string alpha_texname
Definition tiny_obj_loader.h:207
real_t clearcoat_thickness
Definition tiny_obj_loader.h:224
std::string name
Definition tiny_obj_loader.h:186
std::string specular_highlight_texname
Definition tiny_obj_loader.h:204
texture_option_t sheen_texopt
Definition tiny_obj_loader.h:237
real_t dissolve
Definition tiny_obj_loader.h:195
std::string emissive_texname
Definition tiny_obj_loader.h:232
int dummy
Definition tiny_obj_loader.h:199
real_t emission[3]
Definition tiny_obj_loader.h:192
texture_option_t displacement_texopt
Definition tiny_obj_loader.h:215
std::string normal_texname
Definition tiny_obj_loader.h:233
texture_option_t bump_texopt
Definition tiny_obj_loader.h:214
real_t diffuse[3]
Definition tiny_obj_loader.h:189
texture_option_t emissive_texopt
Definition tiny_obj_loader.h:238
std::string roughness_texname
Definition tiny_obj_loader.h:229
real_t roughness
Definition tiny_obj_loader.h:221
int pad2
Definition tiny_obj_loader.h:241
texture_option_t reflection_texopt
Definition tiny_obj_loader.h:217
texture_option_t specular_highlight_texopt
Definition tiny_obj_loader.h:213
real_t sheen
Definition tiny_obj_loader.h:223
texture_option_t normal_texopt
Definition tiny_obj_loader.h:239
texture_option_t roughness_texopt
Definition tiny_obj_loader.h:235
real_t anisotropy_rotation
Definition tiny_obj_loader.h:227
std::string displacement_texname
Definition tiny_obj_loader.h:206
real_t transmittance[3]
Definition tiny_obj_loader.h:191
texture_option_t metallic_texopt
Definition tiny_obj_loader.h:236
real_t specular[3]
Definition tiny_obj_loader.h:190
real_t ior
Definition tiny_obj_loader.h:194
real_t ambient[3]
Definition tiny_obj_loader.h:188
std::string bump_texname
Definition tiny_obj_loader.h:205
std::string metallic_texname
Definition tiny_obj_loader.h:230
texture_option_t ambient_texopt
Definition tiny_obj_loader.h:210
std::string diffuse_texname
Definition tiny_obj_loader.h:202
texture_option_t alpha_texopt
Definition tiny_obj_loader.h:216
std::string ambient_texname
Definition tiny_obj_loader.h:201
texture_option_t specular_texopt
Definition tiny_obj_loader.h:212
real_t shininess
Definition tiny_obj_loader.h:193
std::string specular_texname
Definition tiny_obj_loader.h:203
real_t pad0
Definition tiny_obj_loader.h:228
int illum
Definition tiny_obj_loader.h:197
Definition tiny_obj_loader.h:357
std::vector< unsigned int > num_face_vertices
Definition tiny_obj_loader.h:360
std::vector< int > material_ids
Definition tiny_obj_loader.h:362
std::vector< tag_t > tags
Definition tiny_obj_loader.h:366
std::vector< unsigned int > smoothing_group_ids
Definition tiny_obj_loader.h:363
std::vector< index_t > indices
Definition tiny_obj_loader.h:358
Definition tiny_obj_loader.h:379
std::vector< index_t > indices
Definition tiny_obj_loader.h:380
Definition tiny_obj_loader.h:383
mesh_t mesh
Definition tiny_obj_loader.h:385
points_t points
Definition tiny_obj_loader.h:387
std::string name
Definition tiny_obj_loader.h:384
lines_t lines
Definition tiny_obj_loader.h:386
Definition tiny_obj_loader.h:342
int vertex_id
Definition tiny_obj_loader.h:343
std::vector< joint_and_weight_t > weightValues
Definition tiny_obj_loader.h:346
Definition tiny_obj_loader.h:329
std::vector< std::string > stringValues
Definition tiny_obj_loader.h:334
std::vector< real_t > floatValues
Definition tiny_obj_loader.h:333
std::string name
Definition tiny_obj_loader.h:330
std::vector< int > intValues
Definition tiny_obj_loader.h:332
Definition tiny_obj_loader.h:164
real_t sharpness
Definition tiny_obj_loader.h:166
std::string colorspace
Definition tiny_obj_loader.h:181
char imfchan
Definition tiny_obj_loader.h:175
real_t turbulence[3]
Definition tiny_obj_loader.h:171
real_t contrast
Definition tiny_obj_loader.h:168
real_t brightness
Definition tiny_obj_loader.h:167
bool clamp
Definition tiny_obj_loader.h:174
bool blendu
Definition tiny_obj_loader.h:176
real_t scale[3]
Definition tiny_obj_loader.h:170
bool blendv
Definition tiny_obj_loader.h:177
real_t origin_offset[3]
Definition tiny_obj_loader.h:169
int texture_resolution
Definition tiny_obj_loader.h:172
real_t bump_multiplier
Definition tiny_obj_loader.h:178
texture_type_t type
Definition tiny_obj_loader.h:165
#define TINYOBJ_OVERRIDE
Definition tiny_obj_loader.h:77