Drawing N-Pointed Star in OpenGL - C++ - c++

I've written a code that inputs n and draws N-pointed star,
just like this one:
when n=5 and filed
the problem that is whenever n=7 or 8 or 16 or 25...
I get a problem in the star drawing it becomes like this :
when n=7 and filled
Here's my code:
#include <iostream>
#include <ctime>
#include <vector>
#include <glut.h>
using namespace std;
float starCenterX, starCenterY, starRadius;
int numPoints;
bool bDrawFill = false;
void DrawStar (float cx, float cy, float radius, int numPoints);
void DrawStarFilled (float cx, float cy, float radius, int numPoints);
float width, height; // global variables to store window width and height
// render text
void renderBitmapString (float x, float y, float z, void* font, const char* string)
{
const char *c;
glRasterPos3f (x, y,z);
for (c = string; *c != '\0'; c++)
glutBitmapCharacter (font, *c);
}
void init ()
{
glClearColor (1.0, 1.0, 1.0, 0.0); // set display-window color to white
}
void reshape (int width, int height)
{
::width = width;
::height = height;
glViewport (0, 0, width, height);
glMatrixMode (GL_PROJECTION); // set projection parameters
glLoadIdentity ();
gluOrtho2D (0.0, width, 0.0, height);
glMatrixMode (GL_MODELVIEW); // set projection parameters
glLoadIdentity ();
}
void display ()
{
glClear (GL_COLOR_BUFFER_BIT); // clear display window
glColor3f (0, 0, 1);
renderBitmapString (10, height - 20, 0, GLUT_BITMAP_TIMES_ROMAN_24, "Name : Saif Badran");
renderBitmapString (10, height - 50, 0, GLUT_BITMAP_TIMES_ROMAN_24, "ID : 0142852");
renderBitmapString (10, height - 80, 0, GLUT_BITMAP_TIMES_ROMAN_24, "Section : 2");
DrawStar(starCenterX,starCenterY,starRadius,numPoints);
if(bDrawFill)
DrawStarFilled(starCenterX,starCenterY,starRadius,numPoints);
glFlush (); // process all openGl routines as quickly as possible
}
void processNormalKeys (unsigned char key, int x, int y)
{
if(key=='w' || key=='W')
starCenterY+=4;
else if(key=='z' || key=='Z')
starCenterY-=4;
else if(key=='a' || key=='A')
starCenterX-=4;
else if(key=='d' || key=='D')
starCenterX+=4;
else if(key=='f' || key=='F')
bDrawFill = (bDrawFill==1?0:1);
}
void mouseClick (int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
starCenterX = x;
starCenterY = height - y;
}
}
void activeMouseMotion (int x, int y)
{
starRadius = abs(starCenterX-x);
}
void main (int argc, char** argv)
{
cout<<"Enter number of points : ";
cin>>numPoints;
numPoints = (numPoints < 2) ? 2 : numPoints;
glutInit (&argc, argv); // initialize GLUT
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); // set display mode
glutInitWindowPosition (20, 20); // set top left display window position
glutInitWindowSize (600, 600); // set display window width and height
glutCreateWindow ("Homework#2 : Star Drawing"); // create display window
init (); // execute initialization function
glutKeyboardFunc (processNormalKeys);
glutMouseFunc (mouseClick);
glutMotionFunc (activeMouseMotion);
glutReshapeFunc (reshape);
glutDisplayFunc (display); // send graphics to display window
glutIdleFunc (display);
glutMainLoop (); // dispaly everthing and wait
}
void DrawStar (float cx, float cy, float radius, int numPoints)
{
const float DegToRad = 3.14159 / 180;
glColor3f(1.0,0.0,0.0);
glBegin (GL_POINTS);
int count = 1;
for (int i = 0; i <= 360; i+=360/(numPoints*2)) {
float DegInRad = i * DegToRad;
if(count%2!=0)
glVertex2d (cx + cos (DegInRad) * radius, cy + sin (DegInRad) * radius);
else
glVertex2d ((cx + cos (DegInRad) * radius/2), (cy + sin (DegInRad) * radius/2));
count++;
}
glEnd();
glBegin (GL_LINE_LOOP);
count = 1;
for (int i = 0; i <= 360; i+=360/(numPoints*2)) {
float DegInRad = i * DegToRad;
if(count%2!=0)
glVertex2d (cx + cos (DegInRad) * radius, cy + sin (DegInRad) * radius);
else
glVertex2d ((cx + cos (DegInRad) * radius/2), (cy + sin (DegInRad) * radius/2));
count++;
}
glEnd();
}
void DrawStarFilled (float cx, float cy, float radius, int numPoints)
{
const float DegToRad = 3.14159 / 180;
glBegin (GL_TRIANGLE_FAN);
int count = 1;
glVertex2f(starCenterX, starCenterY);
for (int i = 0; i <= 360; i+=360/(numPoints*2)) {
float DegInRad = i * DegToRad;
if(count%2!=0)
glVertex2d (cx + cos (DegInRad) * radius, cy + sin (DegInRad) * radius);
else
glVertex2d ((cx + cos (DegInRad) * radius/2), (cy + sin (DegInRad) * radius/2));
count++;
}
glEnd();
}

