Code:
//------------------------------------------------------------
/// \file Main.cpp
/// \author Rob Bateman
/// \date 9-feb-2005
/// \brief This is a very simple example of a bezier patch
//------------------------------------------------------------
#include <stdlib.h>
#include <GL/glut.h>
#include <math.h>
#include <stdio.h>
struct Point {
float x;
float y;
float z;
};
/// 4x4 grid of points.
Point Points[4][4] = {
{
{ 10,0,10 },
{ 5,0,10 },
{ -5,0,10 },
{-10,0,10 }
},
{
{ 10,0,5 },
{ 5,6,5 },
{ -5,6,5 },
{-10,0,5 }
},
{
{ 10,0,-5 },
{ 5,6,-5 },
{ -5,6,-5 },
{-10,0,-5 }
},
{
{ 10,0,-10 },
{ 5,0,-10 },
{ -5,0,-10 },
{-10,0,-10 }
}
};
unsigned int num_knots_u=8;
unsigned int num_knots_v=8;
unsigned int num_cvs_u=4;
unsigned int num_cvs_v=4;
unsigned int degree_u=3;
unsigned int degree_v=3;
unsigned int order_u=degree_u+1;
unsigned int order_v=degree_v+1;
float knots_u[] = {0,0,0,0,1,1,1,1};
float knots_v[] = {0,0,0,0,1,1,1,1};
unsigned int LOD=20;
float MinU() {
return knots_u[degree_u];
}
float MinV() {
return knots_v[degree_v];
}
float MaxU() {
return knots_v[num_knots_u-degree_u];
}
float MaxV() {
return knots_v[num_knots_v-degree_v];
}
//------------------------------------------------------------ CoxDeBoor()
//
float CoxDeBoor(float u,int i,int k,const float* Knots) {
if(k==1)
{
if( Knots[i] <= u && u <= Knots[i+1] ) {
return 1.0f;
}
return 0.0f;
}
float Den1 = Knots[i+k-1] - Knots[i];
float Den2 = Knots[i+k] - Knots[i+1];
float Eq1=0,Eq2=0;
if(Den1>0) {
Eq1 = ((u-Knots[i]) / Den1) * CoxDeBoor(u,i,k-1,Knots);
}
if(Den2>0) {
Eq2 = (Knots[i+k]-u) / Den2 * CoxDeBoor(u,i+1,k-1,Knots);
}
return Eq1+Eq2;
}
//------------------------------------------------------------ CalculateU()
//
Point CalculateU(float t,int row) {
Point p = {0,0,0};
// sum the effect of all CV's on the curve at this point to
// get the evaluated curve point
//
for(unsigned int i=0;i!=num_cvs_u;++i) {
// calculate the effect of this point on the curve
float Val = CoxDeBoor(t,i,order_u,knots_u);
if(Val>0.001f) {
// sum effect of CV on this part of the curve
p.x += Val * Points[row][i].x;
p.y += Val * Points[row][i].y;
p.z += Val * Points[row][i].z;
}
}
return p;
}
//------------------------------------------------------------ CalculateV()
//
Point CalculateV(float t,Point* pnts) {
Point p = {0,0,0};
// sum the effect of all CV's on the curve at this point to
// get the evaluated curve point
//
for(unsigned int i=0;i!=num_cvs_v;++i) {
// calculate the effect of this point on the curve
float Val = CoxDeBoor(t,i,order_v,knots_v);
if(Val>0.001f) {
// sum effect of CV on this part of the curve
p.x += Val * pnts[i].x;
p.y += Val * pnts[i].y;
p.z += Val * pnts[i].z;
}
}
return p;
}
//------------------------------------------------------------ Calculate()
//
Point Calculate(float u,float v) {
Point* temp = new Point[num_cvs_v];
for(unsigned int i=0;i!=num_cvs_v;++i) {
// first treat the surface as a set of 4 curves. Calculate
// a point on each of the curves and store the result.
//
temp[i] = CalculateU(u,i);
}
// having got 4 points, we can use it as a bezier curve
// to calculate the v direction
//
Point p = CalculateV(v,temp);
delete [] temp;
return p;
}
//------------------------------------------------------------ OnReshape()
//
void OnReshape(int w, int h)
{
if (h==0) {
h=1;
}
// set the drawable region of the window
glViewport(0,0,w,h);
// set up the projection matrix
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// just use a perspective projection
gluPerspective(45,(float)w/h,0.1,100);
// go back to modelview matrix so we can move the objects about
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
//------------------------------------------------------------ Draw()
//
float x = 5;
float alpha = 0;
float y = 16;
float z = 20 ;
float xLookAt = x;
float yLookAt = y;
float zLookAt = z;
void OnDraw() {
// clear the screen & depth buffer
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
// clear the previous transform
glLoadIdentity();
// set the camera position
gluLookAt( xLookAt,yLookAt,zLookAt, // eye pos
0,0,0, // aim point
0,1,0); // up direction
glColor3f(1,0,1);
glPointSize(2);
glBegin(GL_POINTS);
// use the parametric time value 0 to 1
for(int i=0;i!=LOD;++i) {
// calculate the parametric u value
float u = (MaxU()-MinU())*(float)i/(LOD-1) + MinU();
for(int j=0;j!=LOD;++j) {
// calculate the parametric v value
float v = (MaxV()-MinV())*(float)j/(LOD-1) + MinV();
// calculate the point on the surface
Point p = Calculate(u,v);
// draw point
glVertex3f(p.x,p.y,p.z);
}
}
glEnd();
// currently we've been drawing to the back buffer, we need
// to swap the back buffer with the front one to make the image visible
glutSwapBuffers();
}
//------------------------------------------------------------ OnInit()
//
void OnInit() {
// enable depth testing
glEnable(GL_DEPTH_TEST);
}
//------------------------------------------------------------ OnExit()
//
void OnExit() {
}
//------------------------------------------------------------ OnKeyPress()
//
void OnKeyPress(unsigned char key,int,int) {
switch(key) {
// increase the LOD
case '+':
++LOD;
break;
// decrease the LOD
case '-':
--LOD;
// have a minimum LOD value
if (LOD<3)
LOD=3;
break;
case 'a':
// glPop
break;
case 'b':
if ((x < -6.28) || (x > 6.28))
{
x=0;
xLookAt = 0;
break;
}
x -= 0.1;
xLookAt = cos(x) * sin (z);
break;
default:
break;
}
// ask glut to redraw the screen for us...
//x = cos(y) * sin(z);
glutPostRedisplay();
}
//------------------------------------------------------------ main()
//
int main(int argc,char** argv) {
// initialise glut
glutInit(&argc,argv);
// request a depth buffer, RGBA display mode, and we want double buffering
glutInitDisplayMode(GLUT_DEPTH|GLUT_RGBA|GLUT_DOUBLE);
// set the initial window size
glutInitWindowSize(640,480);
// create the window
glutCreateWindow("Bezier Curve: +/- to Change Level of Detail");
// set the function to use to draw our scene
glutDisplayFunc(OnDraw);
// set the function to handle changes in screen size
glutReshapeFunc(OnReshape);
// set the function for the key presses
glutKeyboardFunc(OnKeyPress);
// run our custom initialisation
OnInit();
// set the function to be called when we exit
atexit(OnExit);
// this function runs a while loop to keep the program running.
glutMainLoop();
return 0;
}