LLVMFuzzerTestOneInput:
   10|     82|extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
   11|     82|    tinyobj::ObjReaderConfig reader_config;
   12|     82|    tinyobj::ObjReader reader;
   13|     82|    if (Size < 2) {
  ------------------
  |  Branch (13:9): [True: 0, False: 82]
  ------------------
   14|      0|        return 0;
   15|      0|    }
   16|  27.7M|    for (size_t i = 0; i < Size-1; i++) {
  ------------------
  |  Branch (16:24): [True: 27.7M, False: 0]
  ------------------
   17|  27.7M|        if (Data[i] == 0) {
  ------------------
  |  Branch (17:13): [True: 82, False: 27.7M]
  ------------------
   18|     82|            std::string obj_text (reinterpret_cast<const char*>(Data), i);
   19|     82|            std::string mtl_text (reinterpret_cast<const char*>(Data+i+1), Size-i-1);
   20|     82|            reader.ParseFromString(obj_text, mtl_text,reader_config);
   21|     82|            return 0;
   22|     82|        }
   23|  27.7M|    }
   24|      0|    return 0;
   25|     82|}

_ZN7tinyobj14MaterialReaderD2Ev:
  691|     82|MaterialReader::~MaterialReader() {}
_ZN7tinyobj25ParseTextureNameAndOptionEPNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEPNS_16texture_option_tEPKc:
 1248|     63|                               const char *linebuf) {
 1249|       |  // @todo { write more robust lexer and parser. }
 1250|     63|  bool found_texname = false;
 1251|     63|  std::string texture_name;
 1252|       |
 1253|     63|  const char *token = linebuf;  // Assume line ends with NULL
 1254|       |
 1255|    141|  while (!IS_NEW_LINE((*token))) {
  ------------------
  |  |  800|    141|#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
  |  |  ------------------
  |  |  |  Branch (800:25): [True: 0, False: 141]
  |  |  |  Branch (800:42): [True: 0, False: 141]
  |  |  |  Branch (800:59): [True: 63, False: 78]
  |  |  ------------------
  ------------------
 1256|     78|    token += strspn(token, " \t");  // skip space
 1257|     78|    if ((0 == strncmp(token, "-blendu", 7)) && IS_SPACE((token[7]))) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (1257:9): [True: 0, False: 78]
  ------------------
 1258|      0|      token += 8;
 1259|      0|      texopt->blendu = parseOnOff(&token, /* default */ true);
 1260|     78|    } else if ((0 == strncmp(token, "-blendv", 7)) && IS_SPACE((token[7]))) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (1260:16): [True: 0, False: 78]
  ------------------
 1261|      0|      token += 8;
 1262|      0|      texopt->blendv = parseOnOff(&token, /* default */ true);
 1263|     78|    } else if ((0 == strncmp(token, "-clamp", 6)) && IS_SPACE((token[6]))) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (1263:16): [True: 0, False: 78]
  ------------------
 1264|      0|      token += 7;
 1265|      0|      texopt->clamp = parseOnOff(&token, /* default */ true);
 1266|     78|    } else if ((0 == strncmp(token, "-boost", 6)) && IS_SPACE((token[6]))) {
  ------------------
  |  |  797|      2|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 2]
  |  |  |  Branch (797:38): [True: 2, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (1266:16): [True: 2, False: 76]
  ------------------
 1267|      2|      token += 7;
 1268|      2|      texopt->sharpness = parseReal(&token, 1.0);
 1269|     76|    } else if ((0 == strncmp(token, "-bm", 3)) && IS_SPACE((token[3]))) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (1269:16): [True: 0, False: 76]
  ------------------
 1270|      0|      token += 4;
 1271|      0|      texopt->bump_multiplier = parseReal(&token, 1.0);
 1272|     76|    } else if ((0 == strncmp(token, "-o", 2)) && IS_SPACE((token[2]))) {
  ------------------
  |  |  797|      1|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 1]
  |  |  |  Branch (797:38): [True: 0, False: 1]
  |  |  ------------------
  ------------------
  |  Branch (1272:16): [True: 1, False: 75]
  ------------------
 1273|      0|      token += 3;
 1274|      0|      parseReal3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]),
 1275|      0|                 &(texopt->origin_offset[2]), &token);
 1276|     76|    } else if ((0 == strncmp(token, "-s", 2)) && IS_SPACE((token[2]))) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (1276:16): [True: 0, False: 76]
  ------------------
 1277|      0|      token += 3;
 1278|      0|      parseReal3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]),
 1279|      0|                 &token, 1.0, 1.0, 1.0);
 1280|     76|    } else if ((0 == strncmp(token, "-t", 2)) && IS_SPACE((token[2]))) {
  ------------------
  |  |  797|      3|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 3]
  |  |  |  Branch (797:38): [True: 0, False: 3]
  |  |  ------------------
  ------------------
  |  Branch (1280:16): [True: 3, False: 73]
  ------------------
 1281|      0|      token += 3;
 1282|      0|      parseReal3(&(texopt->turbulence[0]), &(texopt->turbulence[1]),
 1283|      0|                 &(texopt->turbulence[2]), &token);
 1284|     76|    } else if ((0 == strncmp(token, "-type", 5)) && IS_SPACE((token[5]))) {
  ------------------
  |  |  797|      1|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 1]
  |  |  |  Branch (797:38): [True: 0, False: 1]
  |  |  ------------------
  ------------------
  |  Branch (1284:16): [True: 1, False: 75]
  ------------------
 1285|      0|      token += 5;
 1286|      0|      texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE);
 1287|     76|    } else if ((0 == strncmp(token, "-texres", 7)) && IS_SPACE((token[7]))) {
  ------------------
  |  |  797|      2|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 2]
  |  |  |  Branch (797:38): [True: 2, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (1287:16): [True: 2, False: 74]
  ------------------
 1288|      2|      token += 7;
 1289|       |      // TODO(syoyo): Check if arg is int type.
 1290|      2|      texopt->texture_resolution = parseInt(&token);
 1291|     74|    } else if ((0 == strncmp(token, "-imfchan", 8)) && IS_SPACE((token[8]))) {
  ------------------
  |  |  797|     18|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 5, False: 13]
  |  |  |  Branch (797:38): [True: 13, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (1291:16): [True: 18, False: 56]
  ------------------
 1292|     18|      token += 9;
 1293|     18|      token += strspn(token, " \t");
 1294|     18|      const char *end = token + strcspn(token, " \t\r");
 1295|     18|      if ((end - token) == 1) {  // Assume one char for -imfchan
  ------------------
  |  Branch (1295:11): [True: 0, False: 18]
  ------------------
 1296|      0|        texopt->imfchan = (*token);
 1297|      0|      }
 1298|     18|      token = end;
 1299|     56|    } else if ((0 == strncmp(token, "-mm", 3)) && IS_SPACE((token[3]))) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (1299:16): [True: 0, False: 56]
  ------------------
 1300|      0|      token += 4;
 1301|      0|      parseReal2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0);
 1302|     56|    } else if ((0 == strncmp(token, "-colorspace", 11)) &&
  ------------------
  |  Branch (1302:16): [True: 0, False: 56]
  ------------------
 1303|     56|               IS_SPACE((token[11]))) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 1304|      0|      token += 12;
 1305|      0|      texopt->colorspace = parseString(&token);
 1306|     56|    } else {
 1307|       |// Assume texture filename
 1308|       |#if 0
 1309|       |      size_t len = strcspn(token, " \t\r");  // untile next space
 1310|       |      texture_name = std::string(token, token + len);
 1311|       |      token += len;
 1312|       |
 1313|       |      token += strspn(token, " \t");  // skip space
 1314|       |#else
 1315|       |      // Read filename until line end to parse filename containing whitespace
 1316|       |      // TODO(syoyo): Support parsing texture option flag after the filename.
 1317|     56|      texture_name = std::string(token);
 1318|     56|      token += texture_name.length();
 1319|     56|#endif
 1320|       |
 1321|     56|      found_texname = true;
 1322|     56|    }
 1323|     78|  }
 1324|       |
 1325|     63|  if (found_texname) {
  ------------------
  |  Branch (1325:7): [True: 56, False: 7]
  ------------------
 1326|     56|    (*texname) = texture_name;
 1327|     56|    return true;
 1328|     56|  } else {
 1329|      7|    return false;
 1330|      7|  }
 1331|     63|}
