I am working on animating a fractal (Triangle fractal) frame-by-frame. I know I need to use a call-back method to do this, but I am not sure how to implement it. I wish to get it working via a left-mouse click so I have this code:
void mouse(int button, int state, int x, int y){
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN){
glClear(GL_COLOR_BUFFER_BIT);
divide_triangle(v[0], v[1], v[2], n);
}
//Closes the window on right button
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN){
exit(0);
}
}
This is my mouse click call back, but this doesn't re-animate the triangle each time the triangle is drawn. How can show the process of the drawing each time I recurse through the triangle drawing?
void divide_triangle(point2 a, point2 b, point2 c, int m)
{
/* triangle subdivision using vertex coordinates */
point2 v0, v1, v2;
int j;
if(m>0){
for(j=0; j<2; j++) v0[j]=(a[j]+b[j])/2;
for(j=0; j<2; j++) v1[j]=(a[j]+c[j])/2;
for(j=0; j<2; j++) v2[j]=(b[j]+c[j])/2;
divide_triangle(a, v0, v1, m-1);
divide_triangle(c, v1, v2, m-1);
divide_triangle(b, v2, v0, m-1);
}
else(triangle(a,b,c));
glutPostRedisplay();
/* draw triangle at end of recursion */
}
I want to redisplay once I draw the new triangle here, and make it appear to be an animation, so I guess I would need a delay between the redisplays. How can I set that up? But I also want to make it where I can draw this without animating everytime, I.e. I click a specific mouse key: say 'F1' or some unreserved key and it would just display the final recursive triangle.
Here is my full code for your viewing:
#ifdef __APPLE__ //For use with OS X
#include <GLUT/glut.h>
#else //Linux
#include <GL/glut.h>
#endif
#include <stdlib.h>
#include <GL/glut.h>
typedef GLfloat point2[2];
/* initial triangle – global variables */
point2 v[]={{-2.0, -1.5}, {2.0, -1.5},
{0.0, 1.5}};
int n; /* number of recursive steps */
int windowX, windowY; //Window size parameters.
float red = .25;
float green = .25;
float blue = .70;
bool color_state = true;
void mouse(int button, int state, int x, int y);
void triangle( point2 a, point2 b, point2 c);
void divide_triangle(point2 a, point2 b, point2 c, int m);
void swap_colors();
void display(void){
glClear(GL_COLOR_BUFFER_BIT);
divide_triangle(v[0], v[1], v[2], n);
glFlush();
}
void init(){
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-2.0, 2.0, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glClearColor (0.10, 0.10, 0.10 ,1.0);
glColor3f(red, green, blue);
}
int main(int argc, char **argv){
if(argc <= 1){
windowX = 500;
windowY = 500;
n = 4;
}
else if(argc > 1){
windowX = atoi(argv[1]); //atoi converts char to int
windowY = atoi(argv[2]);
n = atoi(argv[3]);
}
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(windowX, windowY);
glutCreateWindow("N-Force");
glutDisplayFunc(display);
glutTimerFunc(30, recurse, -1)
glutMouseFunc(mouse);
init();
glutMainLoop();
}
void mouse(int button, int state, int x, int y){
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN){ //Swap colors
glClear(GL_COLOR_BUFFER_BIT);
divide_triangle(v[0], v[1], v[2], n);
}
//Closes the window on right button
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN){
exit(0);
}
}
void divide_triangle(point2 a, point2 b, point2 c, int m)
{
/* triangle subdivision using vertex coordinates */
point2 v0, v1, v2;
int j;
if(m>0){
for(j=0; j<2; j++) v0[j]=(a[j]+b[j])/2;
for(j=0; j<2; j++) v1[j]=(a[j]+c[j])/2;
for(j=0; j<2; j++) v2[j]=(b[j]+c[j])/2;
divide_triangle(a, v0, v1, m-1);
divide_triangle(c, v1, v2, m-1);
divide_triangle(b, v2, v0, m-1);
}
else(triangle(a,b,c));
glutPostRedisplay();
/* draw triangle at end of recursion */
}
void triangle( point2 a, point2 b, point2 c){
glBegin(GL_TRIANGLES);
glVertex2fv(a);
glVertex2fv(b);
glVertex2fv(c);
glEnd();
}
void swap_colors(){ //maybe add parameters x and y to change colors based on coordinates
if(color_state == true){
red = blue = green = .1;
color_state = false;
}
else{
red = 0.25;
green = .25;
blue = 0.70;
color_state = true;
}
}
/* TO DO:
1. add cmd line args, (width, depth, and recursive depth) (CHECK)
2. add color swap
3. add exit callback (check> right mouse)
4. Idle callback for animation
*/
Use a glutTimerFunc() callback with a Boolean flag to increment the recursion depth value and post redisplays:
bool animating = false;
unsigned int n = 4;
void timer( int value )
{
if( !animating )
return;
n++;
if( n > 6 )
n = 0;
glutTimerFunc( 200, timer, 0 );
glutPostRedisplay();
}
void mouse(int button, int state, int x, int y)
{
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
animating = !animating;
glutTimerFunc( 0, timer, 0 );
}
}
All together:
#include <GL/glut.h>
bool animating = false;
unsigned int n = 4;
void timer( int value )
{
if( !animating )
return;
n++;
if( n > 6 )
n = 0;
glutTimerFunc( 200, timer, 0 );
glutPostRedisplay();
}
void mouse(int button, int state, int x, int y)
{
if(button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
animating = !animating;
glutTimerFunc( 0, timer, 0 );
}
}
typedef GLfloat point2[2];
void divide_triangle(point2 a, point2 b, point2 c, int m)
{
/* triangle subdivision using vertex coordinates */
if(m>0)
{
point2 v0, v1, v2;
for( int j=0; j<2; j++) v0[j]=(a[j]+b[j])/2;
for( int j=0; j<2; j++) v1[j]=(a[j]+c[j])/2;
for( int j=0; j<2; j++) v2[j]=(b[j]+c[j])/2;
divide_triangle(a, v0, v1, m-1);
divide_triangle(c, v1, v2, m-1);
divide_triangle(b, v2, v0, m-1);
}
else
{
glVertex2fv(a);
glVertex2fv(b);
glVertex2fv(c);
}
}
void display(void)
{
glClearColor (0.10, 0.10, 0.10 ,1.0);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-2.0, 2.0, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
float red = .25;
float green = .25;
float blue = .70;
glColor3f(red, green, blue);
/* initial triangle – global variables */
point2 v[]={{-2.0, -1.5}, {2.0, -1.5}, {0.0, 1.5}};
glBegin(GL_TRIANGLES);
divide_triangle(v[0], v[1], v[2], n);
glEnd();
glFlush();
}
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow("N-Force");
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMainLoop();
}
I guess you want to have an idle() callback function, doing PostRedisplay only if your anim flag is on. (idle is called repetitively by glut).
Related
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;
}
I tried implementing the Cyrus Beck algorithm for convex polygons. The problem that I was encountering was to find the direction of normal vectors as they must always point inside. For solving this I found the coordinates of the centroid, which always lie inside a convex polygon. This method seems to work in the cases I tested. Is this fool proof ? Are there any better alternatives ?
CyrusBeck.cpp
#include<iostream>
#include<cmath>
#include"graphics.hpp"
#define P pair<double, double>
vector<P> V, N;
P C;
double dot(P A, P B){
return (A.first*B.first + A.second*B.second);
}
P operator - (const P &A, const P &B){
return make_pair(A.first-B.first, A.second-B.second);
}
P operator + (const P &A, const P &B){
return make_pair(A.first+B.first, A.second+B.second);
}
P operator * (const P &A, const double t){
return make_pair(t*A.first, t*A.second);
}
void computeNormal(int n = V.size()){
double m;
P prev = V[0];
double x=-1, y;
for(int i=1; i<n; ++i){
m = -(V[i].first-prev.first)/(V[i].second-prev.second);
P d = V[i]-prev;
int lr=1, tb=1;
if(V[i-1].first>C.first)
lr = -1;
if(V[i-1].second>C.second)
tb=-1;
N[i-1].first = lr*abs(cos(atan(m)));
N[i-1].second = tb*abs(sin(atan(m)));
prev = V[i];
}
m = -(V[0].first-prev.first)/(V[0].second-prev.second);
int lr=1, tb=1;
if(V[n-1].first>C.first)
lr = -1;
if(V[n-1].second>C.second)
tb=-1;
N[n-1].first = lr*abs(cos(atan(m)));
N[n-1].second = tb*abs(sin(atan(m)));
}
int check(P A, P B, int n){
P p = B - V[0];
double d1 = dot(p, N[0]);
P q = A - V[0];
double d2 = dot(q, N[0]);
if(d1<0&&d2<0)
return 0;
if(d1>=0&&d2>=0)
return 1;
return -1;
}
void Clip(P A, P B, double &tE, double &tL, int n = V.size()){
tE = 0; tL = 1;
for(int i=0; i<n; ++i){
double d = dot((B-A), N[i]);
if(d==0)
continue;
double t = dot((A-V[i]), N[i])/dot((A-B), N[i]);
if(d>0&&t>tE)
tE = t;
else if(d<0&&t<tL)
tL = t;
}
}
void display(){
cout<<"Enter the number of vertices\n";
int n; cin>>n;
V.resize(n);
N.resize(n);
cout<<"Enter the coordinates of the vertices in order\n";
for(int i=0; i<n; ++i){
cin>>V[i].first>>V[i].second;
C = C + V[i];
}
C.first/=n; C.second/=n;
drawPolygon(V, n, white);
glutSwapBuffers();
cout<<"Enter the co-ordinates of the line(4)\n";
P A, B;
cin>>A.first>>A.second>>B.first>>B.second;
drawLine(A.first, A.second, B.first, B.second, red);
glutSwapBuffers();
char c = '\0';
while(c!='Y'&&c!='y'){
cout<<"Clip? (Y/N)\n";
cin>>c;
}
computeNormal();
int chk = check(A, B, n);
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
drawPolygon(V, n, white);
if(chk==-1){
double tE, tL;
Clip(A, B, tE, tL);
if(tE>tL)
chk = 0;
else{
P E = A + (B-A)*tE;
P L = A + (B-A)*tL;
drawLine(E.first, E.second, L.first, L.second, blue);
}
}
if(chk==1)
drawLine(A.first, A.second, B.first, B.second, blue);
glutSwapBuffers();
}
int main(int argc, char *argv[]){
init(&argc, argv);
}
graphics.hpp
#ifndef GRAPHICS_H
#define GRAPHICS_H
#include<GL/glut.h>
#include<vector>
using namespace std;
extern float red[3];
extern float green[3];
extern float blue[3];
extern float white[3];
int roundoff(double x);
void init(int* argc, char** argv);
void putpixel(float x, float y, float z, float a[3]);
void drawLine(double x1, double y1, double x2, double y2, float a[3]);
void drawRectangle(double x1, double y1, double x2, double y2, float a[3]);
void drawPolygon(vector<pair<double, double>> v, int n, float a[3]);
void MatrixMultiply(vector<vector<double>> &mat1, vector<vector<double>> &mat2, vector<vector<double>> &res,
int n, int m, int r);
void display();
#endif
graphics.cpp
#include<iostream>
#include"graphics.hpp"
float red[3] = { 1.0f, 0.0f, 0.0f };
float green[3] = { 0.0f, 1.0f, 0.0f };
float blue[3] = { 0.0f, 0.0f, 1.0f };
float white[3] = { 1.0f, 1.0f, 1.0f };
int roundoff(double x){
if (x < 0.0)
return (int)(x - 0.5);
else
return (int)(x + 0.5);
}
void init(int *argc, char** argv){
glutInit(argc, argv); // Initialize GLUT
glutInitWindowSize(800, 800); // Set the window's initial width & height
glutInitWindowPosition(0, 0); // Position the window's initial top-left corner
glutCreateWindow("Graphics"); // Create a window with the given title
gluOrtho2D(0, 800, 0, 800); // specifies the projection matrix
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color to black and opaque
glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer (background)
glutDisplayFunc(display); // Register display callback handler for window re-paint
glutMainLoop(); // Enter the event-processing loop
}
void putpixel(float x, float y, float z, float a[3]){
glPointSize(2);
glBegin(GL_POINTS); // HERE THE POINTS SHOULD BE CREATED
glColor3f(a[0], a[1], a[2]);
glVertex3f(x, y, z); // Specify points in 3d plane
std::cout<<x<<' '<<y<<' '<<z<<'\n';
glEnd();
}
void drawLine(double x1, double y1, double x2, double y2, float a[3]){
glLineWidth(2.5);
glColor3f(a[0], a[1], a[2]);
glBegin(GL_LINES);
glVertex2d(x1, y1);
glVertex2d(x2, y2);
glEnd();
}
void drawRectangle(double x1, double y1, double x2, double y2, float a[3]){
glColor3f(a[0], a[1], a[2]);
glRectd(x1, y1, x2, y2);
}
void drawPolygon(vector<pair<double, double>> v, int n, float a[3]){
glColor3f(a[0], a[1], a[2]);
glBegin(GL_POLYGON);
for(int i=0; i<n; ++i)
glVertex2d(v[i].first, v[i].second);
glEnd();
}
void MatrixMultiply(vector<vector<double>> &mat1, vector<vector<double>> &mat2, vector<vector<double>> &res,
int n, int m, int r){
int x, i, j;
for(i = 0; i < n; i++){
for (j = 0; j < r; j++){
res[i][j] = 0;
for (x = 0; x < m; x++){
res[i][j] += mat1[i][x] * mat2[x][j];
}
}
}
}
I have an OpenGL project with a screen size of 1000x800, and I want to be able to draw a triangle when I click the left mouse button.
I already have a mouse function set up that works fine:
struct point
{
int x;
int y;
};
std::vector <point> dots;
point OneDot;
void processMouse(int button, int state, int x, int y)
{
if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN))
{
int yy;
yy = glutGet(GLUT_WINDOW_HEIGHT);
y = yy - y; /* In Glut, Y coordinate increases from top to bottom */
OneDot.x = x;
OneDot.y = y;
dots.push_back(OneDot);
}
}
void display(){
for (int i = 0; i < dots.size();i++){
glPointSize(10)
glBegin(GL_POINTS);
glVertex2i(dots[i].x, dots[i].y);
}
}
So in my display() function, how can I add some code that prints a triangle at the mouse location when I click?
UPDATE:
Here's my current drawCircle function:
void drawCircle(float cx, float cy, float r, float num_segments) {
// Sets variables for X, Y, Radius and Segments
glColor3f(1.0, 0.0, 0.0); // Red
glBegin(GL_POLYGON);
// To set 0 as origin point
for (int i = 0; i < num_segments; i++) {
float theta = 2.0f * 3.14 * i / num_segments;
float x = r * cosf(theta);
float y = r * sinf(theta);
glVertex2f(x + cx, y + cy);
}
glEnd();
}
Is there a way I could draw this function somehow at the mouse location when I left click?
In your code you're almost there. Two things you have to add: In your mouse event handler you have to set the flag that tells your window manager (in your case GLUT) to refresh the display. That function would be glutPostRedisplay.
Then in your display function you have to push 3 vertices instead of 1 and change the primitive type to GL_TRIANGLES. Like this
void processMouse(int button, int state, int x, int y)
{
if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN))
{
int yy;
yy = glutGet(GLUT_WINDOW_HEIGHT);
y = yy - y; /* In Glut, Y coordinate increases from top to bottom */
OneDot.x = x;
OneDot.y = y;
dots.push_back(OneDot);
glutPostRedisplay(); ///<<<<<<<<<<
}
}
and
void display(){
glBegin(GL_TRIANGLES);
for (int i = 0; i < dots.size();i++){
glPointSize(10)
glVertex2i(dots[i].x-3, dots[i].y-5);
glVertex2i(dots[i].x+3, dots[i].y-5);
glVertex2i(dots[i].x, dots[i].y+5);
}
glEnd();
}
or, if you want to define the corners of the triangle(s) by the clicks just
void display(){
glBegin(GL_TRIANGLES);
for (int i = 0; i < dots.size();i++){
glPointSize(10);
glVertex2i(dots[i].x, dots[i].y);
}
glEnd();
}
You don't really have to check if 3 <= dots.size() because OpenGL will simply draw nothing then.
I haven't got experience in glbegin notation, but seems you miss glend
It should be something like this:
void display(){
glPointSize(10)
glBegin(GL_POINTS);
for (int i = 0; i < dots.size();i++){
glVertex2i(dots[i].x, dots[i].y);
}
glEnd()
}
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.
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 ( );
}