/* viewports.c - Jon McCormack, March 2004 */ /* Program to demonstrate the use of multiple viewports. * displays the stars from the displayList program into multiple * viewports. Also shows how to use tessellation using glu. * The left viewport uses GL_LINE_LOOPS, the right GL_POLYGONS * created by tessellating the stars vertices (recall that the star vertices * form a convex polygon. * * As an extension try to colour the background of each viewport a * different colour. Also try to label each viewport with different text, * e.g. "viewport 1" and "viewport 2". * */ /* Copyright 2004 Jon McCormack * Last modified 23 March 2004 * Updated 29 March 2004: Removed platform specific dependencies * Updated 28 March 2006: Removed redundant viewport command */ #include #include #include #ifdef __APPLE__ #include #else #include #endif #include "tessellation.h" #define INNER_RADIUS 0.3 /* star inner radius */ #define OUTER_RADIUS 1.0 /* star outer radius */ #define NUM_STAR_POINTS 8 /* number of points on the star */ #define NUM_STARS 8 /* number of stars in the animation */ #define ROT_INC 0.1 /* how much to rotate each frame */ #define STAR_IDX 1 /* display list for the star */ /* * local static variables: g_rotate used to keep track of global rotation * g_rotInc is the rotation increment each frame * g_w and g_h store window width and height */ static GLfloat g_rotate = 0; static GLfloat g_rotInc = ROT_INC; /* degree increment for rotation animation */ static GLsizei g_w, g_h; /* * defineStarVertices * * Create star vertices with an inner radius, outer radius * and number of points. Note that this creates non-simple polygons. * The function returns a list of vertices representing the star. * NOTE it is the responsibility of the calling function to free the * allocated space when finished with the vertices. * */ GLdouble * * defineStarVertices(GLdouble inner, GLdouble outer, int numPoints) { GLdouble step = M_PI * 2.0 / (GLfloat)(2 * numPoints); register int i; GLdouble angle, r; GLdouble ** verts = malloc(sizeof(GLdouble *) * numPoints * 2); /* alloc space for the vertices */ for (i = 0; i < numPoints * 2; ++i) verts[i] = malloc(sizeof(GLdouble) * 3); for (i = 0; i < numPoints * 2; ++i) { r = (i % 2 == 0 ? inner : outer); angle = i * step; verts[i][0] = r * cos(angle); verts[i][1] = r * sin(angle); verts[i][2] = 0.0; } return verts; } /* * displayStars * * Display a set of stars using the display list index provided as * a parameter. * */ void displayStars(GLuint listIndex) { register int i; register GLfloat c; /* used to change color of each star */ /* set matrix mode to modelview */ glMatrixMode(GL_MODELVIEW); glLoadIdentity(); for (i = 0; i < NUM_STARS; ++i) { /* save matrix */ glPushMatrix(); /* draw the stars in a large circle */ glRotatef(360.0/NUM_STARS * i, 0, 0, 1); glTranslatef(OUTER_RADIUS, 0,0); /* this command does the animated rotation of each star */ glRotatef(g_rotate + (3 * i), 0, 0, 1); /* make each star a different colour */ c = 1.0/NUM_STARS * (GLfloat)i; glColor3f(1.0 - c, 0.0, c); /* call the display list - which draws the star */ glCallList(listIndex); /* restore modelview matrix */ glPopMatrix(); } } /* * display * * called by GLUT. Clear the entire display window, then draws the two * stars in their own viewports. Note that the viewport boundry is not shown */ void display() { glClear(GL_COLOR_BUFFER_BIT); /* clear entire screen */ glViewport(0, 0, g_w/2, g_h); /* left viewport shows GL_LINE_LOOP stars */ displayStars(STAR_IDX); glViewport(g_w/2, 0, g_w/2, g_h); /* right viewport shows polygons */ displayStars(STAR_IDX + 1); glFlush(); /* force OpenGL output */ glutSwapBuffers(); } /* * myReshape * * This function is called whenever the user (or OS) reshapes the * OpenGL window. The GLUT sends the new window dimensions (x,y) * */ void myReshape(int w, int h) { /* save new width and height */ g_w = w; g_h = h; w /= 2; /* * set viewing window in world coordinates */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); /* init projection matrix */ if (w <= h) glOrtho(-2.0, 2.0, -2.0 * (GLfloat) h / (GLfloat) w, 2.0 * (GLfloat) h / (GLfloat) w, -1.0, 1.0); else glOrtho(-2.0 * (GLfloat) w / (GLfloat) h, 2.0 * (GLfloat) w / (GLfloat) h, -2.0, 2.0, -1.0, 1.0); /* set matrix mode to modelview */ glMatrixMode(GL_MODELVIEW); } /* * myKey * * responds to key presses from the user */ void myKey(unsigned char k, int x, int y) { switch (k) { case 'q': case 'Q': exit(0); break; default: printf("Unknown keyboard command \'%c\'.\n", k); break; } } /* * myMouse * * function called by the GLUT when the user presses a mouse button * * Here we increment the global rotation rate with each press - left to do a * positive increment, right for negative, middle to reset */ void myMouse(int btn, int state, int x, int y) { if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN) g_rotInc += ROT_INC; if(btn==GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) g_rotInc = ROT_INC; if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) g_rotInc -= ROT_INC; /* force redisplay */ glutPostRedisplay(); } /* * myIdleFunc * * increments the rotation variable within glutMainLoop */ void myIdleFunc(void) { g_rotate += g_rotInc; /* force glut to call the display function */ glutPostRedisplay(); } /* * myInit * * Perform OpenGL initialization, define display lists, perform tessellation * */ void myInit() { GLdouble ** verts; /* pointer to store vertex list of star */ int i; /* set clear colour */ glClearColor(1.0, 1.0, 1.0, 1.0); /* set current colour to black */ glColor3f(0.0, 0.0, 0.0); /* create star vertices */ verts = defineStarVertices(INNER_RADIUS, OUTER_RADIUS, NUM_STAR_POINTS); /* initialize tessellator */ initTessellator(0); /* create star display lists */ /* first star using LINE_LOOPS */ glNewList(STAR_IDX,GL_COMPILE); glBegin(GL_LINE_LOOP); for (i=0; i < NUM_STAR_POINTS * 2; i++) glVertex3dv(verts[i]); glEnd(); glEndList(); /* now define list as tessellated polygons */ glNewList(STAR_IDX+1,GL_COMPILE); performTess(verts, NUM_STAR_POINTS * 2); glEndList(); /* free space allocated by defineStarVertices */ for (i=0; i < NUM_STAR_POINTS * 2; i++) free(verts[i]); free(verts); } /* * main * * Initialization and sets graphics callbacks * */ int main(int argc, char **argv) { /* glutInit MUST be called before any other GLUT/OpenGL calls */ glutInit(&argc, argv); /* need both double buffering and z buffer */ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutInitWindowSize(800, 400); g_w = 800, g_h = 400; /* store current window size */ glutCreateWindow("Two Viewports"); /* set callback functions */ glutReshapeFunc(myReshape); glutDisplayFunc(display); glutIdleFunc(myIdleFunc); glutKeyboardFunc(myKey); glutMouseFunc(myMouse); myInit(); glutMainLoop(); /* never exits */ return 0; }