_ZN7tinyobj7LoadMtlEPNSt3__13mapINS0_12basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEiNS0_4lessIS7_EENS5_INS0_4pairIKS7_iEEEEEEPNS0_6vectorINS_10material_tENS5_ISH_EEEEPNS0_13basic_istreamIcS4_EEPS7_SO_:
 2045|     50|             std::string *warning, std::string *err) {
 2046|     50|  (void)err;
 2047|       |
 2048|       |  // Create a default material anyway.
 2049|     50|  material_t material;
 2050|     50|  InitMaterial(&material);
 2051|       |
 2052|       |  // Issue 43. `d` wins against `Tr` since `Tr` is not in the MTL specification.
 2053|     50|  bool has_d = false;
 2054|     50|  bool has_tr = false;
 2055|       |
 2056|       |  // has_kd is used to set a default diffuse value when map_Kd is present
 2057|       |  // and Kd is not.
 2058|     50|  bool has_kd = false;
 2059|       |
 2060|     50|  std::stringstream warn_ss;
 2061|       |
 2062|     50|  size_t line_no = 0;
 2063|     50|  std::string linebuf;
 2064|  68.9k|  while (inStream->peek() != -1) {
  ------------------
  |  Branch (2064:10): [True: 68.9k, False: 50]
  ------------------
 2065|  68.9k|    safeGetline(*inStream, linebuf);
 2066|  68.9k|    line_no++;
 2067|       |
 2068|       |    // Trim trailing whitespace.
 2069|  68.9k|    if (linebuf.size() > 0) {
  ------------------
  |  Branch (2069:9): [True: 68.8k, False: 118]
  ------------------
 2070|  68.8k|      linebuf = linebuf.substr(0, linebuf.find_last_not_of(" \t") + 1);
 2071|  68.8k|    }
 2072|       |
 2073|       |    // Trim newline '\r\n' or '\n'
 2074|  68.9k|    if (linebuf.size() > 0) {
  ------------------
  |  Branch (2074:9): [True: 68.8k, False: 135]
  ------------------
 2075|  68.8k|      if (linebuf[linebuf.size() - 1] == '\n')
  ------------------
  |  Branch (2075:11): [True: 0, False: 68.8k]
  ------------------
 2076|      0|        linebuf.erase(linebuf.size() - 1);
 2077|  68.8k|    }
 2078|  68.9k|    if (linebuf.size() > 0) {
  ------------------
  |  Branch (2078:9): [True: 68.8k, False: 135]
  ------------------
 2079|  68.8k|      if (linebuf[linebuf.size() - 1] == '\r')
  ------------------
  |  Branch (2079:11): [True: 0, False: 68.8k]
  ------------------
 2080|      0|        linebuf.erase(linebuf.size() - 1);
 2081|  68.8k|    }
 2082|       |
 2083|       |    // Skip if empty line.
 2084|  68.9k|    if (linebuf.empty()) {
  ------------------
  |  Branch (2084:9): [True: 135, False: 68.8k]
  ------------------
 2085|    135|      continue;
 2086|    135|    }
 2087|       |
 2088|       |    // Skip leading space.
 2089|  68.8k|    const char *token = linebuf.c_str();
 2090|  68.8k|    token += strspn(token, " \t");
 2091|       |
 2092|  68.8k|    assert(token);
 2093|  68.8k|    if (token[0] == '\0') continue;  // empty line
  ------------------
  |  Branch (2093:9): [True: 4, False: 68.8k]
  ------------------
 2094|       |
 2095|  68.8k|    if (token[0] == '#') continue;  // comment line
  ------------------
  |  Branch (2095:9): [True: 15, False: 68.7k]
  ------------------
 2096|       |
 2097|       |    // new mtl
 2098|  68.7k|    if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) {
  ------------------
  |  |  797|  65.6k|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 65.5k, False: 61]
  |  |  |  Branch (797:38): [True: 8, False: 53]
  |  |  ------------------
  ------------------
  |  Branch (2098:9): [True: 65.6k, False: 3.18k]
  ------------------
 2099|       |      // flush previous material.
 2100|  65.5k|      if (!material.name.empty()) {
  ------------------
  |  Branch (2100:11): [True: 65.5k, False: 9]
  ------------------
 2101|  65.5k|        material_map->insert(std::pair<std::string, int>(
 2102|  65.5k|            material.name, static_cast<int>(materials->size())));
 2103|  65.5k|        materials->push_back(material);
 2104|  65.5k|      }
 2105|       |
 2106|       |      // initial temporary material
 2107|  65.5k|      InitMaterial(&material);
 2108|       |
 2109|  65.5k|      has_d = false;
 2110|  65.5k|      has_tr = false;
 2111|       |
 2112|       |      // set new mtl name
 2113|  65.5k|      token += 7;
 2114|  65.5k|      {
 2115|  65.5k|        std::string namebuf = parseString(&token);
 2116|       |        // TODO: empty name check?
 2117|  65.5k|        if (namebuf.empty()) {
  ------------------
  |  Branch (2117:13): [True: 0, False: 65.5k]
  ------------------
 2118|      0|          if (warning) {
  ------------------
  |  Branch (2118:15): [True: 0, False: 0]
  ------------------
 2119|      0|            (*warning) += "empty material name in `newmtl`\n";
 2120|      0|          }
 2121|      0|        }
 2122|  65.5k|        material.name = namebuf;
 2123|  65.5k|      }
 2124|  65.5k|      continue;
 2125|  65.5k|    }
 2126|       |
 2127|       |    // ambient
 2128|  3.23k|    if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2128:9): [True: 0, False: 3.23k]
  |  Branch (2128:28): [True: 0, False: 0]
  ------------------
 2129|      0|      token += 2;
 2130|      0|      real_t r, g, b;
 2131|      0|      parseReal3(&r, &g, &b, &token);
 2132|      0|      material.ambient[0] = r;
 2133|      0|      material.ambient[1] = g;
 2134|      0|      material.ambient[2] = b;
 2135|      0|      continue;
 2136|      0|    }
 2137|       |
 2138|       |    // diffuse
 2139|  3.23k|    if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2139:9): [True: 0, False: 3.23k]
  |  Branch (2139:28): [True: 0, False: 0]
  ------------------
 2140|      0|      token += 2;
 2141|      0|      real_t r, g, b;
 2142|      0|      parseReal3(&r, &g, &b, &token);
 2143|      0|      material.diffuse[0] = r;
 2144|      0|      material.diffuse[1] = g;
 2145|      0|      material.diffuse[2] = b;
 2146|      0|      has_kd = true;
 2147|      0|      continue;
 2148|      0|    }
 2149|       |
 2150|       |    // specular
 2151|  3.23k|    if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2151:9): [True: 0, False: 3.23k]
  |  Branch (2151:28): [True: 0, False: 0]
  ------------------
 2152|      0|      token += 2;
 2153|      0|      real_t r, g, b;
 2154|      0|      parseReal3(&r, &g, &b, &token);
 2155|      0|      material.specular[0] = r;
 2156|      0|      material.specular[1] = g;
 2157|      0|      material.specular[2] = b;
 2158|      0|      continue;
 2159|      0|    }
 2160|       |
 2161|       |    // transmittance
 2162|  3.23k|    if ((token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) ||
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2162:10): [True: 0, False: 3.23k]
  |  Branch (2162:29): [True: 0, False: 0]
  ------------------
 2163|  3.23k|        (token[0] == 'T' && token[1] == 'f' && IS_SPACE((token[2])))) {
  ------------------
  |  |  797|      6|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 6]
  |  |  |  Branch (797:38): [True: 0, False: 6]
  |  |  ------------------
  ------------------
  |  Branch (2163:10): [True: 66, False: 3.17k]
  |  Branch (2163:29): [True: 6, False: 60]
  ------------------
 2164|      0|      token += 2;
 2165|      0|      real_t r, g, b;
 2166|      0|      parseReal3(&r, &g, &b, &token);
 2167|      0|      material.transmittance[0] = r;
 2168|      0|      material.transmittance[1] = g;
 2169|      0|      material.transmittance[2] = b;
 2170|      0|      continue;
 2171|      0|    }
 2172|       |
 2173|       |    // ior(index of refraction)
 2174|  3.23k|    if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) {
  ------------------
  |  |  797|     10|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 10, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2174:9): [True: 11, False: 3.22k]
  |  Branch (2174:28): [True: 10, False: 1]
  ------------------
 2175|     10|      token += 2;
 2176|     10|      material.ior = parseReal(&token);
 2177|     10|      continue;
 2178|     10|    }
 2179|       |
 2180|       |    // emission
 2181|  3.22k|    if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2181:9): [True: 0, False: 3.22k]
  |  Branch (2181:28): [True: 0, False: 0]
  ------------------
 2182|      0|      token += 2;
 2183|      0|      real_t r, g, b;
 2184|      0|      parseReal3(&r, &g, &b, &token);
 2185|      0|      material.emission[0] = r;
 2186|      0|      material.emission[1] = g;
 2187|      0|      material.emission[2] = b;
 2188|      0|      continue;
 2189|      0|    }
 2190|       |
 2191|       |    // shininess
 2192|  3.22k|    if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2192:9): [True: 1, False: 3.22k]
  |  Branch (2192:28): [True: 0, False: 1]
  ------------------
 2193|      0|      token += 2;
 2194|      0|      material.shininess = parseReal(&token);
 2195|      0|      continue;
 2196|      0|    }
 2197|       |
 2198|       |    // illum model
 2199|  3.22k|    if (0 == strncmp(token, "illum", 5) && IS_SPACE(token[5])) {
  ------------------
  |  |  797|     69|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 67, False: 2]
  |  |  |  Branch (797:38): [True: 0, False: 2]
  |  |  ------------------
  ------------------
  |  Branch (2199:9): [True: 69, False: 3.15k]
  ------------------
 2200|     67|      token += 6;
 2201|     67|      material.illum = parseInt(&token);
 2202|     67|      continue;
 2203|     67|    }
 2204|       |
 2205|       |    // dissolve
 2206|  3.15k|    if ((token[0] == 'd' && IS_SPACE(token[1]))) {
  ------------------
  |  |  797|      6|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 1, False: 5]
  |  |  |  Branch (797:38): [True: 4, False: 1]
  |  |  ------------------
  ------------------
  |  Branch (2206:10): [True: 6, False: 3.15k]
  ------------------
 2207|      5|      token += 1;
 2208|      5|      material.dissolve = parseReal(&token);
 2209|       |
 2210|      5|      if (has_tr) {
  ------------------
  |  Branch (2210:11): [True: 4, False: 1]
  ------------------
 2211|      4|        warn_ss << "Both `d` and `Tr` parameters defined for \""
 2212|      4|                << material.name
 2213|      4|                << "\". Use the value of `d` for dissolve (line " << line_no
 2214|      4|                << " in .mtl.)\n";
 2215|      4|      }
 2216|      5|      has_d = true;
 2217|      5|      continue;
 2218|      5|    }
 2219|  3.15k|    if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) {
  ------------------
  |  |  797|     48|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 29, False: 19]
  |  |  |  Branch (797:38): [True: 1, False: 18]
  |  |  ------------------
  ------------------
  |  Branch (2219:9): [True: 66, False: 3.08k]
  |  Branch (2219:28): [True: 48, False: 18]
  ------------------
 2220|     30|      token += 2;
 2221|     30|      if (has_d) {
  ------------------
  |  Branch (2221:11): [True: 21, False: 9]
  ------------------
 2222|       |        // `d` wins. Ignore `Tr` value.
 2223|     21|        warn_ss << "Both `d` and `Tr` parameters defined for \""
 2224|     21|                << material.name
 2225|     21|                << "\". Use the value of `d` for dissolve (line " << line_no
 2226|     21|                << " in .mtl.)\n";
 2227|     21|      } else {
 2228|       |        // We invert value of Tr(assume Tr is in range [0, 1])
 2229|       |        // NOTE: Interpretation of Tr is application(exporter) dependent. For
 2230|       |        // some application(e.g. 3ds max obj exporter), Tr = d(Issue 43)
 2231|      9|        material.dissolve = static_cast<real_t>(1.0) - parseReal(&token);
 2232|      9|      }
 2233|     30|      has_tr = true;
 2234|     30|      continue;
 2235|     30|    }
 2236|       |
 2237|       |    // PBR: roughness
 2238|  3.12k|    if (token[0] == 'P' && token[1] == 'r' && IS_SPACE(token[2])) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2238:9): [True: 16, False: 3.10k]
  |  Branch (2238:28): [True: 0, False: 16]
  ------------------
 2239|      0|      token += 2;
 2240|      0|      material.roughness = parseReal(&token);
 2241|      0|      continue;
 2242|      0|    }
 2243|       |
 2244|       |    // PBR: metallic
 2245|  3.12k|    if (token[0] == 'P' && token[1] == 'm' && IS_SPACE(token[2])) {
  ------------------
  |  |  797|      1|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 1, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2245:9): [True: 16, False: 3.10k]
  |  Branch (2245:28): [True: 1, False: 15]
  ------------------
 2246|      1|      token += 2;
 2247|      1|      material.metallic = parseReal(&token);
 2248|      1|      continue;
 2249|      1|    }
 2250|       |
 2251|       |    // PBR: sheen
 2252|  3.12k|    if (token[0] == 'P' && token[1] == 's' && IS_SPACE(token[2])) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2252:9): [True: 15, False: 3.10k]
  |  Branch (2252:28): [True: 0, False: 15]
  ------------------
 2253|      0|      token += 2;
 2254|      0|      material.sheen = parseReal(&token);
 2255|      0|      continue;
 2256|      0|    }
 2257|       |
 2258|       |    // PBR: clearcoat thickness
 2259|  3.12k|    if (token[0] == 'P' && token[1] == 'c' && IS_SPACE(token[2])) {
  ------------------
  |  |  797|      6|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 6]
  |  |  |  Branch (797:38): [True: 0, False: 6]
  |  |  ------------------
  ------------------
  |  Branch (2259:9): [True: 15, False: 3.10k]
  |  Branch (2259:28): [True: 6, False: 9]
  ------------------
 2260|      0|      token += 2;
 2261|      0|      material.clearcoat_thickness = parseReal(&token);
 2262|      0|      continue;
 2263|      0|    }
 2264|       |
 2265|       |    // PBR: clearcoat roughness
 2266|  3.12k|    if ((0 == strncmp(token, "Pcr", 3)) && IS_SPACE(token[3])) {
  ------------------
  |  |  797|      6|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 6]
  |  |  |  Branch (797:38): [True: 0, False: 6]
  |  |  ------------------
  ------------------
  |  Branch (2266:9): [True: 6, False: 3.11k]
  ------------------
 2267|      0|      token += 4;
 2268|      0|      material.clearcoat_roughness = parseReal(&token);
 2269|      0|      continue;
 2270|      0|    }
 2271|       |
 2272|       |    // PBR: anisotropy
 2273|  3.12k|    if ((0 == strncmp(token, "aniso", 5)) && IS_SPACE(token[5])) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2273:9): [True: 0, False: 3.12k]
  ------------------
 2274|      0|      token += 6;
 2275|      0|      material.anisotropy = parseReal(&token);
 2276|      0|      continue;
 2277|      0|    }
 2278|       |
 2279|       |    // PBR: anisotropy rotation
 2280|  3.12k|    if ((0 == strncmp(token, "anisor", 6)) && IS_SPACE(token[6])) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2280:9): [True: 0, False: 3.12k]
  ------------------
 2281|      0|      token += 7;
 2282|      0|      material.anisotropy_rotation = parseReal(&token);
 2283|      0|      continue;
 2284|      0|    }
 2285|       |
 2286|       |    // ambient or ambient occlusion texture
 2287|  3.12k|    if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2287:9): [True: 0, False: 3.12k]
  ------------------
 2288|      0|      token += 7;
 2289|      0|      ParseTextureNameAndOption(&(material.ambient_texname),
 2290|      0|                                &(material.ambient_texopt), token);
 2291|      0|      continue;
 2292|      0|    }
 2293|       |
 2294|       |    // diffuse texture
 2295|  3.12k|    if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2295:9): [True: 0, False: 3.12k]
  ------------------
 2296|      0|      token += 7;
 2297|      0|      ParseTextureNameAndOption(&(material.diffuse_texname),
 2298|      0|                                &(material.diffuse_texopt), token);
 2299|       |
 2300|       |      // Set a decent diffuse default value if a diffuse texture is specified
 2301|       |      // without a matching Kd value.
 2302|      0|      if (!has_kd) {
  ------------------
  |  Branch (2302:11): [True: 0, False: 0]
  ------------------
 2303|      0|        material.diffuse[0] = static_cast<real_t>(0.6);
 2304|      0|        material.diffuse[1] = static_cast<real_t>(0.6);
 2305|      0|        material.diffuse[2] = static_cast<real_t>(0.6);
 2306|      0|      }
 2307|       |
 2308|      0|      continue;
 2309|      0|    }
 2310|       |
 2311|       |    // specular texture
 2312|  3.12k|    if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2312:9): [True: 0, False: 3.12k]
  ------------------
 2313|      0|      token += 7;
 2314|      0|      ParseTextureNameAndOption(&(material.specular_texname),
 2315|      0|                                &(material.specular_texopt), token);
 2316|      0|      continue;
 2317|      0|    }
 2318|       |
 2319|       |    // specular highlight texture
 2320|  3.12k|    if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) {
  ------------------
  |  |  797|     10|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 10]
  |  |  |  Branch (797:38): [True: 0, False: 10]
  |  |  ------------------
  ------------------
  |  Branch (2320:9): [True: 10, False: 3.11k]
  ------------------
 2321|      0|      token += 7;
 2322|      0|      ParseTextureNameAndOption(&(material.specular_highlight_texname),
 2323|      0|                                &(material.specular_highlight_texopt), token);
 2324|      0|      continue;
 2325|      0|    }
 2326|       |
 2327|       |    // bump texture
 2328|  3.12k|    if (((0 == strncmp(token, "map_bump", 8)) ||
  ------------------
  |  Branch (2328:10): [True: 1, False: 3.12k]
  ------------------
 2329|  3.12k|         (0 == strncmp(token, "map_Bump", 8))) &&
  ------------------
  |  Branch (2329:10): [True: 2, False: 3.12k]
  ------------------
 2330|  3.12k|        IS_SPACE(token[8])) {
  ------------------
  |  |  797|      3|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 1, False: 2]
  |  |  |  Branch (797:38): [True: 0, False: 2]
  |  |  ------------------
  ------------------
 2331|      1|      token += 9;
 2332|      1|      ParseTextureNameAndOption(&(material.bump_texname),
 2333|      1|                                &(material.bump_texopt), token);
 2334|      1|      continue;
 2335|      1|    }
 2336|       |
 2337|       |    // bump texture
 2338|  3.12k|    if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) {
  ------------------
  |  |  797|     48|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 48]
  |  |  |  Branch (797:38): [True: 46, False: 2]
  |  |  ------------------
  ------------------
  |  Branch (2338:9): [True: 48, False: 3.07k]
  ------------------
 2339|     46|      token += 5;
 2340|     46|      ParseTextureNameAndOption(&(material.bump_texname),
 2341|     46|                                &(material.bump_texopt), token);
 2342|     46|      continue;
 2343|     46|    }
 2344|       |
 2345|       |    // alpha texture
 2346|  3.07k|    if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2346:9): [True: 0, False: 3.07k]
  ------------------
 2347|      0|      token += 6;
 2348|      0|      material.alpha_texname = token;
 2349|      0|      ParseTextureNameAndOption(&(material.alpha_texname),
 2350|      0|                                &(material.alpha_texopt), token);
 2351|      0|      continue;
 2352|      0|    }
 2353|       |
 2354|       |    // displacement texture
 2355|  3.07k|    if (((0 == strncmp(token, "map_disp", 8)) ||
  ------------------
  |  Branch (2355:10): [True: 0, False: 3.07k]
  ------------------
 2356|  3.07k|         (0 == strncmp(token, "map_Disp", 8))) &&
  ------------------
  |  Branch (2356:10): [True: 2, False: 3.07k]
  ------------------
 2357|  3.07k|        IS_SPACE(token[8])) {
  ------------------
  |  |  797|      2|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 2, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
 2358|      2|      token += 9;
 2359|      2|      ParseTextureNameAndOption(&(material.displacement_texname),
 2360|      2|                                &(material.displacement_texopt), token);
 2361|      2|      continue;
 2362|      2|    }
 2363|       |
 2364|       |    // displacement texture
 2365|  3.07k|    if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) {
  ------------------
  |  |  797|      1|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 1]
  |  |  |  Branch (797:38): [True: 1, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2365:9): [True: 1, False: 3.07k]
  ------------------
 2366|      1|      token += 5;
 2367|      1|      ParseTextureNameAndOption(&(material.displacement_texname),
 2368|      1|                                &(material.displacement_texopt), token);
 2369|      1|      continue;
 2370|      1|    }
 2371|       |
 2372|       |    // reflection map
 2373|  3.07k|    if ((0 == strncmp(token, "refl", 4)) && IS_SPACE(token[4])) {
  ------------------
  |  |  797|      4|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 2, False: 2]
  |  |  |  Branch (797:38): [True: 0, False: 2]
  |  |  ------------------
  ------------------
  |  Branch (2373:9): [True: 4, False: 3.06k]
  ------------------
 2374|      2|      token += 5;
 2375|      2|      ParseTextureNameAndOption(&(material.reflection_texname),
 2376|      2|                                &(material.reflection_texopt), token);
 2377|      2|      continue;
 2378|      2|    }
 2379|       |
 2380|       |    // PBR: roughness texture
 2381|  3.07k|    if ((0 == strncmp(token, "map_Pr", 6)) && IS_SPACE(token[6])) {
  ------------------
  |  |  797|     14|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 7, False: 7]
  |  |  |  Branch (797:38): [True: 0, False: 7]
  |  |  ------------------
  ------------------
  |  Branch (2381:9): [True: 14, False: 3.05k]
  ------------------
 2382|      7|      token += 7;
 2383|      7|      ParseTextureNameAndOption(&(material.roughness_texname),
 2384|      7|                                &(material.roughness_texopt), token);
 2385|      7|      continue;
 2386|      7|    }
 2387|       |
 2388|       |    // PBR: metallic texture
 2389|  3.06k|    if ((0 == strncmp(token, "map_Pm", 6)) && IS_SPACE(token[6])) {
  ------------------
  |  |  797|      2|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 2]
  |  |  |  Branch (797:38): [True: 2, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2389:9): [True: 2, False: 3.06k]
  ------------------
 2390|      2|      token += 7;
 2391|      2|      ParseTextureNameAndOption(&(material.metallic_texname),
 2392|      2|                                &(material.metallic_texopt), token);
 2393|      2|      continue;
 2394|      2|    }
 2395|       |
 2396|       |    // PBR: sheen texture
 2397|  3.06k|    if ((0 == strncmp(token, "map_Ps", 6)) && IS_SPACE(token[6])) {
  ------------------
  |  |  797|      2|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 2]
  |  |  |  Branch (797:38): [True: 2, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2397:9): [True: 2, False: 3.06k]
  ------------------
 2398|      2|      token += 7;
 2399|      2|      ParseTextureNameAndOption(&(material.sheen_texname),
 2400|      2|                                &(material.sheen_texopt), token);
 2401|      2|      continue;
 2402|      2|    }
 2403|       |
 2404|       |    // PBR: emissive texture
 2405|  3.06k|    if ((0 == strncmp(token, "map_Ke", 6)) && IS_SPACE(token[6])) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2405:9): [True: 0, False: 3.06k]
  ------------------
 2406|      0|      token += 7;
 2407|      0|      ParseTextureNameAndOption(&(material.emissive_texname),
 2408|      0|                                &(material.emissive_texopt), token);
 2409|      0|      continue;
 2410|      0|    }
 2411|       |
 2412|       |    // PBR: normal map texture
 2413|  3.06k|    if ((0 == strncmp(token, "norm", 4)) && IS_SPACE(token[4])) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2413:9): [True: 0, False: 3.06k]
  ------------------
 2414|      0|      token += 5;
 2415|      0|      ParseTextureNameAndOption(&(material.normal_texname),
 2416|      0|                                &(material.normal_texopt), token);
 2417|      0|      continue;
 2418|      0|    }
 2419|       |
 2420|       |    // unknown parameter
 2421|  3.06k|    const char *_space = strchr(token, ' ');
 2422|  3.06k|    if (!_space) {
  ------------------
  |  Branch (2422:9): [True: 1.51k, False: 1.54k]
  ------------------
 2423|  1.51k|      _space = strchr(token, '\t');
 2424|  1.51k|    }
 2425|  3.06k|    if (_space) {
  ------------------
  |  Branch (2425:9): [True: 1.90k, False: 1.16k]
  ------------------
 2426|  1.90k|      std::ptrdiff_t len = _space - token;
 2427|  1.90k|      std::string key(token, static_cast<size_t>(len));
 2428|  1.90k|      std::string value = _space + 1;
 2429|  1.90k|      material.unknown_parameter.insert(
 2430|  1.90k|          std::pair<std::string, std::string>(key, value));
 2431|  1.90k|    }
 2432|  3.06k|  }
 2433|       |  // flush last material.
 2434|     50|  material_map->insert(std::pair<std::string, int>(
 2435|     50|      material.name, static_cast<int>(materials->size())));
 2436|     50|  materials->push_back(material);
 2437|       |
 2438|     50|  if (warning) {
  ------------------
  |  Branch (2438:7): [True: 50, False: 0]
  ------------------
 2439|     50|    (*warning) = warn_ss.str();
 2440|     50|  }
 2441|     50|}
_ZN7tinyobj20MaterialStreamReaderclERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEPNS1_6vectorINS_10material_tENS5_ISB_EEEEPNS1_3mapIS7_iNS1_4lessIS7_EENS5_INS1_4pairIS8_iEEEEEEPS7_SN_:
 2505|    106|                                      std::string *warn, std::string *err) {
 2506|    106|  (void)err;
 2507|    106|  (void)matId;
 2508|    106|  if (!m_inStream) {
  ------------------
  |  Branch (2508:7): [True: 56, False: 50]
  ------------------
 2509|     56|    std::stringstream ss;
 2510|     56|    ss << "Material stream in error state. \n";
 2511|     56|    if (warn) {
  ------------------
  |  Branch (2511:9): [True: 56, False: 0]
  ------------------
 2512|     56|      (*warn) += ss.str();
 2513|     56|    }
 2514|     56|    return false;
 2515|     56|  }
 2516|       |
 2517|     50|  LoadMtl(matMap, materials, &m_inStream, warn, err);
 2518|       |
 2519|     50|  return true;
 2520|    106|}
