| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| |
| <html lang="en"> |
| <head> |
| <title>Using OpenGL with SWT</title> |
| <link rel="stylesheet" href="../default_style.css" type="text/css"> |
| <link rel="stylesheet" href="opengl.css" type="text/css"> |
| <meta http-equiv="Content-Type" content="text/html; charset=us-ascii"> |
| <meta name="author" content="Bo Majewski"> |
| </head> |
| |
| <body> |
| <div align="right"> |
| <span class="copy">Copyright © 2005 Cisco Systems Inc.</span> |
| |
| <table border="0" cellpadding="2" cellspacing="0" width="100%"> |
| <tbody> |
| <tr> |
| <td colspan="2" align="left" bgcolor="#0080C0" valign="top"> |
| <span class="corner"> Eclipse Corner Article</span> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| |
| <div align="left"> |
| <h1><img src="images/Idea.jpg" alt="tag" align="middle" height= |
| "86" width="120"></h1> |
| </div> |
| |
| <p> </p> |
| |
| <h1 align="center">Using OpenGL with SWT</h1> |
| |
| <blockquote> |
| <p><b>Summary</b></p> |
| |
| <p> |
| OpenGL is a vendor-neutral, multi-platform standard for creating |
| high-performance 2D and 3D graphics. Hardware and software implementations |
| exist on various operating systems, including Windows, Linux and |
| MacOS. OpenGL may be used to render simple 2D charts or complex 3D games. This |
| article describes an experimental Eclipse plug-in that facilitates the use |
| of OpenGL for drawing onto SWT widgets. A short history and overview of |
| OpenGL is presented, followed by an example application. |
| </p> |
| |
| <p><b>By Bo Majewski, Cisco Systems, Inc.</b><br> |
| <font size="-1">April 15, 2005 (Eclipse 3.2 Update added June 15, 2006)</font></p> |
| </blockquote> |
| <hr width="100%"> |
| |
| <h2>Update for Eclipse 3.2</h2> |
| <p> |
| As of Eclipse 3.2, OpenGL support has migrated into the org.eclipse.swt project and is |
| officially supported there. This is the new preferred way of drawing with OpenGL in SWT, |
| as opposed to the Experimental OpenGL plug-in which was used previous to eclipse 3.2 and |
| appears throughout this article. While this article is still relevant to using OpenGL in |
| SWT, its example code does not map to the Eclipse 3.2 OpenGL API. For more information |
| about OpenGL support in Eclipse 3.2 see <a href="http://www.eclipse.org/swt/opengl/">http://www.eclipse.org/swt/opengl/</a>. |
| </p> |
| |
| <h2>Introduction</h2> |
| <p> |
| As the common saying goes, a picture is worth a thousand words. Or |
| a thousand database records. In a world flush with terabytes of data, gaining |
| an understanding of information often requires an effective way to visualize |
| it. A field of molecular biology, specifically proteomics, is a good |
| example. The raw data, in the form of an amino acid sequence, is insufficient |
| to understand the function of a given protein. Only knowing a full 3D |
| structure of it can one gain a deeper comprehension of the protein's purpose and |
| the way that it fulfills its tasks (see Figure 1). |
| </p> |
| |
| <div class="figure"> |
| <table align="center"> |
| <tbody> |
| <tr> |
| <td style="font-size: 8pt; font-family: monospace;"> |
| KVFERCELARTLKRLGMDGYRGISLANWMCLAKWESGYNTRATNY<br> |
| NAGDRSTDYGIFQINSRYWCNDGKNPGAVNACHLSCSALLQDNIA<br> |
| DAVACAKRVVRDPQGIRAWVAWRNRCQNRDVRQYVQGCGV<br> |
| <br> |
| ATOM 1 N LYS A 1 19.534 32.582 38.371 1.00 25.04 N<br> |
| ATOM 2 CA LYS A 1 18.911 32.387 37.062 1.00 25.51 C<br> |
| ATOM 3 C LYS A 1 17.908 33.472 36.753 1.00 27.65 C<br> |
| ATOM 4 O LYS A 1 17.251 33.988 37.643 1.00 29.70 O<br> |
| ATOM 5 CB LYS A 1 18.184 31.056 37.123 1.00 27.48 C<br> |
| ATOM 6 CG LYS A 1 17.069 30.921 36.093 1.00 24.63 C<br> |
| ATOM 7 CD LYS A 1 16.059 29.845 36.488 1.00 20.32 C<br> |
| ATOM 8 CE LYS A 1 14.972 29.702 35.432 1.00 17.75 C<br> |
| ATOM 9 NZ LYS A 1 14.270 28.408 35.603 1.00 22.15 N<br> |
| ATOM 10 N VAL A 2 17.863 33.900 35.497 1.00 28.50 N<br> |
| ATOM 11 CA VAL A 2 16.885 34.898 35.083 1.00 30.21 C<br> |
| ATOM 12 C VAL A 2 15.664 34.300 34.397 1.00 28.35 C<br> |
| <span style="font-size: large; font-weight: bold;">…</span> |
| </td> |
| <td valign="top"> |
| <img src="images/1W08-2.png" width="300" height="211" border="0" alt="T70N"> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="figure-caption"> |
| <span class="figure-number">Figure 1</span>. Structure Of T70N Human Lysozyme without side chains<br> |
| (source: <a href="http://www.rcsb.org/">The |
| RSCB Protein Data Bank</a>; 3D rendering done by |
| <a href="http://www.ncbi.nlm.nih.gov/">NCBI</a>'s |
| <a href="http://www.ncbi.nlm.nih.gov/Structure/CN3D/cn3d.shtml">Cn3D 4.1</a>) |
| </div> |
| </div> |
| |
| <p> |
| Eclipse ships with the Standard Widget Toolkit (SWT) which provides access to |
| native widget functionality through a platform-independent API. While the toolkit |
| provides a rich selection of widgets, graphics support was somewhat limited. |
| The SWT Graphics <a href="#winchester">[1]</a> package provided |
| basic functionality needed to do 2D drawings, from rendering 2D primitives such |
| as lines, arcs, rectangles and ovals, through clipping, text drawing |
| and image display. |
| </p> |
| <p> |
| The Draw2D plug-in that builds on top of SWT |
| provides lightweight rendering and layout capabilities. |
| The lightweight term means that you need only one native widget (i.e. heavy widget), |
| such as a <code>Canvas</code> to draw multiple figures. Layout functionality |
| allows you to automatically position multiple <code>IFigures</code>. If your goal was |
| to develop a charting package for Eclipse, Draw2D would provide a good |
| start. |
| </p> |
| |
| <p> |
| Until recently, in order to utilize advanced 2D graphics, one possible approach |
| was to use Java2D. By relying on a <code>BufferedImage</code> a developer could |
| use Java2D APIs to draw in memory, transfer the image to an SWT image, and |
| then render it on any SWT component (see <a href="#saillet">[2]</a> |
| for details). However, the drawback of this technique was added storage |
| and processing time requirements. These limitations were overcome |
| in milestone 5 of the 3.1 release through a new SWT API that utilizes native |
| <a href="http://www.cairographics.org/">Cairo</a> or <a href="http://msdn.microsoft.com/library/en-us/gdicpp/gdiplus/gdiplus.asp">GDI+</a> graphics |
| libraries. Developers now can use |
| transparency, rotation, shearing, brushes, pens and many more techniques |
| for enhancing graphical output, directly in SWT. Unfortunately, even with these additions, |
| the realm of high-performance 3D graphics is still out of reach. |
| </p> |
| |
| <p> |
| To address this need, a |
| <a href="http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/opengl/opengl.html">plug-in</a> was developed that |
| enabled OpenGL rendering onto an SWT <code>Drawable</code>. While the |
| plug-in is still experimental, it can be used to create high-impact, |
| high-performance graphics in Eclipse plug-ins and SWT applications. The goal of this article is to give |
| the reader a gentle introduction to the world of OpenGL and its use in SWT. |
| Immediately I am going to provide caveat lector. The subjects of 3D |
| rendering and OpenGL are so vast that they are well beyond the scope |
| of this short writeup. Readers interested in either of the topics |
| are encouraged to explore the available pool of extensive literature, some of which |
| has been listed in the <a href="#bibliography">Bibliography</a> section. |
| Hands-on experience may be gained by following various online tutorials, |
| with <a href="http://nehe.gamedev.net/">NeHe Productions</a> providing a |
| particularly good selection of 48 OpenGL lessons. |
| </p> |
| |
| |
| <h2>OpenGL</h2> |
| |
| <p> |
| Open Graphics Library, or OpenGL for short, traces its roots to SGI's IRIS GL. |
| Its first public release was made available on July 1, 1992. It went through six |
| revisions, culminating in version 2.0 published on September 7, 2004. |
| The main goal of OpenGL is to provide an efficient and easy-to-use |
| API for creating 2D and 3D computer graphics. Interestingly, and in part |
| due to the fact that it was designed when hardware capable of |
| rendering 3D scenes efficiently was expensive and often only available |
| on a central server, OpenGL can work transparently across a network. OpenGL |
| was designed to be cross-platform, and as a consequence is devoid of methods, |
| also known as commands, for |
| performing windowing tasks or obtaining user input. Instead, the bulk of the |
| calls specify vertices or properties of geometric |
| primitives, such as points, lines, triangles, quads and polygons. |
| Properties may define |
| colors, textures, and material properties such as how they interact |
| with light. Through these and other calls that deal with light sources, |
| scene depth and angles, OpenGL allows one to build sophisticated 3D scenes. |
| Some of the features that go beyond regular graphics are listed |
| below. |
| </p> |
| |
| <dl> |
| <dt>3D world</dt> |
| <dd> |
| Each point may be given a <i>z</i> coordinate, placing it at a |
| particular depth of the scene. If depth testing is enabled, |
| OpenGL removes those surfaces that are hidden by |
| other surfaces located closer to the viewer. A drawing may |
| be depth-cued, so that the lines further from the eye |
| appear dimmer. |
| </dd> |
| <dt>Transparency and Blending</dt> |
| <dd> |
| Colors of several objects may be combined to create a blended |
| color. This creates translucent fragments, and can be used to |
| mimic the effect of light passing through stained glass or a |
| reflection appearing on a surface. By |
| specifying transparency, or the alpha value of colors, you can |
| control how much light can pass through each object. |
| </dd> |
| <dt>Anti-aliasing</dt> |
| <dd> |
| By default, all lines drawn at an angle appear jagged on a |
| computer screen. OpenGL calculates coverage values for |
| pixels for diagonal lines, which in turn is used to compute |
| the correct blending of the pixel color with the background. |
| This blending creates the appearance of smooth rather than |
| sharp, unnatural edges. |
| </dd> |
| <dt>Projection Transformations</dt> |
| <dd> |
| The scene may use either a perspective or orthographic projection. |
| In perspective projection, objects that are further from the |
| viewer appear smaller, while the orthographic projection maintains the |
| original size of the objects. Orthographic projection is useful in applications such as CAD, |
| which should communicate information about the real size |
| of objects rather than how they may look when viewed from a distance. |
| </dd> |
| <dt>Textures</dt> |
| <dd> |
| Textures allow you to glue a 2D image to a polygon. For example, |
| by using a picture of a wooden plank you can easily create a |
| wooden wall. Texture mapping also performs required transformations |
| of the original image when the polygon onto which it was mapped |
| is reshaped. |
| </dd> |
| <dt>Lighting and Shadows</dt> |
| <dd> |
| Scenes may be lit by up to eight sources of light, each with |
| ambient, diffuse, and specular components, as well |
| as color and position. |
| Further, by specifying material type and how it reflects light, in |
| combination with textures, you can create |
| realistic looking objects. Lifelike shadows may be added to a |
| scene to further enhance the illusion of depth. |
| </dd> |
| <dt>Atmospheric effects</dt> |
| <dd> |
| Atmospheric effects add further realism to scenes by blurring |
| and dispersing light, similar to how the light reflected from |
| objects is distorted by air. |
| </dd> |
| </dl> |
| |
| <p> |
| OpenGL concentrates on core 2D and 3D functionality, and as such |
| does not provide high-level commands that describe complex 3D |
| models and their dependencies. As a result, a few extensions have |
| been added for working with higher-level structures. In particular, |
| the OpenGL Utility Library (GLU <a href="#opengl-glu">[9]</a>) provides |
| a number of APIs that allow one to create more complex objects with |
| ease. Disks, cylinders, spheres, and nonuniform rational B-splines |
| (NURBS for short) are a few such examples. |
| </p> |
| |
| <p> |
| Each GL command consists of the library prefix, |
| followed by the command name, followed by an optional argument |
| count, and ends with an optional argument type. This is illustrated in Figure 2. For example, |
| the <code>glVertex3f</code> has the library prefix <code>gl</code>, |
| the command <code>Vertex</code>, and it takes <code>3</code> arguments |
| of the type <code>f</code>loat. The parameter count varies between |
| 2 and 4, and parameters may be of type double (d), float (f), |
| integer (i), short (s), byte (b), unsigned integer (ui), |
| unsigned short (us), unsigned byte (ub), or a vector of any |
| of these types (*v). |
| </p> |
| |
| <div class="figure"> |
| <img src="images/gl_command.png" width="105" height="142" border="0" alt="GL command"><br /> <br /> |
| <div class="figure-caption"> |
| <span class="figure-number">Figure 2</span>. The structure of a GL command |
| </div> |
| </div> |
| |
| <p> |
| One may roughly divide OpenGL methods into two types: those that |
| specify parameters of geometric primitives and those that alter |
| the state of the drawing engine. Because of this, OpenGL is often |
| described as a state machine. Parameters such as color, |
| projection transformation, line and polygon stipple patterns |
| are said to be part of the state of the OpenGL machine. |
| State can be changed by calling methods such as |
| <code>glColor*()</code> or <code>glLight*()</code>. In order |
| for state variables to impact rendering, you need to |
| enable or disable them with the <code>glEnable()</code> |
| and <code>glDisable()</code> methods, respectively. While the |
| full description of the OpenGL state machine |
| <a href="#opengl-machine">[6]</a> is well beyond the scope of this |
| article, the basic concept is simple. You can put the rendering engine |
| in a state by, for instance, defining the current color as blue, and from then on |
| all objects are drawn with this attribute until that particular state |
| variable is changed. |
| </p> |
| |
| <p> |
| Drawing of objects follows the begin/end paradigm. |
| You indicate to the rendering engine, by passing the appropriate value to |
| the <code>glBegin(int)</code> method, what you are going to draw. Next, |
| you specify one or more vertices of the object's surface. Finally, you end drawing |
| by calling the <code>glEnd()</code> method. |
| There are ten geometric objects that can be drawn this way: points, |
| line segment strips, line segment loops, individual line segments, |
| polygons, triangle strips, triangle fans, individual triangles, |
| quad strips, and individual quads (quads are four-vertex surfaces such as |
| rectangles, squares and rhomboids). |
| For example, if you specify that you are drawing line strips, the first |
| vertex specifies the starting point of line segments, and every subsequent |
| vertex defines the end of the previous segment and the start of the next. |
| If you specify <i>i > 1</i> vertices, <i>i-1</i> connected segments are |
| drawn. For efficiency reasons, querying the state of the OpenGL machine between |
| the begin and end calls is not guaranteed to return correct values. A single |
| scene may consist of one or more begin/end blocks. |
| </p> |
| |
| |
| <h2>SWT OpenGL plug-in</h2> |
| |
| <p> |
| SWT exposes the functionality of OpenGL version 1.1. It consists |
| of three core classes and one data class. The core classes are |
| <code>GLContext</code>, <code>GL</code> and <code>GLU</code>. |
| The <code>GLContext</code> provides a bridge between SWT and OpenGL. |
| A context must be created with a <code>Drawable</code>, usually an |
| SWT <code>Canvas</code>, on which OpenGL renders its scenes. It is |
| important that the context be disposed when no longer needed. Also, |
| it is erroneous to attempt to render a scene once the drawable has |
| been disposed. Every time the drawable is resized, the |
| context must be notified about it through a call to its <code>resize</code> |
| method. The call allows the context to adjust its view port and perspective |
| parameters. The <a href="#groundwork">Laying |
| Groundwork</a> section describes a class that |
| takes care of most of these tasks. |
| </p> |
| |
| <p> |
| A scene may be drawn by making a series of calls to methods defined |
| in the <code>GL</code> and <code>GLU</code> classes once the |
| context is made current. |
| The <code>GL</code> class exposes over 330 commands. There are |
| essentially one-to-one mappings between methods |
| defined in the <code>GL</code> and <code>GLU</code> classes |
| and their native counterparts. Figure 3 provides |
| sample code that draws a triangle. For every <code>gl*</code> |
| function in C, there is a corresponding <code>GL.gl*</code> Java method, and |
| for every enumerated value <code>GL_*</code> in C, |
| there is an equivalent <code>GL.GL_*</code> Java constant. |
| Adopting the same APIs in the SWT OpenGL plug-in makes it easy for those |
| familiar with the C language APIs to code in Java. |
| </p> |
| |
| <a name="fig3"></a> |
| <table align="center"> |
| <tbody> |
| <tr> |
| <td> |
| <center><b>(a)</b> C Code</center> |
| <pre class="code" style="background-color: #f0fff0;"> |
| void drawScene() { |
| glClear(GL_COLOR_BUFFER_BIT |
| | GL_DEPTH_BUFFER_BIT); |
| glLoadIdentity(); |
| glTranslatef(0.0f, 0.0f, -5.0f); |
| |
| glBegin(GL_TRIANGLES); |
| glVertex3f(-1.0f, -1.0f, 0.0f); |
| glVertex3f(1.0f, -1.0f, 0.0f); |
| glVertex3f(0.0f, 1.0f, 0.0f); |
| glEnd(); |
| |
| glutSwapBuffers(); |
| }</pre> |
| </td> |
| <td> |
| <center><b>(b)</b> Java Code</center> |
| <pre class="code" style="background-color: #f0f0ff;"> |
| public void drawScene() { |
| GL.glClear(GL.GL_COLOR_BUFFER_BIT |
| | GL.GL_DEPTH_BUFFER_BIT); |
| GL.glLoadIdentity(); |
| GL.glTranslatef(0.0f, 0.0f, -5.0f); |
| |
| GL.glBegin(GL.GL_TRIANGLES); |
| GL.glVertex3f(-1.0f, -1.0f, 0.0f); |
| GL.glVertex3f(1.0f, -1.0f, 0.0f); |
| GL.glVertex3f(0.0f, 1.0f, 0.0f); |
| GL.glEnd(); |
| |
| glContext.swapBuffers(); |
| }</pre> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="figure-caption"> |
| <span class="figure-number">Figure 3</span>. GL scene rendered in C and Java |
| </div> |
| |
| <h3>JNI Interface</h3> |
| <p> |
| The OpenGL plug-in relies on the JNI interface to access the native OpenGL |
| libraries. The native interface consists of roughly two parts. First, |
| as OpenGL was designed to be free of hardware and operating system dependencies, |
| the <code>GL</code> and <code>GLU</code> calls can be translated to |
| identical calls under all operating systems. |
| Thus, on all three platforms you can see the following code |
| for the <code>glBegin</code> method: |
| </p> |
| <pre class="code"> |
| JNIEXPORT void JNICALL GL_NATIVE(glBegin) |
| (JNIEnv *env, jclass that, jint arg0) |
| { |
| GL_NATIVE_ENTER(env, that, glBegin_FUNC); |
| glBegin(arg0); |
| GL_NATIVE_EXIT(env, that, glBegin_FUNC); |
| }</pre> |
| |
| <p> |
| The difference between the three available implementations is how the |
| SWT drawable is hooked up with the native GL context. This code |
| is internal to the SWT OpenGL plug-in and is platform-dependent. For example, both |
| the GTK and Motif implementations use GLX, "the glue connecting |
| OpenGL and the X Windowing System", while the Windows native |
| interface is provided through a similar Windows library called WGL. |
| At the time of this writing there was no plug-in for Apple's |
| OpenGL for Mac OS. |
| </p> |
| |
| <h3>Alternatives</h3> |
| <p> |
| There exist alternative solutions for performing 3D drawing in Java. For example, Sun maintains |
| <a href="http://java.sun.com/products/java-media/3D/">Java 3D</a>, which |
| unlike OpenGL, |
| provides a set of object-oriented interfaces that support a |
| high-level programming model for building, rendering, and controlling |
| the behavior of 3D objects. Closer to the spirit of the SWT OpenGL plug-in |
| is the <a href="https://jogl.dev.java.net/">JOGL</a> project, which provides access to OpenGL commands for drawing on AWT and Swing components. |
| While both solutions are |
| more mature than the SWT OpenGL plug-in project, they both target Swing and |
| AWT, and therefore do not tie in to the Eclipse environment |
| and SWT as directly as the SWT OpenGL plug-in does. |
| </p> |
| |
| <h2>Example Application</h2> |
| |
| <p> |
| In the following sections I describe a simple application that shows a |
| 3D chart of four quantities. The application uses |
| <code>GLScene</code>, which is a utility class for displaying OpenGL scenes. |
| In order to facilitate looking at a scene from various angles |
| and zoom levels, a scene grip is added; the |
| grip uses either the mouse or the keyboard to do zooming and |
| panning. Both the <code>GLScene</code> class and the grip are of a generic nature and may |
| be reused in other applications that use OpenGL. These components |
| are described first. |
| </p> |
| |
| <a name="groundwork"></a> |
| <h3>Laying Groundwork</h3> |
| <p> |
| The <code>GLScene</code> class is similar to SWT's |
| <code>Canvas</code>. However, rather than using |
| a <code>GC</code> to draw on it, its content is |
| rendered by OpenGL commands. This is achieved by associating |
| a <code>GLContext</code> with an SWT <code>Canvas</code> |
| and making it the current context whenever a scene is |
| rendered by the commands defined in the <code>drawScene</code> |
| method. |
| </p> |
| |
| <pre class="code"> |
| <a name="line1"> 1</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">class</span> <span class="c2h_identifier">GLScene</span> <span class="c2h_braces">{</span> |
| <a name="line2"> 2</a> <span class="c2h_reserved_word">private</span> <span class="c2h_identifier">GLContext</span> <span class="c2h_identifier">context</span><span class="c2h_symbol">;</span> |
| <a name="line3"> 3</a> <span class="c2h_reserved_word">private</span> <span class="c2h_identifier">Canvas</span> <span class="c2h_identifier">canvas</span><span class="c2h_symbol">;</span> |
| <a name="line4"> 4</a> |
| <a name="line5"> 5</a> <span class="c2h_reserved_word">public</span> <span class="c2h_identifier">GLScene</span><span class="c2h_braces">(</span><span class="c2h_identifier">Composite</span> <span class="c2h_identifier">parent</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line6"> 6</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">canvas</span> <span class="c2h_symbol">=</span> <span class="c2h_reserved_word">new</span> <span class="c2h_identifier">Canvas</span><span class="c2h_braces">(</span><span class="c2h_identifier">parent</span>, <span class="c2h_identifier">SWT</span>.<span class="c2h_identifier">NONE</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line7"> 7</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">canvas</span>.<span class="c2h_identifier">addControlListener</span><span class="c2h_braces">(</span><span class="c2h_reserved_word">new</span> <span class="c2h_identifier">ControlAdapter</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line8"> 8</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">controlResized</span><span class="c2h_braces">(</span><span class="c2h_identifier">ControlEvent</span> <span class="c2h_identifier">e</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line9"> 9</a> <span class="c2h_identifier">resizeScene</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line10">10</a> <span class="c2h_braces">}</span> |
| <a name="line11">11</a> <span class="c2h_braces">}</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line12">12</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">canvas</span>.<span class="c2h_identifier">addDisposeListener</span><span class="c2h_braces">(</span><span class="c2h_reserved_word">new</span> <span class="c2h_identifier">DisposeListener</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line13">13</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">widgetDisposed</span><span class="c2h_braces">(</span><span class="c2h_identifier">DisposeEvent</span> <span class="c2h_identifier">e</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line14">14</a> <span class="c2h_identifier">dispose</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line15">15</a> <span class="c2h_braces">}</span> |
| <a name="line16">16</a> <span class="c2h_braces">}</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line17">17</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">init</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line18">18</a> <span class="c2h_identifier">Rectangle</span> <span class="c2h_identifier">clientArea</span> <span class="c2h_symbol">=</span> <span class="c2h_identifier">parent</span>.<span class="c2h_identifier">getClientArea</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line19">19</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">canvas</span>.<span class="c2h_identifier">setSize</span><span class="c2h_braces">(</span><span class="c2h_identifier">clientArea</span>.<span class="c2h_identifier">width</span>, <span class="c2h_identifier">clientArea</span>.<span class="c2h_identifier">height</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line20">20</a> <span class="c2h_braces">}</span> |
| </pre> |
| |
| <p> |
| In the constructor, a new SWT <code>Canvas</code> is created. This is |
| the canvas that is associated with a <code>GLContext</code> |
| instance. Immediately, two listeners are registered on it. The first |
| listener makes sure that whenever the canvas is resized the <code>GLContext</code> |
| is notified and appropriately resized. The second listener takes care of |
| disposing the context once the canvas is disposed. In order to make sure |
| that the rendering area is of non-zero size, the client rectangle of |
| the parent is fetched and used to set the initial size of the canvas. |
| This size may later be changed either by a layout manager or user |
| actions. |
| </p> |
| <pre class="code"> |
| <a name="line22">22</a> <span class="c2h_reserved_word">protected</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">resizeScene</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line23">23</a> <span class="c2h_identifier">Rectangle</span> <span class="c2h_identifier">rect</span> <span class="c2h_symbol">=</span> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">canvas</span>.<span class="c2h_identifier">getClientArea</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line24">24</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">context</span>.<span class="c2h_identifier">resize</span><span class="c2h_braces">(</span><span class="c2h_numeric">0</span>, <span class="c2h_numeric">0</span>, <span class="c2h_identifier">rect</span>.<span class="c2h_identifier">width</span>, <span class="c2h_identifier">rect</span>.<span class="c2h_identifier">height</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line25">25</a> <span class="c2h_braces">}</span> |
| <a name="line26">26</a> |
| <a name="line27">27</a> <span class="c2h_reserved_word">protected</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">dispose</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line28">28</a> <span class="c2h_reserved_word">if</span> <span class="c2h_braces">(<span class="c2h_reserved_word">this</span>.</span><span class="c2h_identifier">context</span> <span class="c2h_symbol">!</span><span class="c2h_symbol">=</span> <span class="c2h_reserved_word">null</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line29">29</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">context</span>.<span class="c2h_identifier">dispose</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line30">30</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">context</span> <span class="c2h_symbol">=</span> <span class="c2h_reserved_word">null</span><span class="c2h_symbol">;</span> |
| <a name="line31">31</a> <span class="c2h_braces">}</span> |
| <a name="line32">32</a> <span class="c2h_braces">}</span> |
| </pre> |
| <p> |
| <code>GLScene</code> uses the entire area of the canvas for |
| drawing. Whenever the canvas is resized, we fetch the client area and |
| pass the new width and height to the context. Based on the new width |
| and height, the context adjusts the view appropriately. |
| </p> |
| <p> |
| Disposing the canvas (line 27) requires that we dispose the context. |
| This is particularly important in operating systems where a limited |
| number of device contexts are available. To prevent multiple calls to |
| the <code>dispose</code> method of the context, once it is disposed it |
| is set to <code>null</code>. |
| </p> |
| <pre class="code"> |
| <a name="line34">34</a> <span class="c2h_reserved_word">protected</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">init</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line35">35</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">initGLContext</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line36">36</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">initGL</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line37">37</a> <span class="c2h_braces">}</span> |
| <a name="line38">38</a> |
| <a name="line39">39</a> <span class="c2h_reserved_word">protected</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">initGLContext</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line40">40</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">context</span> <span class="c2h_symbol">=</span> <span class="c2h_reserved_word">new</span> <span class="c2h_identifier">GLContext</span><span class="c2h_braces">(</span><span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">canvas</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line41">41</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">context</span>.<span class="c2h_identifier">setCurrent</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line42">42</a> <span class="c2h_braces">}</span> |
| <a name="line43">43</a> |
| <a name="line44">44</a> <span class="c2h_reserved_word">protected</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">initGL</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line45">45</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glClearColor</span><span class="c2h_braces">(</span><span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">0.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line46">46</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glClearDepth</span><span class="c2h_braces">(</span><span class="c2h_numeric">1.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line47">47</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glDepthFunc</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_LEQUAL</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line48">48</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glEnable</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_DEPTH_TEST</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line49">49</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glShadeModel</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_SMOOTH</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line50">50</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glHint</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_PERSPECTIVE_CORRECTION_HINT</span>, <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_NICEST</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line51">51</a> <span class="c2h_braces">}</span> |
| </pre> |
| <p> |
| The <code>GLScene</code> initialization is split into two parts: |
| initializing the context and initializing the state machine of |
| OpenGL. For the context, we simply create a new <code>GLContext</code> and make it |
| current. OpenGL rendering always draws on the current |
| context, and thus if you have more than one <code>GLScene</code> |
| active, it is important to make its context current before any |
| drawing takes place. The <code>initGL</code> method is a bit more |
| interesting. It begins by specifying the color used to clean color buffers |
| (black). Next, the |
| depth buffer is set up; line 46 establishes the |
| depth value used when the depth buffer is cleared (this value must be between 0.0 and 1.0), and line 47 specifies how |
| depth value comparisons are done. This comparison function is used to |
| reject or accept incoming pixels, and |
| <code>GL.GL_LEQUAL</code> in particular accepts only those pixels that are |
| closer to or at an equal distance from the viewer. Line 48 enables |
| depth testing, since as was mentioned before, not only must the OpenGL state machine |
| be set in a particular state, but the state must also be enabled in order to |
| impact rendering. The |
| next line sets the shade model to <code>GL.GL_SMOOTH</code>, which |
| interpolates colors (smooths them out) if two vertices |
| of a surface have different colors. Finally, line 50 asks |
| the rendering engine to put a significant effort into the computing of color and texture coordinate interpolation. |
| On older and slower hardware you may wish to use <code>GL.GL_FASTEST</code> |
| or <code>GL.GL_DONT_CARE</code> instead. |
| </p> |
| <pre class="code"> |
| <a name="line53">53</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">render</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line54">54</a> <span class="c2h_reserved_word">if</span> <span class="c2h_braces">(</span><span class="c2h_symbol">!</span><span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">context</span>.<span class="c2h_identifier">isCurrent</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line55">55</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">context</span>.<span class="c2h_identifier">setCurrent</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line56">56</a> <span class="c2h_braces">}</span> |
| <a name="line57">57</a> |
| <a name="line58">58</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">drawScene</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line59">59</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">context</span>.<span class="c2h_identifier">swapBuffers</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line60">60</a> <span class="c2h_braces">}</span> |
| <a name="line61">61</a> |
| <a name="line62">62</a> <span class="c2h_reserved_word">protected</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">drawScene</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line63">63</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glClear</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_COLOR_BUFFER_BIT</span> <span class="c2h_symbol">|</span> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_DEPTH_BUFFER_BIT</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line64">64</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glLoadIdentity</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line65">65</a> <span class="c2h_braces">}</span> |
| </pre> |
| |
| <p> |
| The final two methods of the <code>GLScene</code> class deal with |
| repainting and scene drawing. The first method is exposed to other |
| classes and should be used whenever a repaint of the scene is |
| needed. As an example, one could repeatedly call it to display |
| animation. The second method is meant to be overridden by |
| extending classes. Its default implementation simply clears the color and depth buffers and |
| restores the coordinate system by loading the identify matrix. |
| </p> |
| |
| <h3>A Scene Grip</h3> |
| |
| <p> |
| One of the nice things about 3D is that it allows you to view scenes |
| in perspective, with obstructed objects hidden. However, |
| sometimes you might want to view a scene from a different angle, so |
| that what was hidden becomes visible and what was in the foreground |
| moves to the background. OpenGL provides two methods that can be |
| used to achieve just that. The <code>glRotate</code> method allows |
| you to rotate your scene by any angle in the x, y and z planes. |
| For example, <code>GL.glRotatef(180f, 0f, 1f, 0f)</code> rotates |
| the scene by 180 degrees and thus makes its furthest point become the |
| closest to the viewer. <code>GL.glRotatef(180f, 1f, 0f, 0f)</code> |
| flips the scene upside down (see Figure 4). |
| Scene translation can be achieved by calling the <code>GL.glTranslate</code> |
| method, which takes three parameters, <i>x</i>, <i>y</i> and <i>z</i>, |
| to indicate how many units to move the scene in each direction. For |
| example, <code>GL.glTranslatef(5f, -1f, -2f)</code> moves the |
| scene 5 units to the right, 1 unit down, and 2 units away from the viewer. |
| </p> |
| |
| <div class="figure"> |
| <img src="images/rotation5.png" width="242" height="245" border="0" alt="rotation"> |
| <div class="figure-caption"> |
| <span class="figure-number">Figure 4</span>. Scene rotation |
| </div> |
| </div> |
| |
| <p> |
| In order to provide the ability to move and rotate a scene, we |
| need to perform the appropriate transformation before the scene is |
| being rendered. The solution developed in this article relies on an |
| external class, a <code>SceneGrip</code>, that does necessary rotations |
| and translations. How much the scene is transformed is dictated by |
| internal variables. These, in turn, are adjusted on key and mouse events. |
| </p> |
| <pre class="code"> |
| <a name="line31"> 31</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">class</span> <span class="c2h_identifier">SceneGrip</span> <span class="c2h_reserved_word">extends</span> <span class="c2h_identifier">MouseAdapter</span> |
| <a name="line32"> 32</a> <span class="c2h_reserved_word">implements</span> <span class="c2h_identifier">MouseMoveListener</span>, <span class="c2h_identifier">Listener</span>, <span class="c2h_identifier">KeyListener</span> <span class="c2h_braces">{</span> |
| <a name="line33"> 33</a> <span class="c2h_reserved_word">private</span> <span class="c2h_reserved_word">float</span> <span class="c2h_identifier">xrot</span><span class="c2h_symbol">;</span> |
| <a name="line34"> 34</a> <span class="c2h_reserved_word">private</span> <span class="c2h_reserved_word">float</span> <span class="c2h_identifier">yrot</span><span class="c2h_symbol">;</span> |
| <a name="line35"> 35</a> <span class="c2h_reserved_word">private</span> <span class="c2h_reserved_word">float</span> <span class="c2h_identifier">zoff</span><span class="c2h_symbol">;</span> |
| <a name="line36"> 36</a> <span class="c2h_reserved_word">private</span> <span class="c2h_reserved_word">float</span> <span class="c2h_identifier">xoff</span><span class="c2h_symbol">;</span> |
| <a name="line37"> 37</a> <span class="c2h_reserved_word">private</span> <span class="c2h_reserved_word">float</span> <span class="c2h_identifier">yoff</span><span class="c2h_symbol">;</span> |
| ... |
| <a name="line45"> 45</a> <span class="c2h_reserved_word">public</span> <span class="c2h_identifier">SceneGrip</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line46"> 46</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">init</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line47"> 47</a> <span class="c2h_braces">}</span> |
| <a name="line48"> 48</a> |
| <a name="line49"> 49</a> <span class="c2h_reserved_word">protected</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">init</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line50"> 50</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">xrot</span> <span class="c2h_symbol">=</span> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">yrot</span> <span class="c2h_symbol">=</span> <span class="c2h_numeric">0.0f</span><span class="c2h_symbol">;</span> |
| <a name="line51"> 51</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">xoff</span> <span class="c2h_symbol">=</span> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">yoff</span> <span class="c2h_symbol">=</span> <span class="c2h_numeric">0.0f</span><span class="c2h_symbol">;</span> |
| <a name="line52"> 52</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">zoff</span> <span class="c2h_symbol">=</span> <span class="c2h_symbol">-</span><span class="c2h_numeric">8.0f</span><span class="c2h_symbol">;</span> |
| <a name="line53"> 53</a> <span class="c2h_braces">}</span> |
| </pre> |
| |
| <p> |
| The class defines two variables that store the current angle of the |
| rotation along the <i>x</i> and <i>y</i> axis. In addition, three |
| variables remember by how much to move a scene in each of the three |
| directions. The initial values of all of the variables, except for the |
| <i>z</i> offset, are set to 0.0f. The offset along the <i>z</i> axis |
| is set to <i>-8.0f</i> so that the scene has some separation |
| from the viewer. Setting <i>z</i> offset to 0.0f would be equivalent to |
| jamming the scene up against the viewer's nose. |
| </p> |
| <pre class="code"> |
| <a name="line99"> 99</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">keyPressed</span><span class="c2h_braces">(</span><span class="c2h_identifier">KeyEvent</span> <span class="c2h_identifier">e</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line100">100</a> <span class="c2h_reserved_word">switch</span> <span class="c2h_braces">(</span><span class="c2h_identifier">e</span>.<span class="c2h_identifier">keyCode</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line101">101</a> <span class="c2h_reserved_word">case</span> <span class="c2h_identifier">SWT</span>.<span class="c2h_identifier">ARROW_UP</span><span class="c2h_symbol">:</span> |
| <a name="line102">102</a> <span class="c2h_reserved_word">if</span> <span class="c2h_braces">(</span><span class="c2h_braces">(</span><span class="c2h_identifier">e</span>.<span class="c2h_identifier">stateMask</span> <span class="c2h_symbol">&</span> <span class="c2h_identifier">SWT</span>.<span class="c2h_identifier">CTRL</span><span class="c2h_braces">)</span> <span class="c2h_symbol">!</span><span class="c2h_symbol">=</span> <span class="c2h_numeric">0</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line103">103</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">xrot</span> <span class="c2h_symbol">-</span><span class="c2h_symbol">=</span> <span class="c2h_numeric">0.5f</span><span class="c2h_symbol">;</span> |
| <a name="line104">104</a> <span class="c2h_braces">}</span> <span class="c2h_reserved_word">else</span> <span class="c2h_braces">{</span> |
| <a name="line105">105</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">yoff</span> <span class="c2h_symbol">+</span><span class="c2h_symbol">=</span> <span class="c2h_numeric">0.05f</span><span class="c2h_symbol">;</span> |
| <a name="line106">106</a> <span class="c2h_braces">}</span> |
| <a name="line107">107</a> <span class="c2h_reserved_word">break</span><span class="c2h_symbol">;</span> |
| <a name="line108">108</a> <span class="c2h_reserved_word">case</span> <span class="c2h_identifier">SWT</span>.<span class="c2h_identifier">ARROW_DOWN</span><span class="c2h_symbol">:</span> |
| <a name="line109">109</a> <span class="c2h_reserved_word">if</span> <span class="c2h_braces">(</span><span class="c2h_braces">(</span><span class="c2h_identifier">e</span>.<span class="c2h_identifier">stateMask</span> <span class="c2h_symbol">&</span> <span class="c2h_identifier">SWT</span>.<span class="c2h_identifier">CTRL</span><span class="c2h_braces">)</span> <span class="c2h_symbol">!</span><span class="c2h_symbol">=</span> <span class="c2h_numeric">0</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line110">110</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">xrot</span> <span class="c2h_symbol">+</span><span class="c2h_symbol">=</span> <span class="c2h_numeric">0.5f</span><span class="c2h_symbol">;</span> |
| <a name="line111">111</a> <span class="c2h_braces">}</span> <span class="c2h_reserved_word">else</span> <span class="c2h_braces">{</span> |
| <a name="line112">112</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">yoff</span> <span class="c2h_symbol">-</span><span class="c2h_symbol">=</span> <span class="c2h_numeric">0.05f</span><span class="c2h_symbol">;</span> |
| <a name="line113">113</a> <span class="c2h_braces">}</span> |
| <a name="line114">114</a> <span class="c2h_reserved_word">break</span><span class="c2h_symbol">;</span> |
| <a name="line115">115</a> <span class="c2h_reserved_word">case</span> <span class="c2h_identifier">SWT</span>.<span class="c2h_identifier">ARROW_LEFT</span><span class="c2h_symbol">:</span> |
| <a name="line116">116</a> <span class="c2h_reserved_word">if</span> <span class="c2h_braces">(</span><span class="c2h_braces">(</span><span class="c2h_identifier">e</span>.<span class="c2h_identifier">stateMask</span> <span class="c2h_symbol">&</span> <span class="c2h_identifier">SWT</span>.<span class="c2h_identifier">CTRL</span><span class="c2h_braces">)</span> <span class="c2h_symbol">!</span><span class="c2h_symbol">=</span> <span class="c2h_numeric">0</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line117">117</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">yrot</span> <span class="c2h_symbol">-</span><span class="c2h_symbol">=</span> <span class="c2h_numeric">0.5f</span><span class="c2h_symbol">;</span> |
| <a name="line118">118</a> <span class="c2h_braces">}</span> <span class="c2h_reserved_word">else</span> <span class="c2h_braces">{</span> |
| <a name="line119">119</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">xoff</span> <span class="c2h_symbol">-</span><span class="c2h_symbol">=</span> <span class="c2h_numeric">0.05f</span><span class="c2h_symbol">;</span> |
| <a name="line120">120</a> <span class="c2h_braces">}</span> |
| <a name="line121">121</a> <span class="c2h_reserved_word">break</span><span class="c2h_symbol">;</span> |
| <a name="line122">122</a> <span class="c2h_reserved_word">case</span> <span class="c2h_identifier">SWT</span>.<span class="c2h_identifier">ARROW_RIGHT</span><span class="c2h_symbol">:</span> |
| <a name="line123">123</a> <span class="c2h_reserved_word">if</span> <span class="c2h_braces">(</span><span class="c2h_braces">(</span><span class="c2h_identifier">e</span>.<span class="c2h_identifier">stateMask</span> <span class="c2h_symbol">&</span> <span class="c2h_identifier">SWT</span>.<span class="c2h_identifier">CTRL</span><span class="c2h_braces">)</span> <span class="c2h_symbol">!</span><span class="c2h_symbol">=</span> <span class="c2h_numeric">0</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line124">124</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">yrot</span> <span class="c2h_symbol">+</span><span class="c2h_symbol">=</span> <span class="c2h_numeric">0.5f</span><span class="c2h_symbol">;</span> |
| <a name="line125">125</a> <span class="c2h_braces">}</span> <span class="c2h_reserved_word">else</span> <span class="c2h_braces">{</span> |
| <a name="line126">126</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">xoff</span> <span class="c2h_symbol">+</span><span class="c2h_symbol">=</span> <span class="c2h_numeric">0.05f</span><span class="c2h_symbol">;</span> |
| <a name="line127">127</a> <span class="c2h_braces">}</span> |
| <a name="line128">128</a> <span class="c2h_reserved_word">break</span><span class="c2h_symbol">;</span> |
| <a name="line129">129</a> <span class="c2h_reserved_word">case</span> <span class="c2h_identifier">SWT</span>.<span class="c2h_identifier">PAGE_UP</span><span class="c2h_symbol">:</span> |
| <a name="line130">130</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">zoff</span> <span class="c2h_symbol">+</span><span class="c2h_symbol">=</span> <span class="c2h_numeric">0.05f</span><span class="c2h_symbol">;</span> |
| <a name="line131">131</a> <span class="c2h_reserved_word">break</span><span class="c2h_symbol">;</span> |
| <a name="line132">132</a> <span class="c2h_reserved_word">case</span> <span class="c2h_identifier">SWT</span>.<span class="c2h_identifier">PAGE_DOWN</span><span class="c2h_symbol">:</span> |
| <a name="line133">133</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">zoff</span> <span class="c2h_symbol">-</span><span class="c2h_symbol">=</span> <span class="c2h_numeric">0.05f</span><span class="c2h_symbol">;</span> |
| <a name="line134">134</a> <span class="c2h_reserved_word">break</span><span class="c2h_symbol">;</span> |
| <a name="line135">135</a> <span class="c2h_reserved_word">case</span> <span class="c2h_identifier">SWT</span>.<span class="c2h_identifier">HOME</span><span class="c2h_symbol">:</span> |
| <a name="line136">136</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">init</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line137">137</a> <span class="c2h_reserved_word">break</span><span class="c2h_symbol">;</span> |
| <a name="line138">138</a> <span class="c2h_braces">}</span> |
| <a name="line139">139</a> <span class="c2h_braces">}</span> |
| </pre> |
| |
| <p> |
| Upon receiving a key event, we adjust the offset and rotation variables. |
| The convention used here is that if the Ctrl key is pressed, pressing |
| arrow keys rotates the scene. Otherwise, pressing arrow keys moves the scene. For example, |
| when the arrow up key is pressed we either increase the <i>y</i> offset, |
| moving the scene up, or decrease the <i>x</i> angle, twisting the scene |
| so that the part closest to the viewer is lifted up, and the part |
| furthest away from the user is rotated down. The left arrow performs a |
| similar function for the <i>x</i> offset or <i>y</i> axis rotation. |
| Page up and page down keys are used to zoom in and out. |
| Finally, hitting the Home key restores the scene to its original settings. |
| (The step size values |
| chosen here work well for small scenes. For larger scenes, |
| the step size should be calculated based on how far the viewer is from the |
| center of the scene. However, for simplicity this has been omitted in this example.) |
| </p> |
| |
| <pre class="code"> |
| <a name="line144">144</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">adjust</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line145">145</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glTranslatef</span><span class="c2h_braces">(</span><span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">xoff</span>, <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">yoff</span>, <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">zoff</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line146">146</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glRotatef</span><span class="c2h_braces">(</span><span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">xrot</span>, <span class="c2h_numeric">1.0f</span>, <span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">0.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line147">147</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glRotatef</span><span class="c2h_braces">(</span><span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">yrot</span>, <span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">1.0f</span>, <span class="c2h_numeric">0.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line148">148</a> <span class="c2h_braces">}</span> |
| </pre> |
| <p> |
| The <code>adjust</code> method performs necessary translations and |
| rotations of the scene. Just like other OpenGL operations, they |
| are applied to the current context. As the reader may notice, the |
| translations can be performed in one call. However, to enable independent |
| rotation in the <i>x</i> and <i>y</i> axis, two <code>glRotatef</code> calls passing the |
| appropriate <i>x</i> and <i>y</i> angles are made. To make use of the |
| scene grip, the <code>GLScene</code> class needs to be modified. When |
| creating a new instance, a scene grip must be created and register as |
| a listener of mouse, mouse move, and key events of the SWT canvas. In <code>drawScene</code>, |
| a call must be made to the <code>adjust</code> method before any GL |
| calls are made (see next section). |
| </p> |
| |
| <h3>3D Charting</h3> |
| |
| <p> |
| With all the above preparations, we are ready to dive into the main |
| application. The chart shows four sets of data. Each set consists |
| of the same, fixed number of points, each point being a positive value |
| between 0.0 and 10.0. These requirements are intentionally simple, |
| so that the brunt of the work can go into developing OpenGL |
| code rather than dealing with issues of scaling, missing points, |
| disparate axis ranges, and other challenges that a true charting application |
| needs to address. |
| </p> |
| <p> |
| The demo runs as a very simple Eclipse view (a stand-alone SWT |
| application is |
| also included in the provided source code). The only |
| interesting addition is the <code>Refresher</code>, which |
| periodically forces repainting of the OpenGL scene. |
| This way, as the viewpoint is moved or rotated, the up-to-date |
| rendering is shown in the component. The refresher, which is launched |
| just after the SWT control for the view |
| is created, repeatedly calls the |
| <code>redraw</code> method of the scene. The calls are spaced |
| every 100ms, giving it a theoretical rate of 10 frames per second. |
| </p> |
| <pre class="code"> |
| <a name="line13">13</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">class</span> <span class="c2h_identifier">Refresher</span> <span class="c2h_reserved_word">implements</span> <span class="c2h_identifier">Runnable</span> <span class="c2h_braces">{</span> |
| <a name="line14">14</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">static</span> <span class="c2h_reserved_word">final</span> <span class="c2h_reserved_word">int</span> <span class="c2h_identifier">DELAY</span> <span class="c2h_symbol">=</span> <span class="c2h_numeric">100</span><span class="c2h_symbol">;</span> |
| <a name="line15">15</a> |
| <a name="line16">16</a> <span class="c2h_reserved_word">private</span> <span class="c2h_identifier">GLScene</span> <span class="c2h_identifier">scene</span><span class="c2h_symbol">;</span> |
| <a name="line17">17</a> |
| <a name="line18">18</a> <span class="c2h_reserved_word">public</span> <span class="c2h_identifier">Refresher</span><span class="c2h_braces">(</span><span class="c2h_identifier">GLScene</span> <span class="c2h_identifier">scene</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line19">19</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">scene</span> <span class="c2h_symbol">=</span> <span class="c2h_identifier">scene</span><span class="c2h_symbol">;</span> |
| <a name="line20">20</a> <span class="c2h_braces">}</span> |
| <a name="line21">21</a> |
| <a name="line22">22</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">run</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line23">23</a> <span class="c2h_reserved_word">if</span> <span class="c2h_braces">(</span><span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">scene</span> <span class="c2h_symbol">!</span><span class="c2h_symbol">=</span> <span class="c2h_reserved_word">null</span> <span class="c2h_symbol">&</span><span class="c2h_symbol">&</span> <span class="c2h_symbol">!</span><span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">scene</span>.<span class="c2h_identifier">isDisposed</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line24">24</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">scene</span>.<span class="c2h_identifier">render</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line25">25</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">scene</span>.<span class="c2h_identifier">getDisplay</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span>.<span class="c2h_identifier">timerExec</span><span class="c2h_braces">(</span><span class="c2h_identifier">DELAY</span>, <span class="c2h_reserved_word">this</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line26">26</a> <span class="c2h_braces">}</span> |
| <a name="line27">27</a> <span class="c2h_braces">}</span> |
| <a name="line28">28</a> <span class="c2h_braces">}</span> |
| </pre> |
| |
| <p> |
| The values of points of each data set are represented |
| by cylinders. Rendering a cylinder can be achieved |
| by executing three GLU calls: two to render the disks needed at |
| both ends of the cylinder, and one to render the cylinder walls. For |
| example, to draw a cylinder 2 units long, you could use the |
| code shown in Figure 5. |
| </p> |
| |
| <table align="center" width="80%"> |
| <tbody> |
| <tr> |
| <td width="50%"> |
| <pre class="code"> |
| <a name="line1">1</a> <span class="c2h_reserved_word">int</span> <span class="c2h_identifier">qobj</span> <span class="c2h_symbol">=</span> <span class="c2h_identifier">GLU</span>.<span class="c2h_identifier">gluNewQuadric</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line2">2</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glRotatef</span><span class="c2h_braces">(</span><span class="c2h_symbol">-</span><span class="c2h_numeric">90.0f</span>, <span class="c2h_numeric">1.0f</span>, <span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">0.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line3">3</a> <span class="c2h_identifier">GLU</span>.<span class="c2h_identifier">gluDisk</span><span class="c2h_braces">(</span><span class="c2h_identifier">qobj</span>, <span class="c2h_numeric">0.0</span>, <span class="c2h_numeric">1.0</span>, <span class="c2h_numeric">32</span>, <span class="c2h_numeric">1</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line4">4</a> <span class="c2h_identifier">GLU</span>.<span class="c2h_identifier">gluCylinder</span><span class="c2h_braces">(</span><span class="c2h_identifier">qobj</span>, <span class="c2h_numeric">1.0f</span>, <span class="c2h_numeric">1.0</span>, <span class="c2h_numeric">2.0</span>, <span class="c2h_numeric">32</span>, <span class="c2h_numeric">1</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line5">5</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glTranslatef</span><span class="c2h_braces">(</span><span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">2.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line6">6</a> <span class="c2h_identifier">GLU</span>.<span class="c2h_identifier">gluDisk</span><span class="c2h_braces">(</span><span class="c2h_identifier">qobj</span>, <span class="c2h_numeric">0.0</span>, <span class="c2h_numeric">1.0</span>, <span class="c2h_numeric">32</span>, <span class="c2h_numeric">1</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line7">7</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glTranslatef</span><span class="c2h_braces">(</span><span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">0.0f</span>, <span class="c2h_symbol">-</span><span class="c2h_numeric">2.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line8">8</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glRotatef</span><span class="c2h_braces">(</span><span class="c2h_numeric">90.0f</span>, <span class="c2h_numeric">1.0f</span>, <span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">0.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line9">9</a> <span class="c2h_identifier">GLU</span>.<span class="c2h_identifier">gluDeleteQuadric</span><span class="c2h_braces">(</span><span class="c2h_identifier">qobj</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| </pre> |
| </td> |
| <td width="50%" align="center"> |
| <img src="images/cylinder.png" width="82" height="105" alt="Cylinder"> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="figure-caption"> |
| <span class="figure-number">Figure 5</span>. Code for rendering a cylinder and its result |
| </div> |
| |
| <p> |
| The first line allocates a new quadric needed by the disk and cylinder |
| calls. The scene is then rotated by -90 degrees, so that the cylinder is |
| drawn upright. Next, the bottom disk is rendered, followed by the |
| cylinder walls (the value of 32 indicates how many slices are to be used to |
| approximate the circular perimeter of both, and |
| gives a fair approximation of roundness). Before we can draw the |
| top disk, we need to move 2 units along the z-axis, |
| which is done by |
| performing a scene translation. The final disk is then drawn and |
| the coordinate system is restored by moving back by 2 units and |
| twisting it in the opposite direction. Finally, the |
| quadric that was allocated in line 1 is deleted. |
| </p> |
| <p> |
| While this approach works, it is also time-consuming. When drawing |
| one cylinder the inefficiency is not a problem, but rendering hundreds |
| of them could severely impact the program's performance. OpenGL provides |
| a solution for such situations, allowing us to perform a cooking |
| show trick - rather than "baking" the scene in front of a live |
| audience, we can ask OpenGL to use the one we prepared earlier. This |
| trick can be done by using display lists. |
| </p> |
| <p> |
| A display list is a collection of compiled OpenGL commands. A list |
| is defined by the set of commands placed between the |
| <code>glNewList(int list, int mode)</code> and <code>glEndList()</code> |
| method calls. The first parameter must be a positive integer that |
| uniquely identifies the display list being created. You can ask |
| GL to create one or more list identifiers for you, using the |
| <code>glGenLists(int n)</code> |
| method. The second <code>glNewList</code> parameter specifies whether the list is compiled |
| or compiled and immediately executed. Most of the time you probably just |
| want to compile the list. Later, you can display the list by |
| calling the <code>glCallList(int list)</code> method with the |
| identifier of the list to be displayed. For example, the triangle |
| code shown in <a href="#fig3">Figure 3</a> could be turned into a list using the |
| following code: |
| </p> |
| <pre class="code"> |
| <span class="c2h_identifier">triangle</span> <span class="c2h_symbol">=</span> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glGenLists</span><span class="c2h_braces">(</span><span class="c2h_numeric">1</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glNewList</span><span class="c2h_braces">(</span><span class="c2h_identifier">triangle</span>, <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_COMPILE</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glBegin</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_TRIANGLES</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glVertex3f</span><span class="c2h_braces">(</span><span class="c2h_symbol">-</span><span class="c2h_numeric">1.0f</span>, <span class="c2h_symbol">-</span><span class="c2h_numeric">1.0f</span>, <span class="c2h_numeric">0.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glVertex3f</span><span class="c2h_braces">(</span><span class="c2h_numeric">1.0f</span>, <span class="c2h_symbol">-</span><span class="c2h_numeric">1.0f</span>, <span class="c2h_numeric">0.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glVertex3f</span><span class="c2h_braces">(</span><span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">1.0f</span>, <span class="c2h_numeric">0.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glEnd</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glEndList</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| </pre> |
| <p> |
| To display it in, for instance, the <code>drawScene</code> method, you would simply |
| call <code>glCallList(triangle)</code>. Finally, you should also delete |
| any lists no longer needed by calling the <code>glDeleteLists(int list, int range)</code> |
| method. If you allocated just one list, the <code>range</code> is set |
| to 1. |
| </p> |
| <p> |
| In the charting application we are using two kinds of display lists, |
| one to represent a particular value in a chart, and the other to |
| draw chart axes. To simplify chart rendering, I defined a common |
| base class, the <code>CompiledShape</code>. In the constructor, it |
| grabs the next available list index. In addition, it defines three |
| methods: one for accessing the list index (line 8), one for rendering the |
| pre-compiled list (line 12), and one for deleting it (line 16). |
| </p> |
| <pre class="code"> |
| <a name="line1"> 1</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">abstract</span> <span class="c2h_reserved_word">class</span> <span class="c2h_identifier">CompiledShape</span> <span class="c2h_braces">{</span> |
| <a name="line2"> 2</a> <span class="c2h_reserved_word">private</span> <span class="c2h_reserved_word">int</span> <span class="c2h_identifier">listIndex</span><span class="c2h_symbol">;</span> |
| <a name="line3"> 3</a> |
| <a name="line4"> 4</a> <span class="c2h_reserved_word">public</span> <span class="c2h_identifier">CompiledShape</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line5"> 5</a> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">listIndex</span> <span class="c2h_symbol">=</span> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glGenLists</span><span class="c2h_braces">(</span><span class="c2h_numeric">1</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line6"> 6</a> <span class="c2h_braces">}</span> |
| <a name="line7"> 7</a> |
| <a name="line8"> 8</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">int</span> <span class="c2h_identifier">getListIndex</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line9"> 9</a> <span class="c2h_reserved_word">return</span> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">listIndex</span><span class="c2h_symbol">;</span> |
| <a name="line10">10</a> <span class="c2h_braces">}</span> |
| <a name="line11">11</a> |
| <a name="line12">12</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">draw</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line13">13</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glCallList</span><span class="c2h_braces">(</span><span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">getListIndex</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line14">14</a> <span class="c2h_braces">}</span> |
| <a name="line15">15</a> |
| <a name="line16">16</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">dispose</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line17">17</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glDeleteLists</span><span class="c2h_braces">(</span><span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">getListIndex</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span>, <span class="c2h_numeric">1</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line18">18</a> <span class="c2h_braces">}</span> |
| <a name="line19">19</a> <span class="c2h_braces">}</span> |
| </pre> |
| <p> |
| The values of the chart are represented by instances of |
| the <code>CompiledShape</code> class. Note that <code>CompiledShape</code> |
| does not create a display list, but leaves this task to the constructors |
| of extending classes. For the <code>BarValue</code> we reuse the |
| same quadric for each generated list. For a value passed to the |
| constructor, we build a cylinder in a similar manner as previously |
| described. The only two significant differences here are that the cylinder is |
| compiled into a display list (lines 6-14), and the specified <code>value</code> |
| is used to render the cylinder height (lines 8 and 10). |
| </p> |
| <pre class="code"> |
| <a name="line1"> 1</a> <span class="c2h_reserved_word">private</span> <span class="c2h_reserved_word">static</span> <span class="c2h_reserved_word">class</span> <span class="c2h_identifier">BarValue</span> <span class="c2h_reserved_word">extends</span> <span class="c2h_identifier">CompiledShape</span> <span class="c2h_braces">{</span> |
| <a name="line2"> 2</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">static</span> <span class="c2h_reserved_word">final</span> <span class="c2h_reserved_word">float</span> <span class="c2h_identifier">RADIUS</span> <span class="c2h_symbol">=</span> <span class="c2h_numeric">1.0f</span><span class="c2h_symbol">;</span> |
| <a name="line3"> 3</a> <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">static</span> <span class="c2h_reserved_word">int</span> <span class="c2h_identifier">QUADRIC</span></span><span class="c2h_symbol">;</span> |
| <a name="line4"> 4</a> |
| <a name="line5"> 5</a> <span class="c2h_reserved_word">public</span> <span class="c2h_identifier">BarValue</span><span class="c2h_braces">(</span><span class="c2h_reserved_word">float</span> <span class="c2h_identifier">value</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <a name="line6"> 6</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glNewList</span><span class="c2h_braces">(</span><span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">getListIndex</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span>, <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_COMPILE</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line7"> 7</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glRotatef</span><span class="c2h_braces">(</span><span class="c2h_symbol">-</span><span class="c2h_numeric">90.0f</span>, <span class="c2h_numeric">1.0f</span>, <span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">0.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line8"> 8</a> <span class="c2h_identifier">GLU</span>.<span class="c2h_identifier">gluCylinder</span><span class="c2h_braces">(</span><span class="c2h_identifier">BarValue</span>.<span class="c2h_identifier">QUADRIC</span>, <span class="c2h_identifier">RADIUS</span>, <span class="c2h_identifier">RADIUS</span>, <span class="c2h_identifier">value</span>, <span class="c2h_numeric">32</span>, <span class="c2h_numeric">1</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line9"> 9</a> <span class="c2h_identifier">GLU</span>.<span class="c2h_identifier">gluDisk</span><span class="c2h_braces">(</span><span class="c2h_identifier">BarValue</span>.<span class="c2h_identifier">QUADRIC</span>, <span class="c2h_numeric">0.0</span>, <span class="c2h_identifier">RADIUS</span>, <span class="c2h_numeric">32</span>, <span class="c2h_numeric">32</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line10">10</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glTranslatef</span><span class="c2h_braces">(</span><span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">0.0f</span>, <span class="c2h_identifier">value</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line11">11</a> <span class="c2h_identifier">GLU</span>.<span class="c2h_identifier">gluDisk</span><span class="c2h_braces">(</span><span class="c2h_identifier">BarValue</span>.<span class="c2h_identifier">QUADRIC</span>, <span class="c2h_numeric">0.0</span>, <span class="c2h_identifier">RADIUS</span>, <span class="c2h_numeric">32</span>, <span class="c2h_numeric">32</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line12">12</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glTranslatef</span><span class="c2h_braces">(</span><span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">0.0f</span>, <span class="c2h_symbol">-</span><span class="c2h_identifier">value</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line13">13</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glRotatef</span><span class="c2h_braces">(</span><span class="c2h_numeric">90.0f</span>, <span class="c2h_numeric">1.0f</span>, <span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">0.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line14">14</a> <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glEndList</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <a name="line15">15</a> <span class="c2h_braces">}</span> |
| <a name="line16">16</a> <span class="c2h_braces">}</span> |
| </pre> |
| |
| <p> |
| The widget on which the chart is drawn is a modification of the previously |
| introduced <code>GLScene</code> class. It overrides a number of methods |
| to add functionality needed by the application. Its <code>initGL</code> |
| method starts by setting up and enabling color blending. This creates |
| translucent rather than opaque cylinders, allowing us to view chart |
| values that would normally be hidden. To add the 3D realism, a light |
| source is set up. It emits a dim white light and a bright diffuse |
| (directional) light. The light is positioned above and to the left |
| of the scene. Finally, compiled shapes are created. First the axes |
| are set up, then bar values are generated. A simple shifted |
| sinusoidal curve is used for each row. |
| </p> |
| <pre class="code"> |
| <span class="c2h_reserved_word">protected</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">initGL</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <span class="c2h_reserved_word">super</span>.<span class="c2h_identifier">initGL</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| |
| <span class="c2h_identifier">BarValue</span>.<span class="c2h_identifier">QUADRIC</span> <span class="c2h_symbol">=</span> <span class="c2h_identifier">GLU</span>.<span class="c2h_identifier">gluNewQuadric</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span>; |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glBlendFunc</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_SRC_ALPHA</span>, <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_ONE_MINUS_SRC_ALPHA</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glEnable</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_BLEND</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glEnable</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_LINE_SMOOTH</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GLU</span>.<span class="c2h_identifier">gluQuadricNormals</span><span class="c2h_braces">(</span><span class="c2h_identifier">BarValue</span>.<span class="c2h_identifier">QUADRIC</span>, <span class="c2h_identifier">GLU</span>.<span class="c2h_identifier">GLU_SMOOTH</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glLightfv</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_LIGHT1</span>, |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_DIFFUSE</span>, |
| <span class="c2h_reserved_word">new</span> <span class="c2h_reserved_word">float</span><span class="c2h_braces">[</span><span class="c2h_braces">]</span> <span class="c2h_braces">{</span><span class="c2h_numeric">1.0f</span>, <span class="c2h_numeric">1.0f</span>, <span class="c2h_numeric">1.0f</span>, <span class="c2h_numeric">1.0f</span><span class="c2h_braces">}</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glLightfv</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_LIGHT1</span>, |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_AMBIENT</span>, |
| <span class="c2h_reserved_word">new</span> <span class="c2h_reserved_word">float</span><span class="c2h_braces">[</span><span class="c2h_braces">]</span> <span class="c2h_braces">{</span><span class="c2h_numeric">0.5f</span>, <span class="c2h_numeric">0.5f</span>, <span class="c2h_numeric">0.5f</span>, <span class="c2h_numeric">1.0f</span><span class="c2h_braces">}</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glLightfv</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_LIGHT1</span>, |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_POSITION</span>, |
| <span class="c2h_reserved_word">new</span> <span class="c2h_reserved_word">float</span><span class="c2h_braces">[</span><span class="c2h_braces">]</span> <span class="c2h_braces">{</span><span class="c2h_symbol">-</span><span class="c2h_numeric">50.f</span>, <span class="c2h_numeric">50.0f</span>, <span class="c2h_numeric">100.0f</span>, <span class="c2h_numeric">1.0f</span><span class="c2h_braces">}</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glEnable</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_LIGHT1</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glEnable</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_LIGHTING</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glEnable</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_COLOR_MATERIAL</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glColorMaterial</span><span class="c2h_braces">(</span><span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_FRONT</span>, <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">GL_AMBIENT_AND_DIFFUSE</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| |
| <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">axis</span> <span class="c2h_symbol">=</span> <span class="c2h_reserved_word">new</span> <span class="c2h_identifier">Axis</span><span class="c2h_braces">(</span><span class="c2h_numeric">15.0f</span>, <span class="c2h_numeric">9.0f</span>, <span class="c2h_numeric">11.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">chart</span> <span class="c2h_symbol">=</span> <span class="c2h_reserved_word">new</span> <span class="c2h_identifier">BarValue</span><span class="c2h_braces">[</span><span class="c2h_identifier">CHART_COUNT</span><span class="c2h_braces">]</span><span class="c2h_braces">[</span><span class="c2h_identifier">ROW_LENGTH</span><span class="c2h_braces">]</span><span class="c2h_symbol">;</span> |
| <span class="c2h_reserved_word">double</span> <span class="c2h_identifier">slice</span> <span class="c2h_symbol">=</span> <span class="c2h_identifier">Math</span>.<span class="c2h_identifier">PI</span>/<span class="c2h_identifier">ROW_LENGTH</span><span class="c2h_symbol">;</span> |
| |
| <span class="c2h_reserved_word">for</span> <span class="c2h_braces">(</span><span class="c2h_reserved_word">int</span> <span class="c2h_identifier">i</span> <span class="c2h_symbol">=</span> <span class="c2h_numeric">0</span><span class="c2h_symbol">;</span> <span class="c2h_identifier">i</span> <span class="c2h_symbol"><</span> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">chart</span>.<span class="c2h_identifier">length</span><span class="c2h_symbol">;</span> <span class="c2h_symbol">+</span><span class="c2h_symbol">+</span> <span class="c2h_identifier">i</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <span class="c2h_identifier">BarValue</span><span class="c2h_braces">[</span><span class="c2h_braces">]</span> <span class="c2h_identifier">value</span> <span class="c2h_symbol">=</span> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">chart</span><span class="c2h_braces">[</span><span class="c2h_identifier">i</span><span class="c2h_braces">]</span><span class="c2h_symbol">;</span> |
| <span class="c2h_reserved_word">double</span> <span class="c2h_identifier">shift</span> <span class="c2h_symbol">=</span> <span class="c2h_identifier">i</span><span class="c2h_symbol">*</span><span class="c2h_identifier">Math</span>.<span class="c2h_identifier">PI</span>/<span class="c2h_numeric">4.0</span><span class="c2h_symbol">;</span> |
| |
| <span class="c2h_reserved_word">for</span> <span class="c2h_braces">(</span><span class="c2h_reserved_word">int</span> <span class="c2h_identifier">j</span> <span class="c2h_symbol">=</span> <span class="c2h_numeric">1</span><span class="c2h_symbol">;</span> <span class="c2h_identifier">j</span> <span class="c2h_symbol"><</span><span class="c2h_symbol">=</span> <span class="c2h_identifier">value</span>.<span class="c2h_identifier">length</span><span class="c2h_symbol">;</span> <span class="c2h_symbol">+</span><span class="c2h_symbol">+</span> <span class="c2h_identifier">j</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <span class="c2h_identifier">value</span><span class="c2h_braces">[</span><span class="c2h_identifier">j</span><span class="c2h_symbol">-</span><span class="c2h_numeric">1</span><span class="c2h_braces">]</span> <span class="c2h_symbol">=</span> <span class="c2h_reserved_word">new</span> <span class="c2h_identifier">BarValue</span><span class="c2h_braces">(</span><span class="c2h_braces">(</span><span class="c2h_reserved_word">float</span><span class="c2h_braces">)</span> <span class="c2h_braces">(</span><span class="c2h_numeric">8.0</span><span class="c2h_symbol">*</span><span class="c2h_identifier">Math</span>.<span class="c2h_identifier">abs</span><span class="c2h_braces">(</span><span class="c2h_identifier">Math</span>.<span class="c2h_identifier">sin</span><span class="c2h_braces">(</span><span class="c2h_identifier">slice</span><span class="c2h_symbol">*</span><span class="c2h_identifier">j</span> <span class="c2h_symbol">-</span> <span class="c2h_identifier">shift</span><span class="c2h_braces">)</span><span class="c2h_braces">)</span><span class="c2h_braces">)</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_braces">}</span> |
| <span class="c2h_braces">}</span> |
| <span class="c2h_braces">}</span> |
| </pre> |
| |
| <p> |
| To render the chart we override the <code>drawScene</code> method. |
| This method first asks the scene grip to adjust the view point. Next, |
| the axes figure is drawn, followed by the bars. After each bar is drawn, |
| the coordinate system is moved to the right so that bars are |
| arranged in a row. After a complete row of bars is rendered, the |
| coordinate system is translated to the left and forward. |
| </p> |
| <p> |
| When using light sources it is customary to set up |
| material properties. These define how each component of light |
| is reflected by a given material, and whether the material is |
| shiny or dull. To simplify this procedure, the <code>initGL</code> |
| method sets up color tracking. This way, material properties are |
| automatically inferred from the current color. In order to make |
| cylinders translucent rather than opaque, we use the color command |
| that defines four rather than three parameters. The fourth parameter is the |
| alpha composite, which dictates the level of transparency. Objects that have |
| alpha set to <code>1.0f</code> are opaque, while objects with an alpha of <code>0.0f</code> are completely |
| transparent, and hence effectively invisible. |
| The program |
| uses alpha equal to <code>0.7f</code> to allow some but not all |
| light to pass through walls of cylinders. |
| </p> |
| <pre class="code"> |
| <span class="c2h_reserved_word">protected</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">drawScene</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <span class="c2h_reserved_word">super</span>.<span class="c2h_identifier">drawScene</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">grip</span>.<span class="c2h_identifier">adjust</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glLineWidth</span><span class="c2h_braces">(</span><span class="c2h_numeric">1.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">axis</span>.<span class="c2h_identifier">draw</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glTranslatef</span><span class="c2h_braces">(</span><span class="c2h_identifier">BarValue</span>.<span class="c2h_identifier">RADIUS</span>, <span class="c2h_numeric">0.0f</span>, <span class="c2h_identifier">BarValue</span>.<span class="c2h_identifier">RADIUS</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| |
| <span class="c2h_reserved_word">for</span> <span class="c2h_braces">(</span><span class="c2h_reserved_word">int</span> <span class="c2h_identifier">i</span> <span class="c2h_symbol">=</span> <span class="c2h_numeric">0</span><span class="c2h_symbol">;</span> <span class="c2h_identifier">i</span> <span class="c2h_symbol"><</span> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">chart</span>.<span class="c2h_identifier">length</span><span class="c2h_symbol">;</span> <span class="c2h_symbol">+</span><span class="c2h_symbol">+</span> <span class="c2h_identifier">i</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <span class="c2h_identifier">BarValue</span><span class="c2h_braces">[</span><span class="c2h_braces">]</span> <span class="c2h_identifier">value</span> <span class="c2h_symbol">=</span> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">chart</span><span class="c2h_braces">[</span><span class="c2h_identifier">i</span><span class="c2h_braces">]</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glColor4fv</span><span class="c2h_braces">(</span><span class="c2h_identifier">COLOR</span><span class="c2h_braces">[</span><span class="c2h_identifier">i</span> <span class="c2h_symbol">%</span> <span class="c2h_identifier">COLOR</span>.<span class="c2h_identifier">length</span><span class="c2h_braces">]</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| |
| <span class="c2h_reserved_word">for</span> <span class="c2h_braces">(</span><span class="c2h_reserved_word">int</span> <span class="c2h_identifier">j</span> <span class="c2h_symbol">=</span> <span class="c2h_numeric">0</span><span class="c2h_symbol">;</span> <span class="c2h_identifier">j</span> <span class="c2h_symbol"><</span> <span class="c2h_identifier">value</span>.<span class="c2h_identifier">length</span><span class="c2h_symbol">;</span> <span class="c2h_symbol">+</span><span class="c2h_symbol">+</span> <span class="c2h_identifier">j</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <span class="c2h_identifier">value</span><span class="c2h_braces">[</span><span class="c2h_identifier">j</span><span class="c2h_braces">]</span>.<span class="c2h_identifier">draw</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glTranslatef</span><span class="c2h_braces">(</span><span class="c2h_numeric">2.0f</span><span class="c2h_symbol">*</span><span class="c2h_identifier">BarValue</span>.<span class="c2h_identifier">RADIUS</span>, <span class="c2h_numeric">0.0f</span>, <span class="c2h_numeric">0.0f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_braces">}</span> |
| |
| <span class="c2h_identifier">GL</span>.<span class="c2h_identifier">glTranslatef</span><span class="c2h_braces">(</span><span class="c2h_symbol">-</span><span class="c2h_numeric">2.0f</span><span class="c2h_symbol">*</span><span class="c2h_identifier">BarValue</span>.<span class="c2h_identifier">RADIUS</span><span class="c2h_symbol">*</span><span class="c2h_identifier">value</span>.<span class="c2h_identifier">length</span>, |
| <span class="c2h_numeric">0.0f</span>, |
| <span class="c2h_numeric">2.0f</span><span class="c2h_symbol">*</span><span class="c2h_identifier">BarValue</span>.<span class="c2h_identifier">RADIUS</span> <span class="c2h_symbol">+</span> <span class="c2h_numeric">0.5f</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_braces">}</span> |
| <span class="c2h_braces">}</span> |
| </pre> |
| |
| <p> |
| The <code>dispose</code> method is used to free resources used by the |
| program. First, the quadric used by GLU to render cylinders and disks |
| is destroyed. Next, all display lists used by bars are freed, as well |
| as the list used to display the axes. Finally, the parent's <code>dispose</code> |
| method is called to dispose the context. |
| </p> |
| <pre class="code"> |
| <span class="c2h_reserved_word">public</span> <span class="c2h_reserved_word">void</span> <span class="c2h_identifier">dispose</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <span class="c2h_identifier">GLU</span>.<span class="c2h_identifier">gluDeleteQuadric</span><span class="c2h_braces">(</span><span class="c2h_identifier">BarValue</span>.<span class="c2h_identifier">QUADRIC</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| |
| <span class="c2h_reserved_word">for</span> <span class="c2h_braces">(</span><span class="c2h_reserved_word">int</span> <span class="c2h_identifier">i</span> <span class="c2h_symbol">=</span> <span class="c2h_numeric">0</span><span class="c2h_symbol">;</span> <span class="c2h_identifier">i</span> <span class="c2h_symbol"><</span> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">chart</span>.<span class="c2h_identifier">length</span><span class="c2h_symbol">;</span> <span class="c2h_symbol">+</span><span class="c2h_symbol">+</span> <span class="c2h_identifier">i</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <span class="c2h_identifier">BarValue</span><span class="c2h_braces">[</span><span class="c2h_braces">]</span> <span class="c2h_identifier">value</span> <span class="c2h_symbol">=</span> <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">chart</span><span class="c2h_braces">[</span><span class="c2h_identifier">i</span><span class="c2h_braces">]</span><span class="c2h_symbol">;</span> |
| |
| <span class="c2h_reserved_word">for</span> <span class="c2h_braces">(</span><span class="c2h_reserved_word">int</span> <span class="c2h_identifier">j</span> <span class="c2h_symbol">=</span> <span class="c2h_numeric">0</span><span class="c2h_symbol">;</span> <span class="c2h_identifier">j</span> <span class="c2h_symbol"><</span> <span class="c2h_identifier">value</span>.<span class="c2h_identifier">length</span><span class="c2h_symbol">;</span> <span class="c2h_symbol">+</span><span class="c2h_symbol">+</span> <span class="c2h_identifier">j</span><span class="c2h_braces">)</span> <span class="c2h_braces">{</span> |
| <span class="c2h_identifier">value</span><span class="c2h_braces">[</span><span class="c2h_identifier">j</span><span class="c2h_braces">]</span>.<span class="c2h_identifier">dispose</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_identifier">value</span><span class="c2h_braces">[</span><span class="c2h_identifier">j</span><span class="c2h_braces">]</span> <span class="c2h_symbol">=</span> <span class="c2h_reserved_word">null</span><span class="c2h_symbol">;</span> |
| <span class="c2h_braces">}</span> |
| <span class="c2h_braces">}</span> |
| |
| <span class="c2h_reserved_word">this</span>.<span class="c2h_identifier">axis</span>.<span class="c2h_identifier">dispose</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_reserved_word">super</span>.<span class="c2h_identifier">dispose</span><span class="c2h_braces">(</span><span class="c2h_braces">)</span><span class="c2h_symbol">;</span> |
| <span class="c2h_braces">}</span> |
| </pre> |
| |
| <p> |
| The end result is shown in Figure 6. The view point can be moved |
| around and rotated using either the mouse left or right buttons or the |
| keyboard. Depending on the |
| angle from which the chart is inspected, one can observe different |
| interaction of the light source and objects in the scene. The color |
| blending creates the translucent appearance of cylinders. |
| </p> |
| |
| <div class="figure"> |
| <img src="images/3dchart4.png" width="500" height="366" border="0" alt="3D Chart"> |
| <div class="figure-caption"> |
| <span class="figure-number">Figure 6</span>. OpenGL 3D Chart |
| </div> |
| </div> |
| |
| <p> |
| <img src="images/tryit.gif" alt="Try it!" width="61" height="13"> |
| To run this article's demo plug-in in your workspace make sure you |
| have the correct |
| <a href="http://dev.eclipse.org/viewcvs/index.cgi/%7Echeckout%7E/platform-swt-home/opengl/opengl.html">OpenGL</a> |
| plug-in installed. Download |
| <a href="lib/demo_plugin.zip">demo_plugin.zip</a> which contains an |
| Eclipse plug-in that defines a view that shows the OpenGL chart. |
| Unzip it to your Eclipse root directory; it should create the |
| <code>org.bluear.opengl_0.1.0</code> directory in Eclipse's plugins |
| folder. Start Eclipse with the <code>-clean</code> switch to ensure |
| that your newly-installed plug-in is detected. From the |
| <i>Show View</i> dialog, accessible under the <i>Windows</i> menu, |
| select the <i>OpenGL Chart</i> view listed in |
| the <i>OpenGL Examples</i> category. |
| In order to obtain access to the source code, import the plug-in |
| as the source project. The code also contains a stand alone version in the |
| form of an SWT program, with the entry point defined in the <code>Launcher</code> |
| class. To run it you need to set the <code>java.library.path</code> |
| variable with the path to both the SWT and OpenGL binary libraries. |
| </p> |
| <div class="figure"> |
| <img src="images/workbench2.png" width="734" height="400" border="0" alt="Eclipse OpenGL view"> |
| <div class="figure-caption" style="margin-top: 1ex;"> |
| <span class="figure-number">Figure 7</span>. An Eclipse view using <code>GLScene</code>. |
| </div> |
| </div> |
| |
| |
| <h2>Conclusion</h2> |
| |
| <p> |
| This article introduces and presents some of the functionality available |
| today in the OpenGL plug-in for SWT. While the subject of 3D and OpenGL |
| is too vast to be fully explored, I tried to give the reader a taste |
| of what can be achieved. Some of the components and techniques, such |
| as <code>GLScene</code> and <code>SceneGrip</code>, may be reused |
| in other 3D applications. |
| </p> |
| <p> |
| The plug-in is still considered experimental. For example, if you pass a |
| <code>null</code> array to some GL methods, rather than getting a possible to catch |
| <code>NullPointerException</code>, you end up with a JVM crash. These |
| and other issues must be addressed before the final release of the |
| plug-in. |
| </p> |
| <p> |
| OpenGL is not the only game in town; one could expect that a Windows-only |
| DirectX plug-in with similar capabilities could be developed. On |
| the other hand, OpenGL has the enormous benefit of being a platform-neutral |
| solution. The majority of the code for this article has been developed |
| under Linux and then tested, without any additional modifications, |
| under Windows. This fits well with the SWT philosophy of using native platform |
| capabilities but exposing them through platform-agnostic APIs. One |
| can only hope that the plug-in will continue to mature and be deployed |
| in other operating systems to which Eclipse has been ported. |
| </p> |
| |
| <h3>Acknowledgments</h3> |
| <p> |
| I would like to thank Grant Gayed and Ed Burnette for their comments |
| that helped improve the structure and accuracy of this article. My |
| thanks also go to Jill Sueoka for tirelessly reviewing numerous |
| versions that I managed to produce. |
| </p> |
| |
| <a name="bibliography"></a> |
| <h2>Bibliography</h2> |
| |
| <table> |
| <tbody> |
| <tr> |
| <td valign="top"><a name="winchester"></a>[1]</td> |
| <td> |
| Joe Winchester, |
| <a href="http://www.eclipse.org/articles/Article-SWT-graphics/SWT_graphics.html"><i>Introduction |
| to SWT Graphics</i></a>, |
| Eclipse Corner Article, July 2003 |
| </td> |
| </tr> |
| <tr> |
| <td valign="top"><a name="saillet"></a>[2]</td> |
| <td> |
| Yannick Saillet, |
| <a href="http://www-106.ibm.com/developerworks/library/j-2dswt/?ca=dnt-522"><i>Java |
| 2D imaging for the Standard Widget Toolkit</i></a>, |
| IBM developerWorks, Jun 2004 |
| </td> |
| </tr> |
| <tr> |
| <td valign="top"><a name="opengl-pg"></a>[3]</td> |
| <td> |
| OpenGL Architecture Review Board, Dave Shreiner, Mason Woo, Jackie Neider, |
| Tom Davis, |
| <a href="http://fly.cc.fer.hr/~unreal/theredbook/"><i>OpenGL Programming |
| Guide</i></a>, |
| Addison-Wesley, November 14, 2003, ISBN 0321173481. |
| </td> |
| </tr> |
| <tr> |
| <td valign="top"><a name="opengl-pg"></a>[4]</td> |
| <td> |
| OpenGL Architecture Review Board, Dave Shreiner, |
| <a href="http://rush3d.com/reference/opengl-bluebook-1.0/"><i>OpenGL Reference |
| Manual</i></a>, |
| Addison-Wesley, March 16, 2004, ISBN 032117383X. |
| </td> |
| </tr> |
| <tr> |
| <td valign="top"><a name="computer-graphics"></a>[5]</td> |
| <td> |
| James D. Foley, Andries van Dam, Steven K. Feiner, John F. Hughes, |
| <a href="http://www.awprofessional.com/titles/0-201-84840-6"><i>Computer |
| Graphics: Principles and Practice in C</i></a>, |
| Addison-Wesley, August 4, 1995, ISBN 0201848406. |
| </td> |
| </tr> |
| <tr> |
| <td valign="top"><a name="opengl-machine"></a>[6]</td> |
| <td> |
| <a href="http://www.opengl.org/documentation/specs/version1.1/state.pdf"><i>The |
| OpenGL Machine</i></a>, |
| Silicon Graphics, Inc., 1996. |
| </td> |
| </tr> |
| <tr> |
| <td valign="top"><a name="opengl-spec"></a>[7]</td> |
| <td> |
| Mark Segal, Kurt Akeley, |
| <a href="http://www.opengl.org/documentation/specs/version1.1/glspec1.1/index.html"><i>The |
| OpenGL Graphics System: A Specification (Version 1.1)</i></a>, |
| Silicon Graphics, Inc., 1992-1997. |
| </td> |
| </tr> |
| <tr> |
| <td valign="top"><a name="opengl-superbible"></a>[8]</td> |
| <td> |
| Richard S Wright, Benjamin Lipchak, |
| <a href="http://www.starstonesoftware.com/OpenGL/"><i>OpenGL |
| SuperBible</i></a>, |
| Sams, 3rd edition, June 30, 2004, ISBN: 0672326019 |
| </td> |
| </tr> |
| <tr> |
| <td valign="top"><a name="opengl-glu"></a>[9]</td> |
| <td> |
| Norman Chin, Chris Frazier, Paul Ho, Zacheng Liu, Kevin P. Smith, |
| <a href="http://www.opengl.org/documentation/specs/glu/glu1_3.pdf"><i>OpenGL |
| Graphics System Utility Library</i></a>, |
| Editor Jon Leech, version 1.3, November 1998 |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| |
| <p> |
| <small>Java and all Java-based trademarks and logos are trademarks or |
| registered trademarks of Sun Microsystems, Inc. in the United States, |
| other countries, or both.</small> |
| </p> |
| </body> |
| </html> |