The issue is in this line:
for (int i = 0; i <= 360; i+=360/(numPoints*2)) {
For numPoints = 5, for each step i will be incremented with 360/(2*5) = 36.
For numPoints = 7, for each step i will be incremented with 360/(2*7) = 25 (integer division, truncating 25.714... to 25). So, at each step there is a 0.714.. degrees loss. Cummulated, this is: 360 - 14 * 25 = 10 degrees. This can be seen on the output picture.
To solve this we can use a floating point variable for the step counter, and to increment it with a floating point value obtained from a floating point division, using for example 360.0 as the numerator. (Actually 360.0 is stored as a double, to store it as a single precision float it should be 360.0f).
for (float i = 0; i <= 360; i+=360.0/(numPoints*2)) {
But doing so, we may have trouble at the i <= 360 comparison, there are quantization errors resulting from floating point operations (i could be slightly smaller or bigger than the "mathematical" value). So it would be better to keep the integer counter for the loop, and do the floating point operations afterwards. This code part:
for (int i = 0; i <= 360; i+=360/(numPoints*2)) {
float DegInRad = i * DegToRad;
would then be changed to:
for (int i = 0; i <= numPoints*2; i++) {
float DegInRad = i * 360.0/(numPoints*2) * DegToRad;

Related

How to clear my BezierCurve vector to stop writing coordinates on top of each other?

I have built a Bezier Curve tool and each time the coordinates for each curve segment are calculated they are stored in a vector. Every single frame I am adding the entire curve's points on it over and over again. That is, frame 1, might have { p1, p2, p3 } then frame 2, it would have { p1, p2, p3, p1, p2, p3 } and so on. This would cause the line to loop back on itself when the loop at the end of the render function draws lines between the points p3 and p1. I am struggling to find where and how I should clear my BezierCurve vector between frames. Clearing after glClear() or before glSwapBuffers() only shows the previously drawn curve segment and has a straight line between points.
I basically want the straight line in between points to go away and I know why it is happening. My code is below:
#include <iostream>
#include <stdlib.h>
#include <GL/glut.h>
#include <vector>
#include <math.h>
using namespace std;
//Point class for taking the points
class Point {
public:
float x, y;
void setxy(float x2, float y2)
{
x = x2; y = y2;
}
//operator overloading for '=' sign
const Point& operator=(const Point& rPoint)
{
x = rPoint.x;
y = rPoint.y;
return *this;
}
};
int SCREEN_HEIGHT = 500;
vector<Point> Points;
Point Tangent;
Point inverseTangent;
Point cursorLocationLive;
int TangentsSize = 0;
vector<Point> Tangents(TangentsSize);
vector<Point> inverseTangents(TangentsSize);
vector<Point> BezierCurve;
bool MouseReleased = false;
void drawDot(Point p1)
{
glBegin(GL_POINTS);
glVertex2i(p1.x, p1.y);
glEnd();
}
void drawLine(Point p1, Point p2)
{
glBegin(GL_LINE_STRIP);
glVertex2f(p1.x, p1.y);
glVertex2f(p2.x, p2.y);
glEnd();
}
float interpolate(float n1, float n2, float perc)
{
float diff = n2 - n1;
return n1 + (diff * perc);
}
void myMouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON)
{
if (state == GLUT_DOWN)
{
MouseReleased = false;
// Store points into Points vector on click
Point point;
point.setxy(x, SCREEN_HEIGHT - y);
Points.push_back(point);
// Tangents are set to the cursor position
Tangent.setxy(x, SCREEN_HEIGHT - y);
inverseTangent.x = (2 * Points[Points.size() - 1].x) - Tangent.x;
inverseTangent.y = (2 * Points[Points.size() - 1].y) - Tangent.y;
/*Add new element to Tangent & inverseTangent so when we draw the curve
the tangents are accessed at the right index*/
TangentsSize++;
}
else if (state == GLUT_UP)
{
MouseReleased = true;
// Upon mouse release store tangent and inverse tangent into separate vectors
Tangents.push_back(Tangent);
inverseTangents.push_back(inverseTangent);
}
}
}
void passiveMotion(int x, int y)
{
// Sets the location of cursor while moving with no buttons pressed
cursorLocationLive.setxy(x, SCREEN_HEIGHT - y);
}
void motion(int x, int y)
{
// Sets the coordinates of the tangents when mouse moves with a button held down
Tangent.setxy(x, SCREEN_HEIGHT - y);
inverseTangent.x = (2 * Points[Points.size() - 1].x) - Tangent.x;
inverseTangent.y = (2 * Points[Points.size() - 1].y) - Tangent.y;
}
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
// Draw main points in red
glColor3f(255, 0, 0);
for (int i = 0; i < Points.size(); i++)
{
drawDot(Points[i]);
}
// If there is a starting point draw a line to cursor from last drawn point in passive motion
if (Points.size() > 0)
{
glColor3f(0, 0, 0);
drawLine(Points[Points.size() - 1], cursorLocationLive);
}
// Draw live tangent dots in green
glColor3f(0, 255, 0);
drawDot(Tangent);
drawDot(inverseTangent);
// Draw live tangent lines in blue
glColor3f(0, 0, 255);
drawLine(Tangent, inverseTangent);
for (int i = 0; i < Tangents.size(); i++)
{
// Draw stored tangent dots in green
glColor3f(0, 255, 0);
drawDot(Tangents[i]);
drawDot(inverseTangents[i]);
// Draw stored tangent lines in blue
glColor3f(0, 0, 255);
drawLine(Tangents[i], inverseTangents[i]);
}
// Loop through all points
for (int i = 0; i < Points.size(); i++)
{
// If there are two points draw the first segment
if (Points.size() == 2)
{
// p1 is the start of the curve set at first point
Point p1;
p1 = Points[0];
float i;
// Calculate curve coordinates
for (float j = 0; j <= 100; j++)
{
i = j / 100;
// The Green Lines
float xa = interpolate(Points[0].x, inverseTangents[0].x, i);
float ya = interpolate(Points[0].y, inverseTangents[0].y, i);
float xb = interpolate(inverseTangents[0].x, inverseTangent.x, i);
float yb = interpolate(inverseTangents[0].y, inverseTangent.y, i);
float xc = interpolate(inverseTangent.x, Points[1].x, i);
float yc = interpolate(inverseTangent.y, Points[1].y, i);
// The Blue Line
float xm = interpolate(xa, xb, i);
float ym = interpolate(ya, yb, i);
float xn = interpolate(xb, xc, i);
float yn = interpolate(yb, yc, i);
// The Black Dot
float x2 = interpolate(xm, xn, i);
float y2 = interpolate(ym, yn, i);
Point p2;
p2.setxy(x2, y2);
drawLine(p1, p2);
p1 = p2;
// Prevents curves generated during mouse motion from being stored
if (MouseReleased)
{
// Store curvature into Bezier Points
BezierCurve.push_back(p2);
}
}
}
// Second segment onwards
else if (Points.size() > 2)
{
// p1 is the start of the curve set to second last point
Point p1;
p1 = Points[Points.size() - 2];
float i;
// Calculate curve coordinates
for (float j = 0; j <= 100; j++)
{
i = j / 100;
// The Green Lines
float xa = interpolate(Points[Points.size() - 2].x, Tangents[TangentsSize - 2].x, i);
float ya = interpolate(Points[Points.size() - 2].y, Tangents[TangentsSize - 2].y, i);
float xb = interpolate(Tangents[TangentsSize - 2].x, inverseTangent.x, i);
float yb = interpolate(Tangents[TangentsSize - 2].y, inverseTangent.y, i);
float xc = interpolate(inverseTangent.x, Points[Points.size() - 1].x, i);
float yc = interpolate(inverseTangent.y, Points[Points.size() - 1].y, i);
// The Blue Line
float xm = interpolate(xa, xb, i);
float ym = interpolate(ya, yb, i);
float xn = interpolate(xb, xc, i);
float yn = interpolate(yb, yc, i);
// The Black Dot
float x2 = interpolate(xm, xn, i);
float y2 = interpolate(ym, yn, i);
Point p2;
p2.setxy(x2, y2);
drawLine(p1, p2);
p1 = p2;
// Prevents curves generated during mouse motion from being stored
if (MouseReleased)
{
// Store curvature into Bezier Points
BezierCurve.push_back(p2);
}
}
}
}
// Draw all bezier curvature
for (int i = 1; i < BezierCurve.size(); i++)
{
drawLine(BezierCurve[i - 1], BezierCurve[i]);
}
glutSwapBuffers();
}
void timer(int)
{
glutTimerFunc(1000 / 60, timer, 0);
glutPostRedisplay();
}
int main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(640, 500);
glutInitWindowPosition(100, 150);
glutCreateWindow("Bezier Curve");
glutDisplayFunc(myDisplay);
glutIdleFunc(myDisplay);
glutTimerFunc(0, timer, 0);
glutMouseFunc(myMouse);
glutPassiveMotionFunc(passiveMotion);
glutMotionFunc(motion);
glClearColor(255, 255, 255, 0.0);
glPointSize(3);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 640.0, 0.0, 500.0);
glutMainLoop();
return 0;
}
You will want to detect when mouse click changes from down to up:
bool prevMouse;
...
// at the end of Display()
prevMouse = MouseReleased;
Then we check when mouse click changes from pressed to released and add lines to BezierCurve:
if (PrevMouse == 0 && MouseReleased)
{
// Store curvature into Bezier Points
BezierCurve.push_back(p2);
}
The two code paths, if (Points.size() == 2), and else if (Points.size() > 2) inside the for loop can be simplified to if (Points.size() >= 2) and for that matter the for loop is extraneous, we don't need to update the bezier curve for any of the previous points, just the curve between the two newest points, Points[Points.size() - 2] and Points[Points.size() - 1].
The final code:
#include <iostream>
#include <stdlib.h>
#include <GL/glut.h>
#include <vector>
#include <math.h>
using namespace std;
//Point class for taking the points
class Point {
public:
float x, y;
void setxy(float x2, float y2)
{
x = x2; y = y2;
}
//operator overloading for '=' sign
const Point& operator=(const Point& rPoint)
{
x = rPoint.x;
y = rPoint.y;
return *this;
}
};
int SCREEN_HEIGHT = 500;
vector<Point> Points;
Point Tangent;
Point inverseTangent;
Point cursorLocationLive;
int TangentsSize = 0;
vector<Point> Tangents(TangentsSize);
vector<Point> inverseTangents(TangentsSize);
vector<Point> BezierCurve;
bool MouseReleased = false;
bool PrevMouse = false;
void drawDot(Point p1)
{
glBegin(GL_POINTS);
glVertex2i(p1.x, p1.y);
glEnd();
}
void drawLine(Point p1, Point p2)
{
glBegin(GL_LINE_STRIP);
glVertex2f(p1.x, p1.y);
glVertex2f(p2.x, p2.y);
glEnd();
}
float interpolate(float n1, float n2, float perc)
{
float diff = n2 - n1;
return n1 + (diff * perc);
}
void myMouse(int button, int state, int x, int y)
{
if (button == GLUT_LEFT_BUTTON)
{
if (state == GLUT_DOWN)
{
MouseReleased = false;
// Store points into Points vector on click
Point point;
point.setxy(x, SCREEN_HEIGHT - y);
Points.push_back(point);
// Tangents are set to the cursor position
Tangent.setxy(x, SCREEN_HEIGHT - y);
inverseTangent.x = (2 * Points[Points.size() - 1].x) - Tangent.x;
inverseTangent.y = (2 * Points[Points.size() - 1].y) - Tangent.y;
/*Add new element to Tangent & inverseTangent so when we draw the curve
the tangents are accessed at the right index*/
TangentsSize++;
}
else if (state == GLUT_UP)
{
MouseReleased = true;
// Upon mouse release store tangent and inverse tangent into separate vectors
Tangents.push_back(Tangent);
inverseTangents.push_back(inverseTangent);
}
}
}
void passiveMotion(int x, int y)
{
// Sets the location of cursor while moving with no buttons pressed
cursorLocationLive.setxy(x, SCREEN_HEIGHT - y);
}
void motion(int x, int y)
{
// Sets the coordinates of the tangents when mouse moves with a button held down
Tangent.setxy(x, SCREEN_HEIGHT - y);
inverseTangent.x = (2 * Points[Points.size() - 1].x) - Tangent.x;
inverseTangent.y = (2 * Points[Points.size() - 1].y) - Tangent.y;
}
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
// Draw main points in red
glColor3f(255, 0, 0);
for (int i = 0; i < Points.size(); i++)
{
drawDot(Points[i]);
}
// If there is a starting point draw a line to cursor from last drawn point in passive motion
if (Points.size() > 0)
{
glColor3f(0, 0, 0);
drawLine(Points[Points.size() - 1], cursorLocationLive);
}
// Draw live tangent dots in green
glColor3f(0, 255, 0);
drawDot(Tangent);
drawDot(inverseTangent);
// Draw live tangent lines in blue
glColor3f(0, 0, 255);
drawLine(Tangent, inverseTangent);
for (int i = 0; i < Tangents.size(); i++)
{
// Draw stored tangent dots in green
glColor3f(0, 255, 0);
drawDot(Tangents[i]);
drawDot(inverseTangents[i]);
// Draw stored tangent lines in blue
glColor3f(0, 0, 255);
drawLine(Tangents[i], inverseTangents[i]);
}
// Loop through all points
if (Points.size() >= 2)
{
// p1 is the start of the curve set to second last point
Point p1;
p1 = Points[Points.size() - 2];
float i;
// Calculate curve coordinates
for (float j = 0; j <= 100; j++)
{
i = j / 100;
// The Green Lines
float xa = interpolate(Points[Points.size() - 2].x, Tangents[TangentsSize - 2].x, i);
float ya = interpolate(Points[Points.size() - 2].y, Tangents[TangentsSize - 2].y, i);
float xb = interpolate(Tangents[TangentsSize - 2].x, inverseTangent.x, i);
float yb = interpolate(Tangents[TangentsSize - 2].y, inverseTangent.y, i);
float xc = interpolate(inverseTangent.x, Points[Points.size() - 1].x, i);
float yc = interpolate(inverseTangent.y, Points[Points.size() - 1].y, i);
// The Blue Line
float xm = interpolate(xa, xb, i);
float ym = interpolate(ya, yb, i);
float xn = interpolate(xb, xc, i);
float yn = interpolate(yb, yc, i);
// The Black Dot
float x2 = interpolate(xm, xn, i);
float y2 = interpolate(ym, yn, i);
Point p2;
p2.setxy(x2, y2);
drawLine(p1, p2);
p1 = p2;
// Prevents curves generated during mouse motion from being stored
if (PrevMouse == 0 && MouseReleased)
{
// Store curvature into Bezier Points
BezierCurve.push_back(p2);
}
}
}
std::cout << BezierCurve.size() << std::endl;
PrevMouse = MouseReleased;
// Draw all bezier curvature
for (int i = 1; i < BezierCurve.size(); i++)
{
drawLine(BezierCurve[i - 1], BezierCurve[i]);
}
glutSwapBuffers();
}
void timer(int)
{
glutTimerFunc(1000 / 60, timer, 0);
glutPostRedisplay();
}
int main(int argc, char* argv[]) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(640, 500);
glutInitWindowPosition(100, 150);
glutCreateWindow("Bezier Curve");
glutDisplayFunc(myDisplay);
glutIdleFunc(myDisplay);
glutTimerFunc(0, timer, 0);
glutMouseFunc(myMouse);
glutPassiveMotionFunc(passiveMotion);
glutMotionFunc(motion);
glClearColor(255, 255, 255, 0.0);
glPointSize(3);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 640.0, 0.0, 500.0);
glutMainLoop();
return 0;
}