_ZN7tinyobj7LoadObjEPNS_8attrib_tEPNSt3__16vectorINS_7shape_tENS2_9allocatorIS4_EEEEPNS3_INS_10material_tENS5_IS9_EEEEPNS2_12basic_stringIcNS2_11char_traitsIcEENS5_IcEEEESI_PNS2_13basic_istreamIcSF_EEPNS_14MaterialReaderEbb:
 2562|     82|             bool default_vcols_fallback) {
 2563|     82|  std::stringstream errss;
 2564|       |
 2565|     82|  std::vector<real_t> v;
 2566|     82|  std::vector<real_t> vn;
 2567|     82|  std::vector<real_t> vt;
 2568|     82|  std::vector<real_t> vc;
 2569|     82|  std::vector<skin_weight_t> vw;
 2570|     82|  std::vector<tag_t> tags;
 2571|     82|  PrimGroup prim_group;
 2572|     82|  std::string name;
 2573|       |
 2574|       |  // material
 2575|     82|  std::set<std::string> material_filenames;
 2576|     82|  std::map<std::string, int> material_map;
 2577|     82|  int material = -1;
 2578|       |
 2579|       |  // smoothing group id
 2580|     82|  unsigned int current_smoothing_id =
 2581|     82|      0;  // Initial value. 0 means no smoothing.
 2582|       |
 2583|     82|  int greatest_v_idx = -1;
 2584|     82|  int greatest_vn_idx = -1;
 2585|     82|  int greatest_vt_idx = -1;
 2586|       |
 2587|     82|  shape_t shape;
 2588|       |
 2589|     82|  bool found_all_colors = true;
 2590|       |
 2591|     82|  size_t line_num = 0;
 2592|     82|  std::string linebuf;
 2593|  2.65M|  while (inStream->peek() != -1) {
  ------------------
  |  Branch (2593:10): [True: 2.65M, False: 81]
  ------------------
 2594|  2.65M|    safeGetline(*inStream, linebuf);
 2595|       |
 2596|  2.65M|    line_num++;
 2597|       |
 2598|       |    // Trim newline '\r\n' or '\n'
 2599|  2.65M|    if (linebuf.size() > 0) {
  ------------------
  |  Branch (2599:9): [True: 2.64M, False: 9.61k]
  ------------------
 2600|  2.64M|      if (linebuf[linebuf.size() - 1] == '\n')
  ------------------
  |  Branch (2600:11): [True: 0, False: 2.64M]
  ------------------
 2601|      0|        linebuf.erase(linebuf.size() - 1);
 2602|  2.64M|    }
 2603|  2.65M|    if (linebuf.size() > 0) {
  ------------------
  |  Branch (2603:9): [True: 2.64M, False: 9.61k]
  ------------------
 2604|  2.64M|      if (linebuf[linebuf.size() - 1] == '\r')
  ------------------
  |  Branch (2604:11): [True: 0, False: 2.64M]
  ------------------
 2605|      0|        linebuf.erase(linebuf.size() - 1);
 2606|  2.64M|    }
 2607|       |
 2608|       |    // Skip if empty line.
 2609|  2.65M|    if (linebuf.empty()) {
  ------------------
  |  Branch (2609:9): [True: 9.61k, False: 2.64M]
  ------------------
 2610|  9.61k|      continue;
 2611|  9.61k|    }
 2612|       |
 2613|       |    // Skip leading space.
 2614|  2.64M|    const char *token = linebuf.c_str();
 2615|  2.64M|    token += strspn(token, " \t");
 2616|       |
 2617|  2.64M|    assert(token);
 2618|  2.64M|    if (token[0] == '\0') continue;  // empty line
  ------------------
  |  Branch (2618:9): [True: 4.25k, False: 2.64M]
  ------------------
 2619|       |
 2620|  2.64M|    if (token[0] == '#') continue;  // comment line
  ------------------
  |  Branch (2620:9): [True: 135, False: 2.64M]
  ------------------
 2621|       |
 2622|       |    // vertex
 2623|  2.64M|    if (token[0] == 'v' && IS_SPACE((token[1]))) {
  ------------------
  |  |  797|   175k|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 404, False: 175k]
  |  |  |  Branch (797:38): [True: 174k, False: 584]
  |  |  ------------------
  ------------------
  |  Branch (2623:9): [True: 175k, False: 2.46M]
  ------------------
 2624|   175k|      token += 2;
 2625|   175k|      real_t x, y, z;
 2626|   175k|      real_t r, g, b;
 2627|       |
 2628|   175k|      found_all_colors &= parseVertexWithColor(&x, &y, &z, &r, &g, &b, &token);
 2629|       |
 2630|   175k|      v.push_back(x);
 2631|   175k|      v.push_back(y);
 2632|   175k|      v.push_back(z);
 2633|       |
 2634|   175k|      if (found_all_colors || default_vcols_fallback) {
  ------------------
  |  Branch (2634:11): [True: 0, False: 175k]
  |  Branch (2634:31): [True: 175k, False: 0]
  ------------------
 2635|   175k|        vc.push_back(r);
 2636|   175k|        vc.push_back(g);
 2637|   175k|        vc.push_back(b);
 2638|   175k|      }
 2639|       |
 2640|   175k|      continue;
 2641|   175k|    }
 2642|       |
 2643|       |    // normal
 2644|  2.46M|    if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2644:9): [True: 584, False: 2.46M]
  |  Branch (2644:28): [True: 0, False: 584]
  ------------------
 2645|      0|      token += 3;
 2646|      0|      real_t x, y, z;
 2647|      0|      parseReal3(&x, &y, &z, &token);
 2648|      0|      vn.push_back(x);
 2649|      0|      vn.push_back(y);
 2650|      0|      vn.push_back(z);
 2651|      0|      continue;
 2652|      0|    }
 2653|       |
 2654|       |    // texcoord
 2655|  2.46M|    if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) {
  ------------------
  |  |  797|      0|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2655:9): [True: 584, False: 2.46M]
  |  Branch (2655:28): [True: 0, False: 584]
  ------------------
 2656|      0|      token += 3;
 2657|      0|      real_t x, y;
 2658|      0|      parseReal2(&x, &y, &token);
 2659|      0|      vt.push_back(x);
 2660|      0|      vt.push_back(y);
 2661|      0|      continue;
 2662|      0|    }
 2663|       |
 2664|       |    // skin weight. tinyobj extension
 2665|  2.46M|    if (token[0] == 'v' && token[1] == 'w' && IS_SPACE((token[2]))) {
  ------------------
  |  |  797|      2|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 2]
  |  |  |  Branch (797:38): [True: 2, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2665:9): [True: 584, False: 2.46M]
  |  Branch (2665:28): [True: 2, False: 582]
  ------------------
 2666|      2|      token += 3;
 2667|       |
 2668|       |      // vw <vid> <joint_0> <weight_0> <joint_1> <weight_1> ...
 2669|       |      // example:
 2670|       |      // vw 0 0 0.25 1 0.25 2 0.5
 2671|       |
 2672|       |      // TODO(syoyo): Add syntax check
 2673|      2|      int vid = 0;
 2674|      2|      vid = parseInt(&token);
 2675|       |
 2676|      2|      skin_weight_t sw;
 2677|       |
 2678|      2|      sw.vertex_id = vid;
 2679|       |
 2680|   262k|      while (!IS_NEW_LINE(token[0])) {
  ------------------
  |  |  800|   262k|#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
  |  |  ------------------
  |  |  |  Branch (800:25): [True: 0, False: 262k]
  |  |  |  Branch (800:42): [True: 0, False: 262k]
  |  |  |  Branch (800:59): [True: 2, False: 262k]
  |  |  ------------------
  ------------------
 2681|   262k|        real_t j, w;
 2682|       |        // joint_id should not be negative, weight may be negative
 2683|       |        // TODO(syoyo): # of elements check
 2684|   262k|        parseReal2(&j, &w, &token, -1.0);
 2685|       |
 2686|   262k|        if (j < static_cast<real_t>(0)) {
  ------------------
  |  Branch (2686:13): [True: 0, False: 262k]
  ------------------
 2687|      0|          if (err) {
  ------------------
  |  Branch (2687:15): [True: 0, False: 0]
  ------------------
 2688|      0|            std::stringstream ss;
 2689|      0|            ss << "Failed parse `vw' line. joint_id is negative. "
 2690|      0|                  "line "
 2691|      0|               << line_num << ".)\n";
 2692|      0|            (*err) += ss.str();
 2693|      0|          }
 2694|      0|          return false;
 2695|      0|        }
 2696|       |
 2697|   262k|        joint_and_weight_t jw;
 2698|       |
 2699|   262k|        jw.joint_id = int(j);
 2700|   262k|        jw.weight = w;
 2701|       |
 2702|   262k|        sw.weightValues.push_back(jw);
 2703|       |
 2704|   262k|        size_t n = strspn(token, " \t\r");
 2705|   262k|        token += n;
 2706|   262k|      }
 2707|       |
 2708|      2|      vw.push_back(sw);
 2709|      2|    }
 2710|       |
 2711|  2.46M|    warning_context context;
 2712|  2.46M|    context.warn = warn;
 2713|  2.46M|    context.line_number = line_num;
 2714|       |
 2715|       |    // line
 2716|  2.46M|    if (token[0] == 'l' && IS_SPACE((token[1]))) {
  ------------------
  |  |  797|   264k|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 0, False: 264k]
  |  |  |  Branch (797:38): [True: 262k, False: 2.58k]
  |  |  ------------------
  ------------------
  |  Branch (2716:9): [True: 264k, False: 2.20M]
  ------------------
 2717|   262k|      token += 2;
 2718|       |
 2719|   262k|      __line_t line;
 2720|       |
 2721|   262k|      while (!IS_NEW_LINE(token[0])) {
  ------------------
  |  |  800|   262k|#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
  |  |  ------------------
  |  |  |  Branch (800:25): [True: 0, False: 262k]
  |  |  |  Branch (800:42): [True: 0, False: 262k]
  |  |  |  Branch (800:59): [True: 262k, False: 0]
  |  |  ------------------
  ------------------
 2722|      0|        vertex_index_t vi;
 2723|      0|        if (!parseTriple(&token, static_cast<int>(v.size() / 3),
  ------------------
  |  Branch (2723:13): [True: 0, False: 0]
  ------------------
 2724|      0|                         static_cast<int>(vn.size() / 3),
 2725|      0|                         static_cast<int>(vt.size() / 2), &vi, context)) {
 2726|      0|          if (err) {
  ------------------
  |  Branch (2726:15): [True: 0, False: 0]
  ------------------
 2727|      0|            (*err) += "Failed to parse `l' line (e.g. a zero value for vertex index. Line " +
 2728|      0|                toString(line_num) + ").\n";
 2729|      0|          }
 2730|      0|          return false;
 2731|      0|        }
 2732|       |
 2733|      0|        line.vertex_indices.push_back(vi);
 2734|       |
 2735|      0|        size_t n = strspn(token, " \t\r");
 2736|      0|        token += n;
 2737|      0|      }
 2738|       |
 2739|   262k|      prim_group.lineGroup.push_back(line);
 2740|       |
 2741|   262k|      continue;
 2742|   262k|    }
 2743|       |
 2744|       |    // points
 2745|  2.20M|    if (token[0] == 'p' && IS_SPACE((token[1]))) {
  ------------------
  |  |  797|   460k|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 262k, False: 198k]
  |  |  |  Branch (797:38): [True: 197k, False: 1.20k]
  |  |  ------------------
  ------------------
  |  Branch (2745:9): [True: 460k, False: 1.74M]
  ------------------
 2746|   459k|      token += 2;
 2747|       |
 2748|   459k|      __points_t pts;
 2749|       |
 2750|   657k|      while (!IS_NEW_LINE(token[0])) {
  ------------------
  |  |  800|   657k|#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
  |  |  ------------------
  |  |  |  Branch (800:25): [True: 0, False: 657k]
  |  |  |  Branch (800:42): [True: 0, False: 657k]
  |  |  |  Branch (800:59): [True: 459k, False: 197k]
  |  |  ------------------
  ------------------
 2751|   197k|        vertex_index_t vi;
 2752|   197k|        if (!parseTriple(&token, static_cast<int>(v.size() / 3),
  ------------------
  |  Branch (2752:13): [True: 0, False: 197k]
  ------------------
 2753|   197k|                         static_cast<int>(vn.size() / 3),
 2754|   197k|                         static_cast<int>(vt.size() / 2), &vi, context)) {
 2755|      0|          if (err) {
  ------------------
  |  Branch (2755:15): [True: 0, False: 0]
  ------------------
 2756|      0|            (*err) += "Failed to parse `p' line (e.g. a zero value for vertex index. Line " +
 2757|      0|                toString(line_num) + ").\n";
 2758|      0|          }
 2759|      0|          return false;
 2760|      0|        }
 2761|       |
 2762|   197k|        pts.vertex_indices.push_back(vi);
 2763|       |
 2764|   197k|        size_t n = strspn(token, " \t\r");
 2765|   197k|        token += n;
 2766|   197k|      }
 2767|       |
 2768|   459k|      prim_group.pointsGroup.push_back(pts);
 2769|       |
 2770|   459k|      continue;
 2771|   459k|    }
 2772|       |
 2773|       |    // face
 2774|  1.74M|    if (token[0] == 'f' && IS_SPACE((token[1]))) {
  ------------------
  |  |  797|   267k|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 263k, False: 3.19k]
  |  |  |  Branch (797:38): [True: 2.66k, False: 525]
  |  |  ------------------
  ------------------
  |  Branch (2774:9): [True: 267k, False: 1.47M]
  ------------------
 2775|   266k|      token += 2;
 2776|   266k|      token += strspn(token, " \t");
 2777|       |
 2778|   266k|      face_t face;
 2779|       |
 2780|   266k|      face.smoothing_group_id = current_smoothing_id;
 2781|   266k|      face.vertex_indices.reserve(3);
 2782|       |
 2783|  2.23M|      while (!IS_NEW_LINE(token[0])) {
  ------------------
  |  |  800|  2.23M|#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
  |  |  ------------------
  |  |  |  Branch (800:25): [True: 0, False: 2.23M]
  |  |  |  Branch (800:42): [True: 0, False: 2.23M]
  |  |  |  Branch (800:59): [True: 266k, False: 1.97M]
  |  |  ------------------
  ------------------
 2784|  1.97M|        vertex_index_t vi;
 2785|  1.97M|        if (!parseTriple(&token, static_cast<int>(v.size() / 3),
  ------------------
  |  Branch (2785:13): [True: 1, False: 1.97M]
  ------------------
 2786|  1.97M|                         static_cast<int>(vn.size() / 3),
 2787|  1.97M|                         static_cast<int>(vt.size() / 2), &vi, context)) {
 2788|      1|          if (err) {
  ------------------
  |  Branch (2788:15): [True: 1, False: 0]
  ------------------
 2789|      1|            (*err) += "Failed to parse `f' line (e.g. a zero value for vertex index or invalid relative vertex index). Line " +
 2790|      1|                toString(line_num) + ").\n";
 2791|      1|          }
 2792|      1|          return false;
 2793|      1|        }
 2794|       |
 2795|  1.97M|        greatest_v_idx = greatest_v_idx > vi.v_idx ? greatest_v_idx : vi.v_idx;
  ------------------
  |  Branch (2795:26): [True: 1.96M, False: 3.89k]
  ------------------
 2796|  1.97M|        greatest_vn_idx =
 2797|  1.97M|            greatest_vn_idx > vi.vn_idx ? greatest_vn_idx : vi.vn_idx;
  ------------------
  |  Branch (2797:13): [True: 0, False: 1.97M]
  ------------------
 2798|  1.97M|        greatest_vt_idx =
 2799|  1.97M|            greatest_vt_idx > vi.vt_idx ? greatest_vt_idx : vi.vt_idx;
  ------------------
  |  Branch (2799:13): [True: 0, False: 1.97M]
  ------------------
 2800|       |
 2801|  1.97M|        face.vertex_indices.push_back(vi);
 2802|  1.97M|        size_t n = strspn(token, " \t\r");
 2803|  1.97M|        token += n;
 2804|  1.97M|      }
 2805|       |
 2806|       |      // replace with emplace_back + std::move on C++11
 2807|   266k|      prim_group.faceGroup.push_back(face);
 2808|       |
 2809|   266k|      continue;
 2810|   266k|    }
 2811|       |
 2812|       |    // use mtl
 2813|  1.47M|    if ((0 == strncmp(token, "usemtl", 6))) {
  ------------------
  |  Branch (2813:9): [True: 145, False: 1.47M]
  ------------------
 2814|    145|      token += 6;
 2815|    145|      std::string namebuf = parseString(&token);
 2816|       |
 2817|    145|      int newMaterialId = -1;
 2818|    145|      std::map<std::string, int>::const_iterator it =
 2819|    145|          material_map.find(namebuf);
 2820|    145|      if (it != material_map.end()) {
  ------------------
  |  Branch (2820:11): [True: 69, False: 76]
  ------------------
 2821|     69|        newMaterialId = it->second;
 2822|     76|      } else {
 2823|       |        // { error!! material not found }
 2824|     76|        if (warn) {
  ------------------
  |  Branch (2824:13): [True: 76, False: 0]
  ------------------
 2825|     76|          (*warn) += "material [ '" + namebuf + "' ] not found in .mtl\n";
 2826|     76|        }
 2827|     76|      }
 2828|       |
 2829|    145|      if (newMaterialId != material) {
  ------------------
  |  Branch (2829:11): [True: 137, False: 8]
  ------------------
 2830|       |        // Create per-face material. Thus we don't add `shape` to `shapes` at
 2831|       |        // this time.
 2832|       |        // just clear `faceGroup` after `exportGroupsToShape()` call.
 2833|    137|        exportGroupsToShape(&shape, prim_group, tags, material, name,
 2834|    137|                            triangulate, v, warn);
 2835|    137|        prim_group.faceGroup.clear();
 2836|    137|        material = newMaterialId;
 2837|    137|      }
 2838|       |
 2839|    145|      continue;
 2840|    145|    }
 2841|       |
 2842|       |    // load mtl
 2843|  1.47M|    if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) {
  ------------------
  |  |  797|    190|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 15, False: 175]
  |  |  |  Branch (797:38): [True: 175, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2843:9): [True: 190, False: 1.47M]
  ------------------
 2844|    190|      if (readMatFn) {
  ------------------
  |  Branch (2844:11): [True: 190, False: 0]
  ------------------
 2845|    190|        token += 7;
 2846|       |
 2847|    190|        std::vector<std::string> filenames;
 2848|    190|        SplitString(std::string(token), ' ', '\\', filenames);
 2849|       |
 2850|    190|        if (filenames.empty()) {
  ------------------
  |  Branch (2850:13): [True: 0, False: 190]
  ------------------
 2851|      0|          if (warn) {
  ------------------
  |  Branch (2851:15): [True: 0, False: 0]
  ------------------
 2852|      0|            std::stringstream ss;
 2853|      0|            ss << "Looks like empty filename for mtllib. Use default "
 2854|      0|                  "material (line "
 2855|      0|               << line_num << ".)\n";
 2856|       |
 2857|      0|            (*warn) += ss.str();
 2858|      0|          }
 2859|    190|        } else {
 2860|    190|          bool found = false;
 2861|    330|          for (size_t s = 0; s < filenames.size(); s++) {
  ------------------
  |  Branch (2861:30): [True: 190, False: 140]
  ------------------
 2862|    190|            if (material_filenames.count(filenames[s]) > 0) {
  ------------------
  |  Branch (2862:17): [True: 84, False: 106]
  ------------------
 2863|     84|              found = true;
 2864|     84|              continue;
 2865|     84|            }
 2866|       |
 2867|    106|            std::string warn_mtl;
 2868|    106|            std::string err_mtl;
 2869|    106|            bool ok = (*readMatFn)(filenames[s].c_str(), materials,
 2870|    106|                                   &material_map, &warn_mtl, &err_mtl);
 2871|    106|            if (warn && (!warn_mtl.empty())) {
  ------------------
  |  Branch (2871:17): [True: 106, False: 0]
  |  Branch (2871:25): [True: 58, False: 48]
  ------------------
 2872|     58|              (*warn) += warn_mtl;
 2873|     58|            }
 2874|       |
 2875|    106|            if (err && (!err_mtl.empty())) {
  ------------------
  |  Branch (2875:17): [True: 106, False: 0]
  |  Branch (2875:24): [True: 0, False: 106]
  ------------------
 2876|      0|              (*err) += err_mtl;
 2877|      0|            }
 2878|       |
 2879|    106|            if (ok) {
  ------------------
  |  Branch (2879:17): [True: 50, False: 56]
  ------------------
 2880|     50|              found = true;
 2881|     50|              material_filenames.insert(filenames[s]);
 2882|     50|              break;
 2883|     50|            }
 2884|    106|          }
 2885|       |
 2886|    190|          if (!found) {
  ------------------
  |  Branch (2886:15): [True: 56, False: 134]
  ------------------
 2887|     56|            if (warn) {
  ------------------
  |  Branch (2887:17): [True: 56, False: 0]
  ------------------
 2888|     56|              (*warn) +=
 2889|     56|                  "Failed to load material file(s). Use default "
 2890|     56|                  "material.\n";
 2891|     56|            }
 2892|     56|          }
 2893|    190|        }
 2894|    190|      }
 2895|       |
 2896|    190|      continue;
 2897|    190|    }
 2898|       |
 2899|       |    // group name
 2900|  1.47M|    if (token[0] == 'g' && IS_SPACE((token[1]))) {
  ------------------
  |  |  797|  1.89k|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 1.88k, False: 10]
  |  |  |  Branch (797:38): [True: 10, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (2900:9): [True: 1.89k, False: 1.47M]
  ------------------
 2901|       |      // flush previous face group.
 2902|  1.89k|      bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
 2903|  1.89k|                                     triangulate, v, warn);
 2904|  1.89k|      (void)ret;  // return value not used.
 2905|       |
 2906|  1.89k|      if (shape.mesh.indices.size() > 0) {
  ------------------
  |  Branch (2906:11): [True: 0, False: 1.89k]
  ------------------
 2907|      0|        shapes->push_back(shape);
 2908|      0|      }
 2909|       |
 2910|  1.89k|      shape = shape_t();
 2911|       |
 2912|       |      // material = -1;
 2913|  1.89k|      prim_group.clear();
 2914|       |
 2915|  1.89k|      std::vector<std::string> names;
 2916|       |
 2917|   791k|      while (!IS_NEW_LINE(token[0])) {
  ------------------
  |  |  800|   791k|#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
  |  |  ------------------
  |  |  |  Branch (800:25): [True: 0, False: 791k]
  |  |  |  Branch (800:42): [True: 0, False: 791k]
  |  |  |  Branch (800:59): [True: 1.89k, False: 789k]
  |  |  ------------------
  ------------------
 2918|   789k|        std::string str = parseString(&token);
 2919|   789k|        names.push_back(str);
 2920|   789k|        token += strspn(token, " \t\r");  // skip tag
 2921|   789k|      }
 2922|       |
 2923|       |      // names[0] must be 'g'
 2924|       |
 2925|  1.89k|      if (names.size() < 2) {
  ------------------
  |  Branch (2925:11): [True: 1, False: 1.89k]
  ------------------
 2926|       |        // 'g' with empty names
 2927|      1|        if (warn) {
  ------------------
  |  Branch (2927:13): [True: 1, False: 0]
  ------------------
 2928|      1|          std::stringstream ss;
 2929|      1|          ss << "Empty group name. line: " << line_num << "\n";
 2930|      1|          (*warn) += ss.str();
 2931|      1|          name = "";
 2932|      1|        }
 2933|  1.89k|      } else {
 2934|  1.89k|        std::stringstream ss;
 2935|  1.89k|        ss << names[1];
 2936|       |
 2937|       |        // tinyobjloader does not support multiple groups for a primitive.
 2938|       |        // Currently we concatinate multiple group names with a space to get
 2939|       |        // single group name.
 2940|       |
 2941|   787k|        for (size_t i = 2; i < names.size(); i++) {
  ------------------
  |  Branch (2941:28): [True: 785k, False: 1.89k]
  ------------------
 2942|   785k|          ss << " " << names[i];
 2943|   785k|        }
 2944|       |
 2945|  1.89k|        name = ss.str();
 2946|  1.89k|      }
 2947|       |
 2948|  1.89k|      continue;
 2949|  1.89k|    }
 2950|       |
 2951|       |    // object name
 2952|  1.47M|    if (token[0] == 'o' && IS_SPACE((token[1]))) {
  ------------------
  |  |  797|   197k|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 14, False: 197k]
  |  |  |  Branch (797:38): [True: 197k, False: 541]
  |  |  ------------------
  ------------------
  |  Branch (2952:9): [True: 197k, False: 1.27M]
  ------------------
 2953|       |      // flush previous face group.
 2954|   197k|      bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
 2955|   197k|                                     triangulate, v, warn);
 2956|   197k|      (void)ret;  // return value not used.
 2957|       |
 2958|   197k|      if (shape.mesh.indices.size() > 0 || shape.lines.indices.size() > 0 ||
  ------------------
  |  Branch (2958:11): [True: 14, False: 197k]
  |  Branch (2958:44): [True: 0, False: 197k]
  ------------------
 2959|   197k|          shape.points.indices.size() > 0) {
  ------------------
  |  Branch (2959:11): [True: 196k, False: 534]
  ------------------
 2960|   196k|        shapes->push_back(shape);
 2961|   196k|      }
 2962|       |
 2963|       |      // material = -1;
 2964|   197k|      prim_group.clear();
 2965|   197k|      shape = shape_t();
 2966|       |
 2967|       |      // @todo { multiple object name? }
 2968|   197k|      token += 2;
 2969|   197k|      std::stringstream ss;
 2970|   197k|      ss << token;
 2971|   197k|      name = ss.str();
 2972|       |
 2973|   197k|      continue;
 2974|   197k|    }
 2975|       |
 2976|  1.28M|    if (token[0] == 't' && IS_SPACE(token[1])) {
  ------------------
  |  |  797|  1.25M|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 763k, False: 487k]
  |  |  |  Branch (797:38): [True: 483k, False: 3.89k]
  |  |  ------------------
  ------------------
  |  Branch (2976:9): [True: 1.25M, False: 29.7k]
  ------------------
 2977|  1.24M|      const int max_tag_nums = 8192;  // FIXME(syoyo): Parameterize.
 2978|  1.24M|      tag_t tag;
 2979|       |
 2980|  1.24M|      token += 2;
 2981|       |
 2982|  1.24M|      tag.name = parseString(&token);
 2983|       |
 2984|  1.24M|      tag_sizes ts = parseTagTriple(&token);
 2985|       |
 2986|  1.24M|      if (ts.num_ints < 0) {
  ------------------
  |  Branch (2986:11): [True: 0, False: 1.24M]
  ------------------
 2987|      0|        ts.num_ints = 0;
 2988|      0|      }
 2989|  1.24M|      if (ts.num_ints > max_tag_nums) {
  ------------------
  |  Branch (2989:11): [True: 293, False: 1.24M]
  ------------------
 2990|    293|        ts.num_ints = max_tag_nums;
 2991|    293|      }
 2992|       |
 2993|  1.24M|      if (ts.num_reals < 0) {
  ------------------
  |  Branch (2993:11): [True: 0, False: 1.24M]
  ------------------
 2994|      0|        ts.num_reals = 0;
 2995|      0|      }
 2996|  1.24M|      if (ts.num_reals > max_tag_nums) {
  ------------------
  |  Branch (2996:11): [True: 0, False: 1.24M]
  ------------------
 2997|      0|        ts.num_reals = max_tag_nums;
 2998|      0|      }
 2999|       |
 3000|  1.24M|      if (ts.num_strings < 0) {
  ------------------
  |  Branch (3000:11): [True: 0, False: 1.24M]
  ------------------
 3001|      0|        ts.num_strings = 0;
 3002|      0|      }
 3003|  1.24M|      if (ts.num_strings > max_tag_nums) {
  ------------------
  |  Branch (3003:11): [True: 0, False: 1.24M]
  ------------------
 3004|      0|        ts.num_strings = max_tag_nums;
 3005|      0|      }
 3006|       |
 3007|  1.24M|      tag.intValues.resize(static_cast<size_t>(ts.num_ints));
 3008|       |
 3009|  3.82M|      for (size_t i = 0; i < static_cast<size_t>(ts.num_ints); ++i) {
  ------------------
  |  Branch (3009:26): [True: 2.58M, False: 1.24M]
  ------------------
 3010|  2.58M|        tag.intValues[i] = parseInt(&token);
 3011|  2.58M|      }
 3012|       |
 3013|  1.24M|      tag.floatValues.resize(static_cast<size_t>(ts.num_reals));
 3014|  1.24M|      for (size_t i = 0; i < static_cast<size_t>(ts.num_reals); ++i) {
  ------------------
  |  Branch (3014:26): [True: 0, False: 1.24M]
  ------------------
 3015|      0|        tag.floatValues[i] = parseReal(&token);
 3016|      0|      }
 3017|       |
 3018|  1.24M|      tag.stringValues.resize(static_cast<size_t>(ts.num_strings));
 3019|  1.24M|      for (size_t i = 0; i < static_cast<size_t>(ts.num_strings); ++i) {
  ------------------
  |  Branch (3019:26): [True: 0, False: 1.24M]
  ------------------
 3020|      0|        tag.stringValues[i] = parseString(&token);
 3021|      0|      }
 3022|       |
 3023|  1.24M|      tags.push_back(tag);
 3024|       |
 3025|  1.24M|      continue;
 3026|  1.24M|    }
 3027|       |
 3028|  33.6k|    if (token[0] == 's' && IS_SPACE(token[1])) {
  ------------------
  |  |  797|     12|#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
  |  |  ------------------
  |  |  |  Branch (797:22): [True: 12, False: 0]
  |  |  |  Branch (797:38): [True: 0, False: 0]
  |  |  ------------------
  ------------------
  |  Branch (3028:9): [True: 12, False: 33.6k]
  ------------------
 3029|       |      // smoothing group id
 3030|     12|      token += 2;
 3031|       |
 3032|       |      // skip space.
 3033|     12|      token += strspn(token, " \t");  // skip space
 3034|       |
 3035|     12|      if (token[0] == '\0') {
  ------------------
  |  Branch (3035:11): [True: 8, False: 4]
  ------------------
 3036|      8|        continue;
 3037|      8|      }
 3038|       |
 3039|      4|      if (token[0] == '\r' || token[1] == '\n') {
  ------------------
  |  Branch (3039:11): [True: 0, False: 4]
  |  Branch (3039:31): [True: 0, False: 4]
  ------------------
 3040|      0|        continue;
 3041|      0|      }
 3042|       |
 3043|      4|      if (strlen(token) >= 3 && token[0] == 'o' && token[1] == 'f' &&
  ------------------
  |  Branch (3043:11): [True: 4, False: 0]
  |  Branch (3043:33): [True: 0, False: 4]
  |  Branch (3043:52): [True: 0, False: 0]
  ------------------
 3044|      4|          token[2] == 'f') {
  ------------------
  |  Branch (3044:11): [True: 0, False: 0]
  ------------------
 3045|      0|        current_smoothing_id = 0;
 3046|      4|      } else {
 3047|       |        // assume number
 3048|      4|        int smGroupId = parseInt(&token);
 3049|      4|        if (smGroupId < 0) {
  ------------------
  |  Branch (3049:13): [True: 2, False: 2]
  ------------------
 3050|       |          // parse error. force set to 0.
 3051|       |          // FIXME(syoyo): Report warning.
 3052|      2|          current_smoothing_id = 0;
 3053|      2|        } else {
 3054|      2|          current_smoothing_id = static_cast<unsigned int>(smGroupId);
 3055|      2|        }
 3056|      4|      }
 3057|       |
 3058|      4|      continue;
 3059|      4|    }  // smoothing group id
 3060|       |
 3061|       |    // Ignore unknown command.
 3062|  33.6k|  }
 3063|       |
 3064|       |  // not all vertices have colors, no default colors desired? -> clear colors
 3065|     81|  if (!found_all_colors && !default_vcols_fallback) {
  ------------------
  |  Branch (3065:7): [True: 15, False: 66]
  |  Branch (3065:28): [True: 0, False: 15]
  ------------------
 3066|      0|    vc.clear();
 3067|      0|  }
 3068|       |
 3069|     81|  if (greatest_v_idx >= static_cast<int>(v.size() / 3)) {
  ------------------
  |  Branch (3069:7): [True: 11, False: 70]
  ------------------
 3070|     11|    if (warn) {
  ------------------
  |  Branch (3070:9): [True: 11, False: 0]
  ------------------
 3071|     11|      std::stringstream ss;
 3072|     11|      ss << "Vertex indices out of bounds (line " << line_num << ".)\n\n";
 3073|     11|      (*warn) += ss.str();
 3074|     11|    }
 3075|     11|  }
 3076|     81|  if (greatest_vn_idx >= static_cast<int>(vn.size() / 3)) {
  ------------------
  |  Branch (3076:7): [True: 0, False: 81]
  ------------------
 3077|      0|    if (warn) {
  ------------------
  |  Branch (3077:9): [True: 0, False: 0]
  ------------------
 3078|      0|      std::stringstream ss;
 3079|      0|      ss << "Vertex normal indices out of bounds (line " << line_num << ".)\n\n";
 3080|      0|      (*warn) += ss.str();
 3081|      0|    }
 3082|      0|  }
 3083|     81|  if (greatest_vt_idx >= static_cast<int>(vt.size() / 2)) {
  ------------------
  |  Branch (3083:7): [True: 0, False: 81]
  ------------------
 3084|      0|    if (warn) {
  ------------------
  |  Branch (3084:9): [True: 0, False: 0]
  ------------------
 3085|      0|      std::stringstream ss;
 3086|      0|      ss << "Vertex texcoord indices out of bounds (line " << line_num << ".)\n\n";
 3087|      0|      (*warn) += ss.str();
 3088|      0|    }
 3089|      0|  }
 3090|       |
 3091|     81|  bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name,
 3092|     81|                                 triangulate, v, warn);
 3093|       |  // exportGroupsToShape return false when `usemtl` is called in the last
 3094|       |  // line.
 3095|       |  // we also add `shape` to `shapes` when `shape.mesh` has already some
 3096|       |  // faces(indices)
 3097|     81|  if (ret || shape.mesh.indices
  ------------------
  |  Branch (3097:7): [True: 16, False: 65]
  |  Branch (3097:14): [True: 0, False: 65]
  ------------------
 3098|     65|                 .size()) {  // FIXME(syoyo): Support other prims(e.g. lines)
 3099|     16|    shapes->push_back(shape);
 3100|     16|  }
 3101|     81|  prim_group.clear();  // for safety
 3102|       |
 3103|     81|  if (err) {
  ------------------
  |  Branch (3103:7): [True: 81, False: 0]
  ------------------
 3104|     81|    (*err) += errss.str();
 3105|     81|  }
 3106|       |
 3107|     81|  attrib->vertices.swap(v);
 3108|     81|  attrib->vertex_weights.swap(v);
 3109|     81|  attrib->normals.swap(vn);
 3110|     81|  attrib->texcoords.swap(vt);
 3111|     81|  attrib->texcoord_ws.swap(vt);
 3112|     81|  attrib->colors.swap(vc);
 3113|     81|  attrib->skin_weights.swap(vw);
 3114|       |
 3115|     81|  return true;
 3116|     82|}
