Implement more c89 version(stil W.I.P.)

This commit is contained in:
Syoyo Fujita
2016-07-14 20:03:07 +09:00
parent 082d051c86
commit 5f76db8498
2 changed files with 140 additions and 341 deletions

View File

@@ -92,12 +92,13 @@ typedef struct {
/* Parse wavefront .obj(.obj string data is expanded to linear char array /* Parse wavefront .obj(.obj string data is expanded to linear char array
* `buf') * `buf')
*/ */
extern int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, const char *buf, extern int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, size_t *num_shapes, const char *buf, size_t len);
size_t len);
#endif
#ifdef TINYOBJ_LOADER_C_IMPLEMENTATION #ifdef TINYOBJ_LOADER_C_IMPLEMENTATION
#define TINYOBJ_MAX_FACES_PER_F_LINE (32)
#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) #define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
#define IS_DIGIT(x) \ #define IS_DIGIT(x) \
((unsigned int)((x) - '0') < (unsigned int)(10)) ((unsigned int)((x) - '0') < (unsigned int)(10))
@@ -172,7 +173,6 @@ static tinyobj_vertex_index_t parseRawTriple(const char **token) {
vi.vt_idx = (int)(0x80000000); vi.vt_idx = (int)(0x80000000);
vi.v_idx = my_atoi((*token)); vi.v_idx = my_atoi((*token));
/* (*token) += strcspn((*token), "/ \t\r"); */
while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' &&
(*token)[0] != '\t' && (*token)[0] != '\r') { (*token)[0] != '\t' && (*token)[0] != '\r') {
(*token)++; (*token)++;
@@ -186,7 +186,6 @@ static tinyobj_vertex_index_t parseRawTriple(const char **token) {
if ((*token)[0] == '/') { if ((*token)[0] == '/') {
(*token)++; (*token)++;
vi.vn_idx = my_atoi((*token)); vi.vn_idx = my_atoi((*token));
/*(*token) += strcspn((*token), "/ \t\r"); */
while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' &&
(*token)[0] != '\t' && (*token)[0] != '\r') { (*token)[0] != '\t' && (*token)[0] != '\r') {
(*token)++; (*token)++;
@@ -196,7 +195,6 @@ static tinyobj_vertex_index_t parseRawTriple(const char **token) {
/* i/j/k or i/j */ /* i/j/k or i/j */
vi.vt_idx = my_atoi((*token)); vi.vt_idx = my_atoi((*token));
/* (*token) += strcspn((*token), "/ \t\r"); */
while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' &&
(*token)[0] != '\t' && (*token)[0] != '\r') { (*token)[0] != '\t' && (*token)[0] != '\r') {
(*token)++; (*token)++;
@@ -208,7 +206,6 @@ static tinyobj_vertex_index_t parseRawTriple(const char **token) {
/* i/j/k */ /* i/j/k */
(*token)++; /* skip '/' */ (*token)++; /* skip '/' */
vi.vn_idx = my_atoi((*token)); vi.vn_idx = my_atoi((*token));
/* (*token) += strcspn((*token), "/ \t\r"); */
while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' &&
(*token)[0] != '\t' && (*token)[0] != '\r') { (*token)[0] != '\t' && (*token)[0] != '\r') {
(*token)++; (*token)++;
@@ -394,17 +391,12 @@ static float parseFloat(const char **token) {
double val = 0.0; double val = 0.0;
float f = 0.0f; float f = 0.0f;
skip_space(token); skip_space(token);
#ifdef TINY_OBJ_LOADER_OLD_FLOAT_PARSER
f = (float)(atof(*token));
(*token) += strcspn((*token), " \t\r");
#else
end = end =
(*token) + until_space((*token)); (*token) + until_space((*token));
val = 0.0; val = 0.0;
tryParseDouble((*token), end, &val); tryParseDouble((*token), end, &val);
f = (float)(val); f = (float)(val);
(*token) = end; (*token) = end;
#endif
return f; return f;
} }
@@ -671,7 +663,6 @@ static void LoadMtl(std::map<std::string, int> *material_map,
} }
#endif #endif
#if 0
typedef enum { typedef enum {
COMMAND_EMPTY, COMMAND_EMPTY,
COMMAND_V, COMMAND_V,
@@ -681,7 +672,7 @@ typedef enum {
COMMAND_G, COMMAND_G,
COMMAND_O, COMMAND_O,
COMMAND_USEMTL, COMMAND_USEMTL,
COMMAND_MTLLIB, COMMAND_MTLLIB
} CommandType; } CommandType;
@@ -690,10 +681,12 @@ typedef struct {
float nx, ny, nz; float nx, ny, nz;
float tx, ty; float tx, ty;
// for f /* @todo { Use dynamic array } */
std::vector<vertex_index, lt::allocator<vertex_index> > f; tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE];
// std::vector<vertex_index> f; int num_f;
std::vector<int, lt::allocator<int> > f_num_verts;
int f_num_verts[TINYOBJ_MAX_FACES_PER_F_LINE];
int num_f_num_verts;
const char *group_name; const char *group_name;
unsigned int group_name_len; unsigned int group_name_len;
@@ -708,175 +701,136 @@ typedef struct {
CommandType type; CommandType type;
} Command; } Command;
struct CommandCount { static int parseLine(Command *command, const char *p, size_t p_len, int triangulate) {
size_t num_v;
size_t num_vn;
size_t num_vt;
size_t num_f;
size_t num_faces;
CommandCount() {
num_v = 0;
num_vn = 0;
num_vt = 0;
num_f = 0;
num_faces = 0;
}
};
class
LoadOption
{
public:
LoadOption() : req_num_threads(-1), triangulate(true), verbose(false) {}
int req_num_threads;
bool triangulate;
bool verbose;
};
static bool parseLine(Command *command, const char *p, size_t p_len,
bool triangulate = true) {
char linebuf[4096]; char linebuf[4096];
const char *token;
assert(p_len < 4095); assert(p_len < 4095);
// StackVector<char, 256> linebuf;
// linebuf->resize(p_len + 1);
memcpy(&linebuf, p, p_len); memcpy(&linebuf, p, p_len);
linebuf[p_len] = '\0'; linebuf[p_len] = '\0';
const char *token = linebuf; token = linebuf;
command->type = COMMAND_EMPTY; command->type = COMMAND_EMPTY;
// Skip leading space. /* Skip leading space. */
// token += strspn(token, " \t"); skip_space(&token);
skip_space(&token); //(*token) += strspn((*token), " \t");
assert(token); assert(token);
if (token[0] == '\0') { // empty line if (token[0] == '\0') { /* empty line */
return false; return 0;
} }
if (token[0] == '#') { // comment line if (token[0] == '#') { /* comment line */
return false; return 0;
} }
// vertex /* vertex */
if (token[0] == 'v' && IS_SPACE((token[1]))) { if (token[0] == 'v' && IS_SPACE((token[1]))) {
token += 2;
float x, y, z; float x, y, z;
token += 2;
parseFloat3(&x, &y, &z, &token); parseFloat3(&x, &y, &z, &token);
command->vx = x; command->vx = x;
command->vy = y; command->vy = y;
command->vz = z; command->vz = z;
command->type = COMMAND_V; command->type = COMMAND_V;
return true; return 1;
} }
// normal /* normal */
if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) {
token += 3;
float x, y, z; float x, y, z;
token += 3;
parseFloat3(&x, &y, &z, &token); parseFloat3(&x, &y, &z, &token);
command->nx = x; command->nx = x;
command->ny = y; command->ny = y;
command->nz = z; command->nz = z;
command->type = COMMAND_VN; command->type = COMMAND_VN;
return true; return 1;
} }
// texcoord /* texcoord */
if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) {
token += 3;
float x, y; float x, y;
token += 3;
parseFloat2(&x, &y, &token); parseFloat2(&x, &y, &token);
command->tx = x; command->tx = x;
command->ty = y; command->ty = y;
command->type = COMMAND_VT; command->type = COMMAND_VT;
return true; return 1;
} }
// face /* face */
if (token[0] == 'f' && IS_SPACE((token[1]))) { if (token[0] == 'f' && IS_SPACE((token[1]))) {
int num_f = 0;
tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE];
token += 2; token += 2;
// token += strspn(token, " \t");
skip_space(&token); skip_space(&token);
StackVector<vertex_index, 8> f;
while (!IS_NEW_LINE(token[0])) { while (!IS_NEW_LINE(token[0])) {
vertex_index vi = parseRawTriple(&token); tinyobj_vertex_index_t vi = parseRawTriple(&token);
// printf("v = %d, %d, %d\n", vi.v_idx, vi.vn_idx, vi.vt_idx);
// if (callback.index_cb) {
// callback.index_cb(user_data, vi.v_idx, vi.vn_idx, vi.vt_idx);
//}
// size_t n = strspn(token, " \t\r");
// token += n;
skip_space_and_cr(&token); skip_space_and_cr(&token);
f->push_back(vi); f[num_f] = vi;
} }
command->type = COMMAND_F; command->type = COMMAND_F;
if (triangulate) { if (triangulate) {
vertex_index i0 = f[0]; int k;
vertex_index i1(-1); int n = 0;
vertex_index i2 = f[1];
for (size_t k = 2; k < f->size(); k++) { tinyobj_vertex_index_t i0 = f[0];
tinyobj_vertex_index_t i1;
tinyobj_vertex_index_t i2 = f[1];
assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
for (k = 2; k < num_f; k++) {
i1 = i2; i1 = i2;
i2 = f[k]; i2 = f[k];
command->f.emplace_back(i0); command->f[3*n+0] = i0;
command->f.emplace_back(i1); command->f[3*n+1] = i1;
command->f.emplace_back(i2); command->f[3*n+2] = i2;
command->f_num_verts.emplace_back(3); command->f_num_verts[n] = 3;
n++;
} }
command->num_f = 3 * n;
command->num_f_num_verts = n;
} else { } else {
for (size_t k = 0; k < f->size(); k++) { int k = 0;
command->f.emplace_back(f[k]); assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
for (k = 0; k < num_f; k++) {
command->f[k] = f[k];
} }
command->f_num_verts.emplace_back(f->size()); command->f_num_verts[0] = num_f;
command->num_f_num_verts = 1;
} }
return true; return 1;
} }
// use mtl /* use mtl */
if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) {
token += 7; token += 7;
// int newMaterialId = -1;
// if (material_map.find(namebuf) != material_map.end()) {
// newMaterialId = material_map[namebuf];
//} else {
// // { error!! material not found }
//}
// if (newMaterialId != materialId) {
// materialId = newMaterialId;
//}
// command->material_name = .insert(command->material_name->end(), namebuf,
// namebuf + strlen(namebuf));
// command->material_name->push_back('\0');
skip_space(&token); skip_space(&token);
command->material_name = p + (token - linebuf); command->material_name = p + (token - linebuf);
command->material_name_len = command->material_name_len =
length_until_newline(token, p_len - (token - linebuf)) + 1; length_until_newline(token, p_len - (token - linebuf)) + 1;
command->type = COMMAND_USEMTL; command->type = COMMAND_USEMTL;
return true; return 1;
} }
// load mtl /* load mtl */
if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) {
// By specification, `mtllib` should be appear only once in .obj /* By specification, `mtllib` should be appear only once in .obj */
token += 7; token += 7;
skip_space(&token); skip_space(&token);
@@ -885,12 +839,12 @@ static bool parseLine(Command *command, const char *p, size_t p_len,
length_until_newline(token, p_len - (token - linebuf)) + 1; length_until_newline(token, p_len - (token - linebuf)) + 1;
command->type = COMMAND_MTLLIB; command->type = COMMAND_MTLLIB;
return true; return 1;
} }
// group name /* group name */
if (token[0] == 'g' && IS_SPACE((token[1]))) { if (token[0] == 'g' && IS_SPACE((token[1]))) {
// @todo { multiple group name. } /* @todo { multiple group name. } */
token += 2; token += 2;
command->group_name = p + (token - linebuf); command->group_name = p + (token - linebuf);
@@ -898,12 +852,12 @@ static bool parseLine(Command *command, const char *p, size_t p_len,
length_until_newline(token, p_len - (token - linebuf)) + 1; length_until_newline(token, p_len - (token - linebuf)) + 1;
command->type = COMMAND_G; command->type = COMMAND_G;
return true; return 1;
} }
// object name /* object name */
if (token[0] == 'o' && IS_SPACE((token[1]))) { if (token[0] == 'o' && IS_SPACE((token[1]))) {
// @todo { multiple object name? } /* @todo { multiple object name? } */
token += 2; token += 2;
command->object_name = p + (token - linebuf); command->object_name = p + (token - linebuf);
@@ -911,10 +865,10 @@ static bool parseLine(Command *command, const char *p, size_t p_len,
length_until_newline(token, p_len - (token - linebuf)) + 1; length_until_newline(token, p_len - (token - linebuf)) + 1;
command->type = COMMAND_O; command->type = COMMAND_O;
return true; return 1;
} }
return false; return 0;
} }
typedef struct { typedef struct {
@@ -922,166 +876,71 @@ typedef struct {
size_t len; size_t len;
} LineInfo; } LineInfo;
// Idea come from https://github.com/antonmks/nvParse static int is_line_ending(const char *p, size_t i, size_t end_i) {
// 1. mmap file if (p[i] == '\0') return 1;
// 2. find newline(\n, \r\n, \r) and list of line data. if (p[i] == '\n') return 1; /* this includes \r\n */
// 3. Do parallel parsing for each line.
// 4. Reconstruct final mesh data structure.
#define kMaxThreads (32)
static inline bool is_line_ending(const char *p, size_t i, size_t end_i) {
if (p[i] == '\0') return true;
if (p[i] == '\n') return true; // this includes \r\n
if (p[i] == '\r') { if (p[i] == '\r') {
if (((i + 1) < end_i) && (p[i + 1] != '\n')) { // detect only \r case if (((i + 1) < end_i) && (p[i + 1] != '\n')) { /* detect only \r case */
return true; return 1;
} }
} }
return false; return 0;
} }
bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf, int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, size_t *num_shapes, const char *buf, size_t len)
size_t len, const LoadOption& option)
{ {
attrib->vertices.clear(); LineInfo* line_infos = NULL;
attrib->normals.clear(); size_t num_lines = 0;
attrib->texcoords.clear();
attrib->faces.clear();
attrib->face_num_verts.clear();
attrib->material_ids.clear();
shapes->clear();
if (len < 1) return false; if (len < 1) return 0;
auto num_threads = (option.req_num_threads < 0) ? std::thread::hardware_concurrency() /* 1. Find '\n' and create line data. */
: option.req_num_threads; {
num_threads = size_t i;
std::max(1, std::min(static_cast<int>(num_threads), kMaxThreads)); size_t end_idx = len - 1;
size_t prev_pos = 0;
size_t line_no = 0;
/* Count # of lines. */
for (i = 0; i < end_idx; i++) { /* Assume last char is '\0' */
if (is_line_ending(buf, i, end_idx)) {
num_lines++;
}
}
printf("num lines %d\n", (int)num_lines);
if (option.verbose) { line_infos = (LineInfo*)malloc(sizeof(LineInfo) * num_lines);
std::cout << "# of threads = " << num_threads << std::endl;
/* Fill line infoss. */
for (i = 0; i < end_idx; i++) {
if (is_line_ending(buf, i, end_idx)) {
line_infos[line_no].pos = prev_pos;
line_infos[line_no].len = i;
prev_pos = i + 1;
line_no++;
}
}
}
if (line_infos) {
free(line_infos);
} }
auto t1 = std::chrono::high_resolution_clock::now(); #if 0
std::vector<LineInfo, lt::allocator<LineInfo> > line_infos[kMaxThreads]; int line_sum = 0;
for (size_t t = 0; t < static_cast<size_t>(num_threads); t++) {
// Pre allocate enough memory. len / 128 / num_threads is just a heuristic
// value.
line_infos[t].reserve(len / 128 / num_threads);
}
std::chrono::duration<double, std::milli> ms_linedetection;
std::chrono::duration<double, std::milli> ms_alloc;
std::chrono::duration<double, std::milli> ms_parse;
std::chrono::duration<double, std::milli> ms_load_mtl;
std::chrono::duration<double, std::milli> ms_merge;
std::chrono::duration<double, std::milli> ms_construct;
// 1. Find '\n' and create line data.
{
StackVector<std::thread, 16> workers;
auto start_time = std::chrono::high_resolution_clock::now();
auto chunk_size = len / num_threads;
for (size_t t = 0; t < static_cast<size_t>(num_threads); t++) {
workers->push_back(std::thread([&, t]() {
auto start_idx = (t + 0) * chunk_size;
auto end_idx = std::min((t + 1) * chunk_size, len - 1);
if (t == static_cast<size_t>((num_threads - 1))) {
end_idx = len - 1;
}
size_t prev_pos = start_idx;
for (size_t i = start_idx; i < end_idx; i++) {
if (is_line_ending(buf, i, end_idx)) {
if ((t > 0) && (prev_pos == start_idx) &&
(!is_line_ending(buf, start_idx - 1, end_idx))) {
// first linebreak found in (chunk > 0), and a line before this
// linebreak belongs to previous chunk, so skip it.
prev_pos = i + 1;
continue;
} else {
LineInfo info;
info.pos = prev_pos;
info.len = i - prev_pos;
if (info.len > 0) {
line_infos[t].push_back(info);
}
prev_pos = i + 1;
}
}
}
// Find extra line which spand across chunk boundary.
if ((t < num_threads) && (buf[end_idx - 1] != '\n')) {
auto extra_span_idx = std::min(end_idx - 1 + chunk_size, len - 1);
for (size_t i = end_idx; i < extra_span_idx; i++) {
if (is_line_ending(buf, i, extra_span_idx)) {
LineInfo info;
info.pos = prev_pos;
info.len = i - prev_pos;
if (info.len > 0) {
line_infos[t].push_back(info);
}
break;
}
}
}
}));
}
for (size_t t = 0; t < workers->size(); t++) {
workers[t].join();
}
auto end_time = std::chrono::high_resolution_clock::now();
ms_linedetection = end_time - start_time;
}
auto line_sum = 0;
for (size_t t = 0; t < num_threads; t++) { for (size_t t = 0; t < num_threads; t++) {
// std::cout << t << ": # of lines = " << line_infos[t].size() << std::endl;
line_sum += line_infos[t].size(); line_sum += line_infos[t].size();
} }
// std::cout << "# of lines = " << line_sum << std::endl;
std::vector<Command> commands[kMaxThreads]; /* 2. parse each line */
// 2. allocate buffer
auto t_alloc_start = std::chrono::high_resolution_clock::now();
{ {
for (size_t t = 0; t < num_threads; t++) {
commands[t].reserve(line_infos[t].size());
}
}
CommandCount command_count[kMaxThreads];
// Array index to `mtllib` line. According to wavefront .obj spec, `mtllib'
// should appear only once in .obj.
int mtllib_t_index = -1;
int mtllib_i_index = -1;
ms_alloc = std::chrono::high_resolution_clock::now() - t_alloc_start;
// 2. parse each line in parallel.
{
StackVector<std::thread, 16> workers;
auto t_start = std::chrono::high_resolution_clock::now();
for (size_t t = 0; t < num_threads; t++) { for (size_t t = 0; t < num_threads; t++) {
workers->push_back(std::thread([&, t]() { workers->push_back(std::thread([&, t]() {
for (size_t i = 0; i < line_infos[t].size(); i++) { for (size_t i = 0; i < line_infos[t].size(); i++) {
Command command; Command command;
bool ret = parseLine(&command, &buf[line_infos[t][i].pos], int ret = parseLine(&command, &buf[line_infos[t][i].pos],
line_infos[t][i].len, option.triangulate); line_infos[t][i].len, option.triangulate);
if (ret) { if (ret) {
if (command.type == COMMAND_V) { if (command.type == COMMAND_V) {
@@ -1107,13 +966,6 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
})); }));
} }
for (size_t t = 0; t < workers->size(); t++) {
workers[t].join();
}
auto t_end = std::chrono::high_resolution_clock::now();
ms_parse = t_end - t_start;
} }
std::map<std::string, int> material_map; std::map<std::string, int> material_map;
@@ -1144,33 +996,12 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
ms_load_mtl = t2 - t1; ms_load_mtl = t2 - t1;
} }
auto command_sum = 0;
for (size_t t = 0; t < num_threads; t++) {
// std::cout << t << ": # of commands = " << commands[t].size() <<
// std::endl;
command_sum += commands[t].size();
}
// std::cout << "# of commands = " << command_sum << std::endl;
size_t num_v = 0; size_t num_v = 0;
size_t num_vn = 0; size_t num_vn = 0;
size_t num_vt = 0; size_t num_vt = 0;
size_t num_f = 0; size_t num_f = 0;
size_t num_faces = 0; size_t num_faces = 0;
for (size_t t = 0; t < num_threads; t++) {
num_v += command_count[t].num_v;
num_vn += command_count[t].num_vn;
num_vt += command_count[t].num_vt;
num_f += command_count[t].num_f;
num_faces += command_count[t].num_faces;
}
// std::cout << "# v " << num_v << std::endl;
// std::cout << "# vn " << num_vn << std::endl;
// std::cout << "# vt " << num_vt << std::endl;
// std::cout << "# f " << num_f << std::endl;
// 4. merge
// @todo { parallelize merge. }
{ {
auto t_start = std::chrono::high_resolution_clock::now(); auto t_start = std::chrono::high_resolution_clock::now();
@@ -1260,23 +1091,12 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
})); }));
} }
for (size_t t = 0; t < workers->size(); t++) {
workers[t].join();
}
auto t_end = std::chrono::high_resolution_clock::now();
ms_merge = t_end - t_start;
} }
auto t4 = std::chrono::high_resolution_clock::now(); /* 5. Construct shape information. */
// 5. Construct shape information.
{ {
auto t_start = std::chrono::high_resolution_clock::now();
// @todo { Can we boost the performance by multi-threaded execution? }
int face_count = 0; int face_count = 0;
shape_t shape; tinyobj_shape_t shape;
shape.face_offset = 0; shape.face_offset = 0;
shape.length = 0; shape.length = 0;
int face_prev_offset = 0; int face_prev_offset = 0;
@@ -1334,33 +1154,13 @@ bool parseObj(attrib_t *attrib, std::vector<shape_t> *shapes, const char *buf,
shapes->push_back(shape); shapes->push_back(shape);
} }
} else { } else {
// Guess no 'v' line occurrence after 'o' or 'g', so discards current /* Guess no 'v' line occurrence after 'o' or 'g', so discards current shape information. */
// shape information.
} }
auto t_end = std::chrono::high_resolution_clock::now();
ms_construct = t_end - t_start;
} }
#endif /* 0 */
std::chrono::duration<double, std::milli> ms_total = t4 - t1; return 1;
if (option.verbose) {
std::cout << "total parsing time: " << ms_total.count() << " ms\n";
std::cout << " line detection : " << ms_linedetection.count() << " ms\n";
std::cout << " alloc buf : " << ms_alloc.count() << " ms\n";
std::cout << " parse : " << ms_parse.count() << " ms\n";
std::cout << " merge : " << ms_merge.count() << " ms\n";
std::cout << " construct : " << ms_construct.count() << " ms\n";
std::cout << " mtl load : " << ms_load_mtl.count() << " ms\n";
std::cout << "# of vertices = " << attrib->vertices.size() << std::endl;
std::cout << "# of normals = " << attrib->normals.size() << std::endl;
std::cout << "# of texcoords = " << attrib->texcoords.size() << std::endl;
std::cout << "# of face indices = " << attrib->faces.size() << std::endl;
std::cout << "# of faces = " << attrib->material_ids.size() << std::endl;
std::cout << "# of shapes = " << shapes->size() << std::endl;
}
return true;
} }
#endif /* TINYOBJ_LOADER_C_IMPLEMENTATION */ #endif /* TINYOBJ_LOADER_C_IMPLEMENTATION */

