diff --git a/src/half_edge.c b/src/half_edge.c index 8d8e013..1c3bfc3 100644 --- a/src/half_edge.c +++ b/src/half_edge.c @@ -62,7 +62,18 @@ static int32_t get_edge_count(FACES const faces); static double **parse_2d_array(char const * const obj_string, char *item); static FACES parse_face_array(char const * const obj_string); - +static void assemble_HE_stage1(VERTICES obj_v, + HE_vert *vertices, + int32_t *vc); +static void assemble_HE_stage2(FACES obj_f, + HE_vert *vertices, + HE_face *faces, + HE_edge *edges, + int32_t *fc, + int32_t *ec); +static void assemble_HE_stage3(HE_edge *edges, + int32_t *ec, + int32_t *dec); /** * Get all edges that emanate from vertice and return a pointer @@ -274,8 +285,28 @@ static FACES parse_face_array(char const * const obj_string) return arr; } -static void fill_vertices(VERTICES obj_v, HE_vert *vertices, int32_t *vc) +/** + * First stage of assembling the half-edge data structure. + * Here we allocate vertices and fill their coordinates + * with the information we have from parsing the obj file. + * All other yet unknown members such as edge are set to + * NULL. This function isn't really modular, but makes + * reading parse_obj() a bit less painful. + * + * @param obj_v the vertices in the raw form after they are + * parsed from the obj file + * @param vertices pointer the actual half-edge vertices + * @param vc pointer to the vertice count + */ +static void assemble_HE_stage1(VERTICES obj_v, + HE_vert *vertices, + int32_t *vc) { + uint8_t const xpos = 1; + uint8_t const ypos = 2; + uint8_t const zpos = 3; + int8_t const default_col = -1; + *vc = 0; while (obj_v[*vc]) { @@ -288,9 +319,9 @@ static void fill_vertices(VERTICES obj_v, HE_vert *vertices, int32_t *vc) tmp_vec = malloc(sizeof(vector)); CHECK_PTR_VAL(tmp_vec); - tmp_vec->x = obj_v[*vc][1]; - tmp_vec->y = obj_v[*vc][2]; - tmp_vec->z = obj_v[*vc][3]; + tmp_vec->x = obj_v[*vc][xpos]; + tmp_vec->y = obj_v[*vc][ypos]; + tmp_vec->z = obj_v[*vc][zpos]; vertices[*vc].vec = tmp_vec; @@ -302,14 +333,160 @@ static void fill_vertices(VERTICES obj_v, HE_vert *vertices, int32_t *vc) /* allocate color struct and set preliminary colors */ vertices[*vc].col = malloc(sizeof(color)); - vertices[*vc].col->red = -1; - vertices[*vc].col->green = -1; - vertices[*vc].col->blue = -1; + vertices[*vc].col->red = default_col; + vertices[*vc].col->green = default_col; + vertices[*vc].col->blue = default_col; (*vc)++; } } +/** + * Second stage of assembling the half-edge data structure. + * Here we start creating the HE_edges and HE_faces and also + * fill some missing information to the HE_verts along with it. + * The edge pairs are still unknown, as well as some other + * acceleration-structure related members like vertice->dummys. + * This function isn't really modular, but makes + * reading parse_obj() a bit less painful. + * + * @param obj_f the raw faces as they are after parsing the obj file + * @param vertices the half-edge vertices + * @param faces the half-edge faces + * @param edges the half-edge edges + * @param fc the count of half-edge faces + * @param ec the count of half-edge edges + */ +static void assemble_HE_stage2(FACES obj_f, + HE_vert *vertices, + HE_face *faces, + HE_edge *edges, + int32_t *fc, + int32_t *ec) +{ + *ec = 0; + /* create HE_edges and real HE_faces */ + for (uint32_t i = 0; i < (uint32_t)(*fc); i++) { /* for all faces */ + + /* for all vertices of the face */ + for (uint32_t j = 0; j < (uint32_t)obj_f[i][0]; j++) { + uint32_t obj_f_pos = j + 1; /* first pos is reserved for length */ + uint32_t fv_arr_id = + obj_f[i][obj_f_pos] - 1; /* fv_id starts at 1 */ + + edges[*ec].vert = &(vertices[fv_arr_id]); + edges[*ec].face = &(faces[i]); + edges[*ec].pair = NULL; /* preliminary */ + vertices[fv_arr_id].edge = &(edges[*ec]); /* last one wins */ + vertices[fv_arr_id].dummys = NULL; /* preliminary */ + + /* Skip j == 0 here, so we don't underrun the arrays, + * since we always look one edge back. The first edge + * element is taken care of below as well. */ + if (j > 0) { + uint32_t *eac = &(edges[*ec].vert->eac); + + /* connect previous edge to current edge */ + edges[*ec - 1].next = &(edges[*ec]); + + /* Acceleration struct: + * add previous edge to edge_array of current vertice */ + REALLOC(edges[*ec].vert->edge_array, + sizeof(HE_edge*) * (*eac + 1)); + edges[*ec].vert->edge_array[*eac] = &(edges[*ec - 1]); + (*eac)++; + + if (obj_f_pos == (uint32_t)obj_f[i][0]) { /* no vertice left */ + uint32_t *eac; + /* connect last edge to first edge */ + edges[*ec].next = &(edges[*ec - j]); + eac = &(edges[*ec].next->vert->eac); + + /* Acceleration struct: + * add last edge to edge_array element of first vertice */ + REALLOC(edges[*ec].next->vert->edge_array, + sizeof(HE_edge*) * (*eac + 1)); + edges[*ec].next->vert->edge_array[*eac] = &(edges[*ec]); + (*eac)++; + } + } + + (*ec)++; + } + + faces[i].edge = &(edges[*ec - 1]); /* "last" edge */ + } +} + +/** + * Third stage of assembling the half-edge data structure. + * Here we find the pairs of edges and also account for the + * possibility of border-edges, where we have to set up + * dummy edges and connect them properly. + * + * @param edges the half-edge edges + * @param ec the half-edge edges count + * @param dec the dummy edges count + */ +static void assemble_HE_stage3(HE_edge *edges, + int32_t *ec, + int32_t *dec) +{ + /* find pairs */ + for (uint32_t i = 0; i < (uint32_t)(*ec); i++) { /* for all edges */ + uint32_t eac = edges[i].vert->eac; + bool pair_found = false; + + for (uint32_t j = 0; j < eac; j++) { /* for all potential pairs */ + if (edges[i].vert->edge_array[j] && + (edges[i].next->vert == + edges[i].vert->edge_array[j]->vert)) { + edges[i].pair = edges[i].vert->edge_array[j]; + edges[i].vert->edge_array[j] = NULL; + + pair_found = true; + break; + } + } + + /* create dummy pair edge if we have a border edge */ + if (!pair_found) { + uint32_t *vert_dc = &(edges[i].next->vert->dc); + + REALLOC(edges[i].next->vert->dummys, + sizeof(HE_edge*) * (*vert_dc + 1)); + + /* NULL-face indicates border-edge */ + edges[*ec + *dec].face = NULL; + /* we don't know this one yet */ + edges[*ec + *dec].next = NULL; + /* set both pairs */ + edges[*ec + *dec].pair = &(edges[i]); + edges[i].pair = &(edges[*ec + *dec]); + /* set vertex */ + edges[*ec + *dec].vert = edges[i].next->vert; + /* add the dummy edge to the dummys array of the vertex */ + edges[*ec + *dec].vert->dummys[*vert_dc] = &(edges[*ec + *dec]); + (*vert_dc)++; + + (*dec)++; + } + } + + /* now we have to connect the dummy edges together */ + for (uint32_t i = 0; i < (uint32_t) (*dec); i++) { /* for all dummy edges */ + /* vertex the dummy edge points to */ + HE_vert *vert = edges[*ec + i].pair->vert; + + /* iterate over the dummy array */ + for (uint32_t j = 0; j < vert->dc; j++) { + if (vert == vert->dummys[j]->vert) + edges[*ec + i].next = vert->dummys[j]; + j++; + } + } +} + /** * Calculate the normal of a face that corresponds * to edge. @@ -507,137 +684,26 @@ HE_obj *parse_obj(char const * const obj_string) /* obj_vt = parse_2d_array(obj_string, "vt"); */ obj_f = parse_face_array(string); - int32_t count = get_row_count((int32_t const**)obj_v); - vertices = malloc(sizeof(HE_vert) * - count + 1); - - printf("row count %d\n", get_row_count((int32_t const**)obj_v)); - - /* fill the vertices */ - fill_vertices(obj_v, vertices, &vc); - if ((ec = get_edge_count(obj_f)) == -1) ABORT("Invalid edge count!\n"); if ((fc = get_face_count(obj_f)) == -1) ABORT("Invalid face count!\n"); + vertices = malloc(sizeof(HE_vert) * + get_row_count((int32_t const**)obj_v) + 1); + CHECK_PTR_VAL(vertices); faces = (HE_face*) malloc(sizeof(HE_face) * fc); CHECK_PTR_VAL(faces); /* hold enough space for possible dummy edges */ edges = (HE_edge*) malloc(sizeof(HE_edge) * ec * 2); CHECK_PTR_VAL(edges); - ec = 0; - /* create HE_edges and real HE_faces */ - for (uint32_t i = 0; i < (uint32_t)fc; i++) { /* for all faces */ - - /* for all vertices of the face */ - for (uint32_t j = 0; j < (uint32_t)obj_f[i][0]; j++) { - uint32_t obj_f_pos = j + 1; /* first pos is reserved for length */ - uint32_t fv_arr_id = - obj_f[i][obj_f_pos] - 1; /* fv_id starts at 1 */ - - edges[ec].vert = &(vertices[fv_arr_id]); - edges[ec].face = &(faces[i]); - edges[ec].pair = NULL; /* preliminary */ - vertices[fv_arr_id].edge = &(edges[ec]); /* last one wins */ - vertices[fv_arr_id].dummys = NULL; /* preliminary */ - - /* Skip j == 0 here, so we don't underrun the arrays, - * since we always look one edge back. The first edge - * element is taken care of below as well. */ - if (j > 0) { - uint32_t *eac = &(edges[ec].vert->eac); - - /* connect previous edge to current edge */ - edges[ec - 1].next = &(edges[ec]); - - /* Acceleration struct: - * add previous edge to edge_array of current vertice */ - REALLOC(edges[ec].vert->edge_array, - sizeof(HE_edge*) * (*eac + 1)); - edges[ec].vert->edge_array[*eac] = &(edges[ec - 1]); - (*eac)++; - - if (obj_f_pos == (uint32_t)obj_f[i][0]) { /* no vertice left */ - uint32_t *eac; - /* connect last edge to first edge */ - edges[ec].next = &(edges[ec - j]); - eac = &(edges[ec].next->vert->eac); - - /* Acceleration struct: - * add last edge to edge_array element of first vertice */ - REALLOC(edges[ec].next->vert->edge_array, - sizeof(HE_edge*) * (*eac + 1)); - edges[ec].next->vert->edge_array[*eac] = &(edges[ec]); - (*eac)++; - } - } - - ec++; - } - - faces[i].edge = &(edges[ec - 1]); /* "last" edge */ - } - - /* find pairs */ - for (uint32_t i = 0; i < (uint32_t)ec; i++) { /* for all edges */ - uint32_t eac = edges[i].vert->eac; - bool pair_found = false; - - for (uint32_t j = 0; j < eac; j++) { /* for all potential pairs */ - if (edges[i].vert->edge_array[j] && - (edges[i].next->vert == - edges[i].vert->edge_array[j]->vert)) { - edges[i].pair = edges[i].vert->edge_array[j]; - edges[i].vert->edge_array[j] = NULL; - - pair_found = true; - break; - } - } - - /* create dummy pair edge if we have a border edge */ - if (!pair_found) { - uint32_t *vert_dc = &(edges[i].next->vert->dc); - - REALLOC(edges[i].next->vert->dummys, - sizeof(HE_edge*) * (*vert_dc + 1)); - - /* NULL-face indicates border-edge */ - edges[ec + dec].face = NULL; - /* we don't know this one yet */ - edges[ec + dec].next = NULL; - /* set both pairs */ - edges[ec + dec].pair = &(edges[i]); - edges[i].pair = &(edges[ec + dec]); - /* set vertex */ - edges[ec + dec].vert = edges[i].next->vert; - /* add the dummy edge to the dummys array of the vertex */ - edges[ec + dec].vert->dummys[*vert_dc] = &(edges[ec + dec]); - (*vert_dc)++; - - dec++; - } - } - - /* now we have to connect the dummy edges together */ - for (uint32_t i = 0; i < (uint32_t) dec; i++) { /* for all dummy edges */ - /* vertex the dummy edge points to */ - HE_vert *vert = edges[ec + i].pair->vert; - - /* iterate over the dummy array */ - for (uint32_t j = 0; j < vert->dc; j++) { - if (vert == vert->dummys[j]->vert) - edges[ec + i].next = vert->dummys[j]; - j++; - } - } - + assemble_HE_stage1(obj_v, vertices, &vc); + assemble_HE_stage2(obj_f, vertices, faces, edges, &fc, &ec); + assemble_HE_stage3(edges, &ec, &dec); obj = (HE_obj*) malloc(sizeof(HE_obj)); CHECK_PTR_VAL(obj); - obj->edges = edges; obj->vertices = vertices; obj->faces = faces; diff --git a/src/print.c b/src/print.c index 64f37d6..bc01ea9 100644 --- a/src/print.c +++ b/src/print.c @@ -93,7 +93,7 @@ void print_faces(HE_obj *obj) * Print all plain unconverted faces * as they are saved in the .obj file. * - * @param face the plain face struct + * @param faces the plain faces * @param fc the count of faces */ void print_plain_faces(FACES faces, uint32_t fc)