_ZN7tinyobj9ObjReader15ParseFromStringERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES9_RKNS_15ObjReaderConfigE:
 3439|     82|                                const ObjReaderConfig &config) {
 3440|     82|  std::stringbuf obj_buf(obj_text);
 3441|     82|  std::stringbuf mtl_buf(mtl_text);
 3442|       |
 3443|     82|  std::istream obj_ifs(&obj_buf);
 3444|     82|  std::istream mtl_ifs(&mtl_buf);
 3445|       |
 3446|     82|  MaterialStreamReader mtl_ss(mtl_ifs);
 3447|       |
 3448|     82|  valid_ = LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_,
 3449|     82|                   &obj_ifs, &mtl_ss, config.triangulate, config.vertex_color);
 3450|       |
 3451|     82|  return valid_;
 3452|     82|}
fuzz_ParseFromString.cc:_ZN7tinyobjL9parseRealEPPKcd:
 1023|  1.04M|static inline real_t parseReal(const char **token, double default_value = 0.0) {
 1024|  1.04M|  (*token) += strspn((*token), " \t");
 1025|  1.04M|  const char *end = (*token) + strcspn((*token), " \t\r");
 1026|  1.04M|  double val = default_value;
 1027|  1.04M|  tryParseDouble((*token), end, &val);
 1028|  1.04M|  real_t f = static_cast<real_t>(val);
 1029|  1.04M|  (*token) = end;
 1030|  1.04M|  return f;
 1031|  1.04M|}
