Computer graphics/2013-2014/Laboratory 2

IMPORTANT
Va rog frumos sa va inregistrati pe acest formular. La adresele de e-mail pe care le inregistrati veti primii noutati legate de laborator.

Va multumesc.

Formularul il gasiti aici.

What is JOGL?
JOGL is a wrapper library (a binding) that allows OpenGL to be used from the Java language. This is achieved by issuing calls to the OpenGL C API through Java Native Interface (JNI).

Comparison with OpenGL
There are no notable differences between JOGL and OGL.

JOGL wraps the OpengGL 2.0 version and uses the Java language to make OpenGL calls.

JOGL uses as method names the same method (function) names as the OpenGL C API. As a result, if one is familiar with OpenGL for C he/she should have no problems with coding in JOGL. Any tutorials on drawing 2D / 3D scenes in OpenGL are good for JOGL, as the program logic is the same, except minor differences (such as window handling, keyboard and mouse control, network and sound issues). This is why when talking about OpenGL we can apply our knowledge to JOGL -- or vice versa.

JOGL uses no special datatypes to wrap standard ones as OGL does.

All JOGL methods are wrapped inside a huge interface called GL (with more than 1000 methods). The reason for wrapping them is quite simple: contrary to C where we simply have to call a function, in Java we cannot call a method unless it is declared in the current class, or in a super-class. By wrapping we simply need to instantiate an object of type GL and call its methods.

Links:
 * What is openGL?
 * Java OpenGL
 * Java Native Interface
 * Language binding

OpenGL as a state machine
(J)OGL is a state machine. This means that at each moment the programmer must be aware of the state (J)OGL is in. This is important because:


 * certain operations are available only in certain states
 * the state includes also values which control the way the scene is drawn (matrix transformations, light characteristics, material properties, polygon drawing characteristics, etc.)

The (J)OGL state is composed of named values called variables. All variables have default values, and thus we can ignore the majority of them and change only the ones we are interested in. State variables usually remain the same until you activate/deactivate them explicitly by calling either glEnable or glDisable. You can query the current values by using glGet*v where * can have one of the following values: Boolean, Integer, Float or Double. There are also query functions specific for particular state variables: glGetLight*, glGetError, or glGetPolygonStipple. However the latter ones are discouraged from being used.

Saving and retrieving the value of a state variable is done by using glPushAttrib respectively glPopAttrib functions (methods). These functions (methods) manipulate the attribute stack which has a depth of 16 elements. Trying to pop an element from an empty stack will lead to an error. In the same manner an error will be raised of we try to push an element on a full stack.

Links:
 * OpenGL and JOGL
 * OpenGL State Machine
 * glPushAttrib and glPopAttrib

Naming conventions
The JOGL naming convention follows the standard OGL naming.

