An Introduction On OpenGL With 2D Graphics - OpenGL Tutorial
An Introduction On OpenGL With 2D Graphics - OpenGL Tutorial
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
OpenGL Tutorial
An Introduction on
OpenGL with 2D
Graphics
1.Setting Up OpenGL
1.1Example 1: Setting Up OpenGL and GLUT
2.Introduction
3.Vertex, Primitive and Color
3.1Example 2: Vertex, Primitive and Color
3.2OpenGL as a State Machine
3.3Naming Convention for OpenGL Functions
3.4Onetime Initialization initGL()
3.5Callback Handler display()
3.6Setting up GLUT main()
3.7Color
3.8Geometric Primitives
3.92D Coordinate System and the Default View
1.Setting Up OpenGL
To set up OpenGL, depending on your programming platform, read:
How to write OpenGL programs in C/C++.
How to write OpenGL programs in Java: JOGL or LWJGL.
How to write OpenGL|ES programs in Android.
6.Animation
6.1Idle Function
6.2Double Buffering
6.3Example 5: Animation using Idle Function
Make sure that you can run the "GL01Hello.cpp" described in "How to write
1
2
3
4
5
6
7
8
9
10
/*
*GL01Hello.cpp:TestOpenGL/GLUTC/C++Setup
*TestedunderEclipseCDTwithMinGW/CygwinandCodeBlockswithMinGW
*Tocompilewithlfreeglutlglu32lopengl32
*/
#include<windows.h>//forMSWindows
#include<GL/glut.h>//GLUT,includeglu.handgl.h
/*Handlerforwindowrepaintevent.Callbackwhenthewindowfirstappearsand
wheneverthewindowneedstoberepainted.*/
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
1/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
voiddisplay(){
glClearColor(0.0f,0.0f,0.0f,1.0f);//Setbackgroundcolortoblackandopaque
glClear(GL_COLOR_BUFFER_BIT);//Clearthecolorbuffer(background)
//DrawaRed1x1Squarecenteredatorigin
glBegin(GL_QUADS);//Eachsetof4verticesformaquad
glColor3f(1.0f,0.0f,0.0f);//Red
glVertex2f(0.5f,0.5f);//x,y
glVertex2f(0.5f,0.5f);
glVertex2f(0.5f,0.5f);
glVertex2f(0.5f,0.5f);
glEnd();
glFlush();//Rendernow
}
/*Mainfunction:GLUTrunsasaconsoleapplicationstartingatmain()*/
intmain(intargc,char**argv){
glutInit(&argc,argv);//InitializeGLUT
glutCreateWindow("OpenGLSetupTest");//Createawindowwiththegiventitle
glutInitWindowSize(320,320);//Setthewindow'sinitialwidth&height
glutInitWindowPosition(50,50);//Positionthewindow'sinitialtopleftcorner
glutDisplayFunc(display);//Registerdisplaycallbackhandlerforwindowrepaint
glutMainLoop();//Entertheeventprocessingloop
return0;
}
#include<windows.h>
We also included the GLUT header, which is guaranteed to include "glu.h" for GL Utility and "gl.h" for Core
OpenGL.
The rest of the program will be explained in due course.
2.Introduction
OpenGL Open Graphics Library is a crossplatform, hardwareaccelerated, languageindependent, industrial standard
API for producing 3D including 2D graphics. Modern computers have dedicated GPU Graphics Processing Unit with
its own memory to speed up graphics rendering. OpenGL is the software interface to graphics hardware. In other
words, OpenGL graphic rendering commands issued by your applications could be directed to the graphic hardware
and accelerated.
We use 3 sets of libraries in our OpenGL programs:
1. Core OpenGL GL : consists of hundreds of commands, which begin with a prefix "gl" e.g., glColor,
glVertex, glTranslate, glRotate. The Core OpenGL models an object via a set of geometric primitives such as
point, line and polygon.
2. OpenGL Utility Library GLU : built ontop of the core OpenGL to provide important utilities such as
setting camera view and projection and more building models such as qradric surfaces and polygon
tessellation. GLU commands start with a prefix "glu" e.g., gluLookAt, gluPerspective.
3. OpenGL Utilities Toolkit GLUT : OpenGL is designed to be independent of the windowing system or
operating system. GLUT is needed to interact with the Operating System such as creating a window, handling key
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
2/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
and mouse inputs; it also provides more building models such as sphere and torus. GLUT commands start with
a prefix of "glut" e.g., glutCreatewindow, glutMouseFunc. GLUT is platform independent, which is built on
top of platformspecific OpenGL extension such as GLX for X Window System, WGL for Microsoft Window, and
AGL, CGL or Cocoa for Mac OS.
Quoting from the opengl.org: "GLUT is designed for constructing small to medium sized OpenGL programs.
While GLUT is wellsuited to learning OpenGL and developing simple OpenGL applications, GLUT is not a full
featured toolkit so large applications requiring sophisticated user interfaces are better off using native window
system toolkits. GLUT is simple, easy, and small."
Alternative of GLUT includes SDL, ....
4. OpenGL Extension Wrangler Library GLEW : "GLEW is a crossplatform opensource C/C++
extension loading library. GLEW provides efficient runtime mechanisms for determining which OpenGL
extensions are supported on the target platform." Source and prebuild binary available at
http://glew.sourceforge.net/. A standalone utility called "glewinfo.exe" under the "bin" directory can be used
to produce the list of OpenGL functions supported by your graphics system.
5. Others.
/*
*GL02Primitive.cpp:Vertex,PrimitiveandColor
*DrawSimple2DcoloredShapes:quad,triangleandpolygon.
*/
#include<windows.h>//forMSWindows
#include<GL/glut.h>//GLUT,includeglu.handgl.h
/*InitializeOpenGLGraphics*/
voidinitGL(){
//Set"clearing"orbackgroundcolor
glClearColor(0.0f,0.0f,0.0f,1.0f);//Blackandopaque
}
/*Handlerforwindowrepaintevent.Callbackwhenthewindowfirstappearsand
wheneverthewindowneedstoberepainted.*/
voiddisplay(){
glClear(GL_COLOR_BUFFER_BIT);//Clearthecolorbufferwithcurrentclearingcolor
//DefineshapesenclosedwithinapairofglBeginandglEnd
glBegin(GL_QUADS);//Eachsetof4verticesformaquad
glColor3f(1.0f,0.0f,0.0f);//Red
glVertex2f(0.8f,0.1f);//Defineverticesincounterclockwise(CCW)order
glVertex2f(0.2f,0.1f);//sothatthenormal(frontface)isfacingyou
glVertex2f(0.2f,0.7f);
glVertex2f(0.8f,0.7f);
glColor3f(0.0f,1.0f,0.0f);//Green
glVertex2f(0.7f,0.6f);
glVertex2f(0.1f,0.6f);
glVertex2f(0.1f,0.0f);
glVertex2f(0.7f,0.0f);
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
3/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
glColor3f(0.2f,0.2f,0.2f);//DarkGray
glVertex2f(0.9f,0.7f);
glColor3f(1.0f,1.0f,1.0f);//White
glVertex2f(0.5f,0.7f);
glColor3f(0.2f,0.2f,0.2f);//DarkGray
glVertex2f(0.5f,0.3f);
glColor3f(1.0f,1.0f,1.0f);//White
glVertex2f(0.9f,0.3f);
glEnd();
glBegin(GL_TRIANGLES);//Eachsetof3verticesformatriangle
glColor3f(0.0f,0.0f,1.0f);//Blue
glVertex2f(0.1f,0.6f);
glVertex2f(0.7f,0.6f);
glVertex2f(0.4f,0.1f);
glColor3f(1.0f,0.0f,0.0f);//Red
glVertex2f(0.3f,0.4f);
glColor3f(0.0f,1.0f,0.0f);//Green
glVertex2f(0.9f,0.4f);
glColor3f(0.0f,0.0f,1.0f);//Blue
glVertex2f(0.6f,0.9f);
glEnd();
glBegin(GL_POLYGON);//Theseverticesformaclosedpolygon
glColor3f(1.0f,1.0f,0.0f);//Yellow
glVertex2f(0.4f,0.2f);
glVertex2f(0.6f,0.2f);
glVertex2f(0.7f,0.4f);
glVertex2f(0.6f,0.6f);
glVertex2f(0.4f,0.6f);
glVertex2f(0.3f,0.4f);
glEnd();
glFlush();//Rendernow
}
/*Mainfunction:GLUTrunsasaconsoleapplicationstartingatmain()*/
intmain(intargc,char**argv){
glutInit(&argc,argv);//InitializeGLUT
glutCreateWindow("Vertex,Primitive&Color");//Createwindowwiththegiventitle
glutInitWindowSize(320,320);//Setthewindow'sinitialwidth&height
glutInitWindowPosition(50,50);//Positionthewindow'sinitialtopleftcorner
glutDisplayFunc(display);//Registercallbackhandlerforwindowrepaintevent
initGL();//OurownOpenGLinitialization
glutMainLoop();//Entertheeventprocessingloop
return0;
}
The expected output and the coordinates are as follows. Take note that 4 shapes have pure color, and 2 shapes have
color blending from their vertices.
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
4/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
//Indisplay(),clearthecolorbuffer(i.e.,setbackground)withthecurrent"clearing"color
glClear(GL_COLOR_BUFFER_BIT);
Another example: If we use glColor function to set the current foreground color to "red", then "red" will be used for all
the subsequent vertices, until we use another glColor function to change the foreground color.
In a state machine, everything shall remain until you explicitly change it!
5/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
returnTypeglFunction[234][sifd](typevalue,...);//2,3or4parameters
returnTypeglFunction[234][sifd]v(type*value);//anarrayparameter
The function may take 2, 3, or 4 parameters, in type of s GLshort, i GLint, f GLfloat or d GLdouble. The 'v' for
vector denotes that the parameters are kept in an array of 2, 3, or 4 elements, and pass into the function as an array
pointer.
OpenGL defines its own data types:
Signed Integers: GLbyte 8bit, GLshort 16bit, GLint 32bit.
Unsigned Integers: GLubyte 8bit, GLushort 16bit, GLuint 32bit.
Floatingpoint numbers: GLfloat 32bit, GLdouble 64bit, GLclampf and GLclampd between 0.0 and 1.0.
GLboolean unsigned char with 0 for false and non0 for true.
GLsizei 32bit nonnegative integers.
GLenum 32bit enumerated integers.
The OpenGL types are defined via typedef in "gl.h" as follows:
typedefunsignedintGLenum;
typedefunsignedcharGLboolean;
typedefunsignedintGLbitfield;
typedefvoidGLvoid;
typedefsignedcharGLbyte;/*1bytesigned*/
typedefshortGLshort;/*2bytesigned*/
typedefintGLint;/*4bytesigned*/
typedefunsignedcharGLubyte;/*1byteunsigned*/
typedefunsignedshortGLushort;/*2byteunsigned*/
typedefunsignedintGLuint;/*4byteunsigned*/
typedefintGLsizei;/*4bytesigned*/
typedeffloatGLfloat;/*singleprecisionfloat*/
typedeffloatGLclampf;/*singleprecisionfloatin[0,1]*/
typedefdoubleGLdouble;/*doubleprecisionfloat*/
typedefdoubleGLclampd;/*doubleprecisionfloatin[0,1]*/
OpenGL's constants begins with "GL_", "GLU_" or "GLUT_", in uppercase separated with underscores, e.g.,
GL_COLOR_BUFFER_BIT.
For examples,
glVertex3f(1.1f,2.2f,3.3f);//3GLfloatparameters
glVertex2i(4,5);//2GLintparamaters
glColor4f(0.0f,0.0f,0.0f,1.0f);//4GLfloatparameters
GLdoubleaVertex[]={1.1,2.2,3.3};
glVertex3fv(aVertex);//anarrayof3GLfloatvalues
6/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
window e.g., window first appears, window is restored after minimized, and window is resized. Callback means that
the function is invoked by the system, instead of called by the your program.
The Display() runs when the window first appears and once per subsequent repaint request. Observe that we
included OpenGL graphics rendering code inside the display() function, so as to redraw the entire window when the
window first appears and upon each repaint request.
glutInitWindowPosition: positions the topleft corner of the initial window at x, y. The coordinates x, y, in
term of pixels, is measured in window coordinates, i.e., origin 0, 0 is at the topleft corner of the screen; xaxis
pointing right and yaxis pointing down.
voidglutInitWindowPosition(intx,inty)
glutDisplayFunc: registers the callback function or event handler for handling windowpaint event. The OpenGL
graphic system calls back this handler when it receives a window repaint request. In the example, we register the
function display() as the handler.
voidglutDisplayFunc(void(*func)(void))
glutMainLoop: enters the infinite eventprocessing loop, i.e, put the OpenGL graphics system to wait for events
such as repaint, and trigger respective event handlers such as display().
voidglutMainLoop()
We initialize the GLUT and create a window with a title, an initial size and position.
glutDisplayFunc(display);
We register display() function as the callback handler for windowpaint event. That is, display() runs when the
window first appears and whenever there is a request to repaint the window.
initGL();
We call the initGL() to perform all the onetime initialization operations. In this example, we set the clearing
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
7/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
We then put the program into the eventhandling loop, awaiting for events such as windowpaint request to trigger
off the respective event handlers such as display().
3.7Color
We use glColor function to set the foreground color, and glClearColor function to set the background or clearing
color.
voidglColor3f(GLfloatred,GLfloatgreen,GLfloatblue)
voidglColor3fv(GLfloat*colorRGB)
voidglColor4f(GLfloatred,GLfloatgreen,GLfloatblue,GLfloatalpha)
voidglColor4fv(GLfloat*colorRGBA)
voidglClearColor(GLclampfred,GLclampfgreen,GLclampfblue,GLclampfalpha)
//GLclampfintherangeof0.0fto1.0f
Notes:
Color is typically specified in float in the range 0.0f and 1.0f.
Color can be specified using RGB RedGreenBlue or RGBA RedGreenBlueAlpha components. The 'A' or
alpha specifies the transparency or opacity index, with value of 1 denotes opaque nontransparent and cannot
seethru and value of 0 denotes total transparent. We shall discuss alpha later.
In the above example, we set the background color via glClearColor in initGL(), with R=0, G=0, B=0 black and
A=1 opaque and cannot see through.
//IninitGL(),setthe"clearing"orbackgroundcolor
glClearColor(0.0f,0.0f,0.0f,1.0f);//Blackandopague
In display(), we set the vertex color via glColor3f for subsequent vertices. For example, R=1, G=0, B=0 red.
//Indisplay(),settheforegroundcolorofthepixel
glColor3f(1.0f,0.0f,0.0f);//Red
3.8Geometric Primitives
In OpenGL, an object is made up of geometric primitives such as triangle, quad, line segment and point. A primitive is
made up of one or more vertices. OpenGL supports the following primitives:
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
8/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
A geometric primitive is defined by specifying its vertices via glVertex function, enclosed within a pair glBegin and
glEnd.
voidglBegin(GLenumshape)
voidglVertex[234][sifd](typex,typey,typez,...)
voidglVertex[234][sifd]v(type*coords)
voidglEnd()
glBegin specifies the type of geometric object, such as GL_POINTS, GL_LINES, GL_QUADS, GL_TRIANGLES, and
GL_POLYGON. For types that end with 'S', you can define multiple objects of the same type in each glBegin/glEnd pair.
For example, for GL_TRIANGLES, each set of three glVertex's defines a triangle.
The vertices are usually specified in float precision. It is because integer is not suitable for trigonometric operations
needed to carry out transformations such as rotation. Precision of float is sufficient for carrying out intermediate
operations, and render the objects finally into pixels on screen with resolution of says 800x600, integral precision.
double precision is often not necessary.
In the above example:
glBegin(GL_QUADS);
....4quadswith12xglVertex()....
glEnd();
9/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
glVertex2f(0.2f,0.1f);
glVertex2f(0.2f,0.7f);
glVertex2f(0.8f,0.7f);
We set the color to red R=1, G=0, B=0. All subsequent vertices will have the color of red. Take note that in OpenGL,
color and many properties is applied to vertices rather than primitive shapes. The color of the a primitive shape is
interpolated from its vertices.
We similarly define a second quad in green.
For the third quad as follows, the vertices have different color. The color of the quad surface is interpolated from its
vertices, resulting in a shades of white to dark gray, as shown in the output.
glColor3f(0.2f,0.2f,0.2f);//DarkGray
glVertex2f(0.9f,0.7f);
glColor3f(1.0f,1.0f,1.0f);//White
glVertex2f(0.5f,0.7f);
glColor3f(0.2f,0.2f,0.2f);//DarkGray
glVertex2f(0.5f,0.3f);
glColor3f(1.0f,1.0f,1.0f);//White
glVertex2f(0.9f,0.3f);
The default OpenGL 2D clippingarea i.e., what is captured by the camera is an orthographic view with x and y in the
range of 1.0 and 1.0, i.e., a 2x2 square with centered at the origin. This clippingarea is mapped to the viewport on the
screen. Viewport is measured in pixels.
Study the above example to convince yourself that the 2D shapes created are positioned correctly on the screen.
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
10/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
Clipping Area : Clipping area refers to the area that can be seen i.e., captured by the camera, measured in OpenGL
coordinates.
The function gluOrtho2D can be used to set the clipping area of 2D orthographic view. Objects outside the clipping
area will be clipped away and cannot be seen.
voidgluOrtho2D(GLdoubleleft,GLdoubleright,GLdoublebottom,GLdoubletop)
//Thedefaultclippingareais(1.0,1.0,1.0,1.0)inOpenGLcoordinates,
//i.e.,2x2squarecenteredattheorigin.
To set the clipping area, we need to issue a series of commands as follows: we first select the socalled projection
matrix for operation, and reset the projection matrix to identity. We then choose the 2D orthographic view with the
desired clipping area, via gluOrtho2D().
//Setto2Dorthographicprojectionwiththespecifiedclippingarea
glMatrixMode(GL_PROJECTION);//SelecttheProjectionmatrixforoperation
glLoadIdentity();//ResetProjectionmatrix
gluOrtho2D(1.0,1.0,1.0,1.0);//Setclippingarea'sleft,right,bottom,top
Viewport : Viewport refers to the display area on the window screen, which is measured in pixels in screen
coordinates excluding the title bar.
The clipping area is mapped to the viewport. We can use glViewport function to configure the viewport.
voidglViewport(GLintxTopLeft,GLintyTopLeft,GLsizeiwidth,GLsizeiheight)
Suppose the the clipping area's left, right, bottom, top is 1.0, 1.0, 1.0, 1.0 in OpenGL coordinates and the
viewport's xTopLeft, xTopRight, width, height is 0, 0, 640, 480 in screen coordinates in pixels, then the bottomleft
corner 1.0, 1.0 maps to 0, 0 in the viewport, the topright corner 1.0, 1.0 maps to 639, 479. It is obvious that if
the aspect ratios for the clipping area and the viewport are not the same, the shapes will be distorted.
Take note that in the earlier example, the windows' size of 320x320 has a square shape, with a aspect ratio consistent
with the default 2x2 squarish clippingarea.
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
11/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
/*
*GL03Viewport.cpp:ClippingareaandViewport
*Implementingreshapetoensuresameaspectratiobetweenthe
*clippingareaandtheviewport.
*/
#include<windows.h>//forMSWindows
#include<GL/glut.h>//GLUT,includeglu.handgl.h
/*InitializeOpenGLGraphics*/
voidinitGL(){
//Set"clearing"orbackgroundcolor
glClearColor(0.0f,0.0f,0.0f,1.0f);//Blackandopaque
}
voiddisplay(){
glClear(GL_COLOR_BUFFER_BIT);//Clearthecolorbufferwithcurrentclearingcolor
//DefineshapesenclosedwithinapairofglBeginandglEnd
glBegin(GL_QUADS);//Eachsetof4verticesformaquad
glColor3f(1.0f,0.0f,0.0f);//Red
glVertex2f(0.8f,0.1f);//Defineverticesincounterclockwise(CCW)order
glVertex2f(0.2f,0.1f);//sothatthenormal(frontface)isfacingyou
glVertex2f(0.2f,0.7f);
glVertex2f(0.8f,0.7f);
glColor3f(0.0f,1.0f,0.0f);//Green
glVertex2f(0.7f,0.6f);
glVertex2f(0.1f,0.6f);
glVertex2f(0.1f,0.0f);
glVertex2f(0.7f,0.0f);
glColor3f(0.2f,0.2f,0.2f);//DarkGray
glVertex2f(0.9f,0.7f);
glColor3f(1.0f,1.0f,1.0f);//White
glVertex2f(0.5f,0.7f);
glColor3f(0.2f,0.2f,0.2f);//DarkGray
glVertex2f(0.5f,0.3f);
glColor3f(1.0f,1.0f,1.0f);//White
glVertex2f(0.9f,0.3f);
glEnd();
glBegin(GL_TRIANGLES);//Eachsetof3verticesformatriangle
glColor3f(0.0f,0.0f,1.0f);//Blue
glVertex2f(0.1f,0.6f);
glVertex2f(0.7f,0.6f);
glVertex2f(0.4f,0.1f);
glColor3f(1.0f,0.0f,0.0f);//Red
glVertex2f(0.3f,0.4f);
glColor3f(0.0f,1.0f,0.0f);//Green
glVertex2f(0.9f,0.4f);
glColor3f(0.0f,0.0f,1.0f);//Blue
glVertex2f(0.6f,0.9f);
glEnd();
glBegin(GL_POLYGON);//Theseverticesformaclosedpolygon
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
12/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
glColor3f(1.0f,1.0f,0.0f);//Yellow
glVertex2f(0.4f,0.2f);
glVertex2f(0.6f,0.2f);
glVertex2f(0.7f,0.4f);
glVertex2f(0.6f,0.6f);
glVertex2f(0.4f,0.6f);
glVertex2f(0.3f,0.4f);
glEnd();
glFlush();//Rendernow
}
/*Handlerforwindowresizeevent.Calledbackwhenthewindowfirstappearsand
wheneverthewindowisresizedwithitsnewwidthandheight*/
voidreshape(GLsizeiwidth,GLsizeiheight){//GLsizeifornonnegativeinteger
//Computeaspectratioofthenewwindow
if(height==0)height=1;//Topreventdivideby0
GLfloataspect=(GLfloat)width/(GLfloat)height;
//Settheviewporttocoverthenewwindow
glViewport(0,0,width,height);
//Settheaspectratiooftheclippingareatomatchtheviewport
glMatrixMode(GL_PROJECTION);//TooperateontheProjectionmatrix
glLoadIdentity();//Resettheprojectionmatrix
if(width>=height){
//aspect>=1,settheheightfrom1to1,withlargerwidth
gluOrtho2D(1.0*aspect,1.0*aspect,1.0,1.0);
}else{
//aspect<1,setthewidthto1to1,withlargerheight
gluOrtho2D(1.0,1.0,1.0/aspect,1.0/aspect);
}
}
/*Mainfunction:GLUTrunsasaconsoleapplicationstartingatmain()*/
intmain(intargc,char**argv){
glutInit(&argc,argv);//InitializeGLUT
glutInitWindowSize(640,480);//Setthewindow'sinitialwidth&heightnonsquare
glutInitWindowPosition(50,50);//Positionthewindow'sinitialtopleftcorner
glutCreateWindow("ViewportTransform");//Createwindowwiththegiventitle
glutDisplayFunc(display);//Registercallbackhandlerforwindowrepaintevent
glutReshapeFunc(reshape);//Registercallbackhandlerforwindowresizeevent
initGL();//OurownOpenGLinitialization
glutMainLoop();//Entertheinfiniteeventprocessingloop
return0;
}
A reshape() function, which is called back when the window first appears and whenever the window is resized, can
be used to ensure consistent aspect ratio between clippingarea and viewport, as shown in the above example. The
graphics subsystem passes the window's width and height, in pixels, into the reshape().
GLfloataspect=(GLfloat)width/(GLfloat)height;
We compute the aspect ratio of the new resized window, given its new width and height provided by the graphics
subsystem to the callback function reshape().
glViewport(0,0,width,height);
We set the viewport to cover the entire new resized window, in pixels.
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
13/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
Try setting the viewport to cover only a quarter lowerright qradrant of the window via glViewport(0, 0,
width/2,height/2).
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if(width>=height){
gluOrtho2D(1.0*aspect,1.0*aspect,1.0,1.0);
}else{
gluOrtho2D(1.0,1.0,1.0/aspect,1.0/aspect);
}
We set the aspect ratio of the clipping area to match the viewport. To set the clipping area, we first choose the operate
on the projection matrix via glMatrixMode(GL_PROJECTION). OpenGL has two matrices, a projection matrix which
deals with camera projection such as setting the clipping area and a modelview matrix for transforming the objects
from their local spaces to the common world space. We reset the projection matrix via glLoadIdentity().
Finally, we invoke gluOrtho2D() to set the clipping area with an aspect ratio matching the viewport. The shorter side
has the range from 1 to +1, as illustrated below:
We need to register the reshape() callback handler with GLUT via glutReshapeFunc() in the main() as follows:
intmain(intargc,char**argv){
glutInitWindowSize(640,480);
......
glutReshapeFunc(reshape);
}
In the above main() function, we specify the initial window size to 640x480, which is nonsquarish. Try resizing the
window and observe the changes.
Note that the reshape() runs at least once when the window first appears. It is then called back whenever the window
is reshaped. On the other hand, the initGL() runs once and only once; and the display() runs in response to
window repaint request e.g., after the window is resized.
14/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
Instead, we could position each of the shapes by defining their vertices with respective to their own center called
model space or local space. We can then use translation and/or rotation to position the shapes at the desired locations
in the world space, as shown in the following revised display() function.
/*
*GL04ModelTransform.cpp:ModelTransformTranslationandRotation
*Transformprimitivesfromtheirmodelspacestoworldspace.
*/
#include<windows.h>//forMSWindows
#include<GL/glut.h>//GLUT,includeglu.handgl.h
/*InitializeOpenGLGraphics*/
voidinitGL(){
//Set"clearing"orbackgroundcolor
glClearColor(0.0f,0.0f,0.0f,1.0f);//Blackandopaque
}
/*Handlerforwindowrepaintevent.Callbackwhenthewindowfirstappearsand
wheneverthewindowneedstoberepainted.*/
voiddisplay(){
glClear(GL_COLOR_BUFFER_BIT);//Clearthecolorbuffer
glMatrixMode(GL_MODELVIEW);//TooperateonModelViewmatrix
glLoadIdentity();//Resetthemodelviewmatrix
glTranslatef(0.5f,0.4f,0.0f);//Translateleftandup
glBegin(GL_QUADS);//Eachsetof4verticesformaquad
glColor3f(1.0f,0.0f,0.0f);//Red
glVertex2f(0.3f,0.3f);//Defineverticesincounterclockwise(CCW)order
glVertex2f(0.3f,0.3f);//sothatthenormal(frontface)isfacingyou
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
glEnd();
glTranslatef(0.1f,0.7f,0.0f);//Translaterightanddown
glBegin(GL_QUADS);//Eachsetof4verticesformaquad
glColor3f(0.0f,1.0f,0.0f);//Green
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
glEnd();
glTranslatef(0.3f,0.2f,0.0f);//Translateleftanddown
glBegin(GL_QUADS);//Eachsetof4verticesformaquad
glColor3f(0.2f,0.2f,0.2f);//DarkGray
glVertex2f(0.2f,0.2f);
glColor3f(1.0f,1.0f,1.0f);//White
glVertex2f(0.2f,0.2f);
glColor3f(0.2f,0.2f,0.2f);//DarkGray
glVertex2f(0.2f,0.2f);
glColor3f(1.0f,1.0f,1.0f);//White
glVertex2f(0.2f,0.2f);
glEnd();
glTranslatef(1.1f,0.2f,0.0f);//Translaterightandup
glBegin(GL_TRIANGLES);//Eachsetof3verticesformatriangle
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
15/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
glColor3f(0.0f,0.0f,1.0f);//Blue
glVertex2f(0.3f,0.2f);
glVertex2f(0.3f,0.2f);
glVertex2f(0.0f,0.3f);
glEnd();
glTranslatef(0.2f,0.3f,0.0f);//Translaterightanddown
glRotatef(180.0f,0.0f,0.0f,1.0f);//Rotate180degree
glBegin(GL_TRIANGLES);//Eachsetof3verticesformatriangle
glColor3f(1.0f,0.0f,0.0f);//Red
glVertex2f(0.3f,0.2f);
glColor3f(0.0f,1.0f,0.0f);//Green
glVertex2f(0.3f,0.2f);
glColor3f(0.0f,0.0f,1.0f);//Blue
glVertex2f(0.0f,0.3f);
glEnd();
glRotatef(180.0f,0.0f,0.0f,1.0f);//Undopreviousrotate
glTranslatef(0.1f,1.0f,0.0f);//Translaterightanddown
glBegin(GL_POLYGON);//Theverticesformoneclosedpolygon
glColor3f(1.0f,1.0f,0.0f);//Yellow
glVertex2f(0.1f,0.2f);
glVertex2f(0.1f,0.2f);
glVertex2f(0.2f,0.0f);
glVertex2f(0.1f,0.2f);
glVertex2f(0.1f,0.2f);
glVertex2f(0.2f,0.0f);
glEnd();
glFlush();//Rendernow
}
/*Handlerforwindowresizeevent.Calledbackwhenthewindowfirstappearsand
wheneverthewindowisresizedwithitsnewwidthandheight*/
voidreshape(GLsizeiwidth,GLsizeiheight){//GLsizeifornonnegativeinteger
//Computeaspectratioofthenewwindow
if(height==0)height=1;//Topreventdivideby0
GLfloataspect=(GLfloat)width/(GLfloat)height;
//Settheviewporttocoverthenewwindow
glViewport(0,0,width,height);
//Settheaspectratiooftheclippingareatomatchtheviewport
glMatrixMode(GL_PROJECTION);//TooperateontheProjectionmatrix
glLoadIdentity();
if(width>=height){
//aspect>=1,settheheightfrom1to1,withlargerwidth
gluOrtho2D(1.0*aspect,1.0*aspect,1.0,1.0);
}else{
//aspect<1,setthewidthto1to1,withlargerheight
gluOrtho2D(1.0,1.0,1.0/aspect,1.0/aspect);
}
}
/*Mainfunction:GLUTrunsasaconsoleapplicationstartingatmain()*/
intmain(intargc,char**argv){
glutInit(&argc,argv);//InitializeGLUT
glutInitWindowSize(640,480);//Setthewindow'sinitialwidth&heightnonsquare
glutInitWindowPosition(50,50);//Positionthewindow'sinitialtopleftcorner
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
16/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
112
113
114
115
116
117
118
glutCreateWindow("ModelTransform");//Createwindowwiththegiventitle
glutDisplayFunc(display);//Registercallbackhandlerforwindowrepaintevent
glutReshapeFunc(reshape);//Registercallbackhandlerforwindowresizeevent
initGL();//OurownOpenGLinitialization
glutMainLoop();//Entertheinfiniteeventprocessingloop
return0;
}
glMatrixMode(GL_MODELVIEW);//Tooperateonmodelviewmatrix
glLoadIdentity();//Reset
Translation and rotation are parts of socalled model transform, which transform from the objects from the local space
or model space to the common world space. To carry out model transform, we set the matrix mode to modeview
matrix GL_MODELVIEW and reset the matrix. Recall that in the previous example, we set the matrix mode to projection
matrix GL_PROJECTION to set the clipping area.
OpenGL is operating as a state machine. That is, once a state is set, the value of the state persists until it is changed. In
other words, once the coordinates are translated or rotated, all the subsequent operations will be based on this
coordinates.
Translation is done via glTranslate function:
voidgltranslatef(GLfloatx,GLfloaty,GLfloatz)
//where(x,y,z)isthetranslationalvector
Take note that glTranslatef function must be placed outside the glBegin/glEnd, where as glColor can be placed
inside glBegin/glEnd.
Rotation is done via glRotatef function:
voidglRotatef(GLfloatangle,GLfloatx,GLfloaty,GLfloatz)
//whereanglespecifiestherotationindegree,(x,y,z)formstheaxisofrotation.
Take note that the rotational angle is measured in degrees instead of radians in OpenGL.
In the above example, we translate within the xy plane z=0 and rotate about the zaxis which is normal to the xy
plane.
6.Animation
6.1Idle Function
To perform animation e.g., rotating the shapes, you could register an idle() callback handler with GLUT, via
glutIdleFunc command. The graphic system will call back the idle() function when there is no other event to be
processed.
voidglutIdleFunc(void(*func)(void))
In the idle() function, you could issue glutPostRedisplay command to post a window repaint request, which in
turn will activate display() function.
voididle(){
glutPostRedisplay();//Postarepaintrequesttoactivatedisplay()
}
Take note that the above is equivalent to registering display() as the idle function.
//main
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
17/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
glutIdleFunc(display);
6.2Double Buffering
Double buffering uses two display buffers to smoothen animation. The next screen is prepared in a back buffer, while
the current screen is held in a front buffer. Once the preparation is done, you can use glutSwapBuffer command to
swap the front and back buffers.
To use double buffering, you need to make two changes:
1. In the main(), include this line before creating the window:
glutInitDisplayMode(GLUT_DOUBLE);//Setdoublebufferedmode
2. In the display() function, replace glFlush() with glutSwapBuffers(), which swap the front and back buffers.
Double buffering should be used in animation. For static display, single buffering is sufficient. Many graphics hardware
always double buffered, so it is hard to see the differences.
/*
*GL05IdleFunc.cpp:TranslationandRotation
*Transformprimitivesfromtheirmodelspacestoworldspace(ModelTransform).
*/
#include<windows.h>//forMSWindows
#include<GL/glut.h>//GLUT,includeglu.handgl.h
//Globalvariable
GLfloatangle=0.0f;//Currentrotationalangleoftheshapes
/*InitializeOpenGLGraphics*/
voidinitGL(){
//Set"clearing"orbackgroundcolor
glClearColor(0.0f,0.0f,0.0f,1.0f);//Blackandopaque
}
/*Calledbackwhenthereisnoothereventtobehandled*/
voididle(){
glutPostRedisplay();//Postarepaintrequesttoactivatedisplay()
}
/*Handlerforwindowrepaintevent.Callbackwhenthewindowfirstappearsand
wheneverthewindowneedstoberepainted.*/
voiddisplay(){
glClear(GL_COLOR_BUFFER_BIT);//Clearthecolorbuffer
glMatrixMode(GL_MODELVIEW);//TooperateonModelViewmatrix
glLoadIdentity();//Resetthemodelviewmatrix
glPushMatrix();//Savemodelviewmatrixsetting
glTranslatef(0.5f,0.4f,0.0f);//Translate
glRotatef(angle,0.0f,0.0f,1.0f);//rotatebyangleindegrees
glBegin(GL_QUADS);//Eachsetof4verticesformaquad
glColor3f(1.0f,0.0f,0.0f);//Red
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
18/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
glEnd();
glPopMatrix();//Restorethemodelviewmatrix
glPushMatrix();//Savemodelviewmatrixsetting
glTranslatef(0.4f,0.3f,0.0f);//Translate
glRotatef(angle,0.0f,0.0f,1.0f);//rotatebyangleindegrees
glBegin(GL_QUADS);
glColor3f(0.0f,1.0f,0.0f);//Green
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
glEnd();
glPopMatrix();//Restorethemodelviewmatrix
glPushMatrix();//Savemodelviewmatrixsetting
glTranslatef(0.7f,0.5f,0.0f);//Translate
glRotatef(angle,0.0f,0.0f,1.0f);//rotatebyangleindegrees
glBegin(GL_QUADS);
glColor3f(0.2f,0.2f,0.2f);//DarkGray
glVertex2f(0.2f,0.2f);
glColor3f(1.0f,1.0f,1.0f);//White
glVertex2f(0.2f,0.2f);
glColor3f(0.2f,0.2f,0.2f);//DarkGray
glVertex2f(0.2f,0.2f);
glColor3f(1.0f,1.0f,1.0f);//White
glVertex2f(0.2f,0.2f);
glEnd();
glPopMatrix();//Restorethemodelviewmatrix
glPushMatrix();//Savemodelviewmatrixsetting
glTranslatef(0.4f,0.3f,0.0f);//Translate
glRotatef(angle,0.0f,0.0f,1.0f);//rotatebyangleindegrees
glBegin(GL_TRIANGLES);
glColor3f(0.0f,0.0f,1.0f);//Blue
glVertex2f(0.3f,0.2f);
glVertex2f(0.3f,0.2f);
glVertex2f(0.0f,0.3f);
glEnd();
glPopMatrix();//Restorethemodelviewmatrix
glPushMatrix();//Savemodelviewmatrixsetting
glTranslatef(0.6f,0.6f,0.0f);//Translate
glRotatef(180.0f+angle,0.0f,0.0f,1.0f);//Rotate180+angledegree
glBegin(GL_TRIANGLES);
glColor3f(1.0f,0.0f,0.0f);//Red
glVertex2f(0.3f,0.2f);
glColor3f(0.0f,1.0f,0.0f);//Green
glVertex2f(0.3f,0.2f);
glColor3f(0.0f,0.0f,1.0f);//Blue
glVertex2f(0.0f,0.3f);
glEnd();
glPopMatrix();//Restorethemodelviewmatrix
glPushMatrix();//Savemodelviewmatrixsetting
glTranslatef(0.5f,0.4f,0.0f);//Translate
glRotatef(angle,0.0f,0.0f,1.0f);//rotatebyangleindegrees
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
19/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
glBegin(GL_POLYGON);
glColor3f(1.0f,1.0f,0.0f);//Yellow
glVertex2f(0.1f,0.2f);
glVertex2f(0.1f,0.2f);
glVertex2f(0.2f,0.0f);
glVertex2f(0.1f,0.2f);
glVertex2f(0.1f,0.2f);
glVertex2f(0.2f,0.0f);
glEnd();
glPopMatrix();//Restorethemodelviewmatrix
glutSwapBuffers();//Doublebufferedswapthefrontandbackbuffers
//Changetherotationalangleaftereachdisplay()
angle+=0.2f;
}
/*Handlerforwindowresizeevent.Calledbackwhenthewindowfirstappearsand
wheneverthewindowisresizedwithitsnewwidthandheight*/
voidreshape(GLsizeiwidth,GLsizeiheight){//GLsizeifornonnegativeinteger
//Computeaspectratioofthenewwindow
if(height==0)height=1;//Topreventdivideby0
GLfloataspect=(GLfloat)width/(GLfloat)height;
//Settheviewporttocoverthenewwindow
glViewport(0,0,width,height);
//Settheaspectratiooftheclippingareatomatchtheviewport
glMatrixMode(GL_PROJECTION);//TooperateontheProjectionmatrix
glLoadIdentity();
if(width>=height){
//aspect>=1,settheheightfrom1to1,withlargerwidth
gluOrtho2D(1.0*aspect,1.0*aspect,1.0,1.0);
}else{
//aspect<1,setthewidthto1to1,withlargerheight
gluOrtho2D(1.0,1.0,1.0/aspect,1.0/aspect);
}
}
/*Mainfunction:GLUTrunsasaconsoleapplicationstartingatmain()*/
intmain(intargc,char**argv){
glutInit(&argc,argv);//InitializeGLUT
glutInitDisplayMode(GLUT_DOUBLE);//Enabledoublebufferedmode
glutInitWindowSize(640,480);//Setthewindow'sinitialwidth&heightnonsquare
glutInitWindowPosition(50,50);//Positionthewindow'sinitialtopleftcorner
glutCreateWindow("AnimationviaIdleFunction");//Createwindowwiththegiventitle
glutDisplayFunc(display);//Registercallbackhandlerforwindowrepaintevent
glutReshapeFunc(reshape);//Registercallbackhandlerforwindowresizeevent
glutIdleFunc(idle);//Registercallbackhandlerifnootherevent
initGL();//OurownOpenGLinitialization
glutMainLoop();//Entertheinfiniteeventprocessingloop
return0;
}
In the above example, instead of accumulating all the translations and undoing the rotations, we use glPushMatrix to
save the current state, perform transformations, and restore the saved state via glPopMatrix. In the above example,
we can also use glLoadIdentity to reset the matrix before the next transformations.
GLfloatangle=0.0f;//Currentrotationalangleoftheshapes
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
20/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
We define a global variable called angle to keep track of the rotational angle of all the shapes. We will later use
glRotatef to rotate all the shapes to this angle.
angle+=0.2f;
At the end of each refresh in display(), we update the rotational angle of all the shapes.
glutSwapBuffers();//Swapfrontandbackframebuffer
glutInitDisplayMode(GLUT_DOUBLE);//Inmain(),enabledoublebufferedmode
Instead of glFlush() which flushes the framebuffer for display immediately, we enable double buffering and use
glutSwapBuffer() to swap the front and backbuffer during the VSync for smoother display.
voididle(){
glutPostRedisplay();//Postarepaintrequesttoactivatedisplay()
}
glutIdleFunc(idle);//Inmain()Registercallbackhandlerifnootherevent
We define an idle() function, which posts a repaint request and invoke display(), if there is no event outstanding.
We register this idle() function in main() via glutIdleFunc().
6.5Timer Function
With idle(), we have no control to the refresh interval. We could register a Timer() function with GLUT via
glutTimerFunc. The Timer() function will be called back at the specified fixed interval.
voidglutTimerFunc(unsignedintmillis,void(*func)(intvalue),value)
//wheremillisisthedelayinmilliseconds,valuewillbepassedtothetimerfunction.
/*
*GL06TimerFunc.cpp:TranslationandRotation
*Transformprimitivesfromtheirmodelspacestoworldspace(ModelTransform).
*/
#include<windows.h>//forMSWindows
#include<GL/glut.h>//GLUT,includeglu.handgl.h
//globalvariable
GLfloatangle=0.0f;//rotationalangleoftheshapes
intrefreshMills=30;//refreshintervalinmilliseconds
/*InitializeOpenGLGraphics*/
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
21/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
voidinitGL(){
//Set"clearing"orbackgroundcolor
glClearColor(0.0f,0.0f,0.0f,1.0f);//Blackandopaque
}
/*Calledbackwhentimerexpired*/
voidTimer(intvalue){
glutPostRedisplay();//Postrepaintrequesttoactivatedisplay()
glutTimerFunc(refreshMills,Timer,0);//nextTimercallmillisecondslater
}
/*Handlerforwindowrepaintevent.Callbackwhenthewindowfirstappearsand
wheneverthewindowneedstoberepainted.*/
voiddisplay(){
glClear(GL_COLOR_BUFFER_BIT);//Clearthecolorbuffer
glMatrixMode(GL_MODELVIEW);//TooperateonModelViewmatrix
glLoadIdentity();//Resetthemodelviewmatrix
glPushMatrix();//Savemodelviewmatrixsetting
glTranslatef(0.5f,0.4f,0.0f);//Translate
glRotatef(angle,0.0f,0.0f,1.0f);//rotatebyangleindegrees
glBegin(GL_QUADS);//Eachsetof4verticesformaquad
glColor3f(1.0f,0.0f,0.0f);//Red
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
glEnd();
glPopMatrix();//Restorethemodelviewmatrix
glPushMatrix();//Savemodelviewmatrixsetting
glTranslatef(0.4f,0.3f,0.0f);//Translate
glRotatef(angle,0.0f,0.0f,1.0f);//rotatebyangleindegrees
glBegin(GL_QUADS);
glColor3f(0.0f,1.0f,0.0f);//Green
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
glVertex2f(0.3f,0.3f);
glEnd();
glPopMatrix();//Restorethemodelviewmatrix
glPushMatrix();//Savemodelviewmatrixsetting
glTranslatef(0.7f,0.5f,0.0f);//Translate
glRotatef(angle,0.0f,0.0f,1.0f);//rotatebyangleindegrees
glBegin(GL_QUADS);
glColor3f(0.2f,0.2f,0.2f);//DarkGray
glVertex2f(0.2f,0.2f);
glColor3f(1.0f,1.0f,1.0f);//White
glVertex2f(0.2f,0.2f);
glColor3f(0.2f,0.2f,0.2f);//DarkGray
glVertex2f(0.2f,0.2f);
glColor3f(1.0f,1.0f,1.0f);//White
glVertex2f(0.2f,0.2f);
glEnd();
glPopMatrix();//Restorethemodelviewmatrix
glPushMatrix();//Savemodelviewmatrixsetting
glTranslatef(0.4f,0.3f,0.0f);//Translate
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
22/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
glRotatef(angle,0.0f,0.0f,1.0f);//rotatebyangleindegrees
glBegin(GL_TRIANGLES);
glColor3f(0.0f,0.0f,1.0f);//Blue
glVertex2f(0.3f,0.2f);
glVertex2f(0.3f,0.2f);
glVertex2f(0.0f,0.3f);
glEnd();
glPopMatrix();//Restorethemodelviewmatrix
glPushMatrix();//Savemodelviewmatrixsetting
glTranslatef(0.6f,0.6f,0.0f);//Translate
glRotatef(180.0f+angle,0.0f,0.0f,1.0f);//Rotate180+angledegree
glBegin(GL_TRIANGLES);
glColor3f(1.0f,0.0f,0.0f);//Red
glVertex2f(0.3f,0.2f);
glColor3f(0.0f,1.0f,0.0f);//Green
glVertex2f(0.3f,0.2f);
glColor3f(0.0f,0.0f,1.0f);//Blue
glVertex2f(0.0f,0.3f);
glEnd();
glPopMatrix();//Restorethemodelviewmatrix
glPushMatrix();//Savemodelviewmatrixsetting
glTranslatef(0.5f,0.4f,0.0f);//Translate
glRotatef(angle,0.0f,0.0f,1.0f);//rotatebyangleindegrees
glBegin(GL_POLYGON);
glColor3f(1.0f,1.0f,0.0f);//Yellow
glVertex2f(0.1f,0.2f);
glVertex2f(0.1f,0.2f);
glVertex2f(0.2f,0.0f);
glVertex2f(0.1f,0.2f);
glVertex2f(0.1f,0.2f);
glVertex2f(0.2f,0.0f);
glEnd();
glPopMatrix();//Restorethemodelviewmatrix
glutSwapBuffers();//Doublebufferedswapthefrontandbackbuffers
//Changetherotationalangleaftereachdisplay()
angle+=2.0f;
}
/*Handlerforwindowresizeevent.Calledbackwhenthewindowfirstappearsand
wheneverthewindowisresizedwithitsnewwidthandheight*/
voidreshape(GLsizeiwidth,GLsizeiheight){//GLsizeifornonnegativeinteger
//Computeaspectratioofthenewwindow
if(height==0)height=1;//Topreventdivideby0
GLfloataspect=(GLfloat)width/(GLfloat)height;
//Settheviewporttocoverthenewwindow
glViewport(0,0,width,height);
//Settheaspectratiooftheclippingareatomatchtheviewport
glMatrixMode(GL_PROJECTION);//TooperateontheProjectionmatrix
glLoadIdentity();
if(width>=height){
//aspect>=1,settheheightfrom1to1,withlargerwidth
gluOrtho2D(1.0*aspect,1.0*aspect,1.0,1.0);
}else{
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
23/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//aspect<1,setthewidthto1to1,withlargerheight
gluOrtho2D(1.0,1.0,1.0/aspect,1.0/aspect);
}
}
/*Mainfunction:GLUTrunsasaconsoleapplicationstartingatmain()*/
intmain(intargc,char**argv){
glutInit(&argc,argv);//InitializeGLUT
glutInitDisplayMode(GLUT_DOUBLE);//Enabledoublebufferedmode
glutInitWindowSize(640,480);//Setthewindow'sinitialwidth&heightnonsquare
glutInitWindowPosition(50,50);//Positionthewindow'sinitialtopleftcorner
glutCreateWindow("AnimationviaIdleFunction");//Createwindowwiththegiventitle
glutDisplayFunc(display);//Registercallbackhandlerforwindowrepaintevent
glutReshapeFunc(reshape);//Registercallbackhandlerforwindowresizeevent
glutTimerFunc(0,Timer,0);//Firsttimercallimmediately
initGL();//OurownOpenGLinitialization
glutMainLoop();//Entertheinfiniteeventprocessingloop
return0;
}
voidTimer(intvalue){
glutPostRedisplay();//Postrepaintrequesttoactivatedisplay()
glutTimerFunc(refreshMills,Timer,0);//nextTimercallmillisecondslater
}
We replace the idle() function by a timer() function, which post a repaint request to invoke display(), after the
timer expired.
glutTimerFunc(0,Timer,0);//Firsttimercallimmediately
In main(), we register the timer() function, and activate the timer() immediately with initial timer = 0.
For example,
glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
//UseRGBAcolor,enabledoublebufferingandenabledepthbuffer
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
24/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/*
*GL07BouncingBall.cpp:Aballbouncinginsidethewindow
*/
#include<windows.h>//forMSWindows
#include<GL/glut.h>//GLUT,includesglu.handgl.h
#include<Math.h>//Neededforsin,cos
#definePI3.14159265f
//Globalvariables
chartitle[]="BouncingBall(2D)";//Windowedmode'stitle
intwindowWidth=640;//Windowedmode'swidth
intwindowHeight=480;//Windowedmode'sheight
intwindowPosX=50;//Windowedmode'stopleftcornerx
intwindowPosY=50;//Windowedmode'stopleftcornery
GLfloatballRadius=0.5f;//Radiusofthebouncingball
GLfloatballX=0.0f;//Ball'scenter(x,y)position
GLfloatballY=0.0f;
GLfloatballXMax,ballXMin,ballYMax,ballYMin;//Ball'scenter(x,y)bounds
GLfloatxSpeed=0.02f;//Ball'sspeedinxandydirections
GLfloatySpeed=0.007f;
intrefreshMillis=30;//Refreshperiodinmilliseconds
//Projectionclippingarea
GLdoubleclipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop;
/*InitializeOpenGLGraphics*/
voidinitGL(){
glClearColor(0.0,0.0,0.0,1.0);//Setbackground(clear)colortoblack
}
/*Callbackhandlerforwindowrepaintevent*/
voiddisplay(){
glClear(GL_COLOR_BUFFER_BIT);//Clearthecolorbuffer
glMatrixMode(GL_MODELVIEW);//Tooperateonthemodelviewmatrix
glLoadIdentity();//Resetmodelviewmatrix
glTranslatef(ballX,ballY,0.0f);//Translateto(xPos,yPos)
//Usetriangularsegmentstoformacircle
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.0f,0.0f,1.0f);//Blue
glVertex2f(0.0f,0.0f);//Centerofcircle
intnumSegments=100;
GLfloatangle;
for(inti=0;i<=numSegments;i++){//Lastvertexsameasfirstvertex
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
25/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
angle=i*2.0f*PI/numSegments;//360degforallsegments
glVertex2f(cos(angle)*ballRadius,sin(angle)*ballRadius);
}
glEnd();
glutSwapBuffers();//Swapfrontandbackbuffers(ofdoublebufferedmode)
//AnimationControlcomputethelocationforthenextrefresh
ballX+=xSpeed;
ballY+=ySpeed;
//Checkiftheballexceedstheedges
if(ballX>ballXMax){
ballX=ballXMax;
xSpeed=xSpeed;
}elseif(ballX<ballXMin){
ballX=ballXMin;
xSpeed=xSpeed;
}
if(ballY>ballYMax){
ballY=ballYMax;
ySpeed=ySpeed;
}elseif(ballY<ballYMin){
ballY=ballYMin;
ySpeed=ySpeed;
}
}
/*Callbackwhenthewindowsisresized*/
voidreshape(GLsizeiwidth,GLsizeiheight){
//Computeaspectratioofthenewwindow
if(height==0)height=1;//Topreventdivideby0
GLfloataspect=(GLfloat)width/(GLfloat)height;
//Settheviewporttocoverthenewwindow
glViewport(0,0,width,height);
//Settheaspectratiooftheclippingareatomatchtheviewport
glMatrixMode(GL_PROJECTION);//TooperateontheProjectionmatrix
glLoadIdentity();//Resettheprojectionmatrix
if(width>=height){
clipAreaXLeft=1.0*aspect;
clipAreaXRight=1.0*aspect;
clipAreaYBottom=1.0;
clipAreaYTop=1.0;
}else{
clipAreaXLeft=1.0;
clipAreaXRight=1.0;
clipAreaYBottom=1.0/aspect;
clipAreaYTop=1.0/aspect;
}
gluOrtho2D(clipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop);
ballXMin=clipAreaXLeft+ballRadius;
ballXMax=clipAreaXRightballRadius;
ballYMin=clipAreaYBottom+ballRadius;
ballYMax=clipAreaYTopballRadius;
}
/*Calledbackwhenthetimerexpired*/
voidTimer(intvalue){
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
26/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
glutPostRedisplay();//Postapaintrequesttoactivatedisplay()
glutTimerFunc(refreshMillis,Timer,0);//subsequenttimercallatmilliseconds
}
/*Mainfunction:GLUTrunsasaconsoleapplicationstartingatmain()*/
intmain(intargc,char**argv){
glutInit(&argc,argv);//InitializeGLUT
glutInitDisplayMode(GLUT_DOUBLE);//Enabledoublebufferedmode
glutInitWindowSize(windowWidth,windowHeight);//Initialwindowwidthandheight
glutInitWindowPosition(windowPosX,windowPosY);//Initialwindowtopleftcorner(x,y)
glutCreateWindow(title);//Createwindowwithgiventitle
glutDisplayFunc(display);//Registercallbackhandlerforwindowrepaint
glutReshapeFunc(reshape);//Registercallbackhandlerforwindowreshape
glutTimerFunc(0,Timer,0);//Firsttimercallimmediately
initGL();//OurownOpenGLinitialization
glutMainLoop();//Entereventprocessingloop
return0;
}
[TODO] Explanation
glutSpecialFunc: registers callback handler for special key such as arrow keys and function keys.
voidglutSpecialFunc(void(*func)(intspecialKey,intx,inty)
//specialKey:GLUT_KEY_*(*forLEFT,RIGHT,UP,DOWN,HOME,END,PAGE_UP,PAGE_DOWN,F1,...F12).
//(x,y)isthemouselocationinWindows'coordinates
/*
*GL08FullScreen.cpp:Switchingbetweenfullscreenmodeandwindowedmode
*/
#include<windows.h>//forMSWindows
#include<GL/glut.h>//GLUT,includesglu.handgl.h
#include<Math.h>//Neededforsin,cos
#definePI3.14159265f
//Globalvariables
chartitle[]="FullScreen&WindowedMode";//Windowedmode'stitle
intwindowWidth=640;//Windowedmode'swidth
intwindowHeight=480;//Windowedmode'sheight
intwindowPosX=50;//Windowedmode'stopleftcornerx
intwindowPosY=50;//Windowedmode'stopleftcornery
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
27/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
GLfloatballRadius=0.5f;//Radiusofthebouncingball
GLfloatballX=0.0f;//Ball'scenter(x,y)position
GLfloatballY=0.0f;
GLfloatballXMax,ballXMin,ballYMax,ballYMin;//Ball'scenter(x,y)bounds
GLfloatxSpeed=0.02f;//Ball'sspeedinxandydirections
GLfloatySpeed=0.007f;
intrefreshMillis=30;//Refreshperiodinmilliseconds
//Projectionclippingarea
GLdoubleclipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop;
boolfullScreenMode=true;//Fullscreenorwindowedmode?
/*InitializeOpenGLGraphics*/
voidinitGL(){
glClearColor(0.0,0.0,0.0,1.0);//Setbackground(clear)colortoblack
}
/*Callbackhandlerforwindowrepaintevent*/
voiddisplay(){
glClear(GL_COLOR_BUFFER_BIT);//Clearthecolorbuffer
glMatrixMode(GL_MODELVIEW);//Tooperateonthemodelviewmatrix
glLoadIdentity();//Resetmodelviewmatrix
glTranslatef(ballX,ballY,0.0f);//Translateto(xPos,yPos)
//Usetriangularsegmentstoformacircle
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.0f,0.0f,1.0f);//Blue
glVertex2f(0.0f,0.0f);//Centerofcircle
intnumSegments=100;
GLfloatangle;
for(inti=0;i<=numSegments;i++){//Lastvertexsameasfirstvertex
angle=i*2.0f*PI/numSegments;//360degforallsegments
glVertex2f(cos(angle)*ballRadius,sin(angle)*ballRadius);
}
glEnd();
glutSwapBuffers();//Swapfrontandbackbuffers(ofdoublebufferedmode)
//AnimationControlcomputethelocationforthenextrefresh
ballX+=xSpeed;
ballY+=ySpeed;
//Checkiftheballexceedstheedges
if(ballX>ballXMax){
ballX=ballXMax;
xSpeed=xSpeed;
}elseif(ballX<ballXMin){
ballX=ballXMin;
xSpeed=xSpeed;
}
if(ballY>ballYMax){
ballY=ballYMax;
ySpeed=ySpeed;
}elseif(ballY<ballYMin){
ballY=ballYMin;
ySpeed=ySpeed;
}
}
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
28/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*Callbackwhenthewindowsisresized*/
voidreshape(GLsizeiwidth,GLsizeiheight){
//Computeaspectratioofthenewwindow
if(height==0)height=1;//Topreventdivideby0
GLfloataspect=(GLfloat)width/(GLfloat)height;
//Settheviewporttocoverthenewwindow
glViewport(0,0,width,height);
//Settheaspectratiooftheclippingareatomatchtheviewport
glMatrixMode(GL_PROJECTION);//TooperateontheProjectionmatrix
glLoadIdentity();//Resettheprojectionmatrix
if(width>=height){
clipAreaXLeft=1.0*aspect;
clipAreaXRight=1.0*aspect;
clipAreaYBottom=1.0;
clipAreaYTop=1.0;
}else{
clipAreaXLeft=1.0;
clipAreaXRight=1.0;
clipAreaYBottom=1.0/aspect;
clipAreaYTop=1.0/aspect;
}
gluOrtho2D(clipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop);
ballXMin=clipAreaXLeft+ballRadius;
ballXMax=clipAreaXRightballRadius;
ballYMin=clipAreaYBottom+ballRadius;
ballYMax=clipAreaYTopballRadius;
}
/*Calledbackwhenthetimerexpired*/
voidTimer(intvalue){
glutPostRedisplay();//Postapaintrequesttoactivatedisplay()
glutTimerFunc(refreshMillis,Timer,0);//subsequenttimercallatmilliseconds
}
/*Callbackhandlerforspecialkeyevent*/
voidspecialKeys(intkey,intx,inty){
switch(key){
caseGLUT_KEY_F1://F1:Togglebetweenfullscreenandwindowedmode
fullScreenMode=!fullScreenMode;//Togglestate
if(fullScreenMode){//Fullscreenmode
windowPosX=glutGet(GLUT_WINDOW_X);//Saveparametersforrestoringlater
windowPosY=glutGet(GLUT_WINDOW_Y);
windowWidth=glutGet(GLUT_WINDOW_WIDTH);
windowHeight=glutGet(GLUT_WINDOW_HEIGHT);
glutFullScreen();//Switchintofullscreen
}else{//Windowedmode
glutReshapeWindow(windowWidth,windowHeight);//Switchintowindowedmode
glutPositionWindow(windowPosX,windowPosX);//Positiontopleftcorner
}
break;
}
}
/*Mainfunction:GLUTrunsasaconsoleapplicationstartingatmain()*/
intmain(intargc,char**argv){
glutInit(&argc,argv);//InitializeGLUT
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
29/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
133
134
135
136
137
138
139
140
141
142
143
144
145
glutInitDisplayMode(GLUT_DOUBLE);//Enabledoublebufferedmode
glutInitWindowSize(windowWidth,windowHeight);//Initialwindowwidthandheight
glutInitWindowPosition(windowPosX,windowPosY);//Initialwindowtopleftcorner(x,y)
glutCreateWindow(title);//Createwindowwithgiventitle
glutDisplayFunc(display);//Registercallbackhandlerforwindowrepaint
glutReshapeFunc(reshape);//Registercallbackhandlerforwindowreshape
glutTimerFunc(0,Timer,0);//Firsttimercallimmediately
glutSpecialFunc(specialKeys);//Registercallbackhandlerforspecialkeyevent
glutFullScreen();//Putintofullscreen
initGL();//OurownOpenGLinitialization
glutMainLoop();//Entereventprocessingloop
return0;
}
[TODO] Explanation
[TODO] Using glVertex to draw a Circle is inefficient due to the computeintensive sin() and cos() functions. Try
using GLU's quadric.
/*
*GL09KeyControl.cpp:Akeycontrolledbouncingball
*/
#include<windows.h>//forMSWindows
#include<GL/glut.h>//GLUT,includeglu.handgl.h
#include<Math.h>//Neededforsin,cos
#definePI3.14159265f
//Globalvariables
chartitle[]="FullScreen&WindowedMode";//Windowedmode'stitle
intwindowWidth=640;//Windowedmode'swidth
intwindowHeight=480;//Windowedmode'sheight
intwindowPosX=50;//Windowedmode'stopleftcornerx
intwindowPosY=50;//Windowedmode'stopleftcornery
GLfloatballRadius=0.5f;//Radiusofthebouncingball
GLfloatballX=0.0f;//Ball'scenter(x,y)position
GLfloatballY=0.0f;
GLfloatballXMax,ballXMin,ballYMax,ballYMin;//Ball'scenter(x,y)bounds
GLfloatxSpeed=0.02f;//Ball'sspeedinxandydirections
GLfloatySpeed=0.007f;
intrefreshMillis=30;//Refreshperiodinmilliseconds
//Projectionclippingarea
GLdoubleclipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop;
boolfullScreenMode=true;//Fullscreenorwindowedmode?
/*InitializeOpenGLGraphics*/
voidinitGL(){
glClearColor(0.0,0.0,0.0,1.0);//Setbackground(clear)colortoblack
}
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
30/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/*Callbackhandlerforwindowrepaintevent*/
voiddisplay(){
glClear(GL_COLOR_BUFFER_BIT);//Clearthecolorbuffer
glMatrixMode(GL_MODELVIEW);//Tooperateonthemodelviewmatrix
glLoadIdentity();//Resetmodelviewmatrix
glTranslatef(ballX,ballY,0.0f);//Translateto(xPos,yPos)
//Usetriangularsegmentstoformacircle
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.0f,0.0f,1.0f);//Blue
glVertex2f(0.0f,0.0f);//Centerofcircle
intnumSegments=100;
GLfloatangle;
for(inti=0;i<=numSegments;i++){//Lastvertexsameasfirstvertex
angle=i*2.0f*PI/numSegments;//360degforallsegments
glVertex2f(cos(angle)*ballRadius,sin(angle)*ballRadius);
}
glEnd();
glutSwapBuffers();//Swapfrontandbackbuffers(ofdoublebufferedmode)
//AnimationControlcomputethelocationforthenextrefresh
ballX+=xSpeed;
ballY+=ySpeed;
//Checkiftheballexceedstheedges
if(ballX>ballXMax){
ballX=ballXMax;
xSpeed=xSpeed;
}elseif(ballX<ballXMin){
ballX=ballXMin;
xSpeed=xSpeed;
}
if(ballY>ballYMax){
ballY=ballYMax;
ySpeed=ySpeed;
}elseif(ballY<ballYMin){
ballY=ballYMin;
ySpeed=ySpeed;
}
}
/*Callbackwhenthewindowsisresized*/
voidreshape(GLsizeiwidth,GLsizeiheight){
//Computeaspectratioofthenewwindow
if(height==0)height=1;//Topreventdivideby0
GLfloataspect=(GLfloat)width/(GLfloat)height;
//Settheviewporttocoverthenewwindow
glViewport(0,0,width,height);
//Settheaspectratiooftheclippingareatomatchtheviewport
glMatrixMode(GL_PROJECTION);//TooperateontheProjectionmatrix
glLoadIdentity();//Resettheprojectionmatrix
if(width>=height){
clipAreaXLeft=1.0*aspect;
clipAreaXRight=1.0*aspect;
clipAreaYBottom=1.0;
clipAreaYTop=1.0;
}else{
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
31/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
clipAreaXLeft=1.0;
clipAreaXRight=1.0;
clipAreaYBottom=1.0/aspect;
clipAreaYTop=1.0/aspect;
}
gluOrtho2D(clipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop);
ballXMin=clipAreaXLeft+ballRadius;
ballXMax=clipAreaXRightballRadius;
ballYMin=clipAreaYBottom+ballRadius;
ballYMax=clipAreaYTopballRadius;
}
/*Calledbackwhenthetimerexpired*/
voidTimer(intvalue){
glutPostRedisplay();//Postapaintrequesttoactivatedisplay()
glutTimerFunc(refreshMillis,Timer,0);//subsequenttimercallatmilliseconds
}
/*Callbackhandlerfornormalkeyevent*/
voidkeyboard(unsignedcharkey,intx,inty){
switch(key){
case27://ESCkey
exit(0);
break;
}
}
/*Callbackhandlerforspecialkeyevent*/
voidspecialKeys(intkey,intx,inty){
switch(key){
caseGLUT_KEY_F1://F1:Togglebetweenfullscreenandwindowedmode
fullScreenMode=!fullScreenMode;//Togglestate
if(fullScreenMode){//Fullscreenmode
windowPosX=glutGet(GLUT_WINDOW_X);//Saveparametersforrestoringlater
windowPosY=glutGet(GLUT_WINDOW_Y);
windowWidth=glutGet(GLUT_WINDOW_WIDTH);
windowHeight=glutGet(GLUT_WINDOW_HEIGHT);
glutFullScreen();//Switchintofullscreen
}else{//Windowedmode
glutReshapeWindow(windowWidth,windowHeight);//Switchintowindowedmode
glutPositionWindow(windowPosX,windowPosX);//Positiontopleftcorner
}
break;
caseGLUT_KEY_RIGHT://Right:increasexspeed
xSpeed*=1.05f;break;
caseGLUT_KEY_LEFT://Left:decreasexspeed
xSpeed*=0.95f;break;
caseGLUT_KEY_UP://Up:increaseyspeed
ySpeed*=1.05f;break;
caseGLUT_KEY_DOWN://Down:decreaseyspeed
ySpeed*=0.95f;break;
caseGLUT_KEY_PAGE_UP://PageUp:increaseball'sradius
ballRadius*=1.05f;
ballXMin=clipAreaXLeft+ballRadius;
ballXMax=clipAreaXRightballRadius;
ballYMin=clipAreaYBottom+ballRadius;
ballYMax=clipAreaYTopballRadius;
break;
caseGLUT_KEY_PAGE_DOWN://PageDown:decreaseball'sradius
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
32/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
ballRadius*=0.95f;
ballXMin=clipAreaXLeft+ballRadius;
ballXMax=clipAreaXRightballRadius;
ballYMin=clipAreaYBottom+ballRadius;
ballYMax=clipAreaYTopballRadius;
break;
}
}
/*Mainfunction:GLUTrunsasaconsoleapplicationstartingatmain()*/
intmain(intargc,char**argv){
glutInit(&argc,argv);//InitializeGLUT
glutInitDisplayMode(GLUT_DOUBLE);//Enabledoublebufferedmode
glutInitWindowSize(windowWidth,windowHeight);//Initialwindowwidthandheight
glutInitWindowPosition(windowPosX,windowPosY);//Initialwindowtopleftcorner(x,y)
glutCreateWindow(title);//Createwindowwithgiventitle
glutDisplayFunc(display);//Registercallbackhandlerforwindowrepaint
glutReshapeFunc(reshape);//Registercallbackhandlerforwindowreshape
glutTimerFunc(0,Timer,0);//Firsttimercallimmediately
glutSpecialFunc(specialKeys);//Registercallbackhandlerforspecialkeyevent
glutKeyboardFunc(keyboard);//Registercallbackhandlerforspecialkeyevent
glutFullScreen();//Putintofullscreen
initGL();//OurownOpenGLinitialization
glutMainLoop();//Entereventprocessingloop
return0;
}
[TODO] Explanation
glutMotionFunc: registers callback handler for mouse motion when the mouse is clicked and moved.
voidglutMotionFunc(void(*func)(intx,inty)
//where(x,y)isthemouselocationinWindow'scoordinates
/*
*GL10MouseControl.cpp:Amousecontrolledbouncingball
*/
#include<windows.h>//forMSWindows
#include<GL/glut.h>//GLUT,includeglu.handgl.h
#include<Math.h>//Neededforsin,cos
#definePI3.14159265f
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
33/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//Globalvariables
chartitle[]="FullScreen&WindowedMode";//Windowedmode'stitle
intwindowWidth=640;//Windowedmode'swidth
intwindowHeight=480;//Windowedmode'sheight
intwindowPosX=50;//Windowedmode'stopleftcornerx
intwindowPosY=50;//Windowedmode'stopleftcornery
GLfloatballRadius=0.5f;//Radiusofthebouncingball
GLfloatballX=0.0f;//Ball'scenter(x,y)position
GLfloatballY=0.0f;
GLfloatballXMax,ballXMin,ballYMax,ballYMin;//Ball'scenter(x,y)bounds
GLfloatxSpeed=0.02f;//Ball'sspeedinxandydirections
GLfloatySpeed=0.007f;
intrefreshMillis=30;//Refreshperiodinmilliseconds
//Projectionclippingarea
GLdoubleclipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop;
boolfullScreenMode=true;//Fullscreenorwindowedmode?
boolpaused=false;//Movementpausedorresumed
GLfloatxSpeedSaved,ySpeedSaved;//Tosupportresume
/*InitializeOpenGLGraphics*/
voidinitGL(){
glClearColor(0.0,0.0,0.0,1.0);//Setbackground(clear)colortoblack
}
/*Callbackhandlerforwindowrepaintevent*/
voiddisplay(){
glClear(GL_COLOR_BUFFER_BIT);//Clearthecolorbuffer
glMatrixMode(GL_MODELVIEW);//Tooperateonthemodelviewmatrix
glLoadIdentity();//Resetmodelviewmatrix
glTranslatef(ballX,ballY,0.0f);//Translateto(xPos,yPos)
//Usetriangularsegmentstoformacircle
glBegin(GL_TRIANGLE_FAN);
glColor3f(0.0f,0.0f,1.0f);//Blue
glVertex2f(0.0f,0.0f);//Centerofcircle
intnumSegments=100;
GLfloatangle;
for(inti=0;i<=numSegments;i++){//Lastvertexsameasfirstvertex
angle=i*2.0f*PI/numSegments;//360degforallsegments
glVertex2f(cos(angle)*ballRadius,sin(angle)*ballRadius);
}
glEnd();
glutSwapBuffers();//Swapfrontandbackbuffers(ofdoublebufferedmode)
//AnimationControlcomputethelocationforthenextrefresh
ballX+=xSpeed;
ballY+=ySpeed;
//Checkiftheballexceedstheedges
if(ballX>ballXMax){
ballX=ballXMax;
xSpeed=xSpeed;
}elseif(ballX<ballXMin){
ballX=ballXMin;
xSpeed=xSpeed;
}
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
34/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
if(ballY>ballYMax){
ballY=ballYMax;
ySpeed=ySpeed;
}elseif(ballY<ballYMin){
ballY=ballYMin;
ySpeed=ySpeed;
}
}
/*Callbackwhenthewindowsisresized*/
voidreshape(GLsizeiwidth,GLsizeiheight){
//Computeaspectratioofthenewwindow
if(height==0)height=1;//Topreventdivideby0
GLfloataspect=(GLfloat)width/(GLfloat)height;
//Settheviewporttocoverthenewwindow
glViewport(0,0,width,height);
//Settheaspectratiooftheclippingareatomatchtheviewport
glMatrixMode(GL_PROJECTION);//TooperateontheProjectionmatrix
glLoadIdentity();//Resettheprojectionmatrix
if(width>=height){
clipAreaXLeft=1.0*aspect;
clipAreaXRight=1.0*aspect;
clipAreaYBottom=1.0;
clipAreaYTop=1.0;
}else{
clipAreaXLeft=1.0;
clipAreaXRight=1.0;
clipAreaYBottom=1.0/aspect;
clipAreaYTop=1.0/aspect;
}
gluOrtho2D(clipAreaXLeft,clipAreaXRight,clipAreaYBottom,clipAreaYTop);
ballXMin=clipAreaXLeft+ballRadius;
ballXMax=clipAreaXRightballRadius;
ballYMin=clipAreaYBottom+ballRadius;
ballYMax=clipAreaYTopballRadius;
}
/*Calledbackwhenthetimerexpired*/
voidTimer(intvalue){
glutPostRedisplay();//Postapaintrequesttoactivatedisplay()
glutTimerFunc(refreshMillis,Timer,0);//subsequenttimercallatmilliseconds
}
/*Callbackhandlerfornormalkeyevent*/
voidkeyboard(unsignedcharkey,intx,inty){
switch(key){
case27://ESCkey
exit(0);
break;
}
}
/*Callbackhandlerforspecialkeyevent*/
voidspecialKeys(intkey,intx,inty){
switch(key){
caseGLUT_KEY_F1://F1:Togglebetweenfullscreenandwindowedmode
fullScreenMode=!fullScreenMode;//Togglestate
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
35/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
if(fullScreenMode){//Fullscreenmode
windowPosX=glutGet(GLUT_WINDOW_X);//Saveparametersforrestoringlater
windowPosY=glutGet(GLUT_WINDOW_Y);
windowWidth=glutGet(GLUT_WINDOW_WIDTH);
windowHeight=glutGet(GLUT_WINDOW_HEIGHT);
glutFullScreen();//Switchintofullscreen
}else{//Windowedmode
glutReshapeWindow(windowWidth,windowHeight);//Switchintowindowedmode
glutPositionWindow(windowPosX,windowPosX);//Positiontopleftcorner
}
break;
caseGLUT_KEY_RIGHT://Right:increasexspeed
xSpeed*=1.05f;break;
caseGLUT_KEY_LEFT://Left:decreasexspeed
xSpeed*=0.95f;break;
caseGLUT_KEY_UP://Up:increaseyspeed
ySpeed*=1.05f;break;
caseGLUT_KEY_DOWN://Down:decreaseyspeed
ySpeed*=0.95f;break;
caseGLUT_KEY_PAGE_UP://PageUp:increaseball'sradius
ballRadius*=1.05f;
ballXMin=clipAreaXLeft+ballRadius;
ballXMax=clipAreaXRightballRadius;
ballYMin=clipAreaYBottom+ballRadius;
ballYMax=clipAreaYTopballRadius;
break;
caseGLUT_KEY_PAGE_DOWN://PageDown:decreaseball'sradius
ballRadius*=0.95f;
ballXMin=clipAreaXLeft+ballRadius;
ballXMax=clipAreaXRightballRadius;
ballYMin=clipAreaYBottom+ballRadius;
ballYMax=clipAreaYTopballRadius;
break;
}
}
/*Callbackhandlerformouseevent*/
voidmouse(intbutton,intstate,intx,inty){
if(button==GLUT_LEFT_BUTTON&&state==GLUT_DOWN){//Pause/resume
paused=!paused;//Togglestate
if(paused){
xSpeedSaved=xSpeed;//Saveparametersforrestorelater
ySpeedSaved=ySpeed;
xSpeed=0;//Stopmovement
ySpeed=0;
}else{
xSpeed=xSpeedSaved;//Restoreparameters
ySpeed=ySpeedSaved;
}
}
}
/*Mainfunction:GLUTrunsasaconsoleapplicationstartingatmain()*/
intmain(intargc,char**argv){
glutInit(&argc,argv);//InitializeGLUT
glutInitDisplayMode(GLUT_DOUBLE);//Enabledoublebufferedmode
glutInitWindowSize(windowWidth,windowHeight);//Initialwindowwidthandheight
glutInitWindowPosition(windowPosX,windowPosY);//Initialwindowtopleftcorner(x,y)
glutCreateWindow(title);//Createwindowwithgiventitle
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
36/37
9/19/2015
AnintroductiononOpenGLwith2DGraphicsOpenGLTutorial
186
187
188
189
190
191
192
193
194
195
196
glutDisplayFunc(display);//Registercallbackhandlerforwindowrepaint
glutReshapeFunc(reshape);//Registercallbackhandlerforwindowreshape
glutTimerFunc(0,Timer,0);//Firsttimercallimmediately
glutSpecialFunc(specialKeys);//Registercallbackhandlerforspecialkeyevent
glutKeyboardFunc(keyboard);//Registercallbackhandlerforspecialkeyevent
glutFullScreen();//Putintofullscreen
glutMouseFunc(mouse);//Registercallbackhandlerformouseevent
initGL();//OurownOpenGLinitialization
glutMainLoop();//Entereventprocessingloop
return0;
}
[TODO] Explanation
Feedback, comments, corrections, and errata can be sent to Chua HockChuan ([email protected]) | HOME
https://www3.ntu.edu.sg/home/ehchua/programming/opengl/CG_Introduction.html
37/37