fuzz_ParseFromString.cc:_ZN7tinyobjL14tryParseDoubleEPKcS1_Pd:
  891|  1.22M|static bool tryParseDouble(const char *s, const char *s_end, double *result) {
  892|  1.22M|  if (s >= s_end) {
  ------------------
  |  Branch (892:7): [True: 699k, False: 525k]
  ------------------
  893|   699k|    return false;
  894|   699k|  }
  895|       |
  896|   525k|  double mantissa = 0.0;
  897|       |  // This exponent is base 2 rather than 10.
  898|       |  // However the exponent we parse is supposed to be one of ten,
  899|       |  // thus we must take care to convert the exponent/and or the
  900|       |  // mantissa to a * 2^E, where a is the mantissa and E is the
  901|       |  // exponent.
  902|       |  // To get the final double we will use ldexp, it requires the
  903|       |  // exponent to be in base 2.
  904|   525k|  int exponent = 0;
  905|       |
  906|       |  // NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED
  907|       |  // TO JUMP OVER DEFINITIONS.
  908|   525k|  char sign = '+';
  909|   525k|  char exp_sign = '+';
  910|   525k|  char const *curr = s;
  911|       |
  912|       |  // How many characters were read in a loop.
  913|   525k|  int read = 0;
  914|       |  // Tells whether a loop terminated due to reaching s_end.
  915|   525k|  bool end_not_reached = false;
  916|   525k|  bool leading_decimal_dots = false;
  917|       |
  918|       |  /*
  919|       |          BEGIN PARSING.
  920|       |  */
  921|       |
  922|       |  // Find out what sign we've got.
  923|   525k|  if (*curr == '+' || *curr == '-') {
  ------------------
  |  Branch (923:7): [True: 1, False: 525k]
  |  Branch (923:23): [True: 24, False: 525k]
  ------------------
  924|     25|    sign = *curr;
  925|     25|    curr++;
  926|     25|    if ((curr != s_end) && (*curr == '.')) {
  ------------------
  |  Branch (926:9): [True: 24, False: 1]
  |  Branch (926:28): [True: 0, False: 24]
  ------------------
  927|       |      // accept. Somethig like `.7e+2`, `-.5234`
  928|      0|      leading_decimal_dots = true;
  929|      0|    }
  930|   525k|  } else if (IS_DIGIT(*curr)) { /* Pass through. */
  ------------------
  |  |  799|   525k|  (static_cast<unsigned int>((x) - '0') < static_cast<unsigned int>(10))
  |  |  ------------------
  |  |  |  Branch (799:3): [True: 524k, False: 1.38k]
  |  |  ------------------
  ------------------
  931|   524k|  } else if (*curr == '.') {
  ------------------
  |  Branch (931:14): [True: 796, False: 593]
  ------------------
  932|       |    // accept. Somethig like `.7e+2`, `-.5234`
  933|    796|    leading_decimal_dots = true;
  934|    796|  } else {
  935|    593|    goto fail;
  936|    593|  }
  937|       |
  938|       |  // Read the integer part.
  939|   525k|  end_not_reached = (curr != s_end);
  940|   525k|  if (!leading_decimal_dots) {
  ------------------
  |  Branch (940:7): [True: 524k, False: 796]
  ------------------
  941|  1.05M|    while (end_not_reached && IS_DIGIT(*curr)) {
  ------------------
  |  |  799|   527k|  (static_cast<unsigned int>((x) - '0') < static_cast<unsigned int>(10))
  |  |  ------------------
  |  |  |  Branch (799:3): [True: 526k, False: 449]
  |  |  ------------------
  ------------------
  |  Branch (941:12): [True: 527k, False: 523k]
  ------------------
  942|   526k|      mantissa *= 10;
  943|   526k|      mantissa += static_cast<int>(*curr - 0x30);
  944|   526k|      curr++;
  945|   526k|      read++;
  946|   526k|      end_not_reached = (curr != s_end);
  947|   526k|    }
  948|       |
  949|       |    // We must make sure we actually got something.
  950|   524k|    if (read == 0) goto fail;
  ------------------
  |  Branch (950:9): [True: 8, False: 524k]
  ------------------
  951|   524k|  }
  952|       |
  953|       |  // We allow numbers of form "#", "###" etc.
  954|   525k|  if (!end_not_reached) goto assemble;
  ------------------
  |  Branch (954:7): [True: 523k, False: 1.23k]
  ------------------
  955|       |
  956|       |  // Read the decimal part.
  957|  1.23k|  if (*curr == '.') {
  ------------------
  |  Branch (957:7): [True: 796, False: 442]
  ------------------
  958|    796|    curr++;
  959|    796|    read = 1;
  960|    796|    end_not_reached = (curr != s_end);
  961|   525k|    while (end_not_reached && IS_DIGIT(*curr)) {
  ------------------
  |  |  799|   525k|  (static_cast<unsigned int>((x) - '0') < static_cast<unsigned int>(10))
  |  |  ------------------
  |  |  |  Branch (799:3): [True: 525k, False: 398]
  |  |  ------------------
  ------------------
  |  Branch (961:12): [True: 525k, False: 398]
  ------------------
  962|   525k|      static const double pow_lut[] = {
  963|   525k|          1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001,
  964|   525k|      };
  965|   525k|      const int lut_entries = sizeof pow_lut / sizeof pow_lut[0];
  966|       |
  967|       |      // NOTE: Don't use powf here, it will absolutely murder precision.
  968|   525k|      mantissa += static_cast<int>(*curr - 0x30) *
  969|   525k|                  (read < lut_entries ? pow_lut[read] : std::pow(10.0, -read));
  ------------------
  |  Branch (969:20): [True: 798, False: 524k]
  ------------------
  970|   525k|      read++;
  971|   525k|      curr++;
  972|   525k|      end_not_reached = (curr != s_end);
  973|   525k|    }
  974|    796|  } else if (*curr == 'e' || *curr == 'E') {
  ------------------
  |  Branch (974:14): [True: 12, False: 430]
  |  Branch (974:30): [True: 0, False: 430]
  ------------------
  975|    430|  } else {
  976|    430|    goto assemble;
  977|    430|  }
  978|       |
  979|    808|  if (!end_not_reached) goto assemble;
  ------------------
  |  Branch (979:7): [True: 398, False: 410]
  ------------------
  980|       |
  981|       |  // Read the exponent part.
  982|    410|  if (*curr == 'e' || *curr == 'E') {
  ------------------
  |  Branch (982:7): [True: 409, False: 1]
  |  Branch (982:23): [True: 0, False: 1]
  ------------------
  983|    409|    curr++;
  984|       |    // Figure out if a sign is present and if it is.
  985|    409|    end_not_reached = (curr != s_end);
  986|    409|    if (end_not_reached && (*curr == '+' || *curr == '-')) {
  ------------------
  |  Branch (986:9): [True: 407, False: 2]
  |  Branch (986:29): [True: 0, False: 407]
  |  Branch (986:45): [True: 393, False: 14]
  ------------------
  987|    393|      exp_sign = *curr;
  988|    393|      curr++;
  989|    393|    } else if (IS_DIGIT(*curr)) { /* Pass through. */
  ------------------
  |  |  799|     16|  (static_cast<unsigned int>((x) - '0') < static_cast<unsigned int>(10))
  |  |  ------------------
  |  |  |  Branch (799:3): [True: 14, False: 2]
  |  |  ------------------
  ------------------
  990|     14|    } else {
  991|       |      // Empty E is not allowed.
  992|      2|      goto fail;
  993|      2|    }
  994|       |
  995|    407|    read = 0;
  996|    407|    end_not_reached = (curr != s_end);
  997|  3.59k|    while (end_not_reached && IS_DIGIT(*curr)) {
  ------------------
  |  |  799|  3.19k|  (static_cast<unsigned int>((x) - '0') < static_cast<unsigned int>(10))
  |  |  ------------------
  |  |  |  Branch (799:3): [True: 3.18k, False: 3]
  |  |  ------------------
  ------------------
  |  Branch (997:12): [True: 3.19k, False: 404]
  ------------------
  998|       |      // To avoid annoying MSVC's min/max macro definiton,
  999|       |      // Use hardcoded int max value
 1000|  3.18k|      if (exponent > (2147483647/10)) { // 2147483647 = std::numeric_limits<int>::max()
  ------------------
  |  Branch (1000:11): [True: 0, False: 3.18k]
  ------------------
 1001|       |        // Integer overflow
 1002|      0|        goto fail;
 1003|      0|      }
 1004|  3.18k|      exponent *= 10;
 1005|  3.18k|      exponent += static_cast<int>(*curr - 0x30);
 1006|  3.18k|      curr++;
 1007|  3.18k|      read++;
 1008|  3.18k|      end_not_reached = (curr != s_end);
 1009|  3.18k|    }
 1010|    407|    exponent *= (exp_sign == '+' ? 1 : -1);
  ------------------
  |  Branch (1010:18): [True: 14, False: 393]
  ------------------
 1011|    407|    if (read == 0) goto fail;
  ------------------
  |  Branch (1011:9): [True: 0, False: 407]
  ------------------
 1012|    407|  }
 1013|       |
 1014|   525k|assemble:
 1015|   525k|  *result = (sign == '+' ? 1 : -1) *
  ------------------
  |  Branch (1015:14): [True: 525k, False: 17]
  ------------------
 1016|   525k|            (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent)
  ------------------
  |  Branch (1016:14): [True: 407, False: 524k]
  ------------------
 1017|   525k|                      : mantissa);
 1018|   525k|  return true;
 1019|    603|fail:
 1020|    603|  return false;
 1021|    410|}
fuzz_ParseFromString.cc:_ZN7tinyobjL8parseIntEPPKc:
  857|  2.58M|static inline int parseInt(const char **token) {
  858|  2.58M|  (*token) += strspn((*token), " \t");
  859|  2.58M|  int i = atoi((*token));
  860|  2.58M|  (*token) += strcspn((*token), " \t\r");
  861|  2.58M|  return i;
  862|  2.58M|}
fuzz_ParseFromString.cc:_ZN7tinyobjL10parseReal2EPfS0_PPKcdd:
 1048|   262k|                              const double default_y = 0.0) {
 1049|   262k|  (*x) = parseReal(token, default_x);
 1050|   262k|  (*y) = parseReal(token, default_y);
 1051|   262k|}
fuzz_ParseFromString.cc:_ZN7tinyobjL11parseStringEPPKc:
  848|  2.10M|static inline std::string parseString(const char **token) {
  849|  2.10M|  std::string s;
  850|  2.10M|  (*token) += strspn((*token), " \t");
  851|  2.10M|  size_t e = strcspn((*token), " \t\r");
  852|  2.10M|  s = std::string((*token), &(*token)[e]);
  853|  2.10M|  (*token) += e;
  854|  2.10M|  return s;
  855|  2.10M|}
fuzz_ParseFromString.cc:_ZN7tinyobjL12InitMaterialEPNS_10material_tE:
 1359|  65.6k|static void InitMaterial(material_t *material) {
 1360|  65.6k|  InitTexOpt(&material->ambient_texopt, /* is_bump */ false);
 1361|  65.6k|  InitTexOpt(&material->diffuse_texopt, /* is_bump */ false);
 1362|  65.6k|  InitTexOpt(&material->specular_texopt, /* is_bump */ false);
 1363|  65.6k|  InitTexOpt(&material->specular_highlight_texopt, /* is_bump */ false);
 1364|  65.6k|  InitTexOpt(&material->bump_texopt, /* is_bump */ true);
 1365|  65.6k|  InitTexOpt(&material->displacement_texopt, /* is_bump */ false);
 1366|  65.6k|  InitTexOpt(&material->alpha_texopt, /* is_bump */ false);
 1367|  65.6k|  InitTexOpt(&material->reflection_texopt, /* is_bump */ false);
 1368|  65.6k|  InitTexOpt(&material->roughness_texopt, /* is_bump */ false);
 1369|  65.6k|  InitTexOpt(&material->metallic_texopt, /* is_bump */ false);
 1370|  65.6k|  InitTexOpt(&material->sheen_texopt, /* is_bump */ false);
 1371|  65.6k|  InitTexOpt(&material->emissive_texopt, /* is_bump */ false);
 1372|  65.6k|  InitTexOpt(&material->normal_texopt,
 1373|  65.6k|             /* is_bump */ false);  // @fixme { is_bump will be true? }
 1374|  65.6k|  material->name = "";
 1375|  65.6k|  material->ambient_texname = "";
 1376|  65.6k|  material->diffuse_texname = "";
 1377|  65.6k|  material->specular_texname = "";
 1378|  65.6k|  material->specular_highlight_texname = "";
 1379|  65.6k|  material->bump_texname = "";
 1380|  65.6k|  material->displacement_texname = "";
 1381|  65.6k|  material->reflection_texname = "";
 1382|  65.6k|  material->alpha_texname = "";
 1383|   262k|  for (int i = 0; i < 3; i++) {
  ------------------
  |  Branch (1383:19): [True: 196k, False: 65.6k]
  ------------------
 1384|   196k|    material->ambient[i] = static_cast<real_t>(0.0);
 1385|   196k|    material->diffuse[i] = static_cast<real_t>(0.0);
 1386|   196k|    material->specular[i] = static_cast<real_t>(0.0);
 1387|   196k|    material->transmittance[i] = static_cast<real_t>(0.0);
 1388|   196k|    material->emission[i] = static_cast<real_t>(0.0);
 1389|   196k|  }
 1390|  65.6k|  material->illum = 0;
 1391|  65.6k|  material->dissolve = static_cast<real_t>(1.0);
 1392|  65.6k|  material->shininess = static_cast<real_t>(1.0);
 1393|  65.6k|  material->ior = static_cast<real_t>(1.0);
 1394|       |
 1395|  65.6k|  material->roughness = static_cast<real_t>(0.0);
 1396|  65.6k|  material->metallic = static_cast<real_t>(0.0);
 1397|  65.6k|  material->sheen = static_cast<real_t>(0.0);
 1398|  65.6k|  material->clearcoat_thickness = static_cast<real_t>(0.0);
 1399|  65.6k|  material->clearcoat_roughness = static_cast<real_t>(0.0);
 1400|  65.6k|  material->anisotropy_rotation = static_cast<real_t>(0.0);
 1401|  65.6k|  material->anisotropy = static_cast<real_t>(0.0);
 1402|  65.6k|  material->roughness_texname = "";
 1403|  65.6k|  material->metallic_texname = "";
 1404|  65.6k|  material->sheen_texname = "";
 1405|  65.6k|  material->emissive_texname = "";
 1406|  65.6k|  material->normal_texname = "";
 1407|       |
 1408|  65.6k|  material->unknown_parameter.clear();
 1409|  65.6k|}
