From cabc8e8c0971f743f5ed5e667c31fac5b36e9c77 Mon Sep 17 00:00:00 2001 From: hasufell Date: Sun, 1 Jun 2014 02:13:45 +0200 Subject: [PATCH] Draw bezier curve --- src/gl_draw.c | 111 +++++++++++++++++++++++++++++++++++++++--------- src/half_edge.c | 37 ++++++++++++++++ src/half_edge.h | 1 + src/vector.c | 37 ++++++++++++++++ src/vector.h | 13 ++++++ 5 files changed, 179 insertions(+), 20 deletions(-) diff --git a/src/gl_draw.c b/src/gl_draw.c index cb3a69b..ccbbb16 100644 --- a/src/gl_draw.c +++ b/src/gl_draw.c @@ -28,6 +28,7 @@ #include "filereader.h" #include "gl_draw.h" #include "half_edge.h" +#include "print.h" #include #include @@ -66,10 +67,11 @@ bool shademodel = true; /* * static function declaration */ -static void draw_bez(HE_obj const * const obj); +static void draw_bez(HE_obj const * const obj, float step_factor_inc); static void draw_obj(int32_t const myxrot, int32_t const myyrot, - int32_t const myzrot); + int32_t const myzrot, + float bez_inc); static void draw_Planet_1(void); static void draw_Planet_2(void); static void gl_destroy(void); @@ -189,11 +191,16 @@ static void draw_vertices(HE_obj const * const obj, glPopMatrix(); } -static void draw_bez(HE_obj const * const obj) +static void draw_bez(HE_obj const * const obj, float step_factor_inc) { uint32_t i = 0; static float line_width = 2; static float point_size = 10; + static float step_factor = 0.1; + + if (step_factor + step_factor_inc > 0.002 & + step_factor + step_factor_inc < 0.50) + step_factor += step_factor_inc; glPushMatrix(); @@ -201,7 +208,13 @@ static void draw_bez(HE_obj const * const obj) glPointSize(point_size); glColor3f(1.0, 0.0, 0.0); - while (i < obj->bzc) { + while (i < obj->bzc) { /* for all bezier curves */ + vector *v1 = NULL, + *v2 = NULL; + + /* + * draw frame + */ glBegin(GL_LINE_STRIP); for (uint32_t j = 0; j <= obj->bez_curves[i].deg; j++) { glVertex3f(obj->bez_curves[i].vec[j].x, @@ -209,21 +222,69 @@ static void draw_bez(HE_obj const * const obj) obj->bez_curves[i].vec[j].z); } glEnd(); - i++; - } - i = 0; - while (i < obj->bzc) { + /* + * draw control points + */ glBegin(GL_POINTS); for (uint32_t j = 0; j <= obj->bez_curves[i].deg; j++) { glVertex3f(obj->bez_curves[i].vec[j].x, obj->bez_curves[i].vec[j].y, obj->bez_curves[i].vec[j].z); } + glEnd(); + + glBegin(GL_LINES); + + /* + * line segments: first line + */ + v1 = calculate_bezier_point(&(obj->bez_curves[i]), step_factor); + glVertex3f(obj->bez_curves[i].vec[0].x, + obj->bez_curves[i].vec[0].y, + obj->bez_curves[i].vec[0].z); + glVertex3f(v1->x, + v1->y, + v1->z); + + for (float k = step_factor; k < 1 - step_factor; k += step_factor) { + free(v1); + free(v2); + + v1 = calculate_bezier_point(&(obj->bez_curves[i]), k); + v2 = calculate_bezier_point(&(obj->bez_curves[i]), k + + step_factor); + + /* + * line segments: middle lines + */ + glVertex3f(v1->x, + v1->y, + v1->z); + glVertex3f(v2->x, + v2->y, + v2->z); + + } + + /* + * line segments: last line + */ + glVertex3f(v2->x, + v2->y, + v2->z); + glVertex3f(obj->bez_curves[i].vec[obj->bez_curves[i].deg].x, + obj->bez_curves[i].vec[obj->bez_curves[i].deg].y, + obj->bez_curves[i].vec[obj->bez_curves[i].deg].z); + + free(v1); + free(v2); + glEnd(); i++; } + glPopMatrix(); } @@ -237,7 +298,8 @@ static void draw_bez(HE_obj const * const obj) */ static void draw_obj(int32_t const myxrot, int32_t const myyrot, - int32_t const myzrot) + int32_t const myzrot, + float bez_inc) { /* rotation */ static int32_t xrot = 0, @@ -279,7 +341,7 @@ static void draw_obj(int32_t const myxrot, } if (obj->bzc != 0) - draw_bez(obj); + draw_bez(obj, bez_inc); glPopMatrix(); } @@ -451,7 +513,7 @@ void display(void) glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); - draw_obj(0, 0, 0); + draw_obj(0, 0, 0, 0); draw_Planet_1(); draw_Planet_2(); @@ -616,27 +678,27 @@ void keyboard(unsigned char key, int x, int y) glutPostRedisplay(); break; case 'x': - draw_obj(2, 0, 0); + draw_obj(2, 0, 0, 0); glutPostRedisplay(); break; case 'X': - draw_obj(-2, 0, 0); + draw_obj(-2, 0, 0, 0); glutPostRedisplay(); break; case 'y': - draw_obj(0, 2, 0); + draw_obj(0, 2, 0, 0); glutPostRedisplay(); break; case 'Y': - draw_obj(0, -2, 0); + draw_obj(0, -2, 0, 0); glutPostRedisplay(); break; case 'c': - draw_obj(0, 0, 2); + draw_obj(0, 0, 2, 0); glutPostRedisplay(); break; case 'C': - draw_obj(0, 0, -2); + draw_obj(0, 0, -2, 0); glutPostRedisplay(); break; case 'D': @@ -654,13 +716,22 @@ void keyboard(unsigned char key, int x, int y) glutPostRedisplay(); break; case 'k': - draw_normals(obj, 0.01f); + draw_obj(0, 0, 0, 0.02); glutPostRedisplay(); break; - case 'l': - draw_normals(obj, -0.01f); + case 'K': + draw_obj(0, 0, 0, -0.02); glutPostRedisplay(); break; + + /* case 'k': */ + /* draw_normals(obj, 0.01f); */ + /* glutPostRedisplay(); */ + /* break; */ + /* case 'l': */ + /* draw_normals(obj, -0.01f); */ + /* glutPostRedisplay(); */ + /* break; */ case 'w': glTranslatef(0.0f, 1.0f, 0.0f); break; diff --git a/src/half_edge.c b/src/half_edge.c index 3398e66..99c90f0 100644 --- a/src/half_edge.c +++ b/src/half_edge.c @@ -285,6 +285,43 @@ bool normalize_object(HE_obj *obj) return true; } +/** + * Calculate a point on the bezier curve according to the + * bezier vertices. If section is set to 0.5 then it will + * return the vector to the point in the middle of the curve. + * + * @param obj the object holding the bezier vertices information + * @param section the section which will be applied to all + * lines between the bezier vertices + * @return the vector to the calculated point + */ +vector *calculate_bezier_point(bez_curv *bez, float section) +{ + vector vec_arr[bez->deg]; + bez_curv new_bez; + + for (uint32_t i = 0; i < bez->deg; i++) { + vector new_vec; + + SUB_VECTORS(&(bez->vec[i + 1]), &(bez->vec[i]), &new_vec); + VECTOR_LEN_SCAL_MUL(&new_vec, section, &new_vec); + ADD_VECTORS(&new_vec, &(bez->vec[i]), &new_vec); + + vec_arr[i] = new_vec; + } + + new_bez.vec = vec_arr; + new_bez.deg = bez->deg - 1; + + if (new_bez.deg > 0) { + return calculate_bezier_point(&new_bez, section); + } else { + vector *result_vector = malloc(sizeof(*result_vector)); + *result_vector = vec_arr[0]; + return result_vector; + } +} + /** * Free the inner structures of an object. * diff --git a/src/half_edge.h b/src/half_edge.h index e7aac38..5d71330 100644 --- a/src/half_edge.h +++ b/src/half_edge.h @@ -324,6 +324,7 @@ 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); bool normalize_object(HE_obj *obj); +vector *calculate_bezier_point(bez_curv *bez, float section); HE_obj *parse_obj(char const * const filename); void delete_object(HE_obj *obj); diff --git a/src/vector.c b/src/vector.c index ba8151a..cb5b17c 100644 --- a/src/vector.c +++ b/src/vector.c @@ -33,6 +33,43 @@ #include +/** + * Calculate the vector which lengths is reduced by the + * factor scal and store it in c. + * This function is aliasing safe. + * + * @param a vector + * @param scal scalar to multiply the vector with + * @param c vector [out] + * @return true/false for success/failure + */ +bool vector_len_scal_mul(vector *a, float scal, vector *c) +{ + vector a_tmp; + float vector_length; + float factor; + + if (!a || !scal || !c) + return false; + + copy_vector(a, &a_tmp); + + vector_length = sqrt((a_tmp.x * a_tmp.x) + + (a_tmp.y * a_tmp.y) + (a_tmp.z * a_tmp.z)); + + factor = vector_length * scal; + + c->x = a_tmp.x / vector_length; + c->y = a_tmp.y / vector_length; + c->z = a_tmp.z / vector_length; + + c->x = c->x * factor; + c->y = c->y * factor; + c->z = c->z * factor; + + return true; +} + /** * Calculate the vector product of a and b * and store it in c. This function is aliasing safe. diff --git a/src/vector.h b/src/vector.h index 0fe21bb..4f27e78 100644 --- a/src/vector.h +++ b/src/vector.h @@ -31,6 +31,18 @@ #include +/** + * Fault intolerant macro. Will abort the program if the called + * function failed. + */ +#define VECTOR_LEN_SCAL_MUL(...) \ +{ \ + if (!vector_len_scal_mul(__VA_ARGS__)) { \ + fprintf(stderr, "Failure in vector_product()!\n"); \ + abort(); \ + } \ +} + /** * Fault intolerant macro. Will abort the program if the called * function failed. @@ -117,6 +129,7 @@ struct vector { }; +bool vector_len_scal_mul(vector *a, float scal, vector *c); bool vector_product(vector *a, vector *b, vector *c); bool add_vectors(vector *a, vector *b, vector *c); bool sub_vectors(vector *a, vector *b, vector *c);