/* Petit programme C+OpenGL destiné à montrer les courbes Splines/Bézier. On peut contrôler chaque point de contrôle, et changer de base. Se compile simplement par cc -o splines splines.c -L/usr/X11R6/lib -lGL -lGLU -lglut -lXmu -lm */ #include #include #ifdef __APPLE__ #include #else #include #endif #include int beginx, beginy, width, height; int curveType; #define BEZIER 0 #define SPLINE 1 float beginPoint[2]; float controlPoints[7][2] = {{-0.9, -0.9}, {-0.8, -0.5}, {-0.7, 0}, {0, 0}, {0.7, 0} , {0.5, 0.8}, {0.9, 0.9}}; int indexCtrlPt = 0; float colorValues[6][3] = {{0, 0, 1}, {0, 1, 0}, {1, 0, 0}, {0, 1, 1}, {1, 1, 0}, {1, 0, 1}}; int C(int n, int k) { int i; int ret_num, ret_den; if (k > n) return C(k, n); if (k == 0) return 1; if (k == n) return 1; if (k == 1) return n; if (k == (n-1)) return n; ret_num = 1; ret_den = 1; for (i = 0; i < k; i++) { ret_num *= (n - i); ret_den *= (i + 1); } return ret_num/ret_den; } float power(float s, int i) { float tmp; switch (i) { case 0: return 1; case 1: return s; case 2: return s*s; case 3: return s*s*s; case 4: tmp = s*s; return tmp*tmp; default: return pow(s,i); } } float B(int i, int imax, float s) { return power(s, i)*power(1-s, imax-i)*C(imax, i); } float B3(int i, float t) { t += i; if (t < 0) return 0; if (t < 1) return (1.0f/6.0f)*t*t*t; if (t < 2) return -(1.0f/3.0f) + 0.5*t + 0.5*(t-1)*(t-1) - 0.5*(t-1)*(t-1)*(t-1); if (t < 3 ) return (2.0f/3.0f) - (t-2)*(t-2)+0.5*(t-2)*(t-2)*(t-2); if (t < 4) return (5.0f)/(3.0f) - 0.5*t + 0.5*(t-3)*(t-3) - (1.0f)/(6.0f)*(t-3)*(t-3)*(t-3); return 0.0; } void drawSpline(float CP[4][2]) { int i; float t, coeff; float point[2]; float oldPoint[2]; oldPoint[0] = CP[0][0]; oldPoint[1] = CP[0][1]; for (t = 0; t <= 1.01; t+= 0.01) { point[0] = 0; point[1] = 0; for (i = 0; i <= 3; i++) { coeff = B3(i, t); point[0] += CP[i][0] * coeff; point[1] += CP[i][1] * coeff; } if (t != 0.0) { glBegin(GL_LINES); glVertex2fv(oldPoint); glVertex2fv(point); glEnd(); } oldPoint[0] = point[0]; oldPoint[1] = point[1]; } } void drawBezier(float CP[4][2]) { int i; float t, coeff; float point[2]; float oldPoint[2]; oldPoint[0] = CP[0][0]; oldPoint[1] = CP[0][1]; for (t = 0; t <= 1.05; t+= 0.05) { point[0] = 0; point[1] = 0; for (i = 0; i <= 3; i++) { coeff = B(i, 3, t); point[0] += CP[i][0] * coeff; point[1] += CP[i][1] * coeff; } glBegin(GL_LINES); glVertex2fv(oldPoint); glVertex2fv(point); glEnd(); oldPoint[0] = point[0]; oldPoint[1] = point[1]; } } void drawObject() { int i; glPointSize(8.0); glColor3f(1.0, 0.0, 0.0); glBegin(GL_POINTS); for (i = 0; i < 7; i++) { if (i == indexCtrlPt) glColor3f(1.0, 1.0, 0.0); else glColor3f(1.0, 0.0, 0.0); glVertex2fv(controlPoints[i]); } glEnd(); glColor3f(1.0, 1.0, 1.0); glLineWidth(1.0); glLineStipple(1, 0xff); glBegin(GL_LINES); for (i = 0; i < 6; i++) { glVertex2fv(controlPoints[i]); glVertex2fv(controlPoints[i+1]); } glEnd(); glLineStipple(1, 0xffff); glLineWidth(3.0); switch (curveType) { case BEZIER: glColor3fv(colorValues[0]); drawBezier(controlPoints); glColor3fv(colorValues[1]); drawBezier(controlPoints+3); break; case SPLINE: for (i = 0; i < 4; i++) { glColor3fv(colorValues[i]); drawSpline(controlPoints+i); } break; } } void mouse(int button, int state, int x, int y) { if (state == GLUT_DOWN) { beginx = x; beginy = y; beginPoint[0] = controlPoints[indexCtrlPt][0]; beginPoint[1] = controlPoints[indexCtrlPt][1]; } glutPostRedisplay(); } void motion(int x, int y) { int i; controlPoints[indexCtrlPt][0] = beginPoint[0] + 2*(x - beginx)/(float)width; controlPoints[indexCtrlPt][1] = beginPoint[1] - 2*(y - beginy)/(float) height; for (i = 0; i < 2; i++) { if (controlPoints[indexCtrlPt][i] > 1.0) controlPoints[indexCtrlPt][i] = 1.0; if (controlPoints[indexCtrlPt][i] < -1.0) controlPoints[indexCtrlPt][i] = -1.0; } glutPostRedisplay(); } void printHelp() { printf("A small program to show B-splines and Bezier curves\n\n"); } void parsekey(unsigned char key, int x, int y) { switch (key) { case 27: exit(0); case ' ': break; case 'b': curveType = !curveType; glutPostRedisplay(); default: return; } glutPostRedisplay(); } void parsekey_special(int key, int x, int y) { switch (key) { case GLUT_KEY_UP: indexCtrlPt++; if (indexCtrlPt > 6) indexCtrlPt = 0; break; case GLUT_KEY_DOWN: indexCtrlPt--; if (indexCtrlPt < 0) indexCtrlPt = 6; break; case GLUT_KEY_RIGHT: indexCtrlPt++; if (indexCtrlPt > 6) indexCtrlPt = 0; break; case GLUT_KEY_LEFT: indexCtrlPt--; if (indexCtrlPt < 0) indexCtrlPt = 6; break; default: return; } glutPostRedisplay(); } void myReshape(int w, int h) { int xmin, ymin; xmin = 0; ymin = 0; if (w > h) { xmin = (w-h)/2; w = h; } else { ymin = (h-w)/2; h = w; } width = w; height = h; glViewport(xmin, ymin, w, h); glutPostRedisplay(); } void display(void) { glPushMatrix(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); drawObject(); glutSwapBuffers(); glPopMatrix(); } void myinit(void) { glLoadIdentity(); glClearColor(0.0, 0.0, 0.6, 1.0); glEnable(GL_LINE_STIPPLE); } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_RGB | GLUT_DOUBLE | GLUT_MULTISAMPLE | GLUT_STENCIL); glutCreateWindow("B-Splines and Bezier"); glutDisplayFunc(display); glutInitWindowSize(1200, 1200); glutInitWindowPosition(200, 0); glutMouseFunc(mouse); glutMotionFunc(motion); glutKeyboardFunc(parsekey); glutSpecialFunc(parsekey_special); glutReshapeFunc(myReshape); printHelp(); glutSwapBuffers(); glutMainLoop(); return 0; }