View File

@@ -1,3 +1,4 @@
#include <math.h>
#include <GL/glew.h> #include <GL/glew.h>
#ifdef __APPLE__ #ifdef __APPLE__
@@ -63,7 +64,7 @@ static void CalcNormal(float N[3], float v0[3], float v1[3], float v2[3]) {
len2 = N[0] * N[0] + N[1] * N[1] + N[2] * N[2]; len2 = N[0] * N[0] + N[1] * N[1] + N[2] * N[2];
if (len2 > 0.0f) { if (len2 > 0.0f) {
float len = sqrtf(len2); float len = sqrt(len2);
N[0] /= len; N[0] /= len;
N[1] /= len; N[1] /= len;
@@ -208,24 +209,25 @@ static const char* get_file_data(size_t *len, const char* filename)
} }
#if 0
static int LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename) static int LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename)
{ {
#if 1 tinyobj_attrib_t attrib;
tinyobj_opt::attrib_t attrib; tinyobj_shape_t *shapes;
std::vector<tinyobj_opt::shape_t> shapes; size_t num_shapes;
size_t data_len = 0; size_t data_len = 0;
const char* data = get_file_data(&data_len, filename); const char* data = get_file_data(&data_len, filename);
if (data == nullptr) { if (data == NULL) {
exit(-1); exit(-1);
return false; return 0;
} }
printf("filesize: %d\n", (int)data_len); printf("filesize: %d\n", (int)data_len);
tinyobj_opt::LoadOption option;
option.req_num_threads = num_threads; {
bool ret = parseObj(&attrib, &shapes, data, data_len, option); int ret = tinyobj_parse(&attrib, shapes, &num_shapes, data, data_len);
}
#if 0
bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max(); bmin[0] = bmin[1] = bmin[2] = std::numeric_limits<float>::max();
bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max(); bmax[0] = bmax[1] = bmax[2] = -std::numeric_limits<float>::max();
@@ -324,12 +326,11 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename)
printf("bmin = %f, %f, %f\n", bmin[0], bmin[1], bmin[2]); printf("bmin = %f, %f, %f\n", bmin[0], bmin[1], bmin[2]);
printf("bmax = %f, %f, %f\n", bmax[0], bmax[1], bmax[2]); printf("bmax = %f, %f, %f\n", bmax[0], bmax[1], bmax[2]);
return true; return 1;
#else #else
return false; return 0;
#endif #endif
} }
#endif
static void reshapeFunc(GLFWwindow* window, int w, int h) static void reshapeFunc(GLFWwindow* window, int w, int h)
{ {
@@ -491,7 +492,6 @@ static void Init() {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
(void)argv;
if (argc < 2) { if (argc < 2) {
fprintf(stderr, "Needs input.obj\n"); fprintf(stderr, "Needs input.obj\n");
return 0; return 0;
@@ -531,14 +531,13 @@ int main(int argc, char **argv)
{ {
float bmin[3], bmax[3]; float bmin[3], bmax[3];
#if 0 float maxExtent;
if (false == LoadObjAndConvert(bmin, bmax, argv[1], num_threads)) { if (0 == LoadObjAndConvert(bmin, bmax, argv[1])) {
printf("failed to load & conv\n"); printf("failed to load & conv\n");
return -1; return -1;
} }
#endif
float maxExtent = 0.5f * (bmax[0] - bmin[0]); maxExtent = 0.5f * (bmax[0] - bmin[0]);
if (maxExtent < 0.5f * (bmax[1] - bmin[1])) { if (maxExtent < 0.5f * (bmax[1] - bmin[1])) {
maxExtent = 0.5f * (bmax[1] - bmin[1]); maxExtent = 0.5f * (bmax[1] - bmin[1]);
} }