Functions

 * Each function (method) starts with gl
 * All other words are written using camel case convention
 * Some functions (methods) use suffixes -- like 3f -- that denote the number of arguments it takes (3) and the type (f); (this allows us to have the same function but with different argument count and type; this is contrary to OOP programming where we would have method overloading. The possible values for type are:
 * b -- byte -- 8 bit integer
 * s -- short -- 16 bit integer
 * i -- int -- 32 bit integer
 * f -- float -- 32 bit float
 * d -- double -- 64 bit float
 * ub, us, ui -- unsigned byte, short, int
 * Some functions (methods) have a final v appended to them. It denotes that the function (method) takes an array of that many values

Examples of functions (methods):


 * glBegin -- starts a primitive given by the list of verices
 * glEnd -- ends a primitive
 * glVertex2i -- designates a vertex by giving its coordinates as integers (the z coordinate is taken to be 0)
 * glVertex3f -- designates a vertex by giving its coordinates as floats
 * glColor3b -- designates a RGB color given by bytes from 0 to 255 -- we should be careful in Java because byte is from -128 to 127
 * glColor4f -- designates a RGBA color given by floats from 0.0 to 1.0 (A stands for Alpha -- transparency factor)
 * glColor4fv -- the same as above, but there is only one argument -- a float array

Constants

 * Each constant starts with GL_
 * Words are in capitalized
 * Words are separated by underscores: _

Examples of constants:


 * GL_COLOR_BUFFER_BIT
 * GL_LINES
 * GL_TEXTURE

Variable Types
Contrary to OGL, JOGL has no generic datatypes which have been used in OGL due to cross platform issues and thus they were recommended instead C datatypes. The OGL list of datatypes contains: GLbyte (signed char), GLshort (short), GLint and GLsizei (int and long), GLfloat and GLclampf (float), GLdouble and GLclampd (double), GLubyte and GLboolean (unsigned char), GLushort (unsigned short), GLuint and GLenum and GLbitfield (unsigned long).

Creating our first simple JOGL scene using AWT (or the well known Hello World program)
Several steps are required to obtain a minimal functional JOGL application:


 * Installing JOGL libraries
 * Creating an AWT Java application
 * Initializing JOGL
 * Implementing the callback functions (methods)

Installing JOGL libraries
In a few lines it implies: The following paragraph is quoted from the Userguide.html file inside the distribution archive (it applies to Windows):
 * Installing -- or checking if is installed (usually this is the case) -- the OpenGL runtime
 * Downloading the JOGL distribution (version 2.0) from (it is a 7z archive):
 * http://jogamp.org/deployment/webstart/
 * http://jogamp.org/deployment/webstart/archive/jogamp-all-platforms.7z since May 2nd 2012 the .jar, .dll (Windows) and .so (Linux) files have been bundled in a single 7z archive. Please be sure to copy all the archive in your lib/ folder
 * it is highly recommended that you read the Userguide.html file inside the distribution archive
 * Creating a folder named lib inside the your project
 * Copying the entire contents of the jar and lib folders from the distribution archive to the lib folder inside your project
 * Adding the jogl.all.jar and glugen-rt.jar to the application CLASSPATH -- this step depends on the IDE:
 * From Eclipse expand the lib folder, right-click the jogl.all.jar and choose Add to build path option
 * If you use command line tools you could set the CLASSPATH environment variable to include the lib folder
 * Adding the lib folder to the java.library.path environment variable when running the application:
 * From Eclipse select Run -> Open Run Dialog... -> Java Application -> New Configuration (or the name given to the run configuration) -> Arguments tab -> add the line -Djava.library.path=lib (or the path where the DLL's reside) into the VM arguments textbox
 * If you use command line tools you could set the LD_LIBRARY_PATH environment variable to include the lib folder
 * You can find aditional information here
 * The JOGL distribution for developers comes in the form of a zip archive which contains the Java classes to call OpenGL from Java, as well as the associated JNI native libraries. JOGL depends on some run-time support classes and native code provided by the GlueGen project; these classes and native code are also provided in the zip bundles.
 * If you are developing a new application which uses JOGL, download the zip archive for your platform (for example., jogl-[version]-windows-i586.zip) and unzip it. Modify your CLASSPATH environment variable to include the full paths to jogl.all.jar, nativewindow.all.jar, gluegen-rt.jar, and optionally newt.all.jar; for example, ".;C:\Some\Other\Package\foo.jar;C:\Users\myhome\jogl-[version]-windows-i586\lib\jogl.all.jar;C:\Users\myhome\jogl-[version]-windows-i586\lib\nativewindow.all.jar;C:\Users\myhome\jogl-[version]-windows-i586\lib\gluegen-rt.jar;C:\Users\myhome\jogl-[version]-windows-i586\lib\newt.all.jar". (If you did not previously set the CLASSPATH environment variable, you may want to make sure that ".", the current directory, is on your new CLASSPATH.) Modify your PATH environment variable (Windows), LD_LIBRARY_PATH environment variable (Solaris and Linux), or DYLD_LIBRARY_PATH environment variable (Mac OS X) to contain the full path to the "lib" directory; for example, on Windows, add "C:\Users\myhome\jogl-[version]-windows-i586\lib" to your PATH using the System control panel, Advanced tab, Environment Variables button. At this point your Java installation should be able to see the JOGL class files. Users of IDEs such as NetBeans and Eclipse should consult the IDE's documentation to see how to add jar files and native libraries to their current project.
 * Dropping the JOGL jar and native library into the extension directory of the JRE is strongly discouraged. Doing so can cause conflicts with third-party applications launched via Java Web Start, and causes confusion later when upgrading the distribution.

For installation details you should consult -- please note that these tutorials might refer to an older version of JOGL:
 * JOGL Installation -- one version
 * JOGL Installation -- another version
 * mjbWorld - Troubleshooting
 * JOGL in Eclipse

Setting up an AWT window
JOGL puts at our disposal two classes for displaying scenes:


 * GLCanvas -- an AWT component
 * GLJpannel -- an Swing component

Both classes implement the GLAutoDrawable interface, so they can be used interchangeably; but the JOGL user's guide recommends using the AWT component -- GLCanvas -- as it provides better performance.

Thus in what follows we shall use AWT; but you could as easily use Swing.

Links:
 * Mixing heavy and light components
 * Abstract Window Toolkit
 * Swing (Java)
 * JOGL tutorial

In order to obtain a functional AWT application we need to create two classes:


 * MainFrame -- the application frame
 * Test -- the application entry point

MainFrame
'Please note the call to setVisible(true) after initializeJogl''. This is mandatory, otherwise the internal state of the library will be messed-up.'''

Initializing JOGL
Once we have our window we can proceed to the JOGL setup which means taking the following steps:
 * Creating a new GL profile
 * Setting some JOGL parameters -- capabilities as they are called
 * Creating the GLCanvas object and adding it to the window
 * Registering the GLEventListener

Thus we create the initializJogl method which will be concerned with:


 * Obtaining a new GLProfile
 * Setting up various variables -- this is achieved through the GLCapabilities instance. For example we can tune
 * Hardware acceleration: on / off
 * Double buffering: on / off
 * Rendering mode
 * Rendering only a color channel
 * etc.
 * Creating the GLCanvas instance that we shall use for rendering
 * Adding the GLCanvas instance to the center of the frame
 * Registering the GLEventListener to the newly created canvas: in our case the MainFrame class will also implement the needed GLEventListener interface

Links:
 * OpenGL and JOGL
 * JOGL Components and GLEventListener

Callback functions (methods)
(J)OGL uses callback functions (methods) to manage events such as window resizing, rendering, scene initializatin, etc. The four callback functions (methods) available in JOGL are:


 * init -- called when the canvas was initialized
 * reshape -- called when the canvas has changed position or size
 * displayChanged -- called when the rendering mode has been changed
 * display -- called when we are required to describe the scene

Links:
 * OpenGL and JOGL
 * JOGL Components and GLEventListener

Drawing
Is probably one of the most important features of (J)OGL. To handle it we need to implement the display, init and reshape methods found inside the GLEventListener inteface.

This method will be called every time (J)OGL decides that you need to repaint your graphics, and it gives you a reference to a GLAutoDrawable instance which is the canvas instance where you registered the listener inside the initializeJogl method.

The init method will be detailed in the next section when we talk about projections. However we can outline some main aspects which we can handle (initialize) in init:
 * The view
 * The background color
 * The lights
 * etc.

The reshape method will also be detailed in the same section. Its purpose is to ensure that the aspect ratio of the scene is maintained while resizing the canvas (window).

Animation
The display method is called only when there is a need to redraw the scene; but if we want to create animations we should have the possibility to call this method a couple of times per second (the more often the realistic the animation will be). We could do this by creating a background thread that forces the repaint, but the easiest -- and most recommended -- solution is to use the Animator class (behind the scenes the animator does create it's own thread).

For this we shall create a new member of the Animator class, and update the initializeJogl function (method) as to:
 * Create the instance
 * Add the canvas to the animator
 * Start the animator

Links:
 * OpenGL and JOGL:
 * Animation
 * Animator

JOGL Application Template
You can find the application template at the following link: Computer graphics -- 2013-2014 -- info.uvt.ro/JOGL-Template.

Coordinate Systems (JOGL vs. AWT)
In the simple form the coordinate system is Cartesian on 3 axis (X, Y, Z), where the positive Z points towards us. In reality OGL has a forth coordinate that works just like a scaling factor -- homogeneous coordinates.

We should remember that the origin of the world is located on the bottom left corner of the canvas, just as we were taught in geometry classes, and contrary to the origin of a normal AWT or Swing widget which is the upper left corner.

Links:
 * Cartesian coordinate system
 * Homogeneous coordinates
 * 
 * OpenGL and JOGL
 * Homogeneous Coordinates

Projections
(J)OGL offers us two kind of projections:


 * Perspective -- defined by a projection center and a projection plane (where objects are projected)
 * In (J)OGL it can be obtained by using one of the following functions (methods):
 * glFrustum(left, right, bottom, top, near, far) -- from GL instances
 * gluPerspective(fovy, aspect, near, far) -- from GLU instances
 * Good for 3D scenes


 * Orthogonal -- a form of parallel projection defined by a direction and a projection plane (where objects are projected). This kind of projection can be seen as a perspective projection where the projection center is placed at infinity.
 * In (J)OGL it can be obtained by using the glOrtho(left, right, bottom, top, near, far) function (method)
 * Good for 2D scenes

Viewport and View volume
The viewport is a rectangular area -- inside the (J)OGL window -- and is the place where the drawing takes place. It is measured in pixels, and it is positioned relative to the left upper corner of the component.

By default the viewport is setup to be the entire canvas component, but when the component changes its size, we must reset the viewport accordingly -- by calling the glViewport function (method).

When displaying a scene we also need to establish a viewing volume -- a rectangular parallelepiped (orhtographic projection) or a truncated pyramide (perspective projection) -- that will be displayed inside the viewport. Each and every object outside this volume will not be displayed (clipped). Each side of the volume can be seen as a clip plane.

In addition to these planes we can define additional ones by using the glClipPlane(int plane, double[] equation) function (method). The equation parameter refers to the coefficients of the corresponding clip plane.

Additional clip planes can be enabled or disabled at any moment by calling the gl.glEnable(GL.GL_CLIP_PLANE1) respectively the gl.glDisable(GL.GL_CLIP_PLANE1) functions (methods).

In general the aspect ration (the ratio between the width and the height) of the viewport and view volume should be the same. If this is not the resulting image would appear distorted.

(J)OGL uses matrices to manage the view (projection view and model view):


 * projection view -- the matrix is used to setup the viewing volume. It can be selected by calling the glMatrixMode(GLMatrixFunc.GL_PROJECTION) function (method)
 * model view -- the matrix is used to apply geometric transformations to scene objects (translation, rotation, scaling, etc.) and to orientate the viewport. It can be selected by calling the glMatrixMode(GLMatrixFunc.GL_MODELVIEW) function (method)

These matrices are modified each time you perform an operation on the scene, but you can reset them by loading the identity matrix in the current matrix. This is achieved by calling the glLoadIdentity function (method).

Putting all together (or how to use them in (J)OGL)
The projection matrix is handled inside the reshape callback function (method) and initialized in init. The reason for always handling it inside reshape is that there is the place where all resizing events take place. Each time such an event occurs we need to modify the projection and aspect ratio accordingly.

After modifying the projection matrix we need to switch back to the modelview.

The following piece of code exemplifies the previous:

Links:
 * Orthographic projection
 * Perspective (graphical)
 * OpenGL and JOGL:
 * Viewport Transformation
 * Projection Transformations
 * Orthographic Projection
 * Perspective Projection

Coordinate spaces
(J)OGL uses several coordinate spaces in order to transform coordinates from the user given ones to the coordinates used for displaying the scene:
 * Object Coordinates -- raw (Cartesian) coordinates entered with the glVertex* function (method) family
 * Eye Coordinates -- are obtained by the ModelView matrix which contains both modeling and viewing transformations that place the viewer at the origin with the view direction aligned with the negative Z axis. They are obtained from the Object Coordinates
 * Clip Coordinates - are obtained by the Projection Matrix after transforming the Eye Coordinates. Clip coordinate space ranges from -W to W on all three axis (W is the Clip Coordinate W value) and everything outside these boundaries is not displayed (clipped)
 * Normalized Device Coordinates -- range from -1 to 1 and are obtained after the Perspective division is performed on the Clip Coordinates
 * Window Coordinates -- scaling and translating the Normalized Device Coordinates by the viewport. This operation gives us the final coordinates that are used to draw the scene objects. We can control this operation by using the glViewport and glDepthRange functions (methods)

We can notice that the typical coordinate transformation workflow goes like this: Object Coordinates → Eye Coordinates → Clip Coordinates → Normalized Device Coordinates → Window Coordinates.

A special coordinate system is represented by the World Coordinates which results from transforming Object Coordinates by the modeling transformations (rotations, translations, scalings) stored in the ModelView matrix. Basically the World Coordinates system is different for each application. It is created after the Object Coordinates are rotated, scaled or translated into the world constructed inside the application. (For example planets are translated to their coordinates around the Sun, rotated around their axis to simulate orbit tilt -- inclination -- and also scaled).

In the previous section we have seen that an orthographic projection is set up in the following way (inside the init and reshape callback functions (methods)):

Now we want to set up the projection so that one world coordinate unit is equal to one screen pixel. For this we have to modify the glOrtho function (method) in the following way:

This gives us a viewport having the same size (in units) as our (J)OGL window (canvas). This is of interest as it shows us that we can set the dimension of the viewport to be of any size we want. For example if we set up the view volume to be gl.glOrtho(0, 1, 0, 1, -1, 1) we will notice that a vertex drawn with glVertex2f(2.0f, 2.0f) will not be clipped as it will be situated outside the viewing volume. In contrast when using gl.glOrtho(0, 800, 0, 600, -1, 1); it will appear to be placed somewhere in the lower left side of the screen.

(J)OGL does not have a standard measurement unit when placing objects. And a conclusion we could use whatever we find suited for our application. For example we could use astronomical units when creating a space simulator, or nanometers when creating a simulation of an atom.

Important: When setting the Z range from -1 to 1 be sure to use glVertex2* functions to ensure your geometry isn't clipped by the zNear or zFar clipping planes, or if you must use glVertex3* functions be sure to use 0 as the third coordinate.

Links:
 * OpenGL and JOGL:
 * The Camera Analogy
 * Stages of Vertex Transformation

Vertices vs. Points vs. Pixels

 * Vertices are "the most basic" primitives used by (J)OGL
 * Vertices can be seen as points represented by vectors of floating point numbers
 * A vertex is NOT a pixel
 * A vertex is declared by using the glVertex* functions (methods)

Vertices can be grouped together to form various other geometric objects such as lines, triangles, polygons, etc.

To group together vertices one must bound them inside a glBegin and glEnd block:

List of points (points, lines, line strip, line loop)
Vertices can be interpreted by (J)OGL in various ways:


 * points -- specified by GL.GL_POINTS treats vertices as a set of points
 * lines -- specified by GL.GL_LINES treats each pair of vertices as a line segment
 * line strip -- specified by GL.GL_LINE_STRIP treats vertices as a series of interconnected line segments
 * line loop -- specified by GL.GL_LINE_LOOP same as above but adds a line between the first and last vertex

Links:
 * Points
 * Lines
 * Geometric Lines Primitves
 * Specifying Vertices
 * Drawing Primitives in OpenGL:
 * Primitive examples

Changing the properties of points (size) and lines (width, stipple)
Points and lines have properties such as:


 * size (points) -- modified by the glPointSize function (method):


 * width (lines) -- modified by the glLineWidth function (method):


 * stipple (lines) -- modified by the glLineStipple function (method):

Coloring
(J)OGL -- like almost any other software -- uses 24 bit RGB colors, and sometimes RGBA (A stands for Alpha).

Each time the scene is (re)drawn it is filled with a clear color, which can be set by using the glClearColor function (method) -- the default is black RGB = (0, 0, 0). This actually means manipulating the color buffer (the buffer containing the pixel colors of the working window). Buffers will be detailed in a later laboratory

Every other object drawn is done with another default color, which can be set by using the glColor* functions (methods).

Links:
 * OpenGL and JOGL:
 * Bitplanes
 * Colormode: RGBA versus Color-Index Mode
 * Color in RGBA Mode: glColor

API

 * java.media.opengl:
 * GLCapabilities
 * GLCanvas
 * GLAutoDrawable
 * GL:
 * glClear(int)
 * glBegin(int)
 * glEnd
 * glFlush
 * glVertex3f(float, float, float)
 * glColor3f(float, float, float)
 * glClearColor(float, float, float, float)
 * glMatrixMode(int)
 * glLoadIdentity
 * glOrtho(double, double, double, double, double, double)
 * glFrustum(double, double, double, double, double, double)
 * glClipPlane(int, doublev)
 * glPushAttrib(int)
 * glPopAttrib
 * glAccum(int, float)
 * glHint(int, int)


 * javax.media.opengl.glu:
 * GLU
 * void gluPerspective(double, double, double, double)


 * com.sun.opengl.util:
 * Animator:
 * add(GLAutoDrawable)
 * start
 * FPSAnimator:
 * constructor(int)
 * GLUT

Exercises

 * Create a minimal JOGL application in Eclipse which simply instantiates a JOGL rendering window
 * Draw a square by using GL_LINES, GL_LINE_STRIP and GL_LINE_LOOP. Each vertex should have a different colour
 * Draw a circle by using GL_LINE_LOOP
 * Draw a house by first using GL_LINES. Color it in different colours. Add the Sun (yellow circle) and make it move from left to right
 * Draw one of the fractals found here. You can see some nice fractal examples at this page.
 * The method drawing the fractal needs to be recursive!