And for those who really want to help, but the code gives is not enough, here’s the full source code of my mini project
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>
#define MAX_CTRL_POINTS 50 /* Maximum control points for b-spline curve /
#define WIN_WIDTH 640 / Dimentions of Opengl window /
#define WIN_HEIGHT 480
#define CURVE_STEP 0.005 / This represents the resolution of the b-spline on screen. The smaller the value, the smoother the curve */
/* Helper macros /
#define PI (3.14159265359f)
#define DEG2RAD(a) (PI/180(a))
#define RAD2DEG(a) (180/PI*(a))
/********************************************************************/
/ Structure to hold 3d point /
/********************************************************************/
typedef struct {
float x, y, z;
} Point3d;
/********************************************************************/
/ Structure to hold a triangle /
/*******************************************************************/
typedef struct {
/ 3 points that make up the triangle /
/ POINTS MUST BE IN COUNTER CLOCKWISE ORDER !!! /
Point3d p1;
Point3d p2;
Point3d p3;
/ Triangle normal - represented as point, but is really a 3d vector, which is normalized */
Point3d normal;
} Triangle;
/********************************************************************/
/ Structure defining a 3x3 matrix /
/********************************************************************/
typedef struct {
float n00, n01, n02;
float n10, n11, n12;
float n20, n21, n22;
} Matrix3x3;
/********************************************************************/
/ GLOBAL VARIABLES /
/********************************************************************/
int numOfCtrlPoints = 0;
Point3d ctrlPoints [MAX_CTRL_POINTS];
Point3d rotatedCtrlPoints[MAX_CTRL_POINTS];
Point3d newPoint;
float max_t; /* holds the maximum t value from the knot vector /
int order = 4; / Holds the order of the spline */
/* function prototypes */
void drawPoints ();
void drawBspline (float tInit, float tEnd, float stepInT, Point3d ctrls[], int numOfCtrls);
Point3d triangleNormal(Triangle tri);
void rotatePointsOnY ( float degY, Point3d origPts[], Point3d rotatedPts[], int numOfPoints);
/*********************************************************************/
void glInit(void) {
/****** FOR PROGRAM 2 ******/
/* Setup for the lights: */
float ambientLight[] = { 0.5f, 0.5f, 0.5f, 1.0f}; /* Redish ambient light */
float diffuseLight[] = { 0.7f, 0.7f, 0.7f, 1.0f};
/* Position is the same as the camera position */
float lightPosition[] = { 0.0f, 0.0f, 5.0f, 0.0f};
/* Setup materials*/
float matAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
float matDiff[] = { 0.8f, 0.6f, 0.8f, 1.0f };
/****** END FOR PROGRAM 2 ****/
glClearColor (0.0, 0.0, 0.0, 0.0);
glShadeModel(GL_SMOOTH);
glPointSize(5.0f);
/****** FOR PROGRAM 2 ******/
/* Turn on z-buffer */
glEnable(GL_DEPTH_TEST);
/* Turn on the backface culling */
glEnable(GL_CULL_FACE);
/* COUTERCLOCKWISE polygons and triangle faces are kept */
glFrontFace(GL_CCW);
glEnable(GL_LIGHTING);
glMaterialfv(GL_FRONT, GL_AMBIENT, matAmbient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, matDiff);
/* Setup LIGHT0 */
glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight);
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
/* Enable the light */
glEnable(GL_LIGHT0);
/* Turn on auto normalization of normal vectors for Opengl */
glEnable(GL_NORMALIZE);
/****** END FOR PROGRAM 2 ****/
printf("
Welcome to this amazing b-spline drawing program!
");
printf("It currently allows for up to 50 control points.
");
printf("Pressing ‘2’, ‘3’, ‘4’, or ‘5’ on keyboard
“);
printf(” will make the spline change to that order.
“);
printf(” The default order is 4, making the spline cubic.
");
printf("Notice that spline of order 5 will need at least 5 control points to be visible
");
printf("To make a curve sharp at a certain point (to interpolate through that point
“);
printf(” click a few times on that point. The more you click it,the sharper it gets!
");
printf("Pressing ‘d’ on the keyboard while drawing the curve
“);
printf(” will delete the last point of curve.
");
printf("Pressing ‘q’ will quit the program.
");
}
/*********************************************************************/
void display(void) {
Triangle tri;
/*Clear the screen */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glLoadIdentity();
gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
/* These are for testing only */
glutWireCube(3.0);
/***************************** Testing code for triangles ************************/
tri.p1.x = -5.0;
tri.p1.y = 5.0;
tri.p1.z = -50.0;
tri.p2.x = -5.0;
tri.p2.y = -5.0;
tri.p2.z = -50.0;
tri.p3.x = 5.0;
tri.p3.y = -5.0;
tri.p3.z = -40.0;
tri.normal = triangleNormal( tri);
glBegin(GL_TRIANGLES);
glNormal3f(tri.normal.x, tri.normal.y, tri.normal.z);
glVertex3f(tri.p1.x, tri.p1.y, tri.p1.z);
glVertex3f(tri.p2.x, tri.p2.y, tri.p2.z);
glVertex3f(tri.p3.x, tri.p3.y, tri.p3.z);
glEnd();
/********************* End of Testing code for triangles ************************/
/*Draw points in red, spline in blue */
glColor3f(1.0, 0.0, 0.0);
drawPoints();
glColor3f(0.0, 0.0, 1.0);
drawBspline ( 0.0, max_t, CURVE_STEP, ctrlPoints, numOfCtrlPoints);
/********************** Test code for rotation on curve **************************/
rotatePointsOnY ( 100.0, ctrlPoints, rotatedCtrlPoints, numOfCtrlPoints);
drawBspline ( 0.0, max_t, CURVE_STEP, rotatedCtrlPoints, numOfCtrlPoints);
/************** End of Test code for rotation on curve **************************/
glFlush();
glutSwapBuffers();
glutPostRedisplay();
}
/********************************************************************/
/ callback function to handle keyboard input /
/********************************************************************/
void keyboard(unsigned char key, int x, int y) {
/* Quit on any key */
switch (key) {
case 'q':
exit(0);
case '2':
order = 2;
break;
case '3':
order = 3;
break;
case '4':
order = 4;
break;
case '5':
order = 5;
break;
case 'd':
if (numOfCtrlPoints > order)
numOfCtrlPoints -= 1;
else
printf("
Can’t delete a point where number of control points < order of curve!
");
break;
default:
break;
}
}
/********************************************************************/
/ Callback function to handle the mouse /
/********************************************************************/
void mouse (int button, int state, int x, int y) {
GLint viewport [4]; /*holds the viewport data*/
GLdouble mvmatrix[16], projmatrix[16];
GLint real_y; /*OpenGL y coordinate position */
GLdouble wx, wy, wz; /* returned world x, y, z coords */
switch (button) {
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN) {
glGetIntegerv (GL_VIEWPORT, viewport);
glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix);
glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);
/*viewport [3] is height of window in pixels */
/* bottom left of viewport is 0.0, top right is width-1, height -1 */
real_y = viewport[3] - (GLint) y -1;
/*printf ("Coordinates at cursor are (%4d, %4d)
", x, real_y);*/
/* assume world z coordinate is z = 1.0 */
gluUnProject ((GLdouble) x, (GLdouble) real_y, 1.0, mvmatrix, projmatrix, viewport, &wx, &wy, &wz);
/*printf ("world coords at z=1.0 are (%f, %f, %f)
", wx, wy, wz);*/
/* check to see if not max number of control points */
if (numOfCtrlPoints < MAX_CTRL_POINTS ) {
numOfCtrlPoints++;
/* write to newPoint */
newPoint.x = wx;
newPoint.y = wy;
newPoint.z = wz;
/* add to array of control points */
ctrlPoints[numOfCtrlPoints-1] = newPoint;
}
else
printf ("
MAXIMUM NUMBER OF CONTROL POINTS (%d) REACHED !
", MAX_CTRL_POINTS);
}
break;
default:
break;
}
}
/********************************************************************/
/ Callback function to change the Viewport on resizing the screen /
/********************************************************************/
void reshape ( int w, int h) {
glViewport (0,0, (GLsizei)w, (GLsizei)h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (GLfloat) w / (GLfloat) h, 1.0, 100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
/********************************************************************/
/ draw points /
/********************************************************************/
void drawPoints () {
int i;
glBegin (GL_POINTS);
for (i = 0; i < numOfCtrlPoints; i++) {
glVertex3f(ctrlPoints[i].x, ctrlPoints[i].y, ctrlPoints[i].z);
}
glEnd();
}
/********************************************************************/
/ Generates standard knot vector for given values of m and L /
/ Source of code: ‘Computer graphics using Opengl’ by F.S.Hill /
/*******************************************************************/
void buildKnots (int m, int L, float knotV []) {
/ Builds the standard knot vector for L + 1 control points
and b-spline of order m /
int i;
/ For a given m, there must be a sufficient number of control point /
if (L < (m - 1)) return; / Too few control points */
for ( i = 0; i <= L + m; i++ ) {
if (i < m) knotV[i] = 0.0;
else if (i <= L)
knotV[i] = i - m + 1; /i is at least m /
else knotV[i] = L - m + 2; / i exceeds L /
}
/ set the gloabal variable holding maximum value of t in knot vector/
max_t = knotV[L+m];
}
/********************************************************************/
/ Function to calculate recursive formulation of Nk,m(t) /
/ Source of code: ‘Computer graphics using Opengl’ by F.S.Hill /
/********************************************************************/
float bSpline (int k, int m, float t, float knotV []) {
float denom1, denom2, sum = 0.0;
if (m == 1)
return (t >= knotV[k] && t < knotV[k+1]); /* return 1 or 0 */
/* if m exceeds 1, use recursion */
denom1 = knotV[k+m-1] - knotV[k];
if (denom1 != 0.0)
sum = (t - knotV[k]) * bSpline (k, m-1, t, knotV) / denom1;
denom2 = knotV[k+m] - knotV[k+1];
if (denom2 != 0.0)
sum += (knotV[k+m] - t) * bSpline(k+1, m-1, t, knotV) / denom2;
return sum;
}
/********************************************************************/
/ Calculates a 3d point given t and array of control points /
/********************************************************************/
Point3d pointOnBspline (float t, Point3d ctrls[], int numOfCtrls) {
Point3d calculatedPoint;
int k;
float bsplineVal;
float knots[MAX_CTRL_POINTS+10];
buildKnots (order, numOfCtrls-1,knots);
calculatedPoint.x = 0.0;
calculatedPoint.y = 0.0;
for (k = 0; k < numOfCtrls; k++ ) {
bsplineVal = bSpline(k, order, t, knots);
calculatedPoint.x += ctrls[k].x * bsplineVal;
calculatedPoint.y += ctrls[k].y * bsplineVal;
}
calculatedPoint.z = ctrls[0].z; /* Should be able to get any value of z points. Assuming they will all line up on z axis */
return calculatedPoint;
}
//
/ Draw a bSpline curve, given range of t, step - resolution, and control points /
//
void drawBspline (float tInit, float tEnd, float stepInT, Point3d ctrls[], int numOfCtrls) {
Point3d tempPoint;
glBegin(GL_LINE_STRIP);
while (tInit <= tEnd) {
tempPoint = pointOnBspline(tInit, ctrls, numOfCtrls);
glVertex3f(tempPoint.x, tempPoint.y, tempPoint.z);
tInit += stepInT;
}
glEnd();
}
/********************************************************************************************/
/ Take cross product of 2 vectors - in this example Point 3d structur is treated as vector /
/********************************************************************************************/
Point3d crossProd (Point3d a, Point3d b) {
Point3d crossPVec;
crossPVec.x = a.y*b.z - a.z*b.y;
crossPVec.y = a.z*b.x - a.x*b.z;
crossPVec.z = a.x*b.y - a.y*b.x;
/* Note, normally this would have to be normalized, but we will use the GL_NORMALIZE to do it for us */
return crossPVec;
}
//
/* Calculate normal of a triangle */
//
Point3d triangleNormal(Triangle tri) {
Point3d vector1, vector2, normal;
/* Calculate the two vector that we need to calculate the cross product */
vector1.x = tri.p1.x - tri.p2.x;
vector1.y = tri.p1.y - tri.p2.y;
vector1.z = tri.p1.z - tri.p2.z;
vector2.x = tri.p2.x - tri.p3.x;
vector2.y = tri.p2.y - tri.p3.y;
vector2.z = tri.p2.z - tri.p3.z;
normal = crossProd(vector1, vector2);
return normal;
}
//
/ Multiply a point by a matrix /
//
Point3d multPointByMatrix (Point3d p, Matrix3x3 mat) {
float tempZ;
Point3d rp;
/* Get the z value of point */
//tempZ = p.z;
//p.z = 0.0;
rp.x = p.x * mat.n00 + p.y * mat.n01 + p.z * mat.n02;
rp.y = p.x * mat.n10 + p.y * mat.n11 + p.z * mat.n12;
rp.z = p.x * mat.n20 + p.y * mat.n21 + p.z * mat.n22;
/* Add the original z back to the new one */
//p.z += tempZ;
return rp;
}
/*****************************************************************************************/
/ Rotate a set of points around y axis, given the rotation in degrees /
/*****************************************************************************************/
void rotatePointsOnY ( float degRotY, Point3d origPts[], Point3d rotatedPts[], int numOfPoints) {
int i;
/* Build rotation matrix */
Matrix3x3 mat;
/* Convert degrees to radians */
/* degY = DEG2RAD(degRotY); */
mat.n00 = cos(degRotY);
mat.n01 = 0.0;
mat.n02 = sin(degRotY);
mat.n10 = 0.0;
mat.n11 = 1.0;
mat.n12 = 0.0;
mat.n20 = -sin(degRotY);
mat.n21 = 0.0;
mat.n22 = cos(degRotY);
//mat.n00 = cos(degRotY);
//mat.n01 = 0.0;
//mat.n02 = -sin(degRotY);
//mat.n10 = 0.0;
//mat.n11 = 1.0;
//mat.n12 = 0.0;
//mat.n20 = sin(degRotY);
//mat.n21 = 0.0;
//mat.n22 = cos(degRotY);
for (i = 0; i < numOfPoints; i++) {
rotatedPts[i] = multPointByMatrix (origPts[i], mat);
}
}
/*******************************************************************/
int main(int argc, char argv) {
/* Standard glut application framework */
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize (WIN_WIDTH, WIN_HEIGHT);
glutInitWindowPosition (100, 100);
glutCreateWindow(“CS 388 Assignment#3 by Luke Piasecki and Grzesiek Stozek”);
glInit();
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutKeyboardFunc(keyboard);
glutMouseFunc(mouse);
glutMainLoop();
return 0;
}
/*********************************************************************/
/*********************************************************************/