fuzz_ParseFromString.cc:_ZN7tinyobjL10InitTexOptEPNS_16texture_option_tEb:
 1333|   852k|static void InitTexOpt(texture_option_t *texopt, const bool is_bump) {
 1334|   852k|  if (is_bump) {
  ------------------
  |  Branch (1334:7): [True: 65.6k, False: 787k]
  ------------------
 1335|  65.6k|    texopt->imfchan = 'l';
 1336|   787k|  } else {
 1337|   787k|    texopt->imfchan = 'm';
 1338|   787k|  }
 1339|   852k|  texopt->bump_multiplier = static_cast<real_t>(1.0);
 1340|   852k|  texopt->clamp = false;
 1341|   852k|  texopt->blendu = true;
 1342|   852k|  texopt->blendv = true;
 1343|   852k|  texopt->sharpness = static_cast<real_t>(1.0);
 1344|   852k|  texopt->brightness = static_cast<real_t>(0.0);
 1345|   852k|  texopt->contrast = static_cast<real_t>(1.0);
 1346|   852k|  texopt->origin_offset[0] = static_cast<real_t>(0.0);
 1347|   852k|  texopt->origin_offset[1] = static_cast<real_t>(0.0);
 1348|   852k|  texopt->origin_offset[2] = static_cast<real_t>(0.0);
 1349|   852k|  texopt->scale[0] = static_cast<real_t>(1.0);
 1350|   852k|  texopt->scale[1] = static_cast<real_t>(1.0);
 1351|   852k|  texopt->scale[2] = static_cast<real_t>(1.0);
 1352|   852k|  texopt->turbulence[0] = static_cast<real_t>(0.0);
 1353|   852k|  texopt->turbulence[1] = static_cast<real_t>(0.0);
 1354|   852k|  texopt->turbulence[2] = static_cast<real_t>(0.0);
 1355|   852k|  texopt->texture_resolution = -1;
 1356|   852k|  texopt->type = TEXTURE_TYPE_NONE;
 1357|   852k|}
fuzz_ParseFromString.cc:_ZN7tinyobjL11safeGetlineERNSt3__113basic_istreamIcNS0_11char_traitsIcEEEERNS0_12basic_stringIcS3_NS0_9allocatorIcEEEE:
  763|  2.72M|static std::istream &safeGetline(std::istream &is, std::string &t) {
  764|  2.72M|  t.clear();
  765|       |
  766|       |  // The characters in the stream are read one-by-one using a std::streambuf.
  767|       |  // That is faster than reading them one-by-one using the std::istream.
  768|       |  // Code that uses streambuf this way must be guarded by a sentry object.
  769|       |  // The sentry object performs various tasks,
  770|       |  // such as thread synchronization and updating the stream state.
  771|       |
  772|  2.72M|  std::istream::sentry se(is, true);
  773|  2.72M|  std::streambuf *sb = is.rdbuf();
  774|       |
  775|  2.72M|  if (se) {
  ------------------
  |  Branch (775:7): [True: 2.72M, False: 0]
  ------------------
  776|  44.8M|    for (;;) {
  777|  44.8M|      int c = sb->sbumpc();
  778|  44.8M|      switch (c) {
  779|  2.00M|        case '\n':
  ------------------
  |  Branch (779:9): [True: 2.00M, False: 42.8M]
  ------------------
  780|  2.00M|          return is;
  781|   718k|        case '\r':
  ------------------
  |  Branch (781:9): [True: 718k, False: 44.1M]
  ------------------
  782|   718k|          if (sb->sgetc() == '\n') sb->sbumpc();
  ------------------
  |  Branch (782:15): [True: 3, False: 718k]
  ------------------
  783|   718k|          return is;
  784|    110|        case EOF:
  ------------------
  |  Branch (784:9): [True: 110, False: 44.8M]
  ------------------
  785|       |          // Also handle the case when the last line has no line ending
  786|    110|          if (t.empty()) is.setstate(std::ios::eofbit);
  ------------------
  |  Branch (786:15): [True: 0, False: 110]
  ------------------
  787|    110|          return is;
  788|  42.1M|        default:
  ------------------
  |  Branch (788:9): [True: 42.1M, False: 2.72M]
  ------------------
  789|  42.1M|          t += static_cast<char>(c);
  790|  44.8M|      }
  791|  44.8M|    }
  792|  2.72M|  }
  793|       |
  794|      0|  return is;
  795|  2.72M|}
_ZN7tinyobj14MaterialReaderC2Ev:
  461|     82|  MaterialReader() {}
fuzz_ParseFromString.cc:_ZN7tinyobjL20parseVertexWithColorEPfS0_S0_S0_S0_S0_PPKcddd:
 1079|   175k|                                        const double default_z = 0.0) {
 1080|   175k|  (*x) = parseReal(token, default_x);
 1081|   175k|  (*y) = parseReal(token, default_y);
 1082|   175k|  (*z) = parseReal(token, default_z);
 1083|       |
 1084|   175k|  const bool found_color =
 1085|   175k|      parseReal(token, r) && parseReal(token, g) && parseReal(token, b);
  ------------------
  |  Branch (1085:7): [True: 4, False: 175k]
  |  Branch (1085:30): [True: 0, False: 4]
  |  Branch (1085:53): [True: 0, False: 0]
  ------------------
 1086|       |
 1087|   175k|  if (!found_color) {
  ------------------
  |  Branch (1087:7): [True: 175k, False: 0]
  ------------------
 1088|   175k|    (*r) = (*g) = (*b) = 1.0;
 1089|   175k|  }
 1090|       |
 1091|   175k|  return found_color;
 1092|   175k|}
fuzz_ParseFromString.cc:_ZN7tinyobjL9parseRealEPPKcPf:
 1033|   175k|static inline bool parseReal(const char **token, real_t *out) {
 1034|   175k|  (*token) += strspn((*token), " \t");
 1035|   175k|  const char *end = (*token) + strcspn((*token), " \t\r");
 1036|   175k|  double val;
 1037|   175k|  bool ret = tryParseDouble((*token), end, &val);
 1038|   175k|  if (ret) {
  ------------------
  |  Branch (1038:7): [True: 4, False: 175k]
  ------------------
 1039|      4|    real_t f = static_cast<real_t>(val);
 1040|      4|    (*out) = f;
 1041|      4|  }
 1042|   175k|  (*token) = end;
 1043|   175k|  return ret;
 1044|   175k|}
_ZN7tinyobj14vertex_index_tC2Ev:
  695|  2.17M|  vertex_index_t() : v_idx(-1), vt_idx(-1), vn_idx(-1) {}
fuzz_ParseFromString.cc:_ZN7tinyobjL11parseTripleEPPKciiiPNS_14vertex_index_tERKNS_15warning_contextE:
 1162|  2.17M|                        vertex_index_t *ret, const warning_context &context) {
 1163|  2.17M|  if (!ret) {
  ------------------
  |  Branch (1163:7): [True: 0, False: 2.17M]
  ------------------
 1164|      0|    return false;
 1165|      0|  }
 1166|       |
 1167|  2.17M|  vertex_index_t vi(-1);
 1168|       |
 1169|  2.17M|  if (!fixIndex(atoi((*token)), vsize, &vi.v_idx, false, context)) {
  ------------------
  |  Branch (1169:7): [True: 1, False: 2.17M]
  ------------------
 1170|      1|    return false;
 1171|      1|  }
 1172|       |
 1173|  2.17M|  (*token) += strcspn((*token), "/ \t\r");
 1174|  2.17M|  if ((*token)[0] != '/') {
  ------------------
  |  Branch (1174:7): [True: 2.17M, False: 0]
  ------------------
 1175|  2.17M|    (*ret) = vi;
 1176|  2.17M|    return true;
 1177|  2.17M|  }
 1178|      0|  (*token)++;
 1179|       |
 1180|       |  // i//k
 1181|      0|  if ((*token)[0] == '/') {
  ------------------
  |  Branch (1181:7): [True: 0, False: 0]
  ------------------
 1182|      0|    (*token)++;
 1183|      0|    if (!fixIndex(atoi((*token)), vnsize, &vi.vn_idx, true, context)) {
  ------------------
  |  Branch (1183:9): [True: 0, False: 0]
  ------------------
 1184|      0|      return false;
 1185|      0|    }
 1186|      0|    (*token) += strcspn((*token), "/ \t\r");
 1187|      0|    (*ret) = vi;
 1188|      0|    return true;
 1189|      0|  }
 1190|       |
 1191|       |  // i/j/k or i/j
 1192|      0|  if (!fixIndex(atoi((*token)), vtsize, &vi.vt_idx, true, context)) {
  ------------------
  |  Branch (1192:7): [True: 0, False: 0]
  ------------------
 1193|      0|    return false;
 1194|      0|  }
 1195|       |
 1196|      0|  (*token) += strcspn((*token), "/ \t\r");
 1197|      0|  if ((*token)[0] != '/') {
  ------------------
  |  Branch (1197:7): [True: 0, False: 0]
  ------------------
 1198|      0|    (*ret) = vi;
 1199|      0|    return true;
 1200|      0|  }
 1201|       |
 1202|       |  // i/j/k
 1203|      0|  (*token)++;  // skip '/'
 1204|      0|  if (!fixIndex(atoi((*token)), vnsize, &vi.vn_idx, true, context)) {
  ------------------
  |  Branch (1204:7): [True: 0, False: 0]
  ------------------
 1205|      0|    return false;
 1206|      0|  }
 1207|      0|  (*token) += strcspn((*token), "/ \t\r");
 1208|       |
 1209|      0|  (*ret) = vi;
 1210|       |
 1211|      0|  return true;
 1212|      0|}
