Reputation: 89
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
*/
Upvotes: 1
Views: 250
Reputation: 52166
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();
}
Upvotes: 1
Reputation: 734
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).
Upvotes: 0