Refactor parse_obj() and move some subroutines to new functions

This commit is contained in:
hasufell 2014-05-16 19:57:43 +02:00
parent 0ecd0d8e9f
commit dfd978f714
No known key found for this signature in database
GPG Key ID: 220CD1C5BDEED020
2 changed files with 192 additions and 126 deletions

View File

@ -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;

View File

@ -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)