_ZN7tinyobj14vertex_index_tC2Ei:
  696|  2.17M|  explicit vertex_index_t(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {}
fuzz_ParseFromString.cc:_ZN7tinyobjL8fixIndexEiiPibRKNS_15warning_contextE:
  816|  2.17M|static inline bool fixIndex(int idx, int n, int *ret, bool allow_zero, const warning_context &context) {
  817|  2.17M|  if (!ret) {
  ------------------
  |  Branch (817:7): [True: 0, False: 2.17M]
  ------------------
  818|      0|    return false;
  819|      0|  }
  820|       |
  821|  2.17M|  if (idx > 0) {
  ------------------
  |  Branch (821:7): [True: 2.17M, False: 62]
  ------------------
  822|  2.17M|    (*ret) = idx - 1;
  823|  2.17M|    return true;
  824|  2.17M|  }
  825|       |
  826|     62|  if (idx == 0) {
  ------------------
  |  Branch (826:7): [True: 1, False: 61]
  ------------------
  827|       |    // zero is not allowed according to the spec.
  828|      1|    if (context.warn) {
  ------------------
  |  Branch (828:9): [True: 1, False: 0]
  ------------------
  829|      1|      (*context.warn) += "A zero value index found (will have a value of -1 for normal and tex indices. Line "
  830|      1|          + toString(context.line_number) + ").\n";
  831|      1|    }
  832|       |
  833|      1|    (*ret) = idx - 1;
  834|      1|    return allow_zero;
  835|      1|  }
  836|       |
  837|     61|  if (idx < 0) {
  ------------------
  |  Branch (837:7): [True: 61, False: 0]
  ------------------
  838|     61|    (*ret) = n + idx;  // negative value = relative
  839|     61|    if((*ret) < 0){
  ------------------
  |  Branch (839:8): [True: 0, False: 61]
  ------------------
  840|      0|      return false;  // invalid relative index
  841|      0|    }
  842|     61|    return true;
  843|     61|  }
  844|       |
  845|      0|  return false;  // never reach here.
  846|     61|}
_ZN7tinyobj6face_tC2Ev:
  709|   266k|  face_t() : smoothing_group_id(0), pad_(0) {}
fuzz_ParseFromString.cc:_ZN7tinyobjL19exportGroupsToShapeEPNS_7shape_tERKNS_9PrimGroupERKNSt3__16vectorINS_5tag_tENS5_9allocatorIS7_EEEEiRKNS5_12basic_stringIcNS5_11char_traitsIcEENS8_IcEEEEbRKNS6_IfNS8_IfEEEEPSH_:
 1465|   199k|                                std::string *warn) {
 1466|   199k|  if (prim_group.IsEmpty()) {
  ------------------
  |  Branch (1466:7): [True: 1.29k, False: 197k]
  ------------------
 1467|  1.29k|    return false;
 1468|  1.29k|  }
 1469|       |
 1470|   197k|  shape->name = name;
 1471|       |
 1472|       |  // polygon
 1473|   197k|  if (!prim_group.faceGroup.empty()) {
  ------------------
  |  Branch (1473:7): [True: 1.34k, False: 196k]
  ------------------
 1474|       |    // Flatten vertices and indices
 1475|  5.80k|    for (size_t i = 0; i < prim_group.faceGroup.size(); i++) {
  ------------------
  |  Branch (1475:24): [True: 4.46k, False: 1.34k]
  ------------------
 1476|  4.46k|      const face_t &face = prim_group.faceGroup[i];
 1477|       |
 1478|  4.46k|      size_t npolys = face.vertex_indices.size();
 1479|       |
 1480|  4.46k|      if (npolys < 3) {
  ------------------
  |  Branch (1480:11): [True: 2.01k, False: 2.45k]
  ------------------
 1481|       |        // Face must have 3+ vertices.
 1482|  2.01k|        if (warn) {
  ------------------
  |  Branch (1482:13): [True: 2.01k, False: 0]
  ------------------
 1483|  2.01k|          (*warn) += "Degenerated face found\n.";
 1484|  2.01k|        }
 1485|  2.01k|        continue;
 1486|  2.01k|      }
 1487|       |
 1488|  2.45k|      if (triangulate && npolys != 3) {
  ------------------
  |  Branch (1488:11): [True: 2.45k, False: 0]
  |  Branch (1488:26): [True: 2.41k, False: 37]
  ------------------
 1489|  2.41k|        if (npolys == 4) {
  ------------------
  |  Branch (1489:13): [True: 0, False: 2.41k]
  ------------------
 1490|      0|          vertex_index_t i0 = face.vertex_indices[0];
 1491|      0|          vertex_index_t i1 = face.vertex_indices[1];
 1492|      0|          vertex_index_t i2 = face.vertex_indices[2];
 1493|      0|          vertex_index_t i3 = face.vertex_indices[3];
 1494|       |
 1495|      0|          size_t vi0 = size_t(i0.v_idx);
 1496|      0|          size_t vi1 = size_t(i1.v_idx);
 1497|      0|          size_t vi2 = size_t(i2.v_idx);
 1498|      0|          size_t vi3 = size_t(i3.v_idx);
 1499|       |
 1500|      0|          if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) ||
  ------------------
  |  Branch (1500:15): [True: 0, False: 0]
  |  Branch (1500:46): [True: 0, False: 0]
  ------------------
 1501|      0|              ((3 * vi2 + 2) >= v.size()) || ((3 * vi3 + 2) >= v.size())) {
  ------------------
  |  Branch (1501:15): [True: 0, False: 0]
  |  Branch (1501:46): [True: 0, False: 0]
  ------------------
 1502|       |            // Invalid triangle.
 1503|       |            // FIXME(syoyo): Is it ok to simply skip this invalid triangle?
 1504|      0|            if (warn) {
  ------------------
  |  Branch (1504:17): [True: 0, False: 0]
  ------------------
 1505|      0|              (*warn) += "Face with invalid vertex index found.\n";
 1506|      0|            }
 1507|      0|            continue;
 1508|      0|          }
 1509|       |
 1510|      0|          real_t v0x = v[vi0 * 3 + 0];
 1511|      0|          real_t v0y = v[vi0 * 3 + 1];
 1512|      0|          real_t v0z = v[vi0 * 3 + 2];
 1513|      0|          real_t v1x = v[vi1 * 3 + 0];
 1514|      0|          real_t v1y = v[vi1 * 3 + 1];
 1515|      0|          real_t v1z = v[vi1 * 3 + 2];
 1516|      0|          real_t v2x = v[vi2 * 3 + 0];
 1517|      0|          real_t v2y = v[vi2 * 3 + 1];
 1518|      0|          real_t v2z = v[vi2 * 3 + 2];
 1519|      0|          real_t v3x = v[vi3 * 3 + 0];
 1520|      0|          real_t v3y = v[vi3 * 3 + 1];
 1521|      0|          real_t v3z = v[vi3 * 3 + 2];
 1522|       |
 1523|       |          // There are two candidates to split the quad into two triangles.
 1524|       |          //
 1525|       |          // Choose the shortest edge.
 1526|       |          // TODO: Is it better to determine the edge to split by calculating
 1527|       |          // the area of each triangle?
 1528|       |          //
 1529|       |          // +---+
 1530|       |          // |\  |
 1531|       |          // | \ |
 1532|       |          // |  \|
 1533|       |          // +---+
 1534|       |          //
 1535|       |          // +---+
 1536|       |          // |  /|
 1537|       |          // | / |
 1538|       |          // |/  |
 1539|       |          // +---+
 1540|       |
 1541|      0|          real_t e02x = v2x - v0x;
 1542|      0|          real_t e02y = v2y - v0y;
 1543|      0|          real_t e02z = v2z - v0z;
 1544|      0|          real_t e13x = v3x - v1x;
 1545|      0|          real_t e13y = v3y - v1y;
 1546|      0|          real_t e13z = v3z - v1z;
 1547|       |
 1548|      0|          real_t sqr02 = e02x * e02x + e02y * e02y + e02z * e02z;
 1549|      0|          real_t sqr13 = e13x * e13x + e13y * e13y + e13z * e13z;
 1550|       |
 1551|      0|          index_t idx0, idx1, idx2, idx3;
 1552|       |
 1553|      0|          idx0.vertex_index = i0.v_idx;
 1554|      0|          idx0.normal_index = i0.vn_idx;
 1555|      0|          idx0.texcoord_index = i0.vt_idx;
 1556|      0|          idx1.vertex_index = i1.v_idx;
 1557|      0|          idx1.normal_index = i1.vn_idx;
 1558|      0|          idx1.texcoord_index = i1.vt_idx;
 1559|      0|          idx2.vertex_index = i2.v_idx;
 1560|      0|          idx2.normal_index = i2.vn_idx;
 1561|      0|          idx2.texcoord_index = i2.vt_idx;
 1562|      0|          idx3.vertex_index = i3.v_idx;
 1563|      0|          idx3.normal_index = i3.vn_idx;
 1564|      0|          idx3.texcoord_index = i3.vt_idx;
 1565|       |
 1566|      0|          if (sqr02 < sqr13) {
  ------------------
  |  Branch (1566:15): [True: 0, False: 0]
  ------------------
 1567|       |            // [0, 1, 2], [0, 2, 3]
 1568|      0|            shape->mesh.indices.push_back(idx0);
 1569|      0|            shape->mesh.indices.push_back(idx1);
 1570|      0|            shape->mesh.indices.push_back(idx2);
 1571|       |
 1572|      0|            shape->mesh.indices.push_back(idx0);
 1573|      0|            shape->mesh.indices.push_back(idx2);
 1574|      0|            shape->mesh.indices.push_back(idx3);
 1575|      0|          } else {
 1576|       |            // [0, 1, 3], [1, 2, 3]
 1577|      0|            shape->mesh.indices.push_back(idx0);
 1578|      0|            shape->mesh.indices.push_back(idx1);
 1579|      0|            shape->mesh.indices.push_back(idx3);
 1580|       |
 1581|      0|            shape->mesh.indices.push_back(idx1);
 1582|      0|            shape->mesh.indices.push_back(idx2);
 1583|      0|            shape->mesh.indices.push_back(idx3);
 1584|      0|          }
 1585|       |
 1586|       |          // Two triangle faces
 1587|      0|          shape->mesh.num_face_vertices.push_back(3);
 1588|      0|          shape->mesh.num_face_vertices.push_back(3);
 1589|       |
 1590|      0|          shape->mesh.material_ids.push_back(material_id);
 1591|      0|          shape->mesh.material_ids.push_back(material_id);
 1592|       |
 1593|      0|          shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);
 1594|      0|          shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id);
 1595|       |
 1596|  2.41k|        } else {
 1597|       |#ifdef TINYOBJLOADER_USE_MAPBOX_EARCUT
 1598|       |          vertex_index_t i0 = face.vertex_indices[0];
 1599|       |          vertex_index_t i0_2 = i0;
 1600|       |
 1601|       |          // TMW change: Find the normal axis of the polygon using Newell's method
 1602|       |          TinyObjPoint n;
 1603|       |          for (size_t k = 0; k < npolys; ++k) {
 1604|       |            i0 = face.vertex_indices[k % npolys];
 1605|       |            size_t vi0 = size_t(i0.v_idx);
 1606|       |
 1607|       |            size_t j = (k + 1) % npolys;
 1608|       |            i0_2 = face.vertex_indices[j];
 1609|       |            size_t vi0_2 = size_t(i0_2.v_idx);
 1610|       |
 1611|       |            real_t v0x = v[vi0 * 3 + 0];
 1612|       |            real_t v0y = v[vi0 * 3 + 1];
 1613|       |            real_t v0z = v[vi0 * 3 + 2];
 1614|       |
 1615|       |            real_t v0x_2 = v[vi0_2 * 3 + 0];
 1616|       |            real_t v0y_2 = v[vi0_2 * 3 + 1];
 1617|       |            real_t v0z_2 = v[vi0_2 * 3 + 2];
 1618|       |
 1619|       |            const TinyObjPoint point1(v0x,v0y,v0z);
 1620|       |            const TinyObjPoint point2(v0x_2,v0y_2,v0z_2);
 1621|       |
 1622|       |            TinyObjPoint a(point1.x - point2.x, point1.y - point2.y, point1.z - point2.z);
 1623|       |            TinyObjPoint b(point1.x + point2.x, point1.y + point2.y, point1.z + point2.z);
 1624|       |
 1625|       |            n.x += (a.y * b.z);
 1626|       |            n.y += (a.z * b.x);
 1627|       |            n.z += (a.x * b.y);
 1628|       |          }
 1629|       |          real_t length_n = GetLength(n);
 1630|       |          //Check if zero length normal
 1631|       |          if(length_n <= 0) {
 1632|       |            continue;
 1633|       |          }
 1634|       |          //Negative is to flip the normal to the correct direction
 1635|       |          real_t inv_length = -real_t(1.0) / length_n;
 1636|       |          n.x *= inv_length;
 1637|       |          n.y *= inv_length;
 1638|       |          n.z *= inv_length;
 1639|       |
 1640|       |          TinyObjPoint axis_w, axis_v, axis_u;
 1641|       |          axis_w = n;
 1642|       |          TinyObjPoint a;
 1643|       |          if(std::abs(axis_w.x) > real_t(0.9999999)) {
 1644|       |            a = TinyObjPoint(0,1,0);
 1645|       |          } else {
 1646|       |            a = TinyObjPoint(1,0,0);
 1647|       |          }
 1648|       |          axis_v = Normalize(cross(axis_w, a));
 1649|       |          axis_u = cross(axis_w, axis_v);
 1650|       |          using Point = std::array<real_t, 2>;
 1651|       |
 1652|       |          // first polyline define the main polygon.
 1653|       |          // following polylines define holes(not used in tinyobj).
 1654|       |          std::vector<std::vector<Point> > polygon;
 1655|       |
 1656|       |          std::vector<Point> polyline;
 1657|       |
 1658|       |          //TMW change: Find best normal and project v0x and v0y to those coordinates, instead of
 1659|       |          //picking a plane aligned with an axis (which can flip polygons).
 1660|       |
 1661|       |          // Fill polygon data(facevarying vertices).
 1662|       |          for (size_t k = 0; k < npolys; k++) {
 1663|       |            i0 = face.vertex_indices[k];
 1664|       |            size_t vi0 = size_t(i0.v_idx);
 1665|       |
 1666|       |            assert(((3 * vi0 + 2) < v.size()));
 1667|       |
 1668|       |            real_t v0x = v[vi0 * 3 + 0];
 1669|       |            real_t v0y = v[vi0 * 3 + 1];
 1670|       |            real_t v0z = v[vi0 * 3 + 2];
 1671|       |
 1672|       |            TinyObjPoint polypoint(v0x,v0y,v0z);
 1673|       |            TinyObjPoint loc = WorldToLocal(polypoint, axis_u, axis_v, axis_w);
 1674|       |
 1675|       |            polyline.push_back({loc.x, loc.y});
 1676|       |          }
 1677|       |
 1678|       |          polygon.push_back(polyline);
 1679|       |          std::vector<uint32_t> indices = mapbox::earcut<uint32_t>(polygon);
 1680|       |          // => result = 3 * faces, clockwise
 1681|       |
 1682|       |          assert(indices.size() % 3 == 0);
 1683|       |
 1684|       |          // Reconstruct vertex_index_t
 1685|       |          for (size_t k = 0; k < indices.size() / 3; k++) {
 1686|       |            {
 1687|       |              index_t idx0, idx1, idx2;
 1688|       |              idx0.vertex_index = face.vertex_indices[indices[3 * k + 0]].v_idx;
 1689|       |              idx0.normal_index =
 1690|       |                face.vertex_indices[indices[3 * k + 0]].vn_idx;
 1691|       |              idx0.texcoord_index =
 1692|       |                face.vertex_indices[indices[3 * k + 0]].vt_idx;
 1693|       |              idx1.vertex_index = face.vertex_indices[indices[3 * k + 1]].v_idx;
 1694|       |              idx1.normal_index =
 1695|       |                face.vertex_indices[indices[3 * k + 1]].vn_idx;
 1696|       |              idx1.texcoord_index =
 1697|       |                face.vertex_indices[indices[3 * k + 1]].vt_idx;
 1698|       |              idx2.vertex_index = face.vertex_indices[indices[3 * k + 2]].v_idx;
 1699|       |              idx2.normal_index =
 1700|       |                face.vertex_indices[indices[3 * k + 2]].vn_idx;
 1701|       |              idx2.texcoord_index =
 1702|       |                face.vertex_indices[indices[3 * k + 2]].vt_idx;
 1703|       |
 1704|       |              shape->mesh.indices.push_back(idx0);
 1705|       |              shape->mesh.indices.push_back(idx1);
 1706|       |              shape->mesh.indices.push_back(idx2);
 1707|       |
 1708|       |              shape->mesh.num_face_vertices.push_back(3);
 1709|       |              shape->mesh.material_ids.push_back(material_id);
 1710|       |              shape->mesh.smoothing_group_ids.push_back(
 1711|       |                  face.smoothing_group_id);
 1712|       |            }
 1713|       |          }
 1714|       |
 1715|       |#else  // Built-in ear clipping triangulation
 1716|  2.41k|          vertex_index_t i0 = face.vertex_indices[0];
 1717|  2.41k|          vertex_index_t i1(-1);
 1718|  2.41k|          vertex_index_t i2 = face.vertex_indices[1];
 1719|       |
 1720|       |          // find the two axes to work in
 1721|  2.41k|          size_t axes[2] = {1, 2};
 1722|  1.94M|          for (size_t k = 0; k < npolys; ++k) {
  ------------------
  |  Branch (1722:30): [True: 1.94M, False: 2.28k]
  ------------------
 1723|  1.94M|            i0 = face.vertex_indices[(k + 0) % npolys];
 1724|  1.94M|            i1 = face.vertex_indices[(k + 1) % npolys];
 1725|  1.94M|            i2 = face.vertex_indices[(k + 2) % npolys];
 1726|  1.94M|            size_t vi0 = size_t(i0.v_idx);
 1727|  1.94M|            size_t vi1 = size_t(i1.v_idx);
 1728|  1.94M|            size_t vi2 = size_t(i2.v_idx);
 1729|       |
 1730|  1.94M|            if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) ||
  ------------------
  |  Branch (1730:17): [True: 880k, False: 1.06M]
  |  Branch (1730:48): [True: 542k, False: 523k]
  ------------------
 1731|  1.94M|                ((3 * vi2 + 2) >= v.size())) {
  ------------------
  |  Branch (1731:17): [True: 62.6k, False: 460k]
  ------------------
 1732|       |              // Invalid triangle.
 1733|       |              // FIXME(syoyo): Is it ok to simply skip this invalid triangle?
 1734|  1.48M|              continue;
 1735|  1.48M|            }
 1736|   460k|            real_t v0x = v[vi0 * 3 + 0];
 1737|   460k|            real_t v0y = v[vi0 * 3 + 1];
 1738|   460k|            real_t v0z = v[vi0 * 3 + 2];
 1739|   460k|            real_t v1x = v[vi1 * 3 + 0];
 1740|   460k|            real_t v1y = v[vi1 * 3 + 1];
 1741|   460k|            real_t v1z = v[vi1 * 3 + 2];
 1742|   460k|            real_t v2x = v[vi2 * 3 + 0];
 1743|   460k|            real_t v2y = v[vi2 * 3 + 1];
 1744|   460k|            real_t v2z = v[vi2 * 3 + 2];
 1745|   460k|            real_t e0x = v1x - v0x;
 1746|   460k|            real_t e0y = v1y - v0y;
 1747|   460k|            real_t e0z = v1z - v0z;
 1748|   460k|            real_t e1x = v2x - v1x;
 1749|   460k|            real_t e1y = v2y - v1y;
 1750|   460k|            real_t e1z = v2z - v1z;
 1751|   460k|            real_t cx = std::fabs(e0y * e1z - e0z * e1y);
 1752|   460k|            real_t cy = std::fabs(e0z * e1x - e0x * e1z);
 1753|   460k|            real_t cz = std::fabs(e0x * e1y - e0y * e1x);
 1754|   460k|            const real_t epsilon = std::numeric_limits<real_t>::epsilon();
 1755|       |            // std::cout << "cx " << cx << ", cy " << cy << ", cz " << cz <<
 1756|       |            // "\n";
 1757|   460k|            if (cx > epsilon || cy > epsilon || cz > epsilon) {
  ------------------
  |  Branch (1757:17): [True: 41, False: 460k]
  |  Branch (1757:33): [True: 90, False: 460k]
  |  Branch (1757:49): [True: 0, False: 460k]
  ------------------
 1758|       |              // std::cout << "corner\n";
 1759|       |              // found a corner
 1760|    131|              if (cx > cy && cx > cz) {
  ------------------
  |  Branch (1760:19): [True: 33, False: 98]
  |  Branch (1760:30): [True: 33, False: 0]
  ------------------
 1761|       |                // std::cout << "pattern0\n";
 1762|     98|              } else {
 1763|       |                // std::cout << "axes[0] = 0\n";
 1764|     98|                axes[0] = 0;
 1765|     98|                if (cz > cx && cz > cy) {
  ------------------
  |  Branch (1765:21): [True: 90, False: 8]
  |  Branch (1765:32): [True: 0, False: 90]
  ------------------
 1766|       |                  // std::cout << "axes[1] = 1\n";
 1767|      0|                  axes[1] = 1;
 1768|      0|                }
 1769|     98|              }
 1770|    131|              break;
 1771|    131|            }
 1772|   460k|          }
 1773|       |
 1774|  2.41k|          face_t remainingFace = face;  // copy
 1775|  2.41k|          size_t guess_vert = 0;
 1776|  2.41k|          vertex_index_t ind[3];
 1777|  2.41k|          real_t vx[3];
 1778|  2.41k|          real_t vy[3];
 1779|       |
 1780|       |          // How many iterations can we do without decreasing the remaining
 1781|       |          // vertices.
 1782|  2.41k|          size_t remainingIterations = face.vertex_indices.size();
 1783|  2.41k|          size_t previousRemainingVertices =
 1784|  2.41k|              remainingFace.vertex_indices.size();
 1785|       |
 1786|  3.40M|          while (remainingFace.vertex_indices.size() > 3 &&
  ------------------
  |  Branch (1786:18): [True: 3.40M, False: 2.40k]
  ------------------
 1787|  3.40M|                 remainingIterations > 0) {
  ------------------
  |  Branch (1787:18): [True: 3.40M, False: 5]
  ------------------
 1788|       |            // std::cout << "remainingIterations " << remainingIterations <<
 1789|       |            // "\n";
 1790|       |
 1791|  3.40M|            npolys = remainingFace.vertex_indices.size();
 1792|  3.40M|            if (guess_vert >= npolys) {
  ------------------
  |  Branch (1792:17): [True: 6, False: 3.40M]
  ------------------
 1793|      6|              guess_vert -= npolys;
 1794|      6|            }
 1795|       |
 1796|  3.40M|            if (previousRemainingVertices != npolys) {
  ------------------
  |  Branch (1796:17): [True: 520k, False: 2.88M]
  ------------------
 1797|       |              // The number of remaining vertices decreased. Reset counters.
 1798|   520k|              previousRemainingVertices = npolys;
 1799|   520k|              remainingIterations = npolys;
 1800|  2.88M|            } else {
 1801|       |              // We didn't consume a vertex on previous iteration, reduce the
 1802|       |              // available iterations.
 1803|  2.88M|              remainingIterations--;
 1804|  2.88M|            }
 1805|       |
 1806|  13.6M|            for (size_t k = 0; k < 3; k++) {
  ------------------
  |  Branch (1806:32): [True: 10.2M, False: 3.40M]
  ------------------
 1807|  10.2M|              ind[k] = remainingFace.vertex_indices[(guess_vert + k) % npolys];
 1808|  10.2M|              size_t vi = size_t(ind[k].v_idx);
 1809|  10.2M|              if (((vi * 3 + axes[0]) >= v.size()) ||
  ------------------
  |  Branch (1809:19): [True: 5.22M, False: 4.99M]
  ------------------
 1810|  10.2M|                  ((vi * 3 + axes[1]) >= v.size())) {
  ------------------
  |  Branch (1810:19): [True: 0, False: 4.99M]
  ------------------
 1811|       |                // ???
 1812|  5.22M|                vx[k] = static_cast<real_t>(0.0);
 1813|  5.22M|                vy[k] = static_cast<real_t>(0.0);
 1814|  5.22M|              } else {
 1815|  4.99M|                vx[k] = v[vi * 3 + axes[0]];
 1816|  4.99M|                vy[k] = v[vi * 3 + axes[1]];
 1817|  4.99M|              }
 1818|  10.2M|            }
 1819|       |
 1820|       |            //
 1821|       |            // area is calculated per face
 1822|       |            //
 1823|  3.40M|            real_t e0x = vx[1] - vx[0];
 1824|  3.40M|            real_t e0y = vy[1] - vy[0];
 1825|  3.40M|            real_t e1x = vx[2] - vx[1];
 1826|  3.40M|            real_t e1y = vy[2] - vy[1];
 1827|  3.40M|            real_t cross = e0x * e1y - e0y * e1x;
 1828|       |            // std::cout << "axes = " << axes[0] << ", " << axes[1] << "\n";
 1829|       |            // std::cout << "e0x, e0y, e1x, e1y " << e0x << ", " << e0y << ", "
 1830|       |            // << e1x << ", " << e1y << "\n";
 1831|       |
 1832|  3.40M|            real_t area = (vx[0] * vy[1] - vy[0] * vx[1]) * static_cast<real_t>(0.5);
 1833|       |            // std::cout << "cross " << cross << ", area " << area << "\n";
 1834|       |            // if an internal angle
 1835|  3.40M|            if (cross * area < static_cast<real_t>(0.0)) {
  ------------------
  |  Branch (1835:17): [True: 0, False: 3.40M]
  ------------------
 1836|       |              // std::cout << "internal \n";
 1837|      0|              guess_vert += 1;
 1838|       |              // std::cout << "guess vert : " << guess_vert << "\n";
 1839|      0|              continue;
 1840|      0|            }
 1841|       |
 1842|       |            // check all other verts in case they are inside this triangle
 1843|  3.40M|            bool overlap = false;
 1844|   311M|            for (size_t otherVert = 3; otherVert < npolys; ++otherVert) {
  ------------------
  |  Branch (1844:40): [True: 311M, False: 522k]
  ------------------
 1845|   311M|              size_t idx = (guess_vert + otherVert) % npolys;
 1846|       |
 1847|   311M|              if (idx >= remainingFace.vertex_indices.size()) {
  ------------------
  |  Branch (1847:19): [True: 0, False: 311M]
  ------------------
 1848|       |                // std::cout << "???0\n";
 1849|       |                // ???
 1850|      0|                continue;
 1851|      0|              }
 1852|       |
 1853|   311M|              size_t ovi = size_t(remainingFace.vertex_indices[idx].v_idx);
 1854|       |
 1855|   311M|              if (((ovi * 3 + axes[0]) >= v.size()) ||
  ------------------
  |  Branch (1855:19): [True: 144M, False: 166M]
  ------------------
 1856|   311M|                  ((ovi * 3 + axes[1]) >= v.size())) {
  ------------------
  |  Branch (1856:19): [True: 0, False: 166M]
  ------------------
 1857|       |                // std::cout << "???1\n";
 1858|       |                // ???
 1859|   144M|                continue;
 1860|   144M|              }
 1861|   166M|              real_t tx = v[ovi * 3 + axes[0]];
 1862|   166M|              real_t ty = v[ovi * 3 + axes[1]];
 1863|   166M|              if (pnpoly(3, vx, vy, tx, ty)) {
  ------------------
  |  Branch (1863:19): [True: 2.88M, False: 163M]
  ------------------
 1864|       |                // std::cout << "overlap\n";
 1865|  2.88M|                overlap = true;
 1866|  2.88M|                break;
 1867|  2.88M|              }
 1868|   166M|            }
 1869|       |
 1870|  3.40M|            if (overlap) {
  ------------------
  |  Branch (1870:17): [True: 2.88M, False: 522k]
  ------------------
 1871|       |              // std::cout << "overlap2\n";
 1872|  2.88M|              guess_vert += 1;
 1873|  2.88M|              continue;
 1874|  2.88M|            }
 1875|       |
 1876|       |            // this triangle is an ear
 1877|   522k|            {
 1878|   522k|              index_t idx0, idx1, idx2;
 1879|   522k|              idx0.vertex_index = ind[0].v_idx;
 1880|   522k|              idx0.normal_index = ind[0].vn_idx;
 1881|   522k|              idx0.texcoord_index = ind[0].vt_idx;
 1882|   522k|              idx1.vertex_index = ind[1].v_idx;
 1883|   522k|              idx1.normal_index = ind[1].vn_idx;
 1884|   522k|              idx1.texcoord_index = ind[1].vt_idx;
 1885|   522k|              idx2.vertex_index = ind[2].v_idx;
 1886|   522k|              idx2.normal_index = ind[2].vn_idx;
 1887|   522k|              idx2.texcoord_index = ind[2].vt_idx;
 1888|       |
 1889|   522k|              shape->mesh.indices.push_back(idx0);
 1890|   522k|              shape->mesh.indices.push_back(idx1);
 1891|   522k|              shape->mesh.indices.push_back(idx2);
 1892|       |
 1893|   522k|              shape->mesh.num_face_vertices.push_back(3);
 1894|   522k|              shape->mesh.material_ids.push_back(material_id);
 1895|   522k|              shape->mesh.smoothing_group_ids.push_back(
 1896|   522k|                  face.smoothing_group_id);
 1897|   522k|            }
 1898|       |
 1899|       |            // remove v1 from the list
 1900|   522k|            size_t removed_vert_index = (guess_vert + 1) % npolys;
 1901|   203M|            while (removed_vert_index + 1 < npolys) {
  ------------------
  |  Branch (1901:20): [True: 202M, False: 522k]
  ------------------
 1902|   202M|              remainingFace.vertex_indices[removed_vert_index] =
 1903|   202M|                  remainingFace.vertex_indices[removed_vert_index + 1];
 1904|   202M|              removed_vert_index += 1;
 1905|   202M|            }
 1906|   522k|            remainingFace.vertex_indices.pop_back();
 1907|   522k|          }
 1908|       |
 1909|       |          // std::cout << "remainingFace.vi.size = " <<
 1910|       |          // remainingFace.vertex_indices.size() << "\n";
 1911|  2.41k|          if (remainingFace.vertex_indices.size() == 3) {
  ------------------
  |  Branch (1911:15): [True: 2.40k, False: 5]
  ------------------
 1912|  2.40k|            i0 = remainingFace.vertex_indices[0];
 1913|  2.40k|            i1 = remainingFace.vertex_indices[1];
 1914|  2.40k|            i2 = remainingFace.vertex_indices[2];
 1915|  2.40k|            {
 1916|  2.40k|              index_t idx0, idx1, idx2;
 1917|  2.40k|              idx0.vertex_index = i0.v_idx;
 1918|  2.40k|              idx0.normal_index = i0.vn_idx;
 1919|  2.40k|              idx0.texcoord_index = i0.vt_idx;
 1920|  2.40k|              idx1.vertex_index = i1.v_idx;
 1921|  2.40k|              idx1.normal_index = i1.vn_idx;
 1922|  2.40k|              idx1.texcoord_index = i1.vt_idx;
 1923|  2.40k|              idx2.vertex_index = i2.v_idx;
 1924|  2.40k|              idx2.normal_index = i2.vn_idx;
 1925|  2.40k|              idx2.texcoord_index = i2.vt_idx;
 1926|       |
 1927|  2.40k|              shape->mesh.indices.push_back(idx0);
 1928|  2.40k|              shape->mesh.indices.push_back(idx1);
 1929|  2.40k|              shape->mesh.indices.push_back(idx2);
 1930|       |
 1931|  2.40k|              shape->mesh.num_face_vertices.push_back(3);
 1932|  2.40k|              shape->mesh.material_ids.push_back(material_id);
 1933|  2.40k|              shape->mesh.smoothing_group_ids.push_back(
 1934|  2.40k|                  face.smoothing_group_id);
 1935|  2.40k|            }
 1936|  2.40k|          }
 1937|  2.41k|#endif
 1938|  2.41k|        }  // npolys
 1939|  2.41k|      } else {
 1940|    148|        for (size_t k = 0; k < npolys; k++) {
  ------------------
  |  Branch (1940:28): [True: 111, False: 37]
  ------------------
 1941|    111|          index_t idx;
 1942|    111|          idx.vertex_index = face.vertex_indices[k].v_idx;
 1943|    111|          idx.normal_index = face.vertex_indices[k].vn_idx;
 1944|    111|          idx.texcoord_index = face.vertex_indices[k].vt_idx;
 1945|    111|          shape->mesh.indices.push_back(idx);
 1946|    111|        }
 1947|       |
 1948|     37|        shape->mesh.num_face_vertices.push_back(
 1949|     37|            static_cast<unsigned char>(npolys));
 1950|     37|        shape->mesh.material_ids.push_back(material_id);  // per face
 1951|     37|        shape->mesh.smoothing_group_ids.push_back(
 1952|     37|            face.smoothing_group_id);  // per face
 1953|     37|      }
 1954|  2.45k|    }
 1955|       |
 1956|  1.34k|    shape->mesh.tags = tags;
 1957|  1.34k|  }
 1958|       |
 1959|       |  // line
 1960|   197k|  if (!prim_group.lineGroup.empty()) {
  ------------------
  |  Branch (1960:7): [True: 1, False: 197k]
  ------------------
 1961|       |    // Flatten indices
 1962|   262k|    for (size_t i = 0; i < prim_group.lineGroup.size(); i++) {
  ------------------
  |  Branch (1962:24): [True: 262k, False: 1]
  ------------------
 1963|   262k|      for (size_t j = 0; j < prim_group.lineGroup[i].vertex_indices.size();
  ------------------
  |  Branch (1963:26): [True: 0, False: 262k]
  ------------------
 1964|   262k|           j++) {
 1965|      0|        const vertex_index_t &vi = prim_group.lineGroup[i].vertex_indices[j];
 1966|       |
 1967|      0|        index_t idx;
 1968|      0|        idx.vertex_index = vi.v_idx;
 1969|      0|        idx.normal_index = vi.vn_idx;
 1970|      0|        idx.texcoord_index = vi.vt_idx;
 1971|       |
 1972|      0|        shape->lines.indices.push_back(idx);
 1973|      0|      }
 1974|       |
 1975|   262k|      shape->lines.num_line_vertices.push_back(
 1976|   262k|          int(prim_group.lineGroup[i].vertex_indices.size()));
 1977|   262k|    }
 1978|      1|  }
 1979|       |
 1980|       |  // points
 1981|   197k|  if (!prim_group.pointsGroup.empty()) {
  ------------------
  |  Branch (1981:7): [True: 196k, False: 1.33k]
  ------------------
 1982|       |    // Flatten & convert indices
 1983|   656k|    for (size_t i = 0; i < prim_group.pointsGroup.size(); i++) {
  ------------------
  |  Branch (1983:24): [True: 459k, False: 196k]
  ------------------
 1984|   657k|      for (size_t j = 0; j < prim_group.pointsGroup[i].vertex_indices.size();
  ------------------
  |  Branch (1984:26): [True: 197k, False: 459k]
  ------------------
 1985|   459k|           j++) {
 1986|   197k|        const vertex_index_t &vi = prim_group.pointsGroup[i].vertex_indices[j];
 1987|       |
 1988|   197k|        index_t idx;
 1989|   197k|        idx.vertex_index = vi.v_idx;
 1990|   197k|        idx.normal_index = vi.vn_idx;
 1991|   197k|        idx.texcoord_index = vi.vt_idx;
 1992|       |
 1993|   197k|        shape->points.indices.push_back(idx);
 1994|   197k|      }
 1995|   459k|    }
 1996|   196k|  }
 1997|       |
 1998|   197k|  return true;
 1999|   199k|}