Take inputs from keyboard and increase/decrease sides of a shape using GLUT

Take inputs from keyboard such as "+" or "-" and increase/decrease sides accordingly. For example if a triangle is currently displayed and if i press "+", it should transform into a rectangle etc. How can I achieve that?
static void DisplayShape(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3d(1,0.1,0.6);
glBegin(GL_POINTS);
for(int i=0;i<n;++i) // n - sides count
{
glVertex2f(); // the n-sided shape is to be drawn here
}
glEnd();
glutSwapBuffers();
}
static void key(unsigned char key, int x, int y)
{
switch (key)
{
case 27 :
case 'q': // quit
exit(0);
break;
case '+': // increase sides count
n++;
break;
case '-': // decrease sides count
if (n > 3) // cannot be less than 3
{
n--;
}
break;
}
glutPostRedisplay();
}
static void idle(void)
{
glutPostRedisplay();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640,480);
glutInitWindowPosition(10,10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("GLUT Shapes");
glutDisplayFunc(DisplayShape);
glutKeyboardFunc(key);
glutIdleFunc(idle);
glutMainLoop();
return EXIT_SUCCESS;
}
Distribute the N-points around a circle. Compute the angle between the vectors from the center of the circle to the points (360°/N). Calculate the points using their Polar Coordinates:
const float x0 = 0.0f;
const float y0 = 0.0f;
const float sideLen = 0.5;
float dist = sideLen / 2.0f / sin(M_PI * 2.0f / n / 2.0f);
float startAngle = -M_PI * (n - 2) / 2 / n;
glBegin(GL_LINE_LOOP);
for (int i = 0; i < n; ++i) // n - sides count
{
float sideAngle = M_PI * 2.0 * i / n + startAngle;
float x = x0 + dist * cos(sideAngle);
float y = y0 + dist * sin(sideAngle);
glVertex2f(x, y);
}
glEnd();
Complete example:
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/freeglut.h>
#define _USE_MATH_DEFINES
#include <math.h>
int n = 3;
static void DisplayShape(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3d(1, 0.1, 0.6);
const float x0 = 0.0f;
const float y0 = 0.0f;
const float sideLen = 0.5;
float dist = sideLen / 2.0f / sin(M_PI * 2.0f / n / 2.0f);
float startAngle = -M_PI * (n - 2) / 2 / n;
glBegin(GL_LINE_LOOP);
for (int i = 0; i < n; ++i) // n - sides count
{
float sideAngle = M_PI * 2.0 * i / n + startAngle;
float x = x0 + dist * cos(sideAngle);
float y = y0 + dist * sin(sideAngle);
glVertex2f(x, y);
}
glEnd();
glutSwapBuffers();
glutPostRedisplay();
}
static void key(unsigned char key, int x, int y)
{
switch (key)
{
case 27:
case 'q': // quit
exit(0);
break;
case '+': // increase sides count
n++;
break;
case '-': // decrease sides count
if (n > 3) // cannot be less than 3
n--;
break;
}
glutPostRedisplay();
}
static void reshape(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
double aspect = (double)width / height;
glOrtho(-aspect, aspect, -1.0, 1.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
int main(int argc, char* argv[])
{
glutInit(&argc, argv);
glutInitWindowSize(640, 480);
glutInitWindowPosition(10, 10);
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("GLUT Shapes");
glutReshapeFunc(reshape);
glutDisplayFunc(DisplayShape);
glutKeyboardFunc(key);
glutMainLoop();
return EXIT_SUCCESS;
}

How to draw a Bezier curve with C++ in OpenGL using floating point values

I am trying to draw a Bezier curve in OpenGL using floating point values. I have tried using many different code examples. My current code below, runs ,but does not show the curve on screen. The usual way to draw Bezier curves are with integer values, which means using the GLUORTHO2D() function for drawing the curve. But I want to draw a curve using floating point values. Such as x range(-1,1) and y range(-1,1).
like if x=(500) then consider it (-1 to 1) and if y=(800) then consider it (-1,1).
I have already tried using integer values and it worked for me. my code using integer values is below:
#include <GL/glut.h>
#include <math.h>
#include <stdio.h>
#define CTRL_COUNT 100
int ctrlPointsCount;
int ctrlPointsX[CTRL_COUNT], ctrlPointsY[CTRL_COUNT];
int X1[3]={20,25,20}, Y1[3]={5,24,38}; //first point(x1[0],y1[0]) second(x1[1],y1[1]) third(x1[2],y1[2])
void myInit()
{
glClearColor(0.0,0.0,0.0,0.0);
glColor3f(1.0,0.0,0.0);
glPointSize(8.0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0,128.0,0.0,96.0);
}
//p(t)=(1-t)^3*p0+3t(1-t)^2*p1+3t^2(1-t)p2+t^3p3
float getNextBezierPointX(float t)
{
float x=0.0;
for(int i=0; i<ctrlPointsCount; i++)
{
int c;
if(i==0 || i==ctrlPointsCount-1)
c = 1;
else
{
c = ctrlPointsCount-1;
}
x += c * pow(t, i) * pow(1-t, ctrlPointsCount-1-i) * ctrlPointsX[i];
}
return x;
}
float getNextBezierPointY(float t)
{
float y=0.0;
for(int i=0; i<ctrlPointsCount; i++)
{
int c;
if(i==0 || i==ctrlPointsCount-1)
c = 1;
else
{
c = ctrlPointsCount-1;
}
y += c * pow(t, i) * pow(1-t, ctrlPointsCount-1-i) * ctrlPointsY[i];
}
return y;
}
void drawline()
{
// draw control points using red color
for(int i=0; i < 3; i++)
{
glBegin(GL_POINTS);
glVertex2i(ctrlPointsX[i], ctrlPointsY[i]);
glEnd();
glFlush();
}
// draw bezier curve using control poitns by calculating next points using cubic bezier curve formula
float oldX=ctrlPointsX[0], oldY=ctrlPointsY[0];
for(double t = 0.0;t <= 1.0; t += 0.01) {
float x = getNextBezierPointX(t);
float y = getNextBezierPointY(t);
//glColor3f(1.0,t,1.0);
glColor3f(1.0,1.0,1.0);
glBegin(GL_LINES);
glVertex2f(oldX, oldY);
glVertex2f(x, y);
glEnd();
glFlush();
oldX = x;
oldY = y;
}
}
void myDisplay()
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0,0.0,0.0);
ctrlPointsCount=3;
for(int i=0;i<3;i++)
{
ctrlPointsX[i] = X1[i];
ctrlPointsY[i] = Y1[i];
}
drawline();
glFlush();
}
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(640,480);
glutInitWindowPosition(100,150);
glutCreateWindow("Bezier Curve");
glutDisplayFunc(myDisplay);
myInit();
glutMainLoop();
return 0;
}
But when i tried using floating point values , it does not work for me. It does not show the curved line on screen. My code using floating point values is below:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>
using namespace std;
#define CTRL_COUNT 100
int ctrlPointsCount;
int ctrlPointsX[CTRL_COUNT], ctrlPointsY[CTRL_COUNT];
double X1[3] = { 0.26015037593985, 0.43609022556391, 0.6 }, Y1[3] = { 0.946875, 0.884375, 0.946875 };
//Initializes 3D rendering
void initRendering() {
glEnable(GL_DEPTH_TEST);
}
float getNextBezierPointX(float t)
{
float x = 0.0;
for (int i = 0; i<ctrlPointsCount; i++)
{
int c;
if (i == 0 || i == ctrlPointsCount - 1)
c = 1;
else
{
c = ctrlPointsCount - 1;
}
x += c * pow(t, i) * pow(1 - t, ctrlPointsCount - 1 - i) * ctrlPointsX[i];
}
return x;
}
float getNextBezierPointY(float t)
{
float y = 0.0;
for (int i = 0; i<ctrlPointsCount; i++)
{
int c;
if (i == 0 || i == ctrlPointsCount - 1)
c = 1;
else
{
c = ctrlPointsCount - 1;
}
y += c * pow(t, i) * pow(1 - t, ctrlPointsCount - 1 - i) * ctrlPointsY[i];
}
return y;
}
void drawline()
{
// draw control points using red color
for (int i = 0; i < 3; i++)
{
glBegin(GL_POINTS);
glVertex2i(ctrlPointsX[i], ctrlPointsY[i]);
glEnd();
glFlush();
}
// draw bezier curve using control poitns by calculating next points using cubic bezier curve formula
float oldX = ctrlPointsX[0], oldY = ctrlPointsY[0];
for (double t = 0.0; t <= 1.0; t += 0.01)
{
float x = getNextBezierPointX(t);
float y = getNextBezierPointY(t);
//glColor3f(1.0,t,1.0);
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_LINES);
glVertex2f(oldX, oldY);
glVertex2f(x, y);
glEnd();
glFlush();
oldX = x;
oldY = y;
}
}
//Called when the window is resized
void handleResize(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (double)w / (double)h, 1.0, 200.0);
}
float _angle = 0.0;
float _cameraAngle = 0.0;
float _ang_tri = 0.0;
//Draws the 3D scene
void drawScene() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); //Reset the drawing perspective
ctrlPointsCount = 3;
for (int i = 0; i<3; i++)
{
ctrlPointsX[i] = X1[i];
ctrlPointsY[i] = Y1[i];
}
drawline();
glutSwapBuffers();
}
void update(int value) {
_angle += 2.0f;
if (_angle > 360) {
_angle -= 360;
}
_ang_tri += 2.0f;
if (_ang_tri > 360) {
_ang_tri -= 360;
}
glutPostRedisplay(); //Tell GLUT that the display has changed
//Tell GLUT to call update again in 25 milliseconds
glutTimerFunc(25, update, 0);
}
int main(int argc, char** argv) {
//Initialize GLUT
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(1331, 641);
glutInitWindowPosition(0, 0);
//Create the window
glutCreateWindow("Our cg project");
initRendering();
//Set handler functions
glutDisplayFunc(drawScene);
glutReshapeFunc(handleResize);
glutTimerFunc(25, update, 0); //Add a timer
glClearColor(0.0, 0.7, 1.5,0.0);
glutMainLoop();
return 0;
}
The problem is this here:
int ctrlPointsX[CTRL_COUNT], ctrlPointsY[CTRL_COUNT];
double X1[3] = { 0.26015037593985, 0.43609022556391, 0.6 }, Y1[3] = {0.946875, 0.884375, 0.946875 };
for (int i = 0; i<3; i++)
{
ctrlPointsX[i] = X1[i];
ctrlPointsY[i] = Y1[i];
}
ctrlPointsX and ctrlPointsYcan only hold integer values. So when you do ctrlPointsX[i] = X1[i] and ctrlPointsY[i] = Y1[i] you are converting the floats to integers, which will round them down. So all your controlPoints will be 0.
You have to declare the controlPoints arrays as type double too:
double ctrlPointsX[CTRL_COUNT], ctrlPointsY[CTRL_COUNT];
double X1[3] = { 0.26015037593985, 0.43609022556391, 0.6 }, Y1[3] = {0.946875, 0.884375, 0.946875 };
This should fix your problem.

