/* curv_surf.c demonstrate some neat curves and surfaces */ #include #include #include #ifndef M_PI #define M_PI 3.14159265 #endif #include typedef GLfloat pts3[3]; static pts3 points[500]; static int max_pts = 500; static int n_points = 0; static int n = 0; static int width=600; static int height=650; static int drawpts = 0; static int dynamic = 0; static int dyn_pt = 0; static int dyn_pt_max = 498; static float dyn_val = 0.0; static float dyn_val_max = 1.0; static float dyn_val_inc = 0.01; static float param1; static float param2; static double now, next, tinc; #define CYCLOID 20 #define SPIRAL 21 #define LISSAJOUS 22 #define ROSE 23 #define HELIX3D 30 #define TORSPIRAL3D 31 #define QUIT 1 #define DRAWPOINTS 2 #define DYNAMIC 3 #define BULLSEYE 4 #define TARGET 5 #define TRAIL 6 #define SLOWER 7 #define FASTER 8 #define P1UP 9 #define P1DOWN 10 #define P2UP 11 #define P2DOWN 12 static int curve_type = LISSAJOUS; static int target_type = TRAIL; GLUquadricObj *obj; /* function prototypes for curves */ void compute_curve(void); void cycloid(float ab_ratio, float cycles, float xmin, float xmax, float ymin, float ymax, int npts, pts3 points[]); void spiral(float gap, float rmax, int npts, pts3 points[]); void lissajous(float a, float b, float rmax, int npts, pts3 points[]); void rose(float m, float rmax, int npts, pts3 points[]); void helix(float rmax, float gap, int npts, pts3 points[]); void toroidal_spiral(float inrad, float outrad, float cycles, int npts, pts3 points[]); void display(void) { char text[]="arrows change parameters, 'd' toggle dynamic, 'p' toggle point"; char text2[]="mouse selects menu, then drag to curve type or options"; char *p; int i, j; pts3 p1, p2; /* clear window */ glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity (); glColor3f(0.0, 0.0, 0.0); /* draw rectangle -1.0 to 1.0 */ glBegin(GL_LINE_LOOP); glVertex2f(-1.0, 1.0); glVertex2f(-1.0, -1.0); glVertex2f( 1.0, -1.0); glVertex2f( 1.0, 1.0); glEnd(); /* draw text, in its own context */ glPushMatrix(); glLoadIdentity (); glColor3f(0.0, 0.0, 0.0); glEnable(GL_LINE_SMOOTH); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glPushMatrix(); glTranslatef(-1.0, 1.05, 0.0); glScalef(0.0005, 0.0005, 0.0); for(p=text; *p; p++) glutStrokeCharacter(GLUT_STROKE_ROMAN, *p); glPopMatrix(); glTranslatef(-1.0, 1.15, 0.0); glScalef(0.0005, 0.0005, 0.0); for(p=text2; *p; p++) glutStrokeCharacter(GLUT_STROKE_ROMAN, *p); glPopMatrix(); /* Draw the points */ if(drawpts) { glColor3f(1.0, 0.0, 0.0); glPointSize(4.0); for(i=0; i0) { glBegin(GL_LINES); glVertex3fv(points[dyn_pt-1]); glVertex3fv(points[dyn_pt]); glEnd(); } glLineWidth(1.0); if(dyn_pt>1) { glBegin(GL_LINES); glVertex3fv(points[dyn_pt-2]); glVertex3fv(points[dyn_pt-1]); glEnd(); } } else if(dynamic && target_type==TARGET) { p1[0] = points[dyn_pt][0]+0.04; p1[1] = points[dyn_pt][1]; p1[2] = points[dyn_pt][2]; p2[0] = points[dyn_pt][0]-0.04; p2[1] = points[dyn_pt][1]; p2[2] = points[dyn_pt][2]; glColor3f(0.0, 0.0, 1.0); glLineWidth(2.0); glBegin(GL_LINES); glVertex3fv(p1); glVertex3fv(p2); p1[0] = p1[0]-0.04; p2[0] = p2[0]+0.04; p1[1] = p1[1]+0.04; p2[1] = p2[1]-0.04; glVertex3fv(p1); glVertex3fv(p2); glEnd(); glPushMatrix(); glLoadIdentity(); glTranslatef(points[dyn_pt][0],points[dyn_pt][1],points[dyn_pt][2]); gluDisk(obj, 0.03, 0.04, 12, 12); glPopMatrix(); } else if(dynamic && target_type==BULLSEYE) { glPointSize(4.0); glColor3f(1.0, 0.0, 0.0); glBegin(GL_POINTS); glVertex3fv(points[dyn_pt]); glEnd(); glPushMatrix(); glLoadIdentity(); glTranslatef(points[dyn_pt][0],points[dyn_pt][1],points[dyn_pt][2]); gluDisk(obj, 0.02, 0.03, 12, 12); gluDisk(obj, 0.04, 0.05, 12, 12); glPopMatrix(); } glFlush(); glutSwapBuffers(); } void moveit(void) { int i; /* Idle callback, show curve in motion */ dyn_pt++; if(dyn_pt>dyn_pt_max) dyn_pt = 0; dyn_val = dyn_val+dyn_val_inc; if(dyn_val>dyn_val_max) dyn_val = 0.0; glutPostRedisplay(); for(i=0; i<1;) /* at least 'tinc' second between updates */ { now = (double)clock()/(double)CLOCKS_PER_SEC; if(now>next) break; } next = now+tinc; } /* This routine handels mouse events */ static void mouse(int button, int state, int x, int y) { glutPostRedisplay(); } /* This routine handles window resizes */ void reshape(int w, int h) { width = w; height = h; /* Set the transformations */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.1, 1.1, -1.1, 1.3, -1.1, 1.1); glMatrixMode(GL_MODELVIEW); glViewport(0, 0, w, h); } void init() { curve_type = LISSAJOUS; param1 = 3.0; param2 = 5.0; n = max_pts; /* for drawing points*/ n_points = n; /* for drawing lines */ /* set clear color to white */ glClearColor (1.0, 1.0, 1.0, 0.0); /* set fill color to black */ glColor3f(0.0, 0.0, 0.0); now = (double)clock()/(double)CLOCKS_PER_SEC; tinc = 0.1; /* 1/10 second */ next = now+tinc; compute_curve(); } /* end init */ static void keyboard(unsigned char key, int x, int y) { switch (key) { case 'p': drawpts = 1 - drawpts; break; case 'd': dynamic = 1 - dynamic; if(dynamic) glutIdleFunc(moveit); else glutIdleFunc(NULL); break; } glutPostRedisplay(); } /* end keyboard */ static void special(int k, int x, int y) { switch(k) { case GLUT_KEY_LEFT: param2 = 0.75 * param2; break; case GLUT_KEY_RIGHT: param2 = 1.25 * param2; break; case GLUT_KEY_DOWN: param1 = 0.75 * param1; break; case GLUT_KEY_UP: param1 = 1.25 * param1; break; } compute_curve(); } static void ModeMenu(int entry) { if(entry==CYCLOID) { curve_type = CYCLOID; param1 = 2.0; /* abratio */ param2 = 10.0; /* cycles */ } else if(entry==SPIRAL) { curve_type = SPIRAL; param1 = 0.1; /* gap */ param2 = 1.0; /* rmax */ } else if(entry==LISSAJOUS) { curve_type = LISSAJOUS; param1 = 5.0; /* xcycles */ param2 = 7.0; /* ycycles */ } else if(entry==ROSE) { curve_type = ROSE; param1 = 4.0; /* cycles/2 */ param2 = 0.95; /* radius */ } else if(entry==HELIX3D) { curve_type = HELIX3D; param1 = 0.5; /* inner radius */ param2 = 10.0; /* cycles */ } else if(entry==TORSPIRAL3D) { curve_type = TORSPIRAL3D; param1 = 0.2; /* inner radius */ param2 = 0.8; /* outer radius */ /* gap later */ } else if(entry==DRAWPOINTS) { drawpts = 1 - drawpts; } else if(entry==DYNAMIC) { dynamic = 1 - dynamic; if(dynamic) glutIdleFunc(moveit); else glutIdleFunc(NULL); } else if(entry==BULLSEYE) { target_type = BULLSEYE; } else if(entry==TARGET) { target_type = TARGET; } else if(entry==TRAIL) { target_type = TRAIL; } else if(entry==SLOWER) { tinc = 2.0 * tinc; } else if(entry==FASTER) { tinc = 0.5 * tinc; } else if(entry==P1DOWN) { param1 = 0.75 * param1; } else if(entry==P1UP) { param1 = 1.25 * param1; } else if(entry==P2DOWN) { param2 = 0.75 * param2; } else if(entry==P2UP) { param2 = 1.25 * param2; } else if(entry==QUIT) { exit(0); } compute_curve(); } /* end ModeMenu */ void compute_curve() { if(curve_type==CYCLOID) cycloid(param1, param2, -1.0, 1.0, -1.0, 1.0, max_pts, points); if(curve_type==SPIRAL) spiral(param1, param2, max_pts, points); if(curve_type==LISSAJOUS) lissajous(param1, param2, 0.95, max_pts, points); if(curve_type==ROSE) rose(param1, param2, max_pts, points); if(curve_type==HELIX3D) helix(param1, param2, max_pts, points); if(curve_type==TORSPIRAL3D) toroidal_spiral(param1, param2, 20.0, max_pts, points); glutPostRedisplay(); } int main(int argc, char* argv[]) { glutInit(&argc,argv); glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(width, height); glutInitWindowPosition(100,10); glutCreateWindow(argv[0]); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutIdleFunc(NULL); glutKeyboardFunc(keyboard); glutSpecialFunc(special); glutCreateMenu(ModeMenu); glutAddMenuEntry("Cycloid", CYCLOID); glutAddMenuEntry("Spiral", SPIRAL); glutAddMenuEntry("Lissajous", LISSAJOUS); glutAddMenuEntry("Rose", ROSE); glutAddMenuEntry("3D Helix", HELIX3D); glutAddMenuEntry("3D Toroidal Spiral", TORSPIRAL3D); glutAddMenuEntry("Toggle draw points", DRAWPOINTS); glutAddMenuEntry("Toggle dynamic", DYNAMIC); glutAddMenuEntry("Dynamic bulls eye", BULLSEYE); glutAddMenuEntry("Dynamic target", TARGET); glutAddMenuEntry("Dynamic vapor trail", TRAIL); glutAddMenuEntry("Move slower", SLOWER); glutAddMenuEntry("Move faster", FASTER); glutAddMenuEntry("Parameter1 larger", P1UP); glutAddMenuEntry("Parameter1 smaller", P1DOWN); glutAddMenuEntry("Parameter2 larger", P2UP); glutAddMenuEntry("Parameter2 smaller", P2DOWN); glutAddMenuEntry("Quit", QUIT); glutAttachMenu(GLUT_LEFT_BUTTON); glutAttachMenu(GLUT_RIGHT_BUTTON); /* try both */ obj = gluNewQuadric(); gluQuadricDrawStyle(obj, GLU_FILL); init(); glutMainLoop(); return 0; } /* various curves, some with scaling */ void cycloid(float ab_ratio, float cycles, float xmin, float xmax, float ymin, float ymax, int npts, pts3 points[]) { /* ab_ratio of 1.0 tracks rim of rotating wheel, smaller inside */ float cx, cy, dt, t; float cxmin, cxmax, cymin, cymax, cxoff, cxsca, cyoff, cysca; float a; float b; int i; t = 4.0*M_PI*xmin; dt = 3.51*cycles*(xmax-xmin)/(float)npts; a = 1.0/(4.0*M_PI); b = ab_ratio * a; for(i=0; icxmax) cxmax = points[i][0]; if(points[i][1]cymax) cymax = points[i][1]; } cxsca = (xmax-xmin)/(cxmax-cxmin); cysca = (ymax-ymin)/(cymax-cymin); cxoff = xmin-cxmin*cxsca; cyoff = ymin-cymin*cysca; for(i=0; i