Mostly finished porting parser in C89 except for material loading.

This commit is contained in:
Syoyo Fujita
2016-07-15 01:47:01 +09:00
parent 5f76db8498
commit 0d1c60aafd
3 changed files with 119 additions and 129 deletions

View File

@@ -1,4 +1,9 @@
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
LD_FLAGS=-framework OpenGL -lglfw3 -lglew
endif
all: all:
clang -c trackball.c clang -c trackball.c
clang -pedantic -ansi -Wno-deprecated-declarations viewer-c.c trackball.o -framework OpenGL -lglfw3 -lglew clang -o viewer -g -O0 -pedantic -ansi -Wno-deprecated-declarations viewer-c.c trackball.o $(LD_FLAGS)
# clang -pedantic -ansi -Weverything -Wno-deprecated-declarations viewer-c.c trackball.o -framework OpenGL -lglfw3 -lglew # clang -pedantic -ansi -Weverything -Wno-deprecated-declarations viewer-c.c trackball.o -framework OpenGL -lglfw3 -lglew

View File

@@ -84,15 +84,22 @@ typedef struct {
unsigned int num_texcoords; unsigned int num_texcoords;
tinyobj_vertex_index_t *faces; tinyobj_vertex_index_t *faces;
unsigned int num_faces; unsigned int num_faces;
int *face_num_vers; int *face_num_verts;
unsigned int num_face_num_faces; unsigned int num_face_num_verts;
int *material_ids; int *material_ids;
} tinyobj_attrib_t; } tinyobj_attrib_t;
/* Parse wavefront .obj(.obj string data is expanded to linear char array #define TINYOBJ_FLAG_TRIANGULATE (1 << 0)
* `buf') #define TINYOBJ_SUCCESS (0)
#define TINYOBJ_ERROR_EMPTY (-1)
#define TINYOBJ_ERROR_INVALID_PARAMETER (-2)
/* Parse wavefront .obj(.obj string data is expanded to linear char array `buf')
* flags are combination of TINYOBJ_FLAG_***
* Retruns TINYOBJ_SUCCESS if things goes well.
* Retruns TINYOBJ_ERR_*** when there is an error.
*/ */
extern int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, size_t *num_shapes, const char *buf, size_t len); extern int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, size_t *num_shapes, const char *buf, size_t len, unsigned int flags);
#ifdef TINYOBJ_LOADER_C_IMPLEMENTATION #ifdef TINYOBJ_LOADER_C_IMPLEMENTATION
@@ -706,7 +713,7 @@ static int parseLine(Command *command, const char *p, size_t p_len, int triangul
const char *token; const char *token;
assert(p_len < 4095); assert(p_len < 4095);
memcpy(&linebuf, p, p_len); memcpy(linebuf, p, p_len);
linebuf[p_len] = '\0'; linebuf[p_len] = '\0';
token = linebuf; token = linebuf;
@@ -887,11 +894,18 @@ static int is_line_ending(const char *p, size_t i, size_t end_i) {
return 0; return 0;
} }
int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, size_t *num_shapes, const char *buf, size_t len) int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, size_t *num_shapes, const char *buf, size_t len, unsigned int flags)
{ {
LineInfo* line_infos = NULL; LineInfo* line_infos = NULL;
Command* commands = NULL;
size_t num_lines = 0; size_t num_lines = 0;
size_t num_v = 0;
size_t num_vn = 0;
size_t num_vt = 0;
size_t num_f = 0;
size_t num_faces = 0;
if (len < 1) return 0; if (len < 1) return 0;
/* 1. Find '\n' and create line data. */ /* 1. Find '\n' and create line data. */
@@ -909,65 +923,59 @@ int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, size_t *num
} }
printf("num lines %d\n", (int)num_lines); printf("num lines %d\n", (int)num_lines);
if (num_lines == 0) return TINYOBJ_ERROR_EMPTY;
line_infos = (LineInfo*)malloc(sizeof(LineInfo) * num_lines); line_infos = (LineInfo*)malloc(sizeof(LineInfo) * num_lines);
/* Fill line infoss. */ /* Fill line infoss. */
for (i = 0; i < end_idx; i++) { for (i = 0; i < end_idx; i++) {
if (is_line_ending(buf, i, end_idx)) { if (is_line_ending(buf, i, end_idx)) {
line_infos[line_no].pos = prev_pos; line_infos[line_no].pos = prev_pos;
line_infos[line_no].len = i; line_infos[line_no].len = i - prev_pos;
prev_pos = i + 1; prev_pos = i + 1;
line_no++; line_no++;
} }
} }
} }
commands = (Command*)malloc(sizeof(Command) * num_lines);
/* 2. parse each line */
{
size_t i = 0;
for (i = 0; i < num_lines; i++) {
int ret = parseLine(&commands[i], &buf[line_infos[i].pos],
line_infos[i].len, flags & TINYOBJ_FLAG_TRIANGULATE);
if (ret) {
if (commands[i].type == COMMAND_V) {
num_v++;
} else if (commands[i].type == COMMAND_VN) {
num_vn++;
} else if (commands[i].type == COMMAND_VT) {
num_vt++;
} else if (commands[i].type == COMMAND_F) {
num_f += commands[i].num_f;
num_faces++;
}
if (commands[i].type == COMMAND_MTLLIB) {
/* @todo
mtllib_t_index = t;
mtllib_i_index = commands->size();
*/
}
}
}
}
/* line_infos are not used anymore. Release memory. */
if (line_infos) { if (line_infos) {
free(line_infos); free(line_infos);
} }
#if 0 #if 0
int line_sum = 0;
for (size_t t = 0; t < num_threads; t++) {
line_sum += line_infos[t].size();
}
/* 2. parse each line */
{
for (size_t t = 0; t < num_threads; t++) {
workers->push_back(std::thread([&, t]() {
for (size_t i = 0; i < line_infos[t].size(); i++) {
Command command;
int ret = parseLine(&command, &buf[line_infos[t][i].pos],
line_infos[t][i].len, option.triangulate);
if (ret) {
if (command.type == COMMAND_V) {
command_count[t].num_v++;
} else if (command.type == COMMAND_VN) {
command_count[t].num_vn++;
} else if (command.type == COMMAND_VT) {
command_count[t].num_vt++;
} else if (command.type == COMMAND_F) {
command_count[t].num_f += command.f.size();
command_count[t].num_faces++;
}
if (command.type == COMMAND_MTLLIB) {
mtllib_t_index = t;
mtllib_i_index = commands->size();
}
commands[t].emplace_back(std::move(command));
}
}
}));
}
}
std::map<std::string, int> material_map; std::map<std::string, int> material_map;
std::vector<material_t> materials; std::vector<material_t> materials;
@@ -995,58 +1003,31 @@ int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, size_t *num
ms_load_mtl = t2 - t1; ms_load_mtl = t2 - t1;
} }
#endif
size_t num_v = 0; /* Construct attributes */
size_t num_vn = 0;
size_t num_vt = 0;
size_t num_f = 0;
size_t num_faces = 0;
{ {
auto t_start = std::chrono::high_resolution_clock::now(); size_t v_count = 0;
size_t n_count = 0;
size_t t_count = 0;
size_t f_count = 0;
size_t face_count = 0;
int material_id = -1; /* -1 = default unknown material. */
size_t i = 0;
attrib->vertices.resize(num_v * 3); attrib->vertices = (float*)malloc(sizeof(float) * num_v * 3);
attrib->normals.resize(num_vn * 3); attrib->normals = (float*)malloc(sizeof(float) * num_vn * 3);
attrib->texcoords.resize(num_vt * 2); attrib->texcoords = (float*)malloc(sizeof(float) * num_vt * 2);
attrib->faces.resize(num_f); attrib->faces = (tinyobj_vertex_index_t*)malloc(sizeof(tinyobj_vertex_index_t) * num_f);
attrib->face_num_verts.resize(num_faces); attrib->face_num_verts = (int*)malloc(sizeof(int) * num_faces);
attrib->material_ids.resize(num_faces); attrib->material_ids = (int*)malloc(sizeof(int) * num_faces);
size_t v_offsets[kMaxThreads]; for (i = 0; i < num_lines; i++) {
size_t n_offsets[kMaxThreads]; if (commands[i].type == COMMAND_EMPTY) {
size_t t_offsets[kMaxThreads];
size_t f_offsets[kMaxThreads];
size_t face_offsets[kMaxThreads];
v_offsets[0] = 0;
n_offsets[0] = 0;
t_offsets[0] = 0;
f_offsets[0] = 0;
face_offsets[0] = 0;
for (size_t t = 1; t < num_threads; t++) {
v_offsets[t] = v_offsets[t - 1] + command_count[t - 1].num_v;
n_offsets[t] = n_offsets[t - 1] + command_count[t - 1].num_vn;
t_offsets[t] = t_offsets[t - 1] + command_count[t - 1].num_vt;
f_offsets[t] = f_offsets[t - 1] + command_count[t - 1].num_f;
face_offsets[t] = face_offsets[t - 1] + command_count[t - 1].num_faces;
}
StackVector<std::thread, 16> workers;
for (size_t t = 0; t < num_threads; t++) {
int material_id = -1; // -1 = default unknown material.
workers->push_back(std::thread([&, t]() {
size_t v_count = v_offsets[t];
size_t n_count = n_offsets[t];
size_t t_count = t_offsets[t];
size_t f_count = f_offsets[t];
size_t face_count = face_offsets[t];
for (size_t i = 0; i < commands[t].size(); i++) {
if (commands[t][i].type == COMMAND_EMPTY) {
continue; continue;
} else if (commands[t][i].type == COMMAND_USEMTL) { } else if (commands[i].type == COMMAND_USEMTL) {
/* @todo
if (commands[t][i].material_name && if (commands[t][i].material_name &&
commands[t][i].material_name_len > 0) { commands[t][i].material_name_len > 0) {
std::string material_name(commands[t][i].material_name, std::string material_name(commands[t][i].material_name,
@@ -1059,53 +1040,51 @@ int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, size_t *num
material_id = -1; material_id = -1;
} }
} }
} else if (commands[t][i].type == COMMAND_V) { */
attrib->vertices[3 * v_count + 0] = commands[t][i].vx; } else if (commands[i].type == COMMAND_V) {
attrib->vertices[3 * v_count + 1] = commands[t][i].vy; attrib->vertices[3 * v_count + 0] = commands[i].vx;
attrib->vertices[3 * v_count + 2] = commands[t][i].vz; attrib->vertices[3 * v_count + 1] = commands[i].vy;
attrib->vertices[3 * v_count + 2] = commands[i].vz;
v_count++; v_count++;
} else if (commands[t][i].type == COMMAND_VN) { } else if (commands[i].type == COMMAND_VN) {
attrib->normals[3 * n_count + 0] = commands[t][i].nx; attrib->normals[3 * n_count + 0] = commands[i].nx;
attrib->normals[3 * n_count + 1] = commands[t][i].ny; attrib->normals[3 * n_count + 1] = commands[i].ny;
attrib->normals[3 * n_count + 2] = commands[t][i].nz; attrib->normals[3 * n_count + 2] = commands[i].nz;
n_count++; n_count++;
} else if (commands[t][i].type == COMMAND_VT) { } else if (commands[i].type == COMMAND_VT) {
attrib->texcoords[2 * t_count + 0] = commands[t][i].tx; attrib->texcoords[2 * t_count + 0] = commands[i].tx;
attrib->texcoords[2 * t_count + 1] = commands[t][i].ty; attrib->texcoords[2 * t_count + 1] = commands[i].ty;
t_count++; t_count++;
} else if (commands[t][i].type == COMMAND_F) { } else if (commands[i].type == COMMAND_F) {
for (size_t k = 0; k < commands[t][i].f.size(); k++) { size_t k =0;
vertex_index &vi = commands[t][i].f[k]; for (k = 0; k < commands[i].num_f; k++) {
tinyobj_vertex_index_t vi = commands[i].f[k];
int v_idx = fixIndex(vi.v_idx, v_count); int v_idx = fixIndex(vi.v_idx, v_count);
int vn_idx = fixIndex(vi.vn_idx, n_count); int vn_idx = fixIndex(vi.vn_idx, n_count);
int vt_idx = fixIndex(vi.vt_idx, t_count); int vt_idx = fixIndex(vi.vt_idx, t_count);
attrib->faces[f_count + k] = vertex_index(v_idx, vn_idx, vt_idx); attrib->faces[f_count + k].v_idx = v_idx;
attrib->faces[f_count + k].vn_idx = vn_idx;
attrib->faces[f_count + k].vt_idx = vt_idx;
} }
attrib->material_ids[face_count] = material_id; attrib->material_ids[face_count] = material_id;
attrib->face_num_verts[face_count] = commands[t][i].f.size(); attrib->face_num_verts[face_count] = commands[i].num_f;
f_count += commands[t][i].f.size(); f_count += commands[i].num_f;
face_count++; face_count++;
} }
} }
}));
}
} }
/* 5. Construct shape information. */ /* 5. Construct shape information. */
{ {
int face_count = 0; int face_count = 0;
tinyobj_shape_t shape;
shape.face_offset = 0;
shape.length = 0;
int face_prev_offset = 0; int face_prev_offset = 0;
for (size_t t = 0; t < num_threads; t++) { size_t i = 0;
for (size_t i = 0; i < commands[t].size(); i++) { for (i = 0; i < num_lines; i++) {
if (commands[t][i].type == COMMAND_O || if (commands[i].type == COMMAND_O ||
commands[t][i].type == COMMAND_G) { commands[i].type == COMMAND_G) {
std::string name; #if 0 /* @todo */
if (commands[t][i].type == COMMAND_O) { if (commands[i].type == COMMAND_O) {
name = std::string(commands[t][i].object_name, name = std::string(commands[t][i].object_name,
commands[t][i].object_name_len); commands[t][i].object_name_len);
} else { } else {
@@ -1141,26 +1120,31 @@ int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, size_t *num
shape.face_offset = face_count; shape.face_offset = face_count;
shape.length = 0; shape.length = 0;
} }
#endif
} }
if (commands[t][i].type == COMMAND_F) { if (commands[i].type == COMMAND_F) {
face_count++; face_count++;
} }
} }
}
if ((face_count - face_prev_offset) > 0) { if ((face_count - face_prev_offset) > 0) {
#if 0 /* todo */
shape.length = face_count - shape.face_offset; shape.length = face_count - shape.face_offset;
if (shape.length > 0) { if (shape.length > 0) {
shapes->push_back(shape); shapes->push_back(shape);
} }
#endif
} else { } else {
/* Guess no 'v' line occurrence after 'o' or 'g', so discards current shape information. */ /* Guess no 'v' line occurrence after 'o' or 'g', so discards current shape information. */
} }
} }
#endif /* 0 */
return 1; if (commands) {
free(commands);
}
return TINYOBJ_SUCCESS;
} }
#endif /* TINYOBJ_LOADER_C_IMPLEMENTATION */ #endif /* TINYOBJ_LOADER_C_IMPLEMENTATION */

View File

@@ -224,7 +224,8 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename)
printf("filesize: %d\n", (int)data_len); printf("filesize: %d\n", (int)data_len);
{ {
int ret = tinyobj_parse(&attrib, shapes, &num_shapes, data, data_len); unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
int ret = tinyobj_parse(&attrib, shapes, &num_shapes, data, data_len, flags);
} }
#if 0 #if 0