_ZNK7tinyobj9PrimGroup7IsEmptyEv:
  754|   199k|  bool IsEmpty() const {
  755|   199k|    return faceGroup.empty() && lineGroup.empty() && pointsGroup.empty();
  ------------------
  |  Branch (755:12): [True: 197k, False: 1.34k]
  |  Branch (755:33): [True: 197k, False: 1]
  |  Branch (755:54): [True: 1.29k, False: 196k]
  ------------------
  756|   199k|  }
fuzz_ParseFromString.cc:_ZN7tinyobjL6pnpolyIfEEiiPT_S2_S1_S1_:
 1413|   166M|static int pnpoly(int nvert, T *vertx, T *verty, T testx, T testy) {
 1414|   166M|  int i, j, c = 0;
 1415|   665M|  for (i = 0, j = nvert - 1; i < nvert; j = i++) {
  ------------------
  |  Branch (1415:30): [True: 499M, False: 166M]
  ------------------
 1416|   499M|    if (((verty[i] > testy) != (verty[j] > testy)) &&
  ------------------
  |  Branch (1416:9): [True: 15.0M, False: 484M]
  ------------------
 1417|   499M|        (testx <
  ------------------
  |  Branch (1417:9): [True: 2.97M, False: 12.0M]
  ------------------
 1418|  15.0M|         (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) +
 1419|  15.0M|             vertx[i]))
 1420|  2.97M|      c = !c;
 1421|   499M|  }
 1422|   166M|  return c;
 1423|   166M|}
fuzz_ParseFromString.cc:_ZN7tinyobjL11SplitStringERKNSt3__112basic_stringIcNS0_11char_traitsIcEENS0_9allocatorIcEEEEccRNS0_6vectorIS6_NS4_IS6_EEEE:
 2004|    190|                        std::vector<std::string> &elems) {
 2005|    190|  std::string token;
 2006|       |
 2007|    190|  bool escaping = false;
 2008|  7.34M|  for (size_t i = 0; i < s.size(); ++i) {
  ------------------
  |  Branch (2008:22): [True: 7.34M, False: 190]
  ------------------
 2009|  7.34M|    char ch = s[i];
 2010|  7.34M|    if (escaping) {
  ------------------
  |  Branch (2010:9): [True: 14, False: 7.34M]
  ------------------
 2011|     14|      escaping = false;
 2012|  7.34M|    } else if (ch == escape) {
  ------------------
  |  Branch (2012:16): [True: 14, False: 7.34M]
  ------------------
 2013|     14|      escaping = true;
 2014|     14|      continue;
 2015|  7.34M|    } else if (ch == delim) {
  ------------------
  |  Branch (2015:16): [True: 24, False: 7.34M]
  ------------------
 2016|     24|      if (!token.empty()) {
  ------------------
  |  Branch (2016:11): [True: 24, False: 0]
  ------------------
 2017|     24|        elems.push_back(token);
 2018|     24|      }
 2019|     24|      token.clear();
 2020|     24|      continue;
 2021|     24|    }
 2022|  7.34M|    token += ch;
 2023|  7.34M|  }
 2024|       |
 2025|    190|  elems.push_back(token);
 2026|    190|}
_ZN7tinyobj9PrimGroup5clearEv:
  748|   199k|  void clear() {
  749|   199k|    faceGroup.clear();
  750|   199k|    lineGroup.clear();
  751|   199k|    pointsGroup.clear();
  752|   199k|  }
fuzz_ParseFromString.cc:_ZN7tinyobjL14parseTagTripleEPPKc:
 1135|  1.24M|static tag_sizes parseTagTriple(const char **token) {
 1136|  1.24M|  tag_sizes ts;
 1137|       |
 1138|  1.24M|  (*token) += strspn((*token), " \t");
 1139|  1.24M|  ts.num_ints = atoi((*token));
 1140|  1.24M|  (*token) += strcspn((*token), "/ \t\r");
 1141|  1.24M|  if ((*token)[0] != '/') {
  ------------------
  |  Branch (1141:7): [True: 1.24M, False: 0]
  ------------------
 1142|  1.24M|    return ts;
 1143|  1.24M|  }
 1144|       |
 1145|      0|  (*token)++;  // Skip '/'
 1146|       |
 1147|      0|  (*token) += strspn((*token), " \t");
 1148|      0|  ts.num_reals = atoi((*token));
 1149|      0|  (*token) += strcspn((*token), "/ \t\r");
 1150|      0|  if ((*token)[0] != '/') {
  ------------------
  |  Branch (1150:7): [True: 0, False: 0]
  ------------------
 1151|      0|    return ts;
 1152|      0|  }
 1153|      0|  (*token)++;  // Skip '/'
 1154|       |
 1155|      0|  ts.num_strings = parseInt(token);
 1156|       |
 1157|      0|  return ts;
 1158|      0|}
_ZN7tinyobj9tag_sizesC2Ev:
  729|  1.24M|  tag_sizes() : num_ints(0), num_reals(0), num_strings(0) {}
_ZN7tinyobj20MaterialStreamReaderC2ERNSt3__113basic_istreamIcNS1_11char_traitsIcEEEE:
  494|     82|      : m_inStream(inStream) {}
_ZN7tinyobj15ObjReaderConfigC2Ev:
  528|     82|      : triangulate(true), triangulation_method("simple"), vertex_color(true) {}
_ZN7tinyobj9ObjReaderC2Ev:
  536|     82|  ObjReader() : valid_(false) {}
_ZN7tinyobj8attrib_tC2Ev:
  411|     82|  attrib_t() {}
fuzz_ParseFromString.cc:_ZN7tinyobjL8toStringImEENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEERKT_:
  803|      2|static inline std::string toString(const T &t) {
  804|      2|  std::stringstream ss;
  805|      2|  ss << t;
  806|      2|  return ss.str();
  807|      2|}

