OpenGL and GLUT Review Daniel Ritchie Monday, October 3 rd, 2011
Outline Build Environment – Visual Studio – Xcode Structure of a GLUT application – Initialization – Callbacks Simple OpenGL drawing – Clearing – Specifying Vertices – Drawing Primitives
Getting Started with Visual Studio Get Visual Studio 2010 Professional – Students: full version at – Express Edition also okay Might also need to install Windows SDK Download and install GLUT – Details on wiki – GLUT_HowTo
Getting Started with Xcode developer.apple.com/tools/Xcode – (or App Store, if you run Lion) – Includes developer tools (gcc, gdb, etc.) and IDE Using Xcode IDE – Add reference to GLUT.framework Using Makefiles g++ -o myApp -framework GLUT -framework OpenGL myApp.cpp
Structure of a GLUT Application
GLUT Application Structure Typical #include s GLUT application main() function Callbacks – Display – Reshape – Mouse – Keyboard
Typical #include s // General: #include...
Typical #include s // General: #include...
Typical #include s - Windows // Windows users: #include... If using Windows headers, include them before GL, GLUT
Typical #include s - Windows // Windows users: #include... If using Windows headers, include them before GL, GLUT
Typical #include s - MacOS // MacOS X users: #include... GL, GLUT headers live in different directories
Typical #include s - MacOS // MacOS X users: #include... GL, GLUT headers live in different directories
GLUT main() function - initialization int main(int argc, char *argv[]) { // Allow GLUT to “intercept” command-line arguments: glutInit( &argc, argv ); // Read your own command-line arguments... // Set GLUT options and create window: glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH ); glutInitWindowPosition(20, 20); glutInitWindowSize(640, 480); glutCreateWindow(“Window Title”);... }
glutInitDisplayMode(unsigned int mode) “or” together various flags for mode – GLUT_RGBA Can also use GLUT_INDEX – GLUT_ALPHA Request an alpha channel in frame buffer – GLUT_DEPTH, GLUT_STENCIL, GLUT_ACCUM Request additional buffers Depth buffer very useful for 3D drawing – GLUT_SINGLE, GLUT_DOUBLE Choose single (default) or double-buffering – GLUT_MULTISAMPLE, GLUT_STEREO Even more advanced options!
GLUT main() – register callbacks int main(int argc, char *arv[]) { // Initialize //you define these callbacks above in main.cpp glutDisplayFunc( &MyDisplayCallback ); glutReshapeFunc( &MyReshapeCallback ); glutKeyboardFunc( &MyKeyboardCallback ); glutMouseFunc( &MyMouseCallback );... }
GLUT main() – enter main loop int main(int argc, char *arv[]) { // Initialize... // Register callbacks glutMainLoop(); // Finalize... return 0; } Runs “forever” … until Close window Call exit() Crash
GLUT callbacks Allow your code to respond to events – Keyboard, mouse, etc. Ordinary C functions, just need correct signature Called from “inside” glutMainLoop() You will need some globals… – Textures, resources, animation parameters, etc. – Globals are Evil, but *some* unavoidable with GLUT – IDEAL: Package up in a C++ object/struct (i.e. “State” class or “Controller” class)
Display Callback void MyDisplayCallback(void){…} – Called to redraw contents of window Only called when window system decides – Need to force redraw? glutPostRedisplay() Steps: 1) Clear window 2) Perform any updates on state before drawing 3) Use GL to draw 4) Make drawing visible to user – glFlush() if using GLUT_SINGLE – glutSwapBuffers() if using GLUT_DOUBLE
Reshape Callback void MyReshapeCallback(int w, int h) { // Save width and height to global variables gWidth = w; gHeight = h; // Update OpenGL viewport to cover whole window: glViewport( 0, 0, w, h ); // Update OpenGL projection matrix: glMatrixMode( GL_PROJECTION ); glLoadIdentity(); gluOrtho2D(0, w, 0, h); // more on next slide... // Tell GLUT to draw the window: glutPostRedisplay(); }
Setting the projection matrix gluOrtho2D(-1, 1, -1, 1) – Drawing in 2D – (0,0) is at center of screen gluOrtho2D(0, w, 0, h) – 2D drawing with exact pixel coordinates gluPerspective(fov, (float) w / h, near, far) – 3D drawing with pinhole camera – fov is field of view in degrees (try 60) – (float) w / h is aspect ratio – near, far distances determine visible range Precision increases when range is smaller
Keyboard Callback void MyKeyboardCallback(unsigned char key, int x, int y) { // (x,y) tells where mouse when when key pressed switch(key) { case ‘a’:... case ‘q’: exit(0); break; default: } // If state was updated, tell GLUT to re-draw the window glutPostRedisplay(); } Arrow, Function keys handled by glutSpecialFunc Shift, Ctrl, etc. can be determined by glutGetModifiers
Mouse Button Callback void MyMouseCallback(int button, int state, int x, int y){…} button is one of GLUT_{LEFT, RIGHT, MIDDLE}_BUTTON state is one of GLUT_UP, GLUT_DOWN Beware: mouse coordinates might not match your GL coordinates Assignment 1 Default Setup (0,0) (0,1) (1,0) GLUT mouse (0,0) (0,h) (0,w) (w,h) (1,1)
Simple OpenGL Drawing
Clearing Simplest case: Clear window to a solid color Do this before rendering anything else If doing 3D with GLUT_DEPTH, probably want: glClearColor(r, g, b, a); glClear(GL_COLOR_BUFFER_BIT); glClearColor(r, g, b, a); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
Drawing Primitives Pick type of primitive you want to draw, and begin: Submit zero or more vertices: End the primitive: glBegin(GL_LINES); glVertex2f(0, 0); glVertex2f(1, 1); // First line. glVertex2f(0, 0); glVertex2f(1, 1); // Second line. glEnd();
Submitting Vertices Each call to glVertex submits a new vertex Actually a family of functions The main ones you will need are: Position of new vertex specified with arguments Other attributes must be set separately… glVertex2f(float x, float y); glVertex3f(float x, float y, float z);
Vertex Attributes Every vertex can have many attributes – Position and color are enough for assignment 1 Position is specified with glVertex arguments Color and other attributes specified separately Color of new vertex comes from most recent glColor glColor4f(float r, float g, float b, float a);
Primitive Types glBegin(???); glVertex2f(0.0, 0.0); glVertex2f(0.5, 0.0); glVertex2f(0.75, 0.5); glVertex2f(1.0, 1.0); glVertex2f(0.5, 1.0); glVertex2f(0.0, 0.5); glEnd(); (0,0) (0,1) (1,0) (1,1)
Primitive Types - Points glBegin(GL_POINTS); glVertex2f(0.0, 0.0); glVertex2f(0.5, 0.0); glVertex2f(0.75, 0.5); glVertex2f(1.0, 1.0); glVertex2f(0.5, 1.0); glVertex2f(0.0, 0.5); glEnd(); (0,0) (0,1) (1,0) (1,1)
Primitive Types - Lines glBegin(GL_LINES); glVertex2f(0.0, 0.0); glVertex2f(0.5, 0.0); glVertex2f(0.75, 0.5); glVertex2f(1.0, 1.0); glVertex2f(0.5, 1.0); glVertex2f(0.0, 0.5); glEnd(); (0,0) (0,1) (1,0) (1,1)
Primitive Types – Line Strip glBegin(GL_LINE_STRIP); glVertex2f(0.0, 0.0); glVertex2f(0.5, 0.0); glVertex2f(0.75, 0.5); glVertex2f(1.0, 1.0); glVertex2f(0.5, 1.0); glVertex2f(0.0, 0.5); glEnd(); (0,0) (0,1) (1,0) (1,1)
Primitive Types – Line Loop glBegin(GL_LINE_LOOP); glVertex2f(0.0, 0.0); glVertex2f(0.5, 0.0); glVertex2f(0.75, 0.5); glVertex2f(1.0, 1.0); glVertex2f(0.5, 1.0); glVertex2f(0.0, 0.5); glEnd(); (0,0) (0,1) (1,0) (1,1)
Primitive Types – Triangles glBegin(GL_TRIANGLES); glVertex2f(0.0, 0.0); glVertex2f(0.5, 0.0); glVertex2f(0.75, 0.5); glVertex2f(1.0, 1.0); glVertex2f(0.5, 1.0); glVertex2f(0.0, 0.5); glEnd(); (0,0) (0,1) (1,0) (1,1)
Primitive Types – Polygon glBegin(GL_POLYGON); glVertex2f(0.0, 0.0); glVertex2f(0.5, 0.0); glVertex2f(0.75, 0.5); glVertex2f(1.0, 1.0); glVertex2f(0.5, 1.0); glVertex2f(0.0, 0.5); glEnd(); (0,0) (0,1) (1,0) (1,1)
Working with the OpenGL Machine OpenGL is a state machine – GL commands trigger state transitions, actions Your program is generating the input string – Effectively constructing GL program on the fly This means conditionals or loops in your program are not seen by OpenGL. You can use this to your advantage to structure your program
Examples Put a loop inside a glBegin / glEnd pair: Conditionally set pieces of state: // Draw a circle. glBegin(GL_LINE_LOOP); for(int i = 0; i < 100; ++i) { float theta = 2*PI*(i / 100.0f); glVertex2f(cosf(theta), sinf(theta)); } glEnd(); // Draw selected shape in red. if(shape == gSelectedShape) { glColor3f(1, 0, 0); } glBegin(...);
Questions?