xzy, to xyz orientation conversion

I've got some code but the matrix orientation does not appeal to my purposes, can someone teach me how to convert it's orientation, it's currently set up as X Z Y, but i would like it to reflect X Y Z, can someone please highlight what must be done?
when i do vertex3f(100, 100, 10); forexample, the 10 value should reflect the Z value on my grid.
Here is my code:
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <Windows.h>
#include <glut.h>
#include <iostream>
using namespace std;
const float sensitivity = 0.005;
const float walk_speed = 0.5;
float cam_pos[3] = { 100.5, 10.0f, 50 };
float cam_view[3] = { -1.0f, 0.0f, 1.0f };
static int old_x, old_y, half_width, half_height;
int width = 1024, height = 768;
void updateKeys()
{
if (GetAsyncKeyState('W')){
cam_pos[0] += cam_view[0] * walk_speed;
cam_pos[1] += cam_view[1] * walk_speed;
cam_pos[2] += cam_view[2] * walk_speed;
}
if (GetAsyncKeyState('S')){
cam_pos[0] -= cam_view[0] * walk_speed;
cam_pos[1] -= cam_view[1] * walk_speed;
cam_pos[2] -= cam_view[2] * walk_speed;
}
if (GetAsyncKeyState('A')){
cam_pos[0] += cam_view[2] * walk_speed;
cam_pos[2] -= cam_view[0] * walk_speed;
}
if (GetAsyncKeyState('D')){
cam_pos[0] -= cam_view[2] * walk_speed;
cam_pos[2] += cam_view[0] * walk_speed;
}
if (GetAsyncKeyState(VK_SPACE)){
cam_pos[1] += walk_speed;
}
}
void renderScene(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//3d camera
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(
cam_pos[0], cam_pos[1], cam_pos[2],
cam_pos[0] + cam_view[0], cam_pos[1] + cam_view[1], cam_pos[2] + cam_view[2],
0.0f, 1.0f, 0.0f);
//render grid
glBegin(GL_LINES);
for (int i = 0; i <= 100; i++) {
if (i == 0) { glColor3f(.6, .3, .3); }
else { glColor3f(.25, .25, .25); };
glVertex3f(i, 0, 0);
glVertex3f(i, 0, 100);
if (i == 0) { glColor3f(.3, .3, .6); }
else { glColor3f(.25, .25, .25); };
glVertex3f(0, 0, i);
glVertex3f(100, 0, i);
};
glEnd();
glEnable(GL_POINT_SMOOTH);
glPointSize(50.0f);
glColor3f(1, 0, 0);
glBegin(GL_POINTS);
glVertex3f(0, 0, 0);
//X, Z, Y
glVertex3f(10, -10, 10);
glEnd();
updateKeys();
glutSwapBuffers();
}
void normalize(float *v)
{
float magnitude = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
v[0] /= magnitude;
v[1] /= magnitude;
v[2] /= magnitude;
}
void rotate_view(float *view, float angle, float x, float y, float z)
{
float new_x;
float new_y;
float new_z;
float c = cos(angle);
float s = sin(angle);
new_x = (x*x*(1 - c) + c) * view[0];
new_x += (x*y*(1 - c) - z*s) * view[1];
new_x += (x*z*(1 - c) + y*s) * view[2];
new_y = (y*x*(1 - c) + z*s) * view[0];
new_y += (y*y*(1 - c) + c) * view[1];
new_y += (y*z*(1 - c) - x*s) * view[2];
new_z = (x*z*(1 - c) - y*s) * view[0];
new_z += (y*z*(1 - c) + x*s) * view[1];
new_z += (z*z*(1 - c) + c) * view[2];
view[0] = new_x;
view[1] = new_y;
view[2] = new_z;
normalize(view);
}
void motion(int x, int y)
{
float rot_x, rot_y;
float rot_axis[3];
x -= half_width;
y -= half_height;
rot_x = -(float)(x - old_x) * sensitivity;
rot_y = -(float)(y - old_y) * sensitivity;
old_x = x;
old_y = y;
rotate_view(cam_view, rot_x, 0.0f, 1.0f, 0.0f);
rot_axis[0] = -cam_view[2];
rot_axis[1] = 0.0f;
rot_axis[2] = cam_view[0];
normalize(rot_axis);
rotate_view(cam_view, rot_y, rot_axis[0], rot_axis[1], rot_axis[2]);
}
void mouse(int button, int state, int x, int y)
{
old_x = x - half_width;
old_y = y - half_height;
glutPostRedisplay();
}
void idle()
{
glutPostRedisplay();
}
void keys(unsigned char c, int x, int y)
{
glutPostRedisplay();
cout << "camera view: :" << cam_view[0] << "," << cam_view[1] << "," << cam_view[2] << endl;
}
void reshape(int w, int h)
{
width = w;
height = h;
half_height = w / 2;
half_width = h / 2;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, (double)w / (double)h, 1.0, 10000.0);
glViewport(0, 0, w, h);
}
//----------------------------------------------------------------------
// Main program
//----------------------------------------------------------------------
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowPosition(100, 100);
glutInitWindowSize(width, height);
glutCreateWindow("OpenGL");
glutDisplayFunc(renderScene);
glutKeyboardFunc(keys);
glutReshapeFunc(reshape);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutIdleFunc(idle);
// OpenGL init
glEnable(GL_DEPTH_TEST);
// enter GLUT event processing cycle
glutMainLoop();
return 0; // this is just to keep the compiler happy
}
Use a transformation matrix that "remaps" the values. You can push that matrix on your modelview as usual.
The identity matrix is:
(1, 0, 0; 0, 1, 0; 0, 0, 1)
Your matrix would be:
(1, 0, 0; 0, 0, 1; 0, 1, 0)
I guess you can spot the difference. You can extend to a 4D matrix for homogeneous coordinates accordingly.

