From da36cd20dab4028132716d0ce2622e630e5ebf0d Mon Sep 17 00:00:00 2001 From: hasufell Date: Mon, 12 May 2014 20:20:03 +0200 Subject: [PATCH] Implement vertex normals --- src/gl_draw.c | 53 ++++++++++++++++-- src/half_edge.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++-- src/half_edge.h | 3 +- 3 files changed, 190 insertions(+), 12 deletions(-) diff --git a/src/gl_draw.c b/src/gl_draw.c index 061b64e..5cd41b1 100644 --- a/src/gl_draw.c +++ b/src/gl_draw.c @@ -53,6 +53,7 @@ int yearabs = 365; int day; int dayabs = 30; HE_obj *obj; +bool show_normals = false; /* * static function declaration @@ -63,8 +64,37 @@ static void draw_obj(int32_t const myxrot, static void draw_Planet_1(void); static void draw_Planet_2(void); static void gl_destroy(void); +static void draw_normals(HE_obj const * const obj); +static void draw_normals(HE_obj const * const obj) +{ + vector vec; + + for (uint32_t i = 0; i < obj->vc; i++) { + if ((vec_normal(&(obj->vertices[i]), &vec))) { + glPushMatrix(); + + glLineWidth(3); + glColor3f(1.0, 1.0, 1.0); + + glBegin(GL_LINES); + glVertex3f(obj->vertices[i].vec->x, + obj->vertices[i].vec->y, + obj->vertices[i].vec->z); + glVertex3f(obj->vertices[i].vec->x + (vec.x), + obj->vertices[i].vec->y + (vec.y), + obj->vertices[i].vec->z + (vec.z)); + glEnd(); + + glPopMatrix(); + } else { + fprintf(stderr, "Failed drawing the normals!\n"); + return; + } + } +} + /** * Call glVertex3f on all of the vertices of the object, * in appropriate order. @@ -99,10 +129,11 @@ static void draw_obj(int32_t const myxrot, yrot = 0, zrot = 0; vector center_vert; - float scalefactor = get_normalized_scale_factor(obj) * VISIBILITY_FACTOR; - if (!find_center(obj, ¢er_vert)) - return; /* TODO: better error handling */ + if (!find_center(obj, ¢er_vert)) { + fprintf(stderr, "Failed drawing the object!\n"); + return; + } xrot += myxrot; yrot += myyrot; @@ -112,24 +143,28 @@ static void draw_obj(int32_t const myxrot, /* rotate according to static members */ glTranslatef(0.0f, 0.0f, SYSTEM_POS_Z); - glScalef(scalefactor, - scalefactor, - scalefactor); + glScalef(VISIBILITY_FACTOR, + VISIBILITY_FACTOR, + VISIBILITY_FACTOR); glRotatef(xrot, 1.0f, 0.0f, 0.0f); glRotatef(yrot, 0.0f, 1.0f, 0.0f); glRotatef(zrot, 0.0f, 0.0f, 1.0f); glTranslatef(0.0f, 0.0f, SYSTEM_POS_Z_BACK); + /* pull into middle of universe */ glTranslatef(-center_vert.x, -center_vert.y, -center_vert.z + SYSTEM_POS_Z); + if (show_normals) + draw_normals(obj); glBegin(GL_POLYGON); glColor3f(0.0f, 1.0f, 0.0f); draw_vertices(obj); glEnd(); + glPopMatrix(); } @@ -438,6 +473,12 @@ void keyboard(unsigned char key, int x, int y) case 'd': glTranslatef(1.0f, 0.0f, 0.0f); break; + case 'n': + if (show_normals) + show_normals = false; + else + show_normals = true; + break; case '+': glTranslatef(0.0f, 0.0f, 1.0f); break; diff --git a/src/half_edge.c b/src/half_edge.c index 6a58809..b00b0e1 100644 --- a/src/half_edge.c +++ b/src/half_edge.c @@ -24,6 +24,7 @@ * @brief operations on half-edge data structs */ + #include "err.h" #include "filereader.h" #include "half_edge.h" @@ -36,15 +37,133 @@ #include +/* + * static declarations + */ +static HE_edge **get_all_emanating_edges(HE_vert const * const vert, + uint32_t *ec_out); + + /** - * Get all edges that emanate from vertice. + * Get all edges that emanate from vertice and return a pointer + * to that array with the size of ec_out. * * @param vertice the vertice to get the emanating edges of - * @return pointer to a NULL-terminated array of half-edges + * @param ec the edge counter is saved here [out] + * @return pointer to an array of half-edges, size ec_out */ -HE_edge **get_all_emanating_edges(HE_vert *vertice) +static HE_edge **get_all_emanating_edges(HE_vert const * const vert, + uint32_t *ec_out) { - return NULL; + uint32_t ec = 0, /* edge count */ + rc = 0; /* realloc count */ + uint32_t const approx_ec = 20; /* allocation chunk */ + HE_edge **edge_array = malloc(sizeof(HE_edge*) * approx_ec); + HE_edge **tmp_ptr; + + if (!vert) + return NULL; + + HE_edge *edge = vert->edge; + + /* build an array of emanating edges */ + do { + edge_array[ec] = edge; + + edge = edge->pair->next; + ec++; + + /* allocate more chunks */ + if (ec >= approx_ec) { + tmp_ptr = realloc(edge_array, sizeof(HE_edge*) + * approx_ec * (rc + 2)); + CHECK_PTR_VAL(tmp_ptr); + edge_array = tmp_ptr; + rc++; + } + + } while (edge != vert->edge); + + /* this is the real size, not the x[ec] value */ + *ec_out = ec; + + return edge_array; +} + +/** + * Calculate the approximated normal of a vertex. + * + * @param vert the vertex + * @param vec the vector to store the result in [out] + * @return true/false for success/failure + */ +bool vec_normal(HE_vert const * const vert, vector *vec) +{ + HE_edge **edge_array; + uint32_t ec, + vc = 0, + j; + vector he_base; + + if (!vert || !vec) + return false; + + /* get all emanating edges */ + if (!(edge_array = get_all_emanating_edges(vert, &ec))) + return false; + + copy_vector(edge_array[0]->vert->vec, &he_base); + + vector vec_array[ec]; + + /* iterate over all unique(!) + * tuples and calculate their product */ + for (uint32_t i = 0; i < ec; i++) { + j = (i + 1) % ec; + + /* printf("\nTUPLE %d\n", vc + 1); */ + vector he_vec1, + he_vec2, + new_vec; + + copy_vector(edge_array[i]->next->vert->vec, &he_vec1); + copy_vector(edge_array[j]->next->vert->vec, &he_vec2); + + if (!(set_null_vector(&new_vec))) + return false; + + /* calculate vector between vertices */ + sub_vectors(&he_vec1, &he_base, &he_vec1); + sub_vectors(&he_vec2, &he_base, &he_vec2); + + /* calculate vector product */ + if (!(vector_product(&he_vec2, &he_vec1, &new_vec))) + /* if (!(vector_product(&he_vec1, &he_vec2, &new_vec))) */ + return false; + + /* normalize vector */ + if (!(normalize_vector(&new_vec, &new_vec))) + return false; + + /* save into array */ + copy_vector(&new_vec, &(vec_array[vc])); + vc++; + } + + /* avoid side effects due to junk data */ + if (!(set_null_vector(vec))) + return false; + + /* now add all the vectors up */ + for (uint32_t i = 0; i < vc; i++) + if (!(add_vectors(vec, &(vec_array[i]), vec))) + return false; + + /* normalize the result */ + if (!(normalize_vector(vec, vec))) + return false; + + return true; } /** @@ -118,6 +237,24 @@ float get_normalized_scale_factor(HE_obj const * const obj) return 1 / (max - min); } +/** + * Scales down the object to the size of 1. The parameter + * is modified! + * + * @param obj the object we want to scale [mod] + */ +void normalize_object(HE_obj *obj) +{ + float scale_factor; + scale_factor = get_normalized_scale_factor(obj); + + for (uint32_t i = 0; i < obj->vc; i++) { + obj->vertices[i].vec->x = obj->vertices[i].vec->x * scale_factor; + obj->vertices[i].vec->y = obj->vertices[i].vec->y * scale_factor; + obj->vertices[i].vec->z = obj->vertices[i].vec->z * scale_factor; + } +} + /** * Parse an .obj string and return a HE_obj * that represents the whole object. @@ -219,7 +356,6 @@ HE_obj *parse_obj(char const * const obj_string) str_tmp_ptr = strtok_r(NULL, "\n", &str_ptr_newline); } - faces = (HE_face*) malloc(sizeof(HE_face) * fc); CHECK_PTR_VAL(faces); edges = (HE_edge*) malloc(sizeof(HE_edge) * ec); diff --git a/src/half_edge.h b/src/half_edge.h index 8e00c9a..47f6560 100644 --- a/src/half_edge.h +++ b/src/half_edge.h @@ -128,9 +128,10 @@ struct HE_obj { }; -HE_edge **get_all_emanating_edges(HE_vert *vertice); +bool vec_normal(HE_vert const * const vert, vector *vec); bool find_center(HE_obj const * const obj, vector *vec); float get_normalized_scale_factor(HE_obj const * const obj); +void normalize_object(HE_obj *obj); HE_obj *parse_obj(char const * const filename);