How To Project Orthographic Drawing In 2d Opengl
OpenGL Tutorial
An Introduction on OpenGL with 2D Graphics
Setting Upwards OpenGL
To ready 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.
Example i: Setting Up OpenGL and Overabundance (GL01Hello.cpp)
Make sure that you can run the "GL01Hello.cpp" described in "How to write OpenGL programs in C/C++", reproduced below:
1 2 3 iv v six 7 8 ix 10 11 12 thirteen 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <windows.h> #include <GL/glut.h> void display() { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_QUADS); glColor3f(one.0f, 0.0f, 0.0f); glVertex2f(-0.5f, -0.5f); glVertex2f( 0.5f, -0.5f); glVertex2f( 0.5f, 0.5f); glVertex2f(-0.5f, 0.5f); glEnd(); glFlush(); } int main(int argc, char** argv) { glutInit(&argc, argv); glutCreateWindow("OpenGL Setup Test"); glutInitWindowSize(320, 320); glutInitWindowPosition(l, 50); glutDisplayFunc(display); glutMainLoop(); render 0; } |
#include <windows.h>
The header "windows.h" is needed for the Windows platform only.
#include <GL/glut.h>
We also included the Glut header, which is guaranteed to include "glu.h" (for GL Utility) and "gl.h" (for Cadre OpenGL).
The rest of the program volition be explained in due course.
Introduction
OpenGL (Open up Graphics Library) is a cross-platform, hardware-accelerated, linguistic communication-independent, industrial standard API for producing 3D (including 2D) graphics. Mod computers have dedicated GPU (Graphics Processing Unit) with its ain retentiveness to speed up graphics rendering. OpenGL is the software interface to graphics hardware. In other words, OpenGL graphic rendering commands issued past your applications could exist directed to the graphic hardware and accelerated.
We use three sets of libraries in our OpenGL programs:
- Cadre OpenGL (GL): consists of hundreds of commands, which begin with a prefix "
gl" (due east.g.,glColor,glVertex,glTranslate,glRotate). The Cadre OpenGL models an object via a set of geometric primitives such every bit point, line and polygon. - OpenGL Utility Library (GLU): congenital on-elevation of the cadre 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.thousand.,gluLookAt,gluPerspective). - OpenGL Utilities Toolkit (GLUT): OpenGL is designed to be independent of the windowing system or operating system. Overabundance is needed to interact with the Operating System (such every bit creating a window, treatment key and mouse inputs); information technology as well provides more building models (such every bit sphere and torus). Glut commands start with a prefix of "
glut" (e.g.,glutCreatewindow,glutMouseFunc). Overabundance is platform independent, which is built on pinnacle of platform-specific OpenGL extension such as GLX for 10 Window System, WGL for Microsoft Window, and AGL, CGL or Cocoa for Mac OS.
Quoting from the opengl.org: "GLUT is designed for amalgam small to medium sized OpenGL programs. While Overabundance is well-suited to learning OpenGL and developing simple OpenGL applications, Overabundance is not a full-featured toolkit and then big applications requiring sophisticated user interfaces are better off using native window system toolkits. Overabundance is simple, easy, and small."
Culling of GLUT includes SDL, .... - OpenGL Extension Wrangler Library (GLEW): "GLEW is a cross-platform open up-source C/C++ extension loading library. GLEW provides efficient run-fourth dimension mechanisms for determining which OpenGL extensions are supported on the target platform." Source and pre-build binary bachelor 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 organization. - Others.
Vertex, Archaic and Colour
Example 2: Vertex, Archaic and Color (GL02Primitive.cpp)
Try building and runnng this OpenGL C/C++ program:
one 2 3 4 5 6 7 8 ix x 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 twoscore 41 42 43 44 45 46 47 48 49 l 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 | #include <windows.h> #include <GL/glut.h> void initGL() { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); } void display() { glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_QUADS); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(-0.8f, 0.1f); glVertex2f(-0.2f, 0.1f); glVertex2f(-0.2f, 0.7f); glVertex2f(-0.8f, 0.7f); glColor3f(0.0f, 1.0f, 0.0f); 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); glVertex2f(-0.9f, -0.7f); glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(-0.5f, -0.7f); glColor3f(0.2f, 0.2f, 0.2f); glVertex2f(-0.5f, -0.3f); glColor3f(1.0f, one.0f, one.0f); glVertex2f(-0.9f, -0.3f); glEnd(); glBegin(GL_TRIANGLES); glColor3f(0.0f, 0.0f, ane.0f); glVertex2f(0.1f, -0.6f); glVertex2f(0.7f, -0.6f); glVertex2f(0.4f, -0.1f); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(0.3f, -0.4f); glColor3f(0.0f, i.0f, 0.0f); glVertex2f(0.9f, -0.4f); glColor3f(0.0f, 0.0f, i.0f); glVertex2f(0.6f, -0.9f); glEnd(); glBegin(GL_POLYGON); glColor3f(one.0f, 1.0f, 0.0f); 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(); } int primary(int argc, char** argv) { glutInit(&argc, argv); glutCreateWindow("Vertex, Primitive & Color"); glutInitWindowSize(320, 320); glutInitWindowPosition(50, 50); glutDisplayFunc(brandish); initGL(); glutMainLoop(); return 0; } |
The expected output and the coordinates are as follows. Take note that four shapes have pure color, and 2 shapes have color blending from their vertices.
I shall explicate the programme in the following sections.
OpenGL equally a State Machine
OpenGL operates every bit a state car, and maintain a gear up of land variables (such as the foreground color, background color, and many more than). In a state machine, once the value of a state variable is set, the value persists until a new value is given.
For instance, we set the "clearing" (background) color to blackness once in initGL(). We use this setting to clear the window in the display() repeatedly (display() is called dorsum whenever there is a window re-paint request) - the clearing color is not inverse in the entire program.
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT);
Another example: If we apply glColor function to set the electric current foreground color to "ruby-red", then "red" will be used for all the subsequent vertices, until we use another glColor function to modify the foreground color.
In a state machine, everything shall remain until you explicitly change it!
Naming Convention for OpenGL Functions
An OpenGL functions:
- begins with lowercase
gl(for core OpenGL),glu(for OpenGL Utility) orglut(for OpenGL Utility Toolkit). - followed by the purpose of the function, in camel case (initial-capitalized), e.g.,
glColorto specify the drawing color,glVertexto ascertain the position of a vertex. - followed past specifications for the parameters, east.grand.,
glColor3ftakes iiifloatparameters.glVectex2itakes twointparameters.
(This is needed as C Linguistic communication does non support function overloading. Dissimilar versions of the role need to be written for dissimilar parameter lists.)
The convention can be expressed equally follows:
returnType glFunction[234][sifd] (type value, ...); returnType glPart[234][sifd]five (blazon *value);
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(8-bit),GLshort(16-fleck),GLint(32-bit). - Unsigned Integers:
GLubyte(8-fleck),GLushort(xvi-bit),GLuint(32-chip). - Floating-indicate numbers:
GLfloat(32-bit),GLdouble(64-bit),GLclampfandGLclampd(between 0.0 and 1.0). -
GLboolean(unsigned char with 0 for false and non-0 for true). -
GLsizei(32-fleck non-negative integers). -
GLenum(32-bit enumerated integers).
The OpenGL types are defined via typedef in "gl.h" as follows:
typedef unsigned int GLenum; typedef unsigned char GLboolean; typedef unsigned int GLbitfield; typedef void GLvoid; typedef signed char GLbyte; typedef short GLshort; typedef int GLint; typedef unsigned char GLubyte; typedef unsigned short GLushort; typedef unsigned int GLuint; typedef int GLsizei; typedef float GLfloat; typedef bladder GLclampf; typedef double GLdouble; typedef double GLclampd;
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, two.2f, 3.3f); glVertex2i(4, 5); glColor4f(0.0f, 0.0f, 0.0f, 1.0f); GLdouble aVertex[] = {1.1, 2.2, iii.3}; glVertex3fv(aVertex); 1-time Initialization initGL()
The initGL() is meant for carrying out one-time OpenGL initialization tasks, such as setting the immigration color. initGL() is invoked once (and only once) in main().
Callback Handler display()
The function display() is known as a callback event handler. An event handler provides the response to a particular result (such equally cardinal-press, mouse-click, window-paint). The office display() is meant to be the handler for window-paint outcome. The OpenGL graphics system calls back display() in response to a window-paint request to re-paint the window (e.1000., window start appears, window is restored after minimized, and window is resized). Callback means that the function is invoked by the arrangement, instead of called by the your program.
The Brandish() runs when the window showtime appears and once per subsequent re-pigment request. Detect that we included OpenGL graphics rendering code within the display() function, and then as to re-describe the unabridged window when the window first appears and upon each re-paint request.
Setting up Glut - principal()
GLUT provides high-level utilities to simplify OpenGL programming, particularly in interacting with the Operating System (such as creating a window, handling key and mouse inputs). The following Glut functions were used in the above program:
-
glutInit: initializes Glut, must be called before other GL/GLUT functions. Information technology takes the same arguments as theprimary().void glutInit(int *argc, char **argv)
-
glutCreateWindow: creates a window with the given title.int glutCreateWindow(char *title)
-
glutInitWindowSize: specifies the initial window width and height, in pixels.void glutInitWindowSize(int width, int tiptop)
-
glutInitWindowPosition: positions the summit-left 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 acme-left corner of the screen; x-centrality pointing right and y-centrality pointing downwardly.void glutInitWindowPosition(int x, int y)
-
glutDisplayFunc: registers the callback function (or event handler) for treatment window-paint event. The OpenGL graphic system calls dorsum this handler when it receives a window re-paint asking. In the case, we register the partdisplay()as the handler.void glutDisplayFunc(void (*func)(void))
-
glutMainLoop: enters the infinite event-processing loop, i.eastward, put the OpenGL graphics organisation to wait for events (such as re-paint), and trigger respective upshot handlers (such asdisplay()).void glutMainLoop()
In the main() function of the example:
glutInit(&argc, argv); glutCreateWindow("Vertex, Primitive & Colour"); glutInitWindowSize(320, 320); glutInitWindowPosition(50, 50); We initialize the Overabundance and create a window with a title, an initial size and position.
glutDisplayFunc(display);
We annals brandish() function as the callback handler for window-paint effect. That is, display() runs when the window first appears and whenever there is a request to re-pigment the window.
initGL();
We phone call the initGL() to perform all the one-fourth dimension initialization operations. In this instance, we set the clearing (background) color once, and utilize it repeatably in the brandish() function.
glutMainLoop();
We and so put the plan into the upshot-handling loop, awaiting for events (such as window-paint request) to trigger off the respective event handlers (such equally display()).
Color
We use glColor function to set the foreground colour, and glClearColor office to set up the background (or clearing) color.
void glColor3f(GLfloat carmine, GLfloat green, GLfloat bluish) void glColor3fv(GLfloat *colorRGB) void glColor4f(GLfloat cherry, GLfloat greenish, GLfloat blue, GLfloat alpha) void glColor4fv(GLfloat *colorRGBA) void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
Notes:
- Color is typically specified in
bladderin the range0.0fandone.0f. - Color can be specified using RGB (Red-Green-Blue) or RGBA (Red-Dark-green-Bluish-Alpha) components. The 'A' (or alpha) specifies the transparency (or opacity) index, with value of 1 denotes opaque (non-transparent and cannot meet-thru) and value of 0 denotes total transparent. Nosotros shall discuss alpha later.
In the above example, we gear up the background colour via glClearColor in initGL(), with R=0, G=0, B=0 (blackness) and A=i (opaque and cannot see through).
glClearColor(0.0f, 0.0f, 0.0f, ane.0f);
In display(), we set the vertex colour via glColor3f for subsequent vertices. For example, R=ane, G=0, B=0 (cerise).
glColor3f(1.0f, 0.0f, 0.0f);
Geometric Primitives
In OpenGL, an object is made up of geometric primitives such every bit triangle, quad, line segment and point. A primitive is made up of one or more vertices. OpenGL supports the following primitives:
A geometric archaic is defined by specifying its vertices via glVertex function, enclosed within a pair glBegin and glEnd.
void glBegin(GLenum shape) void glVertex[234][sifd] (type x, type y, type z, ...) void glVertex[234][sifd]v (type *coords) void glEnd()
glBegin specifies the blazon of geometric object, such as GL_POINTS, GL_LINES, GL_QUADS, GL_TRIANGLES, and GL_POLYGON. For types that end with 'S', yous tin can ascertain multiple objects of the same type in each glBegin/glEnd pair. For example, for GL_TRIANGLES, each set up of 3 glVertex's defines a triangle.
The vertices are ordinarily specified in bladder precision. It is because integer is not suitable for trigonometric operations (needed to conduct out transformations such as rotation). Precision of float is sufficient for carrying out intermediate operations, and return the objects finally into pixels on screen (with resolution of says 800x600, integral precision). double precision is frequently not necessary.
In the higher up example:
glBegin(GL_QUADS); glEnd();
we define 3 color quads (GL_QUADS) with 12x glVertex() functions.
glColor3f(ane.0f, 0.0f, 0.0f); glVertex2f(-0.8f, 0.1f); glVertex2f(-0.2f, 0.1f); glVertex2f(-0.2f, 0.7f); glVertex2f(-0.8f, 0.7f);
We gear up the color to ruby-red (R=1, Chiliad=0, B=0). All subsequent vertices will have the color of red. Take annotation that in OpenGL, color (and many backdrop) is practical 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 (equally 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 grey, every bit shown in the output.
glColor3f(0.2f, 0.2f, 0.2f); glVertex2f(-0.9f, -0.7f); glColor3f(1.0f, ane.0f, one.0f); glVertex2f(-0.5f, -0.7f); glColor3f(0.2f, 0.2f, 0.2f); glVertex2f(-0.5f, -0.3f); glColor3f(i.0f, 1.0f, 1.0f); glVertex2f(-0.9f, -0.3f);
2D Coordinate Arrangement and the Default View
The following diagram shows the OpenGL 2D Coordinate System, which corresponds to the everyday second Cartesian coordinates with origin located at the bottom-left corner.
The default OpenGL 2D clipping-area (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.due east., a 2x2 square with centered at the origin. This clipping-area 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.
Clipping-Expanse & Viewport
Try dragging the corner of the window to brand it bigger or smaller. Observe that all the shapes are distorted.
Nosotros can handle the re-sizing of window via a callback handler reshape(), which can exist programmed to adjust the OpenGL clipping-expanse according to the window's aspect ratio.
Clipping Area: Clipping area refers to the area that can exist seen (i.eastward., captured past the camera), measured in OpenGL coordinates.
The role gluOrtho2D tin be used to set up the clipping area of 2D orthographic view. Objects outside the clipping surface area will be clipped abroad and cannot be seen.
void gluOrtho2D(GLdouble left, GLdouble correct, GLdouble bottom, GLdouble top)
To fix the clipping expanse, we need to result a series of commands as follows: nosotros first select the and so-chosen projection matrix for operation, and reset the projection matrix to identity. We and then cull the 2D orthographic view with the desired clipping area, via gluOrtho2D().
glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(-1.0, 1.0, -i.0, ane.0);
Viewport: Viewport refers to the display surface area on the window (screen), which is measured in pixels in screen coordinates (excluding the championship bar).
The clipping expanse is mapped to the viewport. We can use glViewport role to configure the viewport.
void glViewport(GLint xTopLeft, GLint yTopLeft, GLsizei width, GLsizei superlative)
Suppose the the clipping expanse's (left, right, bottom, pinnacle) 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 bottom-left corner (-1.0, -1.0) maps to (0, 0) in the viewport, the meridian-right corner (i.0, 1.0) maps to (639, 479). It is obvious that if the aspect ratios for the clipping surface area and the viewport are not the aforementioned, the shapes will be distorted.
Have note that in the earlier case, the windows' size of 320x320 has a foursquare shape, with a attribute ratio consistent with the default 2x2 squarish clipping-area.
Example 3: Clipping-area and Viewport (GL03Viewport.cpp)
1 2 3 iv v half dozen vii 8 nine 10 xi 12 thirteen xiv 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 xxx 31 32 33 34 35 36 37 38 39 twoscore 41 42 43 44 45 46 47 48 49 l 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 eighty 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | #include <windows.h> #include <GL/glut.h> void initGL() { glClearColor(0.0f, 0.0f, 0.0f, i.0f); } void display() { glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_QUADS); glColor3f(one.0f, 0.0f, 0.0f); glVertex2f(-0.8f, 0.1f); glVertex2f(-0.2f, 0.1f); glVertex2f(-0.2f, 0.7f); glVertex2f(-0.8f, 0.7f); glColor3f(0.0f, 1.0f, 0.0f); 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); glVertex2f(-0.9f, -0.7f); glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(-0.5f, -0.7f); glColor3f(0.2f, 0.2f, 0.2f); glVertex2f(-0.5f, -0.3f); glColor3f(one.0f, ane.0f, 1.0f); glVertex2f(-0.9f, -0.3f); glEnd(); glBegin(GL_TRIANGLES); glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(0.1f, -0.6f); glVertex2f(0.7f, -0.6f); glVertex2f(0.4f, -0.1f); glColor3f(i.0f, 0.0f, 0.0f); glVertex2f(0.3f, -0.4f); glColor3f(0.0f, i.0f, 0.0f); glVertex2f(0.9f, -0.4f); glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(0.6f, -0.9f); glEnd(); glBegin(GL_POLYGON); glColor3f(1.0f, one.0f, 0.0f); 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(); } void reshape(GLsizei width, GLsizei height) { if (tiptop == 0) height = ane; GLfloat attribute = (GLfloat)width / (GLfloat)height; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (width >= peak) { gluOrtho2D(-ane.0 * aspect, 1.0 * aspect, -1.0, 1.0); } else { gluOrtho2D(-1.0, 1.0, -i.0 / aspect, ane.0 / aspect); } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitWindowSize(640, 480); glutInitWindowPosition(50, 50); glutCreateWindow("Viewport Transform"); glutDisplayFunc(display); glutReshapeFunc(reshape); initGL(); glutMainLoop(); render 0; } |
A reshape() function, which is called back when the window showtime appears and whenever the window is re-sized, can exist used to ensure consequent aspect ratio betwixt clipping-area and viewport, every bit shown in the above example. The graphics sub-system passes the window'due south width and top, in pixels, into the reshape().
GLfloat aspect = (GLfloat)width / (GLfloat)height;
We compute the aspect ratio of the new re-sized window, given its new width and height provided by the graphics sub-system to the callback office reshape().
glViewport(0, 0, width, height);
We set the viewport to cover the entire new re-sized window, in pixels.
Try setting the viewport to cover only a quarter (lower-right qradrant) of the window via glViewport(0, 0, width/ii, superlative/ii).
glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (width >= height) { gluOrtho2D(-1.0 * aspect, 1.0 * aspect, -one.0, one.0); } else { gluOrtho2D(-1.0, 1.0, -1.0 / aspect, one.0 / attribute); } We set the aspect ratio of the clipping area to match the viewport. To set the clipping expanse, we first choose the operate on the projection matrix via glMatrixMode(GL_PROJECTION). OpenGL has two matrices, a projection matrix (which deals with photographic camera projection such every bit setting the clipping surface area) and a model-view matrix (for transforming the objects from their local spaces to the common world space). We reset the projection matrix via glLoadIdentity().
Finally, nosotros invoke gluOrtho2D() to fix the clipping area with an aspect ratio matching the viewport. The shorter side has the range from -1 to +1, as illustrated beneath:
We need to register the reshape() callback handler with GLUT via glutReshapeFunc() in the main() as follows:
int main(int argc, char** argv) { glutInitWindowSize(640, 480); ...... glutReshapeFunc(reshape); } In the above main() function, we specify the initial window size to 640x480, which is not-squarish. Try re-sizing 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 re-shaped. On the other mitt, the initGL() runs once (and just one time); and the display() runs in response to window re-paint asking (e.chiliad., after the window is re-sized).
Translation & Rotation
In the in a higher place sample, we positioned each of the shapes past defining their vertices with respective to the same origin (called earth space). It took me quite a while to figure out the absolute coordinates of these vertices.
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 tin can then use translation and/or rotation to position the shapes at the desired locations in the world infinite, as shown in the post-obit revised display() function.
Case 4: Translation and Rotation (GL04ModelTransform.cpp)
1 ii three 4 five 6 seven eight 9 x 11 12 13 fourteen 15 16 17 xviii 19 xx 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 lxx 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 | #include <windows.h> #include <GL/glut.h> void initGL() { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); } void brandish() { glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(-0.5f, 0.4f, 0.0f); glBegin(GL_QUADS); glColor3f(one.0f, 0.0f, 0.0f); glVertex2f(-0.3f, -0.3f); glVertex2f( 0.3f, -0.3f); glVertex2f( 0.3f, 0.3f); glVertex2f(-0.3f, 0.3f); glEnd(); glTranslatef(0.1f, -0.7f, 0.0f); glBegin(GL_QUADS); glColor3f(0.0f, i.0f, 0.0f); 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); glBegin(GL_QUADS); glColor3f(0.2f, 0.2f, 0.2f); glVertex2f(-0.2f, -0.2f); glColor3f(1.0f, ane.0f, 1.0f); glVertex2f( 0.2f, -0.2f); glColor3f(0.2f, 0.2f, 0.2f); glVertex2f( 0.2f, 0.2f); glColor3f(i.0f, 1.0f, one.0f); glVertex2f(-0.2f, 0.2f); glEnd(); glTranslatef(one.1f, 0.2f, 0.0f); glBegin(GL_TRIANGLES); glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(-0.3f, -0.2f); glVertex2f( 0.3f, -0.2f); glVertex2f( 0.0f, 0.3f); glEnd(); glTranslatef(0.2f, -0.3f, 0.0f); glRotatef(180.0f, 0.0f, 0.0f, 1.0f); glBegin(GL_TRIANGLES); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(-0.3f, -0.2f); glColor3f(0.0f, one.0f, 0.0f); glVertex2f( 0.3f, -0.2f); glColor3f(0.0f, 0.0f, 1.0f); glVertex2f( 0.0f, 0.3f); glEnd(); glRotatef(-180.0f, 0.0f, 0.0f, 1.0f); glTranslatef(-0.1f, 1.0f, 0.0f); glBegin(GL_POLYGON); glColor3f(1.0f, 1.0f, 0.0f); 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(); } void reshape(GLsizei width, GLsizei acme) { if (top == 0) top = 1; GLfloat attribute = (GLfloat)width / (GLfloat)height; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (width >= height) { gluOrtho2D(-i.0 * aspect, one.0 * aspect, -ane.0, 1.0); } else { gluOrtho2D(-1.0, i.0, -ane.0 / aspect, i.0 / aspect); } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitWindowSize(640, 480); glutInitWindowPosition(l, 50); glutCreateWindow("Model Transform"); glutDisplayFunc(display); glutReshapeFunc(reshape); initGL(); glutMainLoop(); render 0; } |
glMatrixMode(GL_MODELVIEW); glLoadIdentity();
Translation and rotation are parts of and then-called model transform, which transform from the objects from the local space (or model infinite) to the common globe space. To carry out model transform, we set the matrix fashion to mode-view matrix (GL_MODELVIEW) and reset the matrix. (Recall that in the previous case, we gear up the matrix mode to projection matrix (GL_PROJECTION) to gear up the clipping area.)
OpenGL is operating as a state machine. That is, once a land is ready, the value of the country persists until it is changed. In other words, once the coordinates are translated or rotated, all the subsequent operations volition exist based on this coordinates.
Translation is done via glTranslate role:
void gltranslatef (GLfloat x, GLfloat y, GLfloat z)
Take note that glTranslatef part must exist placed exterior the glBegin/glEnd, where as glColor can be placed inside glBegin/glEnd.
Rotation is done via glRotatef function:
void glRotatef (GLfloat angle, GLfloat 10, GLfloat y, GLfloat z)
Have notation that the rotational angle is measured in degrees (instead of radians) in OpenGL.
In the above example, we translate within the x-y airplane (z=0) and rotate about the z-axis (which is normal to the x-y plane).
Animation
Idle Part
To perform animation (due east.g., rotating the shapes), you could register an idle() callback handler with GLUT, via glutIdleFunc command. The graphic system will remember the idle() role when there is no other consequence to exist processed.
void glutIdleFunc(void (*func)(void))
In the idle() function, you could issue glutPostRedisplay control to post a window re-paint request, which in turn will activate brandish() function.
void idle() { glutPostRedisplay(); } Take note that the to a higher place is equivalent to registering brandish() as the idle role.
glutIdleFunc(brandish);
Double Buffering
Double buffering uses two brandish buffers to smooth blitheness. The next screen is prepared in a back buffer, while the current screen is held in a front buffer. Once the training is washed, you can employ glutSwapBuffer control to swap the front and back buffers.
To utilise double buffering, you need to make two changes:
- In the
main(), include this line before creating the window:glutInitDisplayMode(GLUT_DOUBLE);
- In the
display()function, replaceglFlush()withglutSwapBuffers(), which swap the forepart and back buffers.
Double buffering should be used in animation. For static display, single buffering is sufficient. (Many graphics hardware e'er double buffered, so it is hard to see the differences.)
Example 5: Blitheness using Idle Function (GL05IdleFunc.cpp)
The following program rotates all the shapes created in our previous example using idle function with double buffering.
1 2 3 4 v vi 7 8 9 10 11 12 thirteen fourteen 15 xvi 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 xl 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 seventy 71 72 73 74 75 76 77 78 79 fourscore 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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | #include <windows.h> #include <GL/glut.h> GLfloat bending = 0.0f; void initGL() { glClearColor(0.0f, 0.0f, 0.0f, 1.0f); } void idle() { glutPostRedisplay(); } void display() { glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glPushMatrix(); glTranslatef(-0.5f, 0.4f, 0.0f); glRotatef(angle, 0.0f, 0.0f, 1.0f); glBegin(GL_QUADS); glColor3f(1.0f, 0.0f, 0.0f); glVertex2f(-0.3f, -0.3f); glVertex2f( 0.3f, -0.3f); glVertex2f( 0.3f, 0.3f); glVertex2f(-0.3f, 0.3f); glEnd(); glPopMatrix(); glPushMatrix(); glTranslatef(-0.4f, -0.3f, 0.0f); glRotatef(angle, 0.0f, 0.0f, 1.0f); glBegin(GL_QUADS); glColor3f(0.0f, ane.0f, 0.0f); glVertex2f(-0.3f, -0.3f); glVertex2f( 0.3f, -0.3f); glVertex2f( 0.3f, 0.3f); glVertex2f(-0.3f, 0.3f); glEnd(); glPopMatrix(); glPushMatrix(); glTranslatef(-0.7f, -0.5f, 0.0f); glRotatef(bending, 0.0f, 0.0f, 1.0f); glBegin(GL_QUADS); glColor3f(0.2f, 0.2f, 0.2f); glVertex2f(-0.2f, -0.2f); glColor3f(i.0f, 1.0f, 1.0f); glVertex2f( 0.2f, -0.2f); glColor3f(0.2f, 0.2f, 0.2f); glVertex2f( 0.2f, 0.2f); glColor3f(1.0f, 1.0f, 1.0f); glVertex2f(-0.2f, 0.2f); glEnd(); glPopMatrix(); glPushMatrix(); glTranslatef(0.4f, -0.3f, 0.0f); glRotatef(angle, 0.0f, 0.0f, one.0f); glBegin(GL_TRIANGLES); glColor3f(0.0f, 0.0f, i.0f); glVertex2f(-0.3f, -0.2f); glVertex2f( 0.3f, -0.2f); glVertex2f( 0.0f, 0.3f); glEnd(); glPopMatrix(); glPushMatrix(); glTranslatef(0.6f, -0.6f, 0.0f); glRotatef(180.0f + angle, 0.0f, 0.0f, ane.0f); glBegin(GL_TRIANGLES); glColor3f(i.0f, 0.0f, 0.0f); glVertex2f(-0.3f, -0.2f); glColor3f(0.0f, ane.0f, 0.0f); glVertex2f( 0.3f, -0.2f); glColor3f(0.0f, 0.0f, i.0f); glVertex2f( 0.0f, 0.3f); glEnd(); glPopMatrix(); glPushMatrix(); glTranslatef(0.5f, 0.4f, 0.0f); glRotatef(angle, 0.0f, 0.0f, i.0f); glBegin(GL_POLYGON); glColor3f(1.0f, 1.0f, 0.0f); 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(); glutSwapBuffers(); angle += 0.2f; } void reshape(GLsizei width, GLsizei top) { if (height == 0) top = one; GLfloat aspect = (GLfloat)width / (GLfloat)height; glViewport(0, 0, width, peak); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (width >= height) { gluOrtho2D(-1.0 * aspect, one.0 * aspect, -ane.0, 1.0); } else { gluOrtho2D(-i.0, ane.0, -1.0 / attribute, 1.0 / attribute); } } int principal(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE); glutInitWindowSize(640, 480); glutInitWindowPosition(l, 50); glutCreateWindow("Animation via Idle Function"); glutDisplayFunc(display); glutReshapeFunc(reshape); glutIdleFunc(idle); initGL(); glutMainLoop(); render 0; } |
In the above case, instead of accumulating all the translations and undoing the rotations, we apply glPushMatrix to save the current state, perform transformations, and restore the saved state via glPopMatrix. (In the above example, we can likewise use glLoadIdentity to reset the matrix before the next transformations.)
GLfloat angle = 0.0f;
We define a global variable called bending to go along track of the rotational angle of all the shapes. We volition 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(); glutInitDisplayMode(GLUT_DOUBLE);
Instead of glFlush() which flushes the framebuffer for display immediately, nosotros enable double buffering and apply glutSwapBuffer() to swap the front- and back-buffer during the VSync for smoother display.
void idle() { glutPostRedisplay(); } glutIdleFunc(idle); Nosotros define an idle() function, which posts a re-paint request and invoke display(), if there is no effect outstanding. We register this idle() function in chief() via glutIdleFunc().
Double Buffering & Refresh Charge per unit
When double buffering is enabled, glutSwapBuffers synchronizes with the screen refresh interval (VSync). That is, the buffers will be swapped at the same time when the monitor is putting upward a new frame. Every bit the result, idle() function, at best, refreshes the blitheness at the same rate as the refresh rate of the monitor (60Hz for LCD/LED monitor). It may operates at one-half the monitor refresh charge per unit (if the computations takes more than than 1 refresh interval), i-tertiary, 1-quaternary, and then on, because it need to wait for the VSync.
Timer Function
With idle(), we accept 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.
void glutTimerFunc(unsigned int millis, void (*func)(int value), value)
Example vi: Blitheness via Timer Function (GL06TimerFunc.cpp)
The following modifications rotate all the shapes created in the earlier instance counter-clockwise by 2 degree per thirty milliseconds.
1 2 3 4 5 6 7 8 9 10 xi 12 13 14 xv 16 17 18 19 20 21 22 23 24 25 26 27 28 29 thirty 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 lxx 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 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | #include <windows.h> #include <GL/glut.h> GLfloat angle = 0.0f; int refreshMills = 30; void initGL() { glClearColor(0.0f, 0.0f, 0.0f, i.0f); } void Timer(int value) { glutPostRedisplay(); glutTimerFunc(refreshMills, Timer, 0); } void display() { glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glPushMatrix(); glTranslatef(-0.5f, 0.4f, 0.0f); glRotatef(angle, 0.0f, 0.0f, 1.0f); glBegin(GL_QUADS); glColor3f(i.0f, 0.0f, 0.0f); glVertex2f(-0.3f, -0.3f); glVertex2f( 0.3f, -0.3f); glVertex2f( 0.3f, 0.3f); glVertex2f(-0.3f, 0.3f); glEnd(); glPopMatrix(); glPushMatrix(); glTranslatef(-0.4f, -0.3f, 0.0f); glRotatef(angle, 0.0f, 0.0f, ane.0f); glBegin(GL_QUADS); glColor3f(0.0f, 1.0f, 0.0f); glVertex2f(-0.3f, -0.3f); glVertex2f( 0.3f, -0.3f); glVertex2f( 0.3f, 0.3f); glVertex2f(-0.3f, 0.3f); glEnd(); glPopMatrix(); glPushMatrix(); glTranslatef(-0.7f, -0.5f, 0.0f); glRotatef(angle, 0.0f, 0.0f, 1.0f); glBegin(GL_QUADS); glColor3f(0.2f, 0.2f, 0.2f); glVertex2f(-0.2f, -0.2f); glColor3f(i.0f, 1.0f, 1.0f); glVertex2f( 0.2f, -0.2f); glColor3f(0.2f, 0.2f, 0.2f); glVertex2f( 0.2f, 0.2f); glColor3f(ane.0f, 1.0f, i.0f); glVertex2f(-0.2f, 0.2f); glEnd(); glPopMatrix(); glPushMatrix(); glTranslatef(0.4f, -0.3f, 0.0f); glRotatef(angle, 0.0f, 0.0f, i.0f); glBegin(GL_TRIANGLES); glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(-0.3f, -0.2f); glVertex2f( 0.3f, -0.2f); glVertex2f( 0.0f, 0.3f); glEnd(); glPopMatrix(); glPushMatrix(); glTranslatef(0.6f, -0.6f, 0.0f); glRotatef(180.0f + angle, 0.0f, 0.0f, i.0f); glBegin(GL_TRIANGLES); glColor3f(i.0f, 0.0f, 0.0f); glVertex2f(-0.3f, -0.2f); glColor3f(0.0f, i.0f, 0.0f); glVertex2f( 0.3f, -0.2f); glColor3f(0.0f, 0.0f, ane.0f); glVertex2f( 0.0f, 0.3f); glEnd(); glPopMatrix(); glPushMatrix(); glTranslatef(0.5f, 0.4f, 0.0f); glRotatef(bending, 0.0f, 0.0f, one.0f); glBegin(GL_POLYGON); glColor3f(1.0f, one.0f, 0.0f); 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(); glutSwapBuffers(); angle += 2.0f; } void reshape(GLsizei width, GLsizei peak) { if (height == 0) superlative = 1; GLfloat aspect = (GLfloat)width / (GLfloat)elevation; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (width >= height) { gluOrtho2D(-i.0 * attribute, 1.0 * aspect, -i.0, 1.0); } else { gluOrtho2D(-one.0, 1.0, -1.0 / attribute, 1.0 / aspect); } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE); glutInitWindowSize(640, 480); glutInitWindowPosition(l, 50); glutCreateWindow("Blitheness via Idle Part"); glutDisplayFunc(brandish); glutReshapeFunc(reshape); glutTimerFunc(0, Timer, 0); initGL(); glutMainLoop(); return 0; } |
void Timer(int value) { glutPostRedisplay(); glutTimerFunc(refreshMills, Timer, 0); } We supervene upon the idle() office by a timer() function, which mail service a re-paint request to invoke display(), later on the timer expired.
glutTimerFunc(0, Timer, 0);
In chief(), we annals the timer() office, and activate the timer() immediately (with initial timer = 0).
More Glut functions
-
glutInitDisplayMode: requests a display with the specified mode, such every bit color way (GLUT_RGB,GLUT_RGBA,GLUT_INDEX), single/double buffering (GLUT_SINGLE,GLUT_DOUBLE), enable depth (GLUT_DEPTH), joined with a bitOR'|'.void glutInitDisplayMode(unsigned int displayMode)
For example,
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
Instance seven: A Billowy Brawl (GL07BouncingBall.cpp)
This example shows a brawl bouncing within the window. Take annotation that circle is not a primitive geometric shape in OpenGL. This example uses TRIANGLE_FAN to compose a circle.
1 2 3 4 5 6 7 8 nine 10 11 12 13 14 15 16 17 18 19 xx 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 lx 61 62 63 64 65 66 67 68 69 lxx 71 72 73 74 75 76 77 78 79 lxxx 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 | #include <windows.h> #include <GL/glut.h> #include <Math.h> #ascertain PI iii.14159265f char title[] = "Bouncing Ball (2D)"; int windowWidth = 640; int windowHeight = 480; int windowPosX = 50; int windowPosY = 50; GLfloat ballRadius = 0.5f; GLfloat ballX = 0.0f; GLfloat ballY = 0.0f; GLfloat ballXMax, ballXMin, ballYMax, ballYMin; GLfloat xSpeed = 0.02f; GLfloat ySpeed = 0.007f; int refreshMillis = 30; GLdouble clipAreaXLeft, clipAreaXRight, clipAreaYBottom, clipAreaYTop; void initGL() { glClearColor(0.0, 0.0, 0.0, one.0); } void display() { glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(ballX, ballY, 0.0f); glBegin(GL_TRIANGLE_FAN); glColor3f(0.0f, 0.0f, one.0f); glVertex2f(0.0f, 0.0f); int numSegments = 100; GLfloat angle; for (int i = 0; i <= numSegments; i++) { bending = i * ii.0f * PI / numSegments; glVertex2f(cos(angle) * ballRadius, sin(bending) * ballRadius); } glEnd(); glutSwapBuffers(); ballX += xSpeed; ballY += ySpeed; if (ballX > ballXMax) { ballX = ballXMax; xSpeed = -xSpeed; } else if (ballX < ballXMin) { ballX = ballXMin; xSpeed = -xSpeed; } if (ballY > ballYMax) { ballY = ballYMax; ySpeed = -ySpeed; } else if (ballY < ballYMin) { ballY = ballYMin; ySpeed = -ySpeed; } } void reshape(GLsizei width, GLsizei top) { if (height == 0) height = 1; GLfloat aspect = (GLfloat)width / (GLfloat)height; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (width >= height) { clipAreaXLeft = -1.0 * attribute; clipAreaXRight = 1.0 * aspect; clipAreaYBottom = -1.0; clipAreaYTop = 1.0; } else { clipAreaXLeft = -1.0; clipAreaXRight = 1.0; clipAreaYBottom = -1.0 / aspect; clipAreaYTop = i.0 / aspect; } gluOrtho2D(clipAreaXLeft, clipAreaXRight, clipAreaYBottom, clipAreaYTop); ballXMin = clipAreaXLeft + ballRadius; ballXMax = clipAreaXRight - ballRadius; ballYMin = clipAreaYBottom + ballRadius; ballYMax = clipAreaYTop - ballRadius; } void Timer(int value) { glutPostRedisplay(); glutTimerFunc(refreshMillis, Timer, 0); } int primary(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE); glutInitWindowSize(windowWidth, windowHeight); glutInitWindowPosition(windowPosX, windowPosY); glutCreateWindow(title); glutDisplayFunc(display); glutReshapeFunc(reshape); glutTimerFunc(0, Timer, 0); initGL(); glutMainLoop(); return 0; } |
[TODO] Caption
Treatment Keyboard Inputs with GLUT
We can annals callback functions to handle keyboard inputs for normal and special keys, respectively.
-
glutKeyboardFunc: registers callback handler for keyboard result.void glutKeyboardFunc (void (*func)(unsigned char key, int x, int y)
-
glutSpecialFunc: registers callback handler for special fundamental (such as arrow keys and function keys).void glutSpecialFunc (void (*func)(int specialKey, int x, int y)
Example 8: Switching between Full-Screen and Windowed-fashion (GL08FullScreen.cpp)
For the bouncing ball plan, the following special-key handler toggles between full-screen and windowed modes using F1 primal.
1 two 3 iv 5 6 7 viii 9 ten xi 12 xiii 14 15 16 17 xviii xix 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 74 75 76 77 78 79 lxxx 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 133 134 135 136 137 138 139 140 141 142 143 144 145 | #include <windows.h> #include <GL/overabundance.h> #include <Math.h> #define PI iii.14159265f char title[] = "Full-Screen & Windowed Fashion"; int windowWidth = 640; int windowHeight = 480; int windowPosX = 50; int windowPosY = 50; GLfloat ballRadius = 0.5f; GLfloat ballX = 0.0f; GLfloat ballY = 0.0f; GLfloat ballXMax, ballXMin, ballYMax, ballYMin; GLfloat xSpeed = 0.02f; GLfloat ySpeed = 0.007f; int refreshMillis = 30; GLdouble clipAreaXLeft, clipAreaXRight, clipAreaYBottom, clipAreaYTop; bool fullScreenMode = true; void initGL() { glClearColor(0.0, 0.0, 0.0, i.0); } void display() { glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(ballX, ballY, 0.0f); glBegin(GL_TRIANGLE_FAN); glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(0.0f, 0.0f); int numSegments = 100; GLfloat bending; for (int i = 0; i <= numSegments; i++) { angle = i * 2.0f * PI / numSegments; glVertex2f(cos(bending) * ballRadius, sin(angle) * ballRadius); } glEnd(); glutSwapBuffers(); ballX += xSpeed; ballY += ySpeed; if (ballX > ballXMax) { ballX = ballXMax; xSpeed = -xSpeed; } else if (ballX < ballXMin) { ballX = ballXMin; xSpeed = -xSpeed; } if (ballY > ballYMax) { ballY = ballYMax; ySpeed = -ySpeed; } else if (ballY < ballYMin) { ballY = ballYMin; ySpeed = -ySpeed; } } void reshape(GLsizei width, GLsizei height) { if (height == 0) height = 1; GLfloat attribute = (GLfloat)width / (GLfloat)height; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (width >= superlative) { clipAreaXLeft = -i.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 = clipAreaXRight - ballRadius; ballYMin = clipAreaYBottom + ballRadius; ballYMax = clipAreaYTop - ballRadius; } void Timer(int value) { glutPostRedisplay(); glutTimerFunc(refreshMillis, Timer, 0); } void specialKeys(int key, int x, int y) { switch (fundamental) { example GLUT_KEY_F1: fullScreenMode = !fullScreenMode; if (fullScreenMode) { windowPosX = glutGet(GLUT_WINDOW_X); windowPosY = glutGet(GLUT_WINDOW_Y); windowWidth = glutGet(GLUT_WINDOW_WIDTH); windowHeight = glutGet(GLUT_WINDOW_HEIGHT); glutFullScreen(); } else { glutReshapeWindow(windowWidth, windowHeight); glutPositionWindow(windowPosX, windowPosX); } break; } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE); glutInitWindowSize(windowWidth, windowHeight); glutInitWindowPosition(windowPosX, windowPosY); glutCreateWindow(title); glutDisplayFunc(display); glutReshapeFunc(reshape); glutTimerFunc(0, Timer, 0); glutSpecialFunc(specialKeys); glutFullScreen(); initGL(); glutMainLoop(); return 0; } |
[TODO] Caption
[TODO] Using glVertex to describe a Circle is inefficient (due to the compute-intensive sin() and cos() functions). Try using GLU's quadric.
Example 9: Key-Controlled (GL09KeyControl.cpp)
For the billowy ball programme, the post-obit key and special-key handlers provide exits with ESC (27), increment/decrease y speed with upwardly-/down-pointer key, increase/decrease x speed with left-/right-arrow key, increase/decrease brawl'southward radius with PageUp/PageDown central.
1 2 three 4 5 six seven 8 9 ten xi 12 13 14 15 16 17 18 nineteen 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 sixty 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 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 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 | #include <windows.h> #include <GL/glut.h> #include <Math.h> #define PI 3.14159265f char title[] = "Full-Screen & Windowed Manner"; int windowWidth = 640; int windowHeight = 480; int windowPosX = fifty; int windowPosY = 50; GLfloat ballRadius = 0.5f; GLfloat ballX = 0.0f; GLfloat ballY = 0.0f; GLfloat ballXMax, ballXMin, ballYMax, ballYMin; GLfloat xSpeed = 0.02f; GLfloat ySpeed = 0.007f; int refreshMillis = xxx; GLdouble clipAreaXLeft, clipAreaXRight, clipAreaYBottom, clipAreaYTop; bool fullScreenMode = true; void initGL() { glClearColor(0.0, 0.0, 0.0, 1.0); } void display() { glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(ballX, ballY, 0.0f); glBegin(GL_TRIANGLE_FAN); glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(0.0f, 0.0f); int numSegments = 100; GLfloat angle; for (int i = 0; i <= numSegments; i++) { angle = i * ii.0f * PI / numSegments; glVertex2f(cos(angle) * ballRadius, sin(bending) * ballRadius); } glEnd(); glutSwapBuffers(); ballX += xSpeed; ballY += ySpeed; if (ballX > ballXMax) { ballX = ballXMax; xSpeed = -xSpeed; } else if (ballX < ballXMin) { ballX = ballXMin; xSpeed = -xSpeed; } if (ballY > ballYMax) { ballY = ballYMax; ySpeed = -ySpeed; } else if (ballY < ballYMin) { ballY = ballYMin; ySpeed = -ySpeed; } } void reshape(GLsizei width, GLsizei pinnacle) { if (elevation == 0) height = 1; GLfloat attribute = (GLfloat)width / (GLfloat)meridian; glViewport(0, 0, width, acme); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (width >= peak) { clipAreaXLeft = -one.0 * aspect; clipAreaXRight = 1.0 * attribute; clipAreaYBottom = -i.0; clipAreaYTop = ane.0; } else { clipAreaXLeft = -1.0; clipAreaXRight = ane.0; clipAreaYBottom = -1.0 / aspect; clipAreaYTop = i.0 / aspect; } gluOrtho2D(clipAreaXLeft, clipAreaXRight, clipAreaYBottom, clipAreaYTop); ballXMin = clipAreaXLeft + ballRadius; ballXMax = clipAreaXRight - ballRadius; ballYMin = clipAreaYBottom + ballRadius; ballYMax = clipAreaYTop - ballRadius; } void Timer(int value) { glutPostRedisplay(); glutTimerFunc(refreshMillis, Timer, 0); } void keyboard(unsigned char key, int ten, int y) { switch (primal) { instance 27: go out(0); break; } } void specialKeys(int key, int x, int y) { switch (primal) { case GLUT_KEY_F1: fullScreenMode = !fullScreenMode; if (fullScreenMode) { windowPosX = glutGet(GLUT_WINDOW_X); windowPosY = glutGet(GLUT_WINDOW_Y); windowWidth = glutGet(GLUT_WINDOW_WIDTH); windowHeight = glutGet(GLUT_WINDOW_HEIGHT); glutFullScreen(); } else { glutReshapeWindow(windowWidth, windowHeight); glutPositionWindow(windowPosX, windowPosX); } break; case GLUT_KEY_RIGHT: xSpeed *= ane.05f; break; case GLUT_KEY_LEFT: xSpeed *= 0.95f; suspension; instance GLUT_KEY_UP: ySpeed *= 1.05f; break; case GLUT_KEY_DOWN: ySpeed *= 0.95f; break; case GLUT_KEY_PAGE_UP: ballRadius *= 1.05f; ballXMin = clipAreaXLeft + ballRadius; ballXMax = clipAreaXRight - ballRadius; ballYMin = clipAreaYBottom + ballRadius; ballYMax = clipAreaYTop - ballRadius; break; case GLUT_KEY_PAGE_DOWN: ballRadius *= 0.95f; ballXMin = clipAreaXLeft + ballRadius; ballXMax = clipAreaXRight - ballRadius; ballYMin = clipAreaYBottom + ballRadius; ballYMax = clipAreaYTop - ballRadius; interruption; } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE); glutInitWindowSize(windowWidth, windowHeight); glutInitWindowPosition(windowPosX, windowPosY); glutCreateWindow(title); glutDisplayFunc(display); glutReshapeFunc(reshape); glutTimerFunc(0, Timer, 0); glutSpecialFunc(specialKeys); glutKeyboardFunc(keyboard); |
[TODO] Explanation
Handling Mouse Inputs with Overabundance
Similarly, we tin can register callback part to handle mouse-click and mouse-motility.
-
glutMouseFunc: registers callback handler for mouse click.void glutMouseFunc(void (*func)(int button, int land, int 10, int y)
-
glutMotionFunc: registers callback handler for mouse motion (when the mouse is clicked and moved).void glutMotionFunc(void (*func)(int 10, int y)
Example 10: Mouse-Controlled (GL10MouseControl.cpp)
For the bouncing ball program, the following mouse handler pause the movement with left-mouse click, and resume with right-mouse click.
i two 3 4 5 6 7 8 ix x xi 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 thirty 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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 xc 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 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 186 187 188 189 190 191 192 193 194 195 196 | #include <windows.h> #include <GL/overabundance.h> #include <Math.h> #ascertain PI 3.14159265f char title[] = "Full-Screen & Windowed Mode"; int windowWidth = 640; int windowHeight = 480; int windowPosX = fifty; int windowPosY = 50; GLfloat ballRadius = 0.5f; GLfloat ballX = 0.0f; GLfloat ballY = 0.0f; GLfloat ballXMax, ballXMin, ballYMax, ballYMin; GLfloat xSpeed = 0.02f; GLfloat ySpeed = 0.007f; int refreshMillis = thirty; GLdouble clipAreaXLeft, clipAreaXRight, clipAreaYBottom, clipAreaYTop; bool fullScreenMode = true; bool paused = false; GLfloat xSpeedSaved, ySpeedSaved; void initGL() { glClearColor(0.0, 0.0, 0.0, one.0); } void display() { glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(ballX, ballY, 0.0f); glBegin(GL_TRIANGLE_FAN); glColor3f(0.0f, 0.0f, 1.0f); glVertex2f(0.0f, 0.0f); int numSegments = 100; GLfloat bending; for (int i = 0; i <= numSegments; i++) { bending = i * ii.0f * PI / numSegments; glVertex2f(cos(angle) * ballRadius, sin(bending) * ballRadius); } glEnd(); glutSwapBuffers(); ballX += xSpeed; ballY += ySpeed; if (ballX > ballXMax) { ballX = ballXMax; xSpeed = -xSpeed; } else if (ballX < ballXMin) { ballX = ballXMin; xSpeed = -xSpeed; } if (ballY > ballYMax) { ballY = ballYMax; ySpeed = -ySpeed; } else if (ballY < ballYMin) { ballY = ballYMin; ySpeed = -ySpeed; } } void reshape(GLsizei width, GLsizei height) { if (height == 0) summit = 1; GLfloat attribute = (GLfloat)width / (GLfloat)height; glViewport(0, 0, width, pinnacle); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (width >= peak) { clipAreaXLeft = -i.0 * aspect; clipAreaXRight = ane.0 * aspect; clipAreaYBottom = -ane.0; clipAreaYTop = one.0; } else { clipAreaXLeft = -one.0; clipAreaXRight = 1.0; clipAreaYBottom = -1.0 / aspect; clipAreaYTop = 1.0 / aspect; } gluOrtho2D(clipAreaXLeft, clipAreaXRight, clipAreaYBottom, clipAreaYTop); ballXMin = clipAreaXLeft + ballRadius; ballXMax = clipAreaXRight - ballRadius; ballYMin = clipAreaYBottom + ballRadius; ballYMax = clipAreaYTop - ballRadius; } void Timer(int value) { glutPostRedisplay(); glutTimerFunc(refreshMillis, Timer, 0); } void keyboard(unsigned char primal, int x, int y) { switch (key) { case 27: exit(0); break; } } void specialKeys(int primal, int 10, int y) { switch (key) { case GLUT_KEY_F1: fullScreenMode = !fullScreenMode; if (fullScreenMode) { windowPosX = glutGet(GLUT_WINDOW_X); windowPosY = glutGet(GLUT_WINDOW_Y); windowWidth = glutGet(GLUT_WINDOW_WIDTH); windowHeight = glutGet(GLUT_WINDOW_HEIGHT); glutFullScreen(); } else { glutReshapeWindow(windowWidth, windowHeight); glutPositionWindow(windowPosX, windowPosX); } pause; instance GLUT_KEY_RIGHT: xSpeed *= 1.05f; break; example GLUT_KEY_LEFT: xSpeed *= 0.95f; break; example GLUT_KEY_UP: ySpeed *= 1.05f; break; case GLUT_KEY_DOWN: ySpeed *= 0.95f; break; case GLUT_KEY_PAGE_UP: ballRadius *= 1.05f; ballXMin = clipAreaXLeft + ballRadius; ballXMax = clipAreaXRight - ballRadius; ballYMin = clipAreaYBottom + ballRadius; ballYMax = clipAreaYTop - ballRadius; suspension; case GLUT_KEY_PAGE_DOWN: ballRadius *= 0.95f; ballXMin = clipAreaXLeft + ballRadius; ballXMax = clipAreaXRight - ballRadius; ballYMin = clipAreaYBottom + ballRadius; ballYMax = clipAreaYTop - ballRadius; intermission; } } void mouse(int push, int country, int x, int y) { if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { paused = !paused; if (paused) { xSpeedSaved = xSpeed; ySpeedSaved = ySpeed; xSpeed = 0; ySpeed = 0; } else { xSpeed = xSpeedSaved; ySpeed = ySpeedSaved; } } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE); glutInitWindowSize(windowWidth, windowHeight); glutInitWindowPosition(windowPosX, windowPosY); glutCreateWindow(title); glutDisplayFunc(display); glutReshapeFunc(reshape); glutTimerFunc(0, Timer, 0); glutSpecialFunc(specialKeys); glutKeyboardFunc(keyboard); glutFullScreen(); glutMouseFunc(mouse); initGL(); glutMainLoop(); render 0; } |
[TODO] Explanation
Example 11: A Simple Pigment plan
[TODO] Employ mouse-motion and GL_LINE_STRIP.
Link to OpenGL/Computer Graphics References and Resource
Source: https://www3.ntu.edu.sg/home/ehchua/programming/opengl/cg_introduction.html
Posted by: robbfarome.blogspot.com

0 Response to "How To Project Orthographic Drawing In 2d Opengl"
Post a Comment