How to drag a graph around the window in OpenGL/c++

below is the code so far, my problem lies in dragging the graph around the window ? i can't seem to do it ? any tips for me guys ?? What i want is when you click and hold down the left mouse button you should be able to drag the graph around the window ?
#include <GL/glut.h>
#include <stdlib.h>
#include <math.h>
#if !defined(GLUT_WHEEL_UP)
# define GLUT_WHEEL_UP
# define GLUT_WHEEL_DOWN 4
#endif
/* Set initial size of the display window. */
GLsizei winWidth = 600, winHeight = 600;
/* Set size of world-coordinate clipping window. */
GLfloat xwcMin = -50.0, xwcMax = 50.0;
GLfloat ywcMin = -50.0, ywcMax = 50.0;
bool leftButton;
int downX, downY;
class wcPt3D {
public:
GLfloat x, y, z;
};
void init (void) {
/* Set color of display window to white. */
glClearColor (1.0, 1.0, 1.0, 0.0);
}
void plotPoint (wcPt3D bezCurvePt) {
glBegin (GL_POINTS);
glVertex2f (bezCurvePt.x, bezCurvePt.y);
glEnd ( );
}
/* Compute binomial coefficients C for given value of n. */
void binomialCoeffs (GLint n, GLint * C) {
GLint k, j;
for (k = 0; k <= n; k++) {
/* Compute n!/(k!(n - k)!). */
C [k] = 1;
for (j = n; j >= k + 1; j--)
C [k] *= j;
for (j = n - k; j >= 2; j--)
C [k] /= j;
}
}
void computeBezPt (GLfloat t, wcPt3D * bezPt, GLint nCtrlPts,
wcPt3D * ctrlPts, GLint * C) {
GLint k, n = nCtrlPts - 1;
GLfloat bezBlendFcn;
bezPt->x = bezPt->y = bezPt->z = 0.0;
/* Compute blending functions and blend control points. */
for (k = 0; k < nCtrlPts; k++) {
bezBlendFcn = C [k] * pow (t, k) * pow (1 - t, n - k);
bezPt->x += ctrlPts [k].x * bezBlendFcn;
bezPt->y += ctrlPts [k].y * bezBlendFcn;
bezPt->z += ctrlPts [k].z * bezBlendFcn;
}
}
void bezier (wcPt3D * ctrlPts, GLint nCtrlPts, GLint nBezCurvePts) {
wcPt3D bezCurvePt;
GLfloat t;
GLint *C;
/* Allocate space for binomial coefficients */
C = new GLint [nCtrlPts];
binomialCoeffs (nCtrlPts - 1, C);
for (int i = 0; i <= nBezCurvePts; i++) {
t = GLfloat (i) / GLfloat (nBezCurvePts);
computeBezPt (t, &bezCurvePt, nCtrlPts, ctrlPts, C);
plotPoint (bezCurvePt);
}
delete [ ] C;
}
void displayFcn (void) {
glClear (GL_COLOR_BUFFER_BIT); // Clear display window.
/* Set example number of control points and number of
* curve positions to be plotted along the Bezier curve.
*/ GLint nCtrlPts = 4, nBezCurvePts = 1000;
wcPt3D ctrlPts [4] = { {-40.0, -40.0, 0.0}, {-10.0, 200.0, 0.0},
{10.0, -200.0, 0.0}, {40.0, 40.0, 0.0} };
glPointSize (4);
glColor3f (1.0, 0.0, 0.0); // Set point color to red.
bezier (ctrlPts, nCtrlPts, nBezCurvePts);
glutSwapBuffers();
}
void winReshapeFcn (GLint newWidth, GLint newHeight) {
/* Maintain an aspect ratio of 1.0. */
glViewport (0, 0, xwcMin, ywcMin);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ( );
gluOrtho2D (xwcMin, xwcMax, ywcMin, ywcMax);
glutPostRedisplay();
}
void MouseCallback(int button, int state, int x, int y) {
downX = x;
downY = y;
leftButton = ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN));
glutPostRedisplay();
}
void MotionCallback(int x, int y) {
if (leftButton){
downX=downX+x;
downY=downY+y;
gluOrtho2D (xwcMin, xwcMax, ywcMin, ywcMax);
}
downX = x;
downY = y;
glutPostRedisplay();
}
/*
void MouseCallback(int button, int state, int x, int y) {
if (button == GLUT_WHEEL_UP && glutGetModifiers()==GLUT_ACTIVE_CTRL) {
}else if (button == GLUT_WHEEL_DOWN)
glutPostRedisplay();
}
*/
int main (int argc, char** argv) {
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition (50, 50);
glutInitWindowSize (winWidth, winHeight);
glutCreateWindow ("Bezier Curve");
init ( );
glutDisplayFunc (displayFcn);
glutReshapeFunc (winReshapeFcn);
glutMouseFunc(MouseCallback);
glutMotionFunc(MotionCallback);
glutMainLoop ( );
}
Try this:
#include <GL/glut.h>
#include <cmath>
// Compute binomial coefficients C for given value of n.
void binomialCoeffs
(
GLint n,
GLint* C
)
{
for (GLint k = 0; k <= n; k++)
{
// Compute n!/(k!(n - k)!).
C [k] = 1;
for (GLint j = n; j >= k + 1; j--)
C [k] *= j;
for (GLint j = n - k; j >= 2; j--)
C [k] /= j;
}
}
struct wcPt3D
{
GLfloat x, y, z;
};
void computeBezPt
(
GLfloat t,
wcPt3D* bezPt,
GLint nCtrlPts,
wcPt3D* ctrlPts,
GLint* C
)
{
GLint n = nCtrlPts - 1;
GLfloat bezBlendFcn;
bezPt->x = bezPt->y = bezPt->z = 0.0;
// Compute blending functions and blend control points.
for (GLint k = 0; k < nCtrlPts; k++)
{
bezBlendFcn = C [k] * pow (t, k) * pow (1 - t, n - k);
bezPt->x += ctrlPts [k].x * bezBlendFcn;
bezPt->y += ctrlPts [k].y * bezBlendFcn;
bezPt->z += ctrlPts [k].z * bezBlendFcn;
}
}
void bezier
(
wcPt3D* ctrlPts,
GLint nCtrlPts,
GLint nBezCurvePts
)
{
// Allocate space for binomial coefficients
GLint* C = new GLint [nCtrlPts];
binomialCoeffs (nCtrlPts - 1, C);
glBegin (GL_POINTS);
for (int i = 0; i <= nBezCurvePts; i++)
{
GLfloat t = GLfloat (i) / GLfloat (nBezCurvePts);
wcPt3D bezCurvePt;
computeBezPt (t, &bezCurvePt, nCtrlPts, ctrlPts, C);
glVertex2f (bezCurvePt.x, bezCurvePt.y);
}
glEnd();
delete [ ] C;
}
int btn;
int startMouseX = 0;
int startMouseY = 0;
int startTransX = 0;
int startTransY = 0;
int curTransX = 0;
int curTransY = 0;
void MouseCallback(int button, int state, int x, int y)
{
btn = button;
if( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN )
{
startMouseX = x;
startMouseY = glutGet( GLUT_WINDOW_HEIGHT ) - y;
startTransX = curTransX;
startTransY = curTransY;
}
glutPostRedisplay();
}
void MotionCallback(int x, int y)
{
int curMouseX = x;
int curMouseY = glutGet( GLUT_WINDOW_HEIGHT ) - y;
if ( btn == GLUT_LEFT_BUTTON )
{
curTransX = startTransX + ( curMouseX - startMouseX );
curTransY = startTransY + ( curMouseY - startMouseY );
}
glutPostRedisplay();
}
// Set size of world-coordinate clipping window.
GLfloat xwcMin = -50.0, xwcMax = 50.0;
GLfloat ywcMin = -50.0, ywcMax = 50.0;
void displayFcn ()
{
// Clear display window.
glClearColor (1.0, 1.0, 1.0, 0.0);
glClear (GL_COLOR_BUFFER_BIT);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ( );
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
glTranslatef( curTransX / w * 2, curTransY / h * 2, 0 );
gluOrtho2D (xwcMin, xwcMax, ywcMin, ywcMax);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity();
// Set example number of control points and number of
// curve positions to be plotted along the Bezier curve.
GLint nCtrlPts = 4, nBezCurvePts = 1000;
wcPt3D ctrlPts [4] =
{
{-40.0, -40.0, 0.0},
{-10.0, 200.0, 0.0},
{10.0, -200.0, 0.0},
{40.0, 40.0, 0.0}
};
// Set point color to red.
glPointSize (4);
glColor3f (1.0, 0.0, 0.0);
bezier (ctrlPts, nCtrlPts, nBezCurvePts);
glutSwapBuffers();
}
int main (int argc, char** argv)
{
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition (50, 50);
glutInitWindowSize (600, 600);
glutCreateWindow ("Bezier Curve");
glutDisplayFunc (displayFcn);
glutMouseFunc(MouseCallback);
glutMotionFunc(MotionCallback);
glutMainLoop ( );
}
Adapted from my answer here.
EDIT: Minimal(-ish) difference version:
#include <GL/glut.h>
#include <stdlib.h>
#include <math.h>
#if !defined(GLUT_WHEEL_UP)
# define GLUT_WHEEL_UP
# define GLUT_WHEEL_DOWN 4
#endif
/* Set initial size of the display window. */
GLsizei winWidth = 600, winHeight = 600;
/* Set size of world-coordinate clipping window. */
GLfloat xwcMin = -50.0, xwcMax = 50.0;
GLfloat ywcMin = -50.0, ywcMax = 50.0;
class wcPt3D {
public:
GLfloat x, y, z;
};
void init (void) {
/* Set color of display window to white. */
glClearColor (1.0, 1.0, 1.0, 0.0);
}
void plotPoint (wcPt3D bezCurvePt) {
glBegin (GL_POINTS);
glVertex2f (bezCurvePt.x, bezCurvePt.y);
glEnd ( );
}
/* Compute binomial coefficients C for given value of n. */
void binomialCoeffs (GLint n, GLint * C) {
GLint k, j;
for (k = 0; k <= n; k++) {
/* Compute n!/(k!(n - k)!). */
C [k] = 1;
for (j = n; j >= k + 1; j--)
C [k] *= j;
for (j = n - k; j >= 2; j--)
C [k] /= j;
}
}
void computeBezPt (GLfloat t, wcPt3D * bezPt, GLint nCtrlPts,
wcPt3D * ctrlPts, GLint * C) {
GLint k, n = nCtrlPts - 1;
GLfloat bezBlendFcn;
bezPt->x = bezPt->y = bezPt->z = 0.0;
/* Compute blending functions and blend control points. */
for (k = 0; k < nCtrlPts; k++) {
bezBlendFcn = C [k] * pow (t, k) * pow (1 - t, n - k);
bezPt->x += ctrlPts [k].x * bezBlendFcn;
bezPt->y += ctrlPts [k].y * bezBlendFcn;
bezPt->z += ctrlPts [k].z * bezBlendFcn;
}
}
void bezier (wcPt3D * ctrlPts, GLint nCtrlPts, GLint nBezCurvePts) {
wcPt3D bezCurvePt;
GLfloat t;
GLint *C;
/* Allocate space for binomial coefficients */
C = new GLint [nCtrlPts];
binomialCoeffs (nCtrlPts - 1, C);
for (int i = 0; i <= nBezCurvePts; i++) {
t = GLfloat (i) / GLfloat (nBezCurvePts);
computeBezPt (t, &bezCurvePt, nCtrlPts, ctrlPts, C);
plotPoint (bezCurvePt);
}
delete [ ] C;
}
int curTransX = 0;
int curTransY = 0;
void displayFcn (void) {
glClear (GL_COLOR_BUFFER_BIT); // Clear display window.
glMatrixMode (GL_PROJECTION);
glLoadIdentity ( );
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
glTranslatef( curTransX / w * 2, curTransY / h * 2, 0 );
gluOrtho2D (xwcMin, xwcMax, ywcMin, ywcMax);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity();
/* Set example number of control points and number of
* curve positions to be plotted along the Bezier curve.
*/ GLint nCtrlPts = 4, nBezCurvePts = 1000;
wcPt3D ctrlPts [4] = { {-40.0, -40.0, 0.0}, {-10.0, 200.0, 0.0},
{10.0, -200.0, 0.0}, {40.0, 40.0, 0.0} };
glPointSize (4);
glColor3f (1.0, 0.0, 0.0); // Set point color to red.
bezier (ctrlPts, nCtrlPts, nBezCurvePts);
glutSwapBuffers();
}
int btn;
int startMouseX = 0;
int startMouseY = 0;
int startTransX = 0;
int startTransY = 0;
void MouseCallback(int button, int state, int x, int y) {
btn = button;
if( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN )
{
startMouseX = x;
startMouseY = glutGet( GLUT_WINDOW_HEIGHT ) - y;
startTransX = curTransX;
startTransY = curTransY;
}
glutPostRedisplay();
}
void MotionCallback(int x, int y) {
int curMouseX = x;
int curMouseY = glutGet( GLUT_WINDOW_HEIGHT ) - y;
if ( btn == GLUT_LEFT_BUTTON )
{
curTransX = startTransX + ( curMouseX - startMouseX );
curTransY = startTransY + ( curMouseY - startMouseY );
}
glutPostRedisplay();
}
/*
void MouseCallback(int button, int state, int x, int y) {
if (button == GLUT_WHEEL_UP && glutGetModifiers()==GLUT_ACTIVE_CTRL) {
}else if (button == GLUT_WHEEL_DOWN)
glutPostRedisplay();
}
*/
int main (int argc, char** argv) {
glutInit (&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);
glutInitWindowPosition (50, 50);
glutInitWindowSize (winWidth, winHeight);
glutCreateWindow ("Bezier Curve");
init ( );
glutDisplayFunc (displayFcn);
glutMouseFunc(MouseCallback);
glutMotionFunc(MotionCallback);
glutMainLoop ( );
}