From 3a96dc11ca31493cbd23d9c5d36e3a7b2ba2958e Mon Sep 17 00:00:00 2001 From: Syoyo Fujita Date: Fri, 15 Jul 2016 19:46:36 +0900 Subject: [PATCH] Construct shape information. --- experimental/Makefile | 3 + experimental/tinyobj_loader_c.h | 584 ++++++++++++++++++-------------- experimental/viewer-c.c | 132 ++++---- 3 files changed, 408 insertions(+), 311 deletions(-) diff --git a/experimental/Makefile b/experimental/Makefile index eaa96a9..c89f8fd 100644 --- a/experimental/Makefile +++ b/experimental/Makefile @@ -2,6 +2,9 @@ UNAME_S := $(shell uname -s) ifeq ($(UNAME_S),Darwin) LD_FLAGS=-framework OpenGL -lglfw3 -lglew endif +ifeq ($(UNAME_S),Linux) +LD_FLAGS=-lGL -lGLU -lglfw3 -lGLEW -lX11 -lXrandr -lXinerama -lXxf86vm -lXcursor -lm -pthread -ldl +endif all: clang -c trackball.c diff --git a/experimental/tinyobj_loader_c.h b/experimental/tinyobj_loader_c.h index 6d83ac1..def492d 100644 --- a/experimental/tinyobj_loader_c.h +++ b/experimental/tinyobj_loader_c.h @@ -43,7 +43,7 @@ THE SOFTWARE. #include typedef struct { - const char* name; + const char *name; float ambient[3]; float diffuse[3]; @@ -51,45 +51,46 @@ typedef struct { float transmittance[3]; float emission[3]; float shininess; - float ior; /* index of refraction */ - float dissolve; /* 1 == opaque; 0 == fully transparent */ + float ior; /* index of refraction */ + float dissolve; /* 1 == opaque; 0 == fully transparent */ /* illumination model (see http://www.fileformat.info/format/material/) */ int illum; - const char* ambient_texname; /* map_Ka */ - const char* diffuse_texname; /* map_Kd */ - const char* specular_texname; /* map_Ks */ - const char* specular_highlight_texname; /* map_Ns */ - const char* bump_texname; /* map_bump, bump */ - const char* displacement_texname; /* disp */ - const char* alpha_texname; /* map_d */ + const char *ambient_texname; /* map_Ka */ + const char *diffuse_texname; /* map_Kd */ + const char *specular_texname; /* map_Ks */ + const char *specular_highlight_texname; /* map_Ns */ + const char *bump_texname; /* map_bump, bump */ + const char *displacement_texname; /* disp */ + const char *alpha_texname; /* map_d */ } tinyobj_material_t; typedef struct { - const char* name; /* group name or object name. */ + const char *name; /* group name or object name. */ unsigned int face_offset; unsigned int length; } tinyobj_shape_t; -typedef struct { - int v_idx, vt_idx, vn_idx; -} tinyobj_vertex_index_t; +typedef struct { int v_idx, vt_idx, vn_idx; } tinyobj_vertex_index_t; typedef struct { - float* vertices; + float *vertices; unsigned int num_vertices; - float* normals; + float *normals; unsigned int num_normals; - float* texcoords; + float *texcoords; unsigned int num_texcoords; tinyobj_vertex_index_t *faces; unsigned int num_faces; int *face_num_verts; - unsigned int num_face_num_verts; + unsigned int num_face_num_verts; int *material_ids; } tinyobj_attrib_t; -#define TINYOBJ_FLAG_TRIANGULATE (1 << 0) +#define TINYOBJ_FLAG_TRIANGULATE (1 << 0) + +#define TINYOBJ_INVALID_INDEX (0x80000000) + #define TINYOBJ_SUCCESS (0) #define TINYOBJ_ERROR_EMPTY (-1) #define TINYOBJ_ERROR_INVALID_PARAMETER (-2) @@ -99,16 +100,23 @@ typedef struct { * 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, unsigned int flags); +extern int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, + size_t *num_shapes, const char *buf, size_t len, + unsigned int flags); +extern void tinyobj_attrib_init(tinyobj_attrib_t *attrib); +extern void tinyobj_attrib_free(tinyobj_attrib_t *attrib); +extern void tinyobj_shape_free(tinyobj_shape_t *shapes, size_t num_shapes); + +/* Parse .mtl string and construct material struct */ +static int tinyobj_parse_mtl(tinyobj_material_t **materials, int *num_materials, const char* buf, size_t len); #ifdef TINYOBJ_LOADER_C_IMPLEMENTATION -#define TINYOBJ_MAX_FACES_PER_F_LINE (32) +#define TINYOBJ_MAX_FACES_PER_F_LINE (32) #define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) -#define IS_DIGIT(x) \ - ((unsigned int)((x) - '0') < (unsigned int)(10)) +#define IS_DIGIT(x) ((unsigned int)((x) - '0') < (unsigned int)(10)) #define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) static void skip_space(const char **token) { @@ -148,7 +156,8 @@ static int length_until_newline(const char *token, int n) { return len; } -/* http://stackoverflow.com/questions/5710091/how-does-atoi-function-in-c-work */ +/* http://stackoverflow.com/questions/5710091/how-does-atoi-function-in-c-work + */ static int my_atoi(const char *c) { int value = 0; int sign = 1; @@ -156,7 +165,7 @@ static int my_atoi(const char *c) { if (*c == '-') sign = -1; c++; } - while (((*c) >= '0') && ((*c) <= '9')) { /* isdigit(*c) */ + while (((*c) >= '0') && ((*c) <= '9')) { /* isdigit(*c) */ value *= 10; value += (int)(*c - '0'); c++; @@ -168,7 +177,7 @@ static int my_atoi(const char *c) { static int fixIndex(int idx, int n) { if (idx > 0) return idx - 1; if (idx == 0) return 0; - return n + idx; /* negative value = relative */ + return n + idx; /* negative value = relative */ } /* Parse raw triples: i, i/j/k, i//k, i/j */ @@ -211,7 +220,7 @@ static tinyobj_vertex_index_t parseRawTriple(const char **token) { } /* i/j/k */ - (*token)++; /* skip '/' */ + (*token)++; /* skip '/' */ vi.vn_idx = my_atoi((*token)); while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && (*token)[0] != '\t' && (*token)[0] != '\r') { @@ -223,7 +232,7 @@ static tinyobj_vertex_index_t parseRawTriple(const char **token) { /* assume `s' has enough storage spage to store parsed string. */ static void parseString(char *s, int *n, const char **token) { int e = 0; - skip_space(token); + skip_space(token); e = until_space((*token)); memcpy(s, (*token), e); (*n) = e; @@ -232,7 +241,7 @@ static void parseString(char *s, int *n, const char **token) { static int parseInt(const char **token) { int i = 0; - skip_space(token); + skip_space(token); i = my_atoi((*token)); (*token) += until_space((*token)); return i; @@ -320,7 +329,7 @@ static int tryParseDouble(const char *s, const char *s_end, double *result) { /* We must make sure we actually got something. */ if (read == 0) goto fail; /* We allow numbers of form "#", "###" etc. */ - if (!end_not_reached) goto assemble; + if (!end_not_reached) goto assemble; /* Read the decimal part. */ if (*curr == '.') { @@ -375,18 +384,19 @@ static int tryParseDouble(const char *s, const char *s_end, double *result) { assemble : - { - /* = pow(5.0, exponent); */ - double a = 5.0; - int i; - for (i = 0; i < exponent; i++) { - a = a * a; - } - *result = - /* (sign == '+' ? 1 : -1) * ldexp(mantissa * pow(5.0, exponent), exponent); */ - (sign == '+' ? 1 : -1) * (mantissa * a) * - (double)(1 << exponent); /* 5.0^exponent * 2^exponent */ +{ + /* = pow(5.0, exponent); */ + double a = 1.0; + int i; + for (i = 0; i < exponent; i++) { + a = a * 5.0; } + *result = + /* (sign == '+' ? 1 : -1) * ldexp(mantissa * pow(5.0, exponent), + exponent); */ + (sign == '+' ? 1 : -1) * (mantissa * a) * + (double)(1 << exponent); /* 5.0^exponent * 2^exponent */ +} return 1; fail: @@ -397,9 +407,8 @@ static float parseFloat(const char **token) { const char *end; double val = 0.0; float f = 0.0f; - skip_space(token); - end = - (*token) + until_space((*token)); + skip_space(token); + end = (*token) + until_space((*token)); val = 0.0; tryParseDouble((*token), end, &val); f = (float)(val); @@ -412,23 +421,22 @@ static void parseFloat2(float *x, float *y, const char **token) { (*y) = parseFloat(token); } -static void parseFloat3(float *x, float *y, float *z, - const char **token) { +static void parseFloat3(float *x, float *y, float *z, const char **token) { (*x) = parseFloat(token); (*y) = parseFloat(token); (*z) = parseFloat(token); } -static void InitMaterial(tinyobj_material_t *material) { +static void initMaterial(tinyobj_material_t *material) { int i; - material->name = ""; - material->ambient_texname = ""; - material->diffuse_texname = ""; - material->specular_texname = ""; - material->specular_highlight_texname = ""; - material->bump_texname = ""; - material->displacement_texname = ""; - material->alpha_texname = ""; + material->name = NULL; + material->ambient_texname = NULL; + material->diffuse_texname = NULL; + material->specular_texname = NULL; + material->specular_highlight_texname = NULL; + material->bump_texname = NULL; + material->displacement_texname = NULL; + material->alpha_texname = NULL; for (i = 0; i < 3; i++) { material->ambient[i] = 0.f; material->diffuse[i] = 0.f; @@ -442,16 +450,19 @@ static void InitMaterial(tinyobj_material_t *material) { material->ior = 1.f; } -#if 0 /* todo */ -static void LoadMtl(std::map *material_map, - std::vector *materials, - std::istream *inStream) { - // Create a default material anyway. - material_t material; - InitMaterial(&material); +static tinyobj_material_t *tinyobj_material_add(tinyobj_material_t *prev, int num_materials, tinyobj_material_t *new_mat) +{ + tinyobj_material_t* dst = (tinyobj_material_t*)realloc(prev, sizeof(tinyobj_material_t) * (num_materials + 1)); - size_t maxchars = 8192; // Alloc enough size. - std::vector buf(maxchars); // Alloc enough size. + return dst; +} + +int tinyobj_parse_mtl(tinyobj_material_t **materials, int *num_materials, const char* buf, size_t len) { + /* Create a default material */ + tinyobj_material_t default_material; + initMaterial(&default_material); + +#if 0 while (inStream->peek() != -1) { inStream->getline(&buf[0], static_cast(maxchars)); @@ -597,79 +608,67 @@ static void LoadMtl(std::map *material_map, // ambient texture if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { token += 7; - material.ambient_texname = token; + material.ambient_texname = strdup(token); continue; } // diffuse texture if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) { token += 7; - material.diffuse_texname = token; + material.diffuse_texname = strdup(token); continue; } // specular texture if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) { token += 7; - material.specular_texname = token; + material.specular_texname = strdup(token); continue; } // specular highlight texture if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) { token += 7; - material.specular_highlight_texname = token; + material.specular_highlight_texname = strdup(token); continue; } // bump texture if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) { token += 9; - material.bump_texname = token; + material.bump_texname = strdup(token); continue; } // alpha texture if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) { token += 6; - material.alpha_texname = token; + material.alpha_texname = strdup(token); continue; } // bump texture if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) { token += 5; - material.bump_texname = token; + material.bump_texname = strdup(token); continue; } // displacement texture if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) { token += 5; - material.displacement_texname = token; + material.displacement_texname = strdup(token); continue; } - // unknown parameter - const char *_space = strchr(token, ' '); - if (!_space) { - _space = strchr(token, '\t'); - } - if (_space) { - std::ptrdiff_t len = _space - token; - std::string key(token, static_cast(len)); - std::string value = _space + 1; - material.unknown_parameter.insert( - std::pair(key, value)); - } + /* @todo { unknown parameter } */ } - // flush last material. - material_map->insert(std::pair( - material.name, static_cast(materials->size()))); - materials->push_back(material); -} #endif + + return TINYOBJ_SUCCESS; +} + typedef enum { COMMAND_EMPTY, COMMAND_V, @@ -688,12 +687,12 @@ typedef struct { float nx, ny, nz; float tx, ty; - /* @todo { Use dynamic array } */ - tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE]; - int num_f; + /* @todo { Use dynamic array } */ + tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE]; + int num_f; - int f_num_verts[TINYOBJ_MAX_FACES_PER_F_LINE]; - int num_f_num_verts; + int f_num_verts[TINYOBJ_MAX_FACES_PER_F_LINE]; + int num_f_num_verts; const char *group_name; unsigned int group_name_len; @@ -708,9 +707,10 @@ typedef struct { CommandType type; } Command; -static int parseLine(Command *command, const char *p, size_t p_len, int triangulate) { +static int parseLine(Command *command, const char *p, size_t p_len, + int triangulate) { char linebuf[4096]; - const char *token; + const char *token; assert(p_len < 4095); memcpy(linebuf, p, p_len); @@ -724,11 +724,11 @@ static int parseLine(Command *command, const char *p, size_t p_len, int triangul skip_space(&token); assert(token); - if (token[0] == '\0') { /* empty line */ + if (token[0] == '\0') { /* empty line */ return 0; } - if (token[0] == '#') { /* comment line */ + if (token[0] == '#') { /* comment line */ return 0; } @@ -769,13 +769,12 @@ static int parseLine(Command *command, const char *p, size_t p_len, int triangul /* face */ if (token[0] == 'f' && IS_SPACE((token[1]))) { - int num_f = 0; + int num_f = 0; - tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE]; + tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE]; token += 2; skip_space(&token); - while (!IS_NEW_LINE(token[0])) { tinyobj_vertex_index_t vi = parseRawTriple(&token); skip_space_and_cr(&token); @@ -787,38 +786,38 @@ static int parseLine(Command *command, const char *p, size_t p_len, int triangul command->type = COMMAND_F; if (triangulate) { - int k; - int n = 0; + int k; + int n = 0; 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); + assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE); for (k = 2; k < num_f; k++) { i1 = i2; i2 = f[k]; - command->f[3*n+0] = i0; - command->f[3*n+1] = i1; - command->f[3*n+2] = i2; + command->f[3 * n + 0] = i0; + command->f[3 * n + 1] = i1; + command->f[3 * n + 2] = i2; command->f_num_verts[n] = 3; - n++; + n++; } - command->num_f = 3 * n; - command->num_f_num_verts = n; + command->num_f = 3 * n; + command->num_f_num_verts = n; } else { - int k = 0; - assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE); + int k = 0; + assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE); for (k = 0; k < num_f; k++) { command->f[k] = f[k]; } command->num_f = num_f; command->f_num_verts[0] = num_f; - command->num_f_num_verts = 1; + command->num_f_num_verts = 1; } return 1; @@ -880,6 +879,26 @@ static int parseLine(Command *command, const char *p, size_t p_len, int triangul return 0; } +static char *my_strndup(const char *s, size_t len) +{ + char *d; + int slen; + + if (len == 0) return NULL; + + d = (char *)malloc(len + 1); /* + '\0' */ + slen = strlen(s); + if (slen < len) { + memcpy(d, s, slen); + d[slen] = '\0'; + } else { + memcpy(d, s, len); + d[len] = '\0'; + } + + return d; +} + typedef struct { size_t pos; size_t len; @@ -887,66 +906,73 @@ typedef struct { static int is_line_ending(const char *p, size_t i, size_t end_i) { if (p[i] == '\0') return 1; - if (p[i] == '\n') return 1; /* this includes \r\n */ + if (p[i] == '\n') return 1; /* this includes \r\n */ 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 1; } } return 0; } -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; - Command* commands = NULL; - size_t num_lines = 0; +int tinyobj_parse_obj(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; + Command *commands = NULL; + 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; + 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 TINYOBJ_ERROR_INVALID_PARAMETER; + if (attrib == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (num_shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + if (buf == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; + + tinyobj_attrib_init(attrib); /* 1. Find '\n' and create line data. */ { - size_t i; - 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' */ + size_t i; + 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++; - } - } + 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. */ - for (i = 0; i < end_idx; i++) { + /* 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; - prev_pos = i + 1; - line_no++; - } - } + line_infos[line_no].pos = prev_pos; + line_infos[line_no].len = i - prev_pos; + prev_pos = i + 1; + line_no++; + } + } } - commands = (Command*)malloc(sizeof(Command) * num_lines); + 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); + line_infos[i].len, flags & TINYOBJ_FLAG_TRIANGULATE); if (ret) { if (commands[i].type == COMMAND_V) { num_v++; @@ -956,7 +982,7 @@ int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, size_t *num num_vt++; } else if (commands[i].type == COMMAND_F) { num_f += commands[i].num_f; - num_faces++; + num_faces += commands[i].num_f_num_verts; } if (commands[i].type == COMMAND_MTLLIB) { @@ -965,15 +991,14 @@ int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, size_t *num mtllib_i_index = commands->size(); */ } - } } } /* line_infos are not used anymore. Release memory. */ - if (line_infos) { - free(line_infos); - } + if (line_infos) { + free(line_infos); + } #if 0 @@ -1014,136 +1039,169 @@ int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, size_t *num size_t t_count = 0; size_t f_count = 0; size_t face_count = 0; - int material_id = -1; /* -1 = default unknown material. */ + int material_id = -1; /* -1 = default unknown material. */ size_t i = 0; - attrib->vertices = (float*)malloc(sizeof(float) * num_v * 3); + attrib->vertices = (float *)malloc(sizeof(float) * num_v * 3); attrib->num_vertices = num_v; - attrib->normals = (float*)malloc(sizeof(float) * num_vn * 3); + attrib->normals = (float *)malloc(sizeof(float) * num_vn * 3); attrib->num_normals = num_vn; - attrib->texcoords = (float*)malloc(sizeof(float) * num_vt * 2); + attrib->texcoords = (float *)malloc(sizeof(float) * num_vt * 2); attrib->num_texcoords = num_vt; - attrib->faces = (tinyobj_vertex_index_t*)malloc(sizeof(tinyobj_vertex_index_t) * num_f); + attrib->faces = (tinyobj_vertex_index_t *)malloc( + sizeof(tinyobj_vertex_index_t) * num_f); attrib->num_faces = num_f; - attrib->face_num_verts = (int*)malloc(sizeof(int) * num_faces); - attrib->material_ids = (int*)malloc(sizeof(int) * num_faces); + attrib->face_num_verts = (int *)malloc(sizeof(int) * num_faces); + attrib->material_ids = (int *)malloc(sizeof(int) * num_faces); attrib->num_face_num_verts = num_faces; - for (i = 0; i < num_lines; i++) { - if (commands[i].type == COMMAND_EMPTY) { - continue; - } else if (commands[i].type == COMMAND_USEMTL) { - /* @todo - if (commands[t][i].material_name && - commands[t][i].material_name_len > 0) { - std::string material_name(commands[t][i].material_name, - commands[t][i].material_name_len); + for (i = 0; i < num_lines; i++) { + if (commands[i].type == COMMAND_EMPTY) { + continue; + } else if (commands[i].type == COMMAND_USEMTL) { + /* @todo + if (commands[t][i].material_name && + commands[t][i].material_name_len > 0) { + std::string material_name(commands[t][i].material_name, + commands[t][i].material_name_len); - if (material_map.find(material_name) != material_map.end()) { - material_id = material_map[material_name]; - } else { - // Assign invalid material ID - material_id = -1; - } - } - */ - } else if (commands[i].type == COMMAND_V) { - attrib->vertices[3 * v_count + 0] = commands[i].vx; - attrib->vertices[3 * v_count + 1] = commands[i].vy; - attrib->vertices[3 * v_count + 2] = commands[i].vz; - v_count++; - } else if (commands[i].type == COMMAND_VN) { - attrib->normals[3 * n_count + 0] = commands[i].nx; - attrib->normals[3 * n_count + 1] = commands[i].ny; - attrib->normals[3 * n_count + 2] = commands[i].nz; - n_count++; - } else if (commands[i].type == COMMAND_VT) { - attrib->texcoords[2 * t_count + 0] = commands[i].tx; - attrib->texcoords[2 * t_count + 1] = commands[i].ty; - t_count++; - } else if (commands[i].type == COMMAND_F) { - size_t k =0; - 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 vn_idx = fixIndex(vi.vn_idx, n_count); - int vt_idx = fixIndex(vi.vt_idx, t_count); - 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->face_num_verts[face_count] = commands[i].num_f; - - f_count += commands[i].num_f; - face_count++; + if (material_map.find(material_name) != material_map.end()) { + material_id = material_map[material_name]; + } else { + // Assign invalid material ID + material_id = -1; } } + */ + } else if (commands[i].type == COMMAND_V) { + attrib->vertices[3 * v_count + 0] = commands[i].vx; + attrib->vertices[3 * v_count + 1] = commands[i].vy; + attrib->vertices[3 * v_count + 2] = commands[i].vz; + v_count++; + } else if (commands[i].type == COMMAND_VN) { + attrib->normals[3 * n_count + 0] = commands[i].nx; + attrib->normals[3 * n_count + 1] = commands[i].ny; + attrib->normals[3 * n_count + 2] = commands[i].nz; + n_count++; + } else if (commands[i].type == COMMAND_VT) { + attrib->texcoords[2 * t_count + 0] = commands[i].tx; + attrib->texcoords[2 * t_count + 1] = commands[i].ty; + t_count++; + } else if (commands[i].type == COMMAND_F) { + size_t k = 0; + 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 vn_idx = fixIndex(vi.vn_idx, n_count); + int vt_idx = fixIndex(vi.vt_idx, t_count); + 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; + } + + for (k = 0; k < commands[i].num_f_num_verts; k++) { + attrib->material_ids[face_count + k] = material_id; + attrib->face_num_verts[face_count + k] = commands[i].f_num_verts[k]; + } + + f_count += commands[i].num_f; + face_count += commands[i].num_f_num_verts; + } + } } /* 5. Construct shape information. */ { int face_count = 0; - int face_prev_offset = 0; size_t i = 0; - for (i = 0; i < num_lines; i++) { - if (commands[i].type == COMMAND_O || - commands[i].type == COMMAND_G) { -#if 0 /* @todo */ + size_t n = 0; + size_t shape_idx = 0; + + const char* shape_name = NULL; + int shape_name_len = 0; + const char* prev_shape_name = NULL; + int prev_shape_name_len = 0; + int prev_shape_face_offset = 0; + int prev_shape_length = 0; + int prev_face_offset = 0; + tinyobj_shape_t prev_shape = {NULL, 0, 0}; + + /* Find the number of shapes in .obj */ + for (i = 0; i < num_lines; i++) { + if (commands[i].type == COMMAND_O || commands[i].type == COMMAND_G) { + n++; + } + } + + /* Allocate array of shapes with maximum possible size(+1 for unnamed group/object). + * Actual # of shapes found in .obj is determined in the later */ + (*shapes) = malloc(sizeof(tinyobj_shape_t) * (n + 1)); + + for (i = 0; i < num_lines; i++) { + if (commands[i].type == COMMAND_O || commands[i].type == COMMAND_G) { + if (commands[i].type == COMMAND_O) { - name = std::string(commands[t][i].object_name, - commands[t][i].object_name_len); + shape_name = commands[i].object_name; + shape_name_len = commands[i].object_name_len; } else { - name = std::string(commands[t][i].group_name, - commands[t][i].group_name_len); + shape_name = commands[i].group_name; + shape_name_len = commands[i].group_name_len; } if (face_count == 0) { - // 'o' or 'g' appears before any 'f' - shape.name = name; - shape.face_offset = face_count; - face_prev_offset = face_count; + /* 'o' or 'g' appears before any 'f' */ + prev_shape_name = shape_name; + prev_shape_name_len = shape_name_len; + prev_shape_face_offset = face_count; + prev_face_offset = face_count; } else { - if (shapes->size() == 0) { - // 'o' or 'g' after some 'v' lines. - // create a shape with null name - shape.length = face_count - face_prev_offset; - face_prev_offset = face_count; + if (shape_idx == 0) { + /* 'o' or 'g' after some 'v' lines. */ + (*shapes)[shape_idx].name = my_strndup(prev_shape_name, prev_shape_name_len); /* may be NULL */ + (*shapes)[shape_idx].face_offset = prev_shape.face_offset; + (*shapes)[shape_idx].length = face_count - prev_face_offset; + shape_idx++; - shapes->push_back(shape); + prev_shape_length = face_count - prev_face_offset; + prev_face_offset = face_count; } else { - if ((face_count - face_prev_offset) > 0) { - // push previous shape - shape.length = face_count - face_prev_offset; - shapes->push_back(shape); - face_prev_offset = face_count; + if ((face_count - prev_face_offset) > 0) { + (*shapes)[shape_idx].name = my_strndup(prev_shape_name, prev_shape_name_len); + (*shapes)[shape_idx].face_offset = prev_face_offset; + (*shapes)[shape_idx].length = face_count - prev_face_offset; + shape_idx++; + prev_shape_length = face_count - prev_face_offset; + prev_face_offset = face_count; } } - // redefine shape. - shape.name = name; - shape.face_offset = face_count; - shape.length = 0; + /* Record shape info for succeeding 'o' or 'g' command. */ + prev_shape_name = shape_name; + prev_shape_name_len = shape_name_len; + prev_shape_face_offset = face_count; + prev_shape_length = 0; } -#endif - } - if (commands[i].type == COMMAND_F) { - face_count++; - } } - - if ((face_count - face_prev_offset) > 0) { -#if 0 /* todo */ - shape.length = face_count - shape.face_offset; - if (shape.length > 0) { - shapes->push_back(shape); + if (commands[i].type == COMMAND_F) { + face_count++; } -#endif - } else { - /* Guess no 'v' line occurrence after 'o' or 'g', so discards current shape information. */ } + if ((face_count - prev_face_offset) > 0) { + size_t len = face_count - prev_shape_face_offset; + if (len > 0) { + (*shapes)[shape_idx].name = my_strndup(prev_shape_name, prev_shape_name_len); + (*shapes)[shape_idx].face_offset = prev_face_offset; + (*shapes)[shape_idx].length = face_count - prev_face_offset; + shape_idx++; + } + } else { + /* Guess no 'v' line occurrence after 'o' or 'g', so discards current + * shape information. */ + } + + (*num_shapes) = shape_idx; } if (commands) { @@ -1152,6 +1210,32 @@ int tinyobj_parse(tinyobj_attrib_t *attrib, tinyobj_shape_t *shapes, size_t *num return TINYOBJ_SUCCESS; } -#endif /* TINYOBJ_LOADER_C_IMPLEMENTATION */ -#endif /* TINOBJ_LOADER_C_H_ */ +void tinyobj_attrib_init(tinyobj_attrib_t *attrib) +{ + attrib->vertices = NULL; + attrib->num_vertices = 0; + attrib->normals = NULL; + attrib->num_normals = 0; + attrib->texcoords = NULL; + attrib->num_texcoords = 0; + attrib->faces = NULL; + attrib->num_faces = 0; + attrib->face_num_verts = NULL; + attrib->num_face_num_verts = 0; + attrib->material_ids = NULL; +} + +void tinyobj_attrib_free(tinyobj_attrib_t *attrib) +{ + if (attrib->vertices) free(attrib->vertices); + if (attrib->normals) free(attrib->normals); + if (attrib->texcoords) free(attrib->texcoords); + if (attrib->faces) free(attrib->faces); + if (attrib->face_num_verts) free(attrib->face_num_verts); + if (attrib->material_ids) free(attrib->material_ids); +} + +#endif /* TINYOBJ_LOADER_C_IMPLEMENTATION */ + +#endif /* TINOBJ_LOADER_C_H_ */ diff --git a/experimental/viewer-c.c b/experimental/viewer-c.c index 22bc4a5..98b254a 100644 --- a/experimental/viewer-c.c +++ b/experimental/viewer-c.c @@ -23,8 +23,7 @@ typedef struct { int numTriangles; } DrawObject; -static DrawObject gDrawObjects[MAX_OBJECTS]; -static int gNumDrawObjects; +static DrawObject gDrawObject; static int width = 768; static int height = 768; @@ -214,7 +213,7 @@ static const char* get_file_data(size_t *len, const char* filename) static int LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename) { tinyobj_attrib_t attrib; - tinyobj_shape_t *shapes; + tinyobj_shape_t *shapes = NULL; size_t num_shapes; size_t data_len = 0; @@ -227,10 +226,19 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename) { unsigned int flags = TINYOBJ_FLAG_TRIANGULATE; - int ret = tinyobj_parse(&attrib, shapes, &num_shapes, data, data_len, flags); + int ret = tinyobj_parse_obj(&attrib, &shapes, &num_shapes, data, data_len, flags); if (ret != TINYOBJ_SUCCESS) { return 0; } + + printf("# of shapes = %d\n", num_shapes); + + { + int i; + for (i = 0; i < num_shapes; i++) { + printf("shape[%d] name = %s\n", i, shapes[i].name); + } + } } bmin[0] = bmin[1] = bmin[2] = FLT_MAX; @@ -238,17 +246,27 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename) { DrawObject o; - /* std::vector vb; // pos(3float), normal(3float), color(3float) */ + float *vb; + /* std::vector vb; // */ size_t face_offset = 0; - size_t v; + size_t i; - for (v = 0; v < attrib.num_face_num_verts; v++) { + /* Assume triangulated face. */ + size_t num_triangles = attrib.num_face_num_verts; + size_t stride = 9; /* 9 = pos(3float), normal(3float), color(3float) */ + + vb = (float*)malloc(sizeof(float) * stride * num_triangles * 3); + + for (i = 0; i < attrib.num_face_num_verts; i++) { size_t f; - assert(attrib.face_num_verts[v] % 3 == 0); /* assume all triangle faces. */ - for (f = 0; f < attrib.face_num_verts[v] / 3; f++) { + assert(attrib.face_num_verts[i] % 3 == 0); /* assume all triangle faces. */ + for (f = 0; f < attrib.face_num_verts[i] / 3; f++) { int k; float v[3][3]; float n[3][3]; + float c[3]; + float len2; + tinyobj_vertex_index_t idx0 = attrib.faces[face_offset+3*f+0]; tinyobj_vertex_index_t idx1 = attrib.faces[face_offset+3*f+1]; tinyobj_vertex_index_t idx2 = attrib.faces[face_offset+3*f+2]; @@ -272,21 +290,24 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename) bmax[k] = (v[2][k] > bmax[k]) ? v[2][k] : bmax[k]; } - - if (attrib.normals) { + if (attrib.num_normals > 0) { int f0 = idx0.vn_idx; int f1 = idx1.vn_idx; int f2 = idx2.vn_idx; - assert(f0 >= 0); - assert(f1 >= 0); - assert(f2 >= 0); - assert(3*f0+2 < attrib.num_normals); - assert(3*f1+2 < attrib.num_normals); - assert(3*f2+2 < attrib.num_normals); - for (k = 0; k < 3; k++) { - n[0][k] = attrib.normals[3*f0+k]; - n[1][k] = attrib.normals[3*f1+k]; - n[2][k] = attrib.normals[3*f2+k]; + if (f0 >=0 && f1 >= 0 && f2 >= 0) { + assert(3*f0+2 < attrib.num_normals); + assert(3*f1+2 < attrib.num_normals); + assert(3*f2+2 < attrib.num_normals); + for (k = 0; k < 3; k++) { + n[0][k] = attrib.normals[3*f0+k]; + n[1][k] = attrib.normals[3*f1+k]; + n[2][k] = attrib.normals[3*f2+k]; + } + } else { /* normal index is not defined for this face */ + /* compute geometric normal */ + CalcNormal(n[0], v[0], v[1], v[2]); + n[1][0] = n[0][0]; n[1][1] = n[0][1]; n[1][2] = n[0][2]; + n[2][0] = n[0][0]; n[2][1] = n[0][1]; n[2][2] = n[0][2]; } } else { /* compute geometric normal */ @@ -296,17 +317,14 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename) } for (k = 0; k < 3; k++) { -#if 0 - vb.push_back(v[k][0]); - vb.push_back(v[k][1]); - vb.push_back(v[k][2]); - vb.push_back(n[k][0]); - vb.push_back(n[k][1]); - vb.push_back(n[k][2]); -#endif + vb[(3 * i + k) * stride + 0] = v[k][0]; + vb[(3 * i + k) * stride + 1] = v[k][1]; + vb[(3 * i + k) * stride + 2] = v[k][2]; + vb[(3 * i + k) * stride + 3] = n[k][0]; + vb[(3 * i + k) * stride + 4] = n[k][1]; + vb[(3 * i + k) * stride + 5] = n[k][2]; + /* Use normal as color. */ - float c[3]; - float len2; c[0] = n[k][0]; c[1] = n[k][1]; c[2] = n[k][2]; @@ -318,33 +336,34 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], const char* filename) c[1] /= len; c[2] /= len; } -#if 0 - vb.push_back(c[0] * 0.5 + 0.5); - vb.push_back(c[1] * 0.5 + 0.5); - vb.push_back(c[2] * 0.5 + 0.5); -#endif + + vb[(3 * i + k) * stride + 6] = (c[0] * 0.5 + 0.5); + vb[(3 * i + k) * stride + 7] = (c[1] * 0.5 + 0.5); + vb[(3 * i + k) * stride + 8] = (c[2] * 0.5 + 0.5); } } - face_offset += attrib.face_num_verts[v]; + face_offset += attrib.face_num_verts[i]; } o.vb = 0; o.numTriangles = 0; -#if 0 /* @todo */ - if (vb.size() > 0) { + if (num_triangles > 0) { glGenBuffers(1, &o.vb); glBindBuffer(GL_ARRAY_BUFFER, o.vb); - glBufferData(GL_ARRAY_BUFFER, vb.size() * sizeof(float), &vb.at(0), GL_STATIC_DRAW); - o.numTriangles = vb.size() / 9 / 3; + glBufferData(GL_ARRAY_BUFFER, num_triangles * 3 * stride * sizeof(float), vb, GL_STATIC_DRAW); + o.numTriangles = num_triangles; } - gDrawObjects.push_back(o); -#endif + free(vb); + + gDrawObject = o; } printf("bmin = %f, %f, %f\n", bmin[0], bmin[1], bmin[2]); printf("bmax = %f, %f, %f\n", bmax[0], bmax[1], bmax[2]); + tinyobj_attrib_free(&attrib); + return 1; } @@ -437,7 +456,7 @@ static void motionFunc(GLFWwindow* window, double mouse_x, double mouse_y){ prevMouseY = (float)mouse_y; } -static void Draw(const DrawObject* draw_objects, int num_draw_objects) +static void Draw(const DrawObject* draw_object) { int i; @@ -447,13 +466,8 @@ static void Draw(const DrawObject* draw_objects, int num_draw_objects) glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(1.0, 1.0); glColor3f(1.0f, 1.0f, 1.0f); - for (i = 0; i < num_draw_objects; i++) { - const DrawObject o = draw_objects[i]; - if (o.vb < 1) { - continue; - } - - glBindBuffer(GL_ARRAY_BUFFER, o.vb); + if (draw_object->vb >= 1) { + glBindBuffer(GL_ARRAY_BUFFER, draw_object->vb); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_COLOR_ARRAY); @@ -461,7 +475,7 @@ static void Draw(const DrawObject* draw_objects, int num_draw_objects) glNormalPointer(GL_FLOAT, 36, (const void*)(sizeof(float)*3)); glColorPointer(3, GL_FLOAT, 36, (const void*)(sizeof(float)*6)); - glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles); + glDrawArrays(GL_TRIANGLES, 0, 3 * draw_object->numTriangles); CheckErrors("drawarrays"); } @@ -471,20 +485,16 @@ static void Draw(const DrawObject* draw_objects, int num_draw_objects) glPolygonMode(GL_BACK, GL_LINE); glColor3f(0.0f, 0.0f, 0.4f); - for (i = 0; i < num_draw_objects; i++) { - DrawObject o = draw_objects[i]; - if (o.vb < 1) { - continue; - } - - glBindBuffer(GL_ARRAY_BUFFER, o.vb); + + if (draw_object->vb >= 1) { + glBindBuffer(GL_ARRAY_BUFFER, draw_object->vb); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glVertexPointer(3, GL_FLOAT, 36, (const void*)0); glNormalPointer(GL_FLOAT, 36, (const void*)(sizeof(float)*3)); - glDrawArrays(GL_TRIANGLES, 0, 3 * o.numTriangles); + glDrawArrays(GL_TRIANGLES, 0, 3 * draw_object->numTriangles); CheckErrors("drawarrays"); } } @@ -582,7 +592,7 @@ int main(int argc, char **argv) /* Centerize object. */ glTranslatef(-0.5f*(bmax[0] + bmin[0]), -0.5f*(bmax[1] + bmin[1]), -0.5f*(bmax[2] + bmin[2])); - Draw(gDrawObjects, gNumDrawObjects); + Draw(&gDrawObject); glfwSwapBuffers(gWindow); }