Labels

Thursday, 17 October 2013

Bit Shift and ... in java

source: http://rodrigosasaki.com/2013/06/06/bit-shift-and-bitwise-operators/



Bit Shift and Bitwise Operators

Hello, everyone! :)
Today we’re gonna talk a little about Java’s Bit Shift and Bitwise operators, that allow us to work directly with binary values, which means that we’re working directly with bits
What are these ‘bits’?
Bit is the abbreviation to (BInary digiT), which is the smallest unit where we can store information. And as it name says, this unit can only store 2 different values, which are and 1.

Bitwise

When working with these bits we can perform some operations that are called bitwise.
And for each of these operations we have a correspondent Java Operator. So I’ll explain the operation itself, describe how it works and then tell you the corresponding operator. Shall we?
NOT 
The first operation is the easiest to understand. It’s called NOT. This is an unary operator, which means that it only has one operand, so it’s result depends entirely on a single value.
What this operation does is invert (negate) the value of a bit, and it’s quite simple, if it’s a 0 the result will be 1, and if it is an 1 the result will be 0.
The Java operator that performs this operation is the ~
We can do a quick test, when we run this code:
public static void main(String[] args){
    System.out.println(Integer.toBinaryString(Integer.MAX_VALUE));
}
The printed value is: 01111111111111111111111111111111
The value you get may not have that left-hand zero, but it exists nonetheless and it’s quite important, we’ll see more about him later.
Now we can invert the printed value like this:
public static void main(String[] args){
    System.out.println(Integer.toBinaryString(~Integer.MAX_VALUE));
}
And now the printed value is:  10000000000000000000000000000000.
As we can see, all the 1s became 0s and the initial 0 became 1.

AND

This operation receives 2 values and return a result that will vary depending on these operands. We follow the basic rule:
The result will be 1 if, and only if, both operands are 1.
We can use the following table as reference:
Based on that we can see that if either of the operands are 0, the result will also be 0.
The Java operator that performs an AND is the & and we can see that in the following example:
public static void main(String[] args) {
    System.out.println(0 & 0); // Prints 0
    System.out.println(0 & 1); // Prints 0
    System.out.println(1 & 0); // Prints 0
    System.out.println(1 & 1); // Prints 1
}

OR

This operation as well as the AND and the XOR (that we’ll talk about soon) receives  2 values. What changes is the condition that says if the result is 1 or 0. In this case our rule is this:
The result will be 1 whenever either of the operands is 1.
So what we end up with is this:
We can see that in fact if either of the operands is 1 (which means the same is true if they both are), that will also be the result.
The Java operator responsible for performing an OR operation is the | and we can see him in action below:
public static void main(String[] args){
    System.out.println(0 | 0); // Prints 0
    System.out.println(0 | 1); // Prints 1
    System.out.println(1 | 0); // Prints 1
    System.out.println(1 | 1); // Prints 1
}

XOR

The XOR usually is one of the operations that cause most confusion, because it’s usage is not as intuitive as the ones explained before, even though it’s extensively used in criptography and some other algorithms. It’s basic rule is this:
The result will be 1 if, and only if, one of the operands is 1.
Pay a lot of attention to the sentence above, it basically says that it will only reaturn a 1 when both operands have different values. When they both have the same value (even if both values are 1), the result will be a 0.

Check the cheatsheet:
And there’s also a Java operator for this operation, that is the ^
public static void main(String[] args){
    System.out.println(0 ^ 0); // Prints 0
    System.out.println(0 ^ 1); // Prints 1
    System.out.println(1 ^ 0); // Prints 1
    System.out.println(1 ^ 1); // Prints 0
}
You can play around with them and check all the different results, but remember that numbers in Java are not in binary form by default, so you may have to tinker with them a little to get the results you want.
Example: I want to know the result of an AND operation between the numbers 11010100 and 10101111, here’s the sample code for that particular operation, in version 6 of Java:
public static void main(String[] args){
    int n1 = Integer.valueOf("11010100", 2);
    int n2 = Integer.valueOf("10101111", 2);
    System.out.println(Integer.toBinaryString(n1 & n2));
}
For the Java 7 version we have a syntactic sugar that allows us to do this in a more direct way. We can say that a number is in base 2 by simply adding 0b ad a prefix to our binary pattern, Like this:
public static void main(String[] args){
    int n = 0b1010;
    System.out.println(n); // Prints 10
}
We can see that the code prints 10, because the binary number 1010 when showed in decimal format is in fact 10.
So the same example as before, rewritten for Java 7 is like this:
public static void main(String[] args){
    int n1 = 0b11010100;
    int n2 = 0b10101111;
    System.out.println(Integer.toBinaryString(n1 & n2));
}
The method Integer.toBinaryString still is necessary, because if we don’t use it, the value will be printed in base 10.
PS: If you’d like to read a bit more about number literals, you can read this.

Bit Shifting

Now that you already became a bitwise machine, it’s time we give you a new tool to play with. Let’s talk a little about Bit Shifting
If you think about the word Shift you’ll see that it’s a synonym to move, or dislocate. And that’s exactly what we’re about to do, dislocate bits. Fun, right?
In some moments of the explanation you may wonder: “But why am I going to want to shift a bit pattern? Where is this used in practice?”
Well, bit shifting is a very common technique applied into some more complex algorithms. As examples we have some mathematical operations (depending on your environment), CG, hash generation and so on.
To shift the bits the Java language offers urs 3 operators, and I’ll explain all of them here.
For all the operators we follow the same basic rule. The pattern to be shifted is given by the left-hand operand, and the number of bits that we’re gonna shift the pattern is given by the right-hand operand.
The first of these operators is the << that we can intuitively assume that it’ll be used to shift bits to the left, and that’s in fact what it does.
Let’s see an example:
You have the pattern 01101001 and you want to shift it one bit to the left and then see the result, so you just do it like this:
public static void main(String[] args){
    System.out.println(Integer.toBinaryString(0b01101001 << 1));
}
And when you print it you see the result 11010010, and you can see that it’s the same pattern, only shifted 1 bit to the left.
    01101001
 <<        1
    11010010
As you may have noticed, in case you want to shift it 3 bits, just send 3 as the second operand.
     01101001
<<          3
   1101001000
After that we have the operators that shift bits to the right, and there are 2 of those (>> and >>>), but to understand the difference between them, we need to understand some basics of how numbers work internally.
The problem here is related to the sign of the number, whether it’s positive or negative. To represent a negative number in base 2, we have a control bit, that is the bit that stays most to the left (remember the left bit I said was important?), so if a binary number starts with 1, we’re talking about a negative number, if it starts with a 0, we’re talking about a positive one.
An int in Java ranges from the pattern:
10000000000000000000000000000000 (in decimal it's the number -2147483648)
To the pattern:
01111111111111111111111111111111 (in decimal it's the number 2147483647)
We can see that the highest number that can be represented by an int starts with a zero, which we know now that this specific zero tells us it’s a positive number.
And the lowest number that can be represented by an int starts with a 1 followed by zeros.
So let’s get back to the operators. What’s the difference between them?
The first operator (>>) is used to shift a bit pattern to the right preserving the sign bit, which means that everything else gets shifted, but the control bit stays put. If it was a 0 it remains as 0, and if it was a 0 it remains as 1.

Now the second operator (>>>) does not preserve the sign bit, everything gets shifted, no matter where it is. And a 0 is put at the left-most bit of the pattern.
Check out the examples:
    10000000000000000000000000000111
>>                                 2
    11100000000000000000000000000001

    10000000000000000000000000000111
>>>                                2
    00100000000000000000000000000001
On the first operator (>>) we can see that the 1 is preserved at the left, whilst in the second that value is shifted.
Now that’s play with it a little. In a forum I saw an user that wanted to store the information of a Date (day, month year), in a 3-byte array. Now how would he do that?
With a 3-byte array we have 24 bits to work with
00000000 00000000 00000000
  byte1    byte2    byte3
And the information will be divided like this:
  • The first 5 bits of byte1 will store the day
  • The last 3 bits of byte1 and the first bit of byte2 will store the month
  • The rest of the bits will store the year
 day month     year
00000000 00000000 00000000
  byte1    byte2    byte3
All of this takes a little bit of Bit Shifting and Bitwise operations, but as a final result, we get a class like this:
public class Date{
    byte[] d;
    public Date(){
        d = new byte[3];
    }
    public Data(int day, int month, int year){
        this();
        setDay(day);
        setMonth(month);
        setYear(year);
    }
    public void setDay(int day){
        d[0] = (byte) (day << 3);
    }
    public int getDay(){
        return d[0] >>> 3 & 0x1F;
    }
    public void setMonth(int month){
        d[0] = (byte) (d[0] | month >>> 1);
        d[1] = (byte) (month << 7);
    }
    public int getMonth(){
        return (d[0] & 0x7) << 1 | d[1] >>> 7 & 0x1;
    }
    public void setYear(int year){
        d[1] = (byte) (d[1] | year >>> 8);
        d[2] = (byte) year;
    }
    public int getYear(){
        return (d[1] << 8 & 0x7FFF) | d[2] & 0xFF;
    }
}
Now I recommend you all play a little with this class, run tests to try to understand what happens and why it happens, so the concepts can really sink in. 
That’s all for today. See you next time :)

Nghien cuu ngay Javanotes

http://www.leepoint.net/notes-java/index.html

good website: http://uaihebert.com

Tuesday, 8 October 2013

Java I/O

Reading and writing text files

In JDK 7, the most important classes for text files are:
  • Paths and Path - file locations/names, but not their content.
  • Files - operations on file content.
  • StandardCharsets and Charset (an older class), for encodings of text files.
  • the File.toPath method, which lets older code interact nicely with the newer java.nio API.
In addition, the following classes are also commonly used with text files, for both JDK 7 and earlier versions:
When reading and writing text files:
  • it's often a good idea to use buffering (default size is 8K)
  • there's always a need to pay attention to exceptions (in particular, IOException and FileNotFoundException)
Character Encoding
In order to correctly read and write text files, you need to understand that those read/write operations always use an implicit character encoding to translate raw bytes - the 1s and 0s - into text. When a text file is saved, the tool that saves it must always use a character encoding (UTF-8 is recommended). There's a problem, however. The character encoding is not, in general, explicit: it's not saved as part of the file itself. Thus, a program that consumes a text file should know beforehand what its encoding is. If it doesn't, then the best it can do is make an assumption. Problems with encoding usually show up as weird characters in a tool that has read the file.
The FileReader and FileWriter classes are a bit tricky, since they implicitly use the system's default character encoding. If this default is not appropriate, the recommended alternatives are, for example:
FileInputStream fis = new FileInputStream("test.txt");
InputStreamReader in = new InputStreamReader(fis, "UTF-8");
FileOutputStream fos = new FileOutputStream("test.txt");
OutputStreamWriter out = new OutputStreamWriter(fos, "UTF-8");
Scanner scanner = new Scanner(file, "UTF-8");
Example 1 - JDK 7+

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

public class ReadWriteTextFileJDK7 {
  
  public static void main(String... aArgs) throws IOException{
    ReadWriteTextFileJDK7 text = new ReadWriteTextFileJDK7();
    
    //treat as a small file
    List<String> lines = text.readSmallTextFile(FILE_NAME);
    log(lines);
    lines.add("This is a line added in code.");
    text.writeSmallTextFile(lines, FILE_NAME);
    
    //treat as a large file - use some buffering
    text.readLargerTextFile(FILE_NAME);
    lines = Arrays.asList("Down to the Waterline", "Water of Love");
    text.writeLargerTextFile(OUTPUT_FILE_NAME, lines);   
  }

  final static String FILE_NAME = "C:\\Temp\\input.txt";
  final static String OUTPUT_FILE_NAME = "C:\\Temp\\output.txt";
  final static Charset ENCODING = StandardCharsets.UTF_8;
  
  //For smaller files

  /**
   Note: the javadoc of Files.readAllLines says it's intended for small
   files. But its implementation uses buffering, so it's likely good 
   even for fairly large files.
  */  
  List<String> readSmallTextFile(String aFileName) throws IOException {
    Path path = Paths.get(aFileName);
    return Files.readAllLines(path, ENCODING);
  }
  
  void writeSmallTextFile(List<String> aLines, String aFileName) throws IOException {
    Path path = Paths.get(aFileName);
    Files.write(path, aLines, ENCODING);
  }

  //For larger files
  
  void readLargerTextFile(String aFileName) throws IOException {
    Path path = Paths.get(aFileName);
    try (Scanner scanner =  new Scanner(path, ENCODING.name())){
      while (scanner.hasNextLine()){
        //process each line in some way
        log(scanner.nextLine());
      }      
    }
  }
  
  void readLargerTextFileAlternate(String aFileName) throws IOException {
    Path path = Paths.get(aFileName);
    try (BufferedReader reader = Files.newBufferedReader(path, ENCODING)){
      String line = null;
      while ((line = reader.readLine()) != null) {
        //process each line in some way
        log(line);
      }      
    }
  }
  
  void writeLargerTextFile(String aFileName, List<String> aLines) throws IOException {
    Path path = Paths.get(aFileName);
    try (BufferedWriter writer = Files.newBufferedWriter(path, ENCODING)){
      for(String line : aLines){
        writer.write(line);
        writer.newLine();
      }
    }
  }

  private static void log(Object aMsg){
    System.out.println(String.valueOf(aMsg));
  }
  
} 

Example 2 - JDK 7+
This example demonstrates using Scanner to read a file containing lines of structured data. One Scanner is used to read in each line, and a second Scanner is used to parse each line into a simple name-value pair. The Scanner class is only used for reading, not for writing.

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Scanner;

/** Assumes UTF-8 encoding. JDK 7+. */
public class ReadWithScanner {

  public static void main(String... aArgs) throws IOException {
    ReadWithScanner parser = new ReadWithScanner("C:\\Temp\\test.txt");
    parser.processLineByLine();
    log("Done.");
  }
  
  /**
   Constructor.
   @param aFileName full name of an existing, readable file.
  */
  public ReadWithScanner(String aFileName){
    fFilePath = Paths.get(aFileName);
  }
  
  
  /** Template method that calls {@link #processLine(String)}.  */
  public final void processLineByLine() throws IOException {
    try (Scanner scanner =  new Scanner(fFilePath, ENCODING.name())){
      while (scanner.hasNextLine()){
        processLine(scanner.nextLine());
      }      
    }
  }
  
  /** 
   Overridable method for processing lines in different ways.
    
   <P>This simple default implementation expects simple name-value pairs, separated by an 
   '=' sign. Examples of valid input: 
   <tt>height = 167cm</tt>
   <tt>mass =  65kg</tt>
   <tt>disposition =  "grumpy"</tt>
   <tt>this is the name = this is the value</tt>
  */
  protected void processLine(String aLine){
    //use a second Scanner to parse the content of each line 
    Scanner scanner = new Scanner(aLine);
    scanner.useDelimiter("=");
    if (scanner.hasNext()){
      //assumes the line has a certain structure
      String name = scanner.next();
      String value = scanner.next();
      log("Name is : " + quote(name.trim()) + ", and Value is : " + quote(value.trim()));
    }
    else {
      log("Empty or invalid line. Unable to process.");
    }
  }
  
  // PRIVATE 
  private final Path fFilePath;
  private final static Charset ENCODING = StandardCharsets.UTF_8;  
  
  private static void log(Object aObject){
    System.out.println(String.valueOf(aObject));
  }
  
  private String quote(String aText){
    String QUOTE = "'";
    return QUOTE + aText + QUOTE;
  }
} 


Example run of this class:
Name is : 'height', and Value is : '167cm'
Name is : 'mass', and Value is : '65kg'
Name is : 'disposition', and Value is : '"grumpy"'
Name is : 'this is the name', and Value is : 'this is the value'
Done.
Example 3 - JDK < 7
The try-with-resources feature is not available prior to JDK 7. In this case, you need to exercise care with respect to the close method:
  • it always needs to be called, or else resources will leak
  • it will automatically flush the stream, if necessary
  • calling close on a "wrapper" stream will automatically call close on its underlying stream
  • closing a stream a second time has no consequence
  • when called on a Scanner, the close operation only works if the item passed to its constructor implements Closeable. Warning: if you pass a File to a Scanner, you will not be able to close it! Try using a FileReader instead.
Here's a fairly compact example (for JDK 1.5) of reading and writing a text file, using an explicit encoding. If you remove all references to encoding from this class, it will still work -- the system's default encoding will simply be used instead.
import java.io.*;
import java.util.Scanner;

/** 
 Read and write a file using an explicit encoding.
 JDK 1.5.
 Removing the encoding from this code will simply cause the 
 system's default encoding to be used instead.  
*/
public final class ReadWriteTextFileWithEncoding {

  /** Requires two arguments - the file name, and the encoding to use.  */
  public static void main(String... aArgs) throws IOException {
    String fileName = aArgs[0];
    String encoding = aArgs[1];
    ReadWriteTextFileWithEncoding test = new ReadWriteTextFileWithEncoding(
      fileName, encoding
    );
    test.write();
    test.read();
  }
  
  /** Constructor. */
  ReadWriteTextFileWithEncoding(String aFileName, String aEncoding){
    fEncoding = aEncoding;
    fFileName = aFileName;
  }
  
  /** Write fixed content to the given file. */
  void write() throws IOException  {
    log("Writing to file named " + fFileName + ". Encoding: " + fEncoding);
    Writer out = new OutputStreamWriter(new FileOutputStream(fFileName), fEncoding);
    try {
      out.write(FIXED_TEXT);
    }
    finally {
      out.close();
    }
  }
  
  /** Read the contents of the given file. */
  void read() throws IOException {
    log("Reading from file.");
    StringBuilder text = new StringBuilder();
    String NL = System.getProperty("line.separator");
    Scanner scanner = new Scanner(new FileInputStream(fFileName), fEncoding);
    try {
      while (scanner.hasNextLine()){
        text.append(scanner.nextLine() + NL);
      }
    }
    finally{
      scanner.close();
    }
    log("Text read in: " + text);
  }
  
  // PRIVATE 
  private final String fFileName;
  private final String fEncoding;
  private final String FIXED_TEXT = "But soft! what code in yonder program breaks?";
  
  private void log(String aMessage){
    System.out.println(aMessage);
  }
}
 


Example 4 - JDK < 7 This example uses FileReader and FileWriter, which implicitly use the system's default encoding. It also uses buffering. To make this example compatible with JDK 1.4, just change StringBuilder to StringBuffer:

import java.io.*;

/** JDK 6 or before. */
public class ReadWriteTextFile {

  /**
  * Fetch the entire contents of a text file, and return it in a String.
  * This style of implementation does not throw Exceptions to the caller.
  *
  * @param aFile is a file which already exists and can be read.
  */
  static public String getContents(File aFile) {
    //...checks on aFile are elided
    StringBuilder contents = new StringBuilder();
    
    try {
      //use buffering, reading one line at a time
      //FileReader always assumes default encoding is OK!
      BufferedReader input =  new BufferedReader(new FileReader(aFile));
      try {
        String line = null; //not declared within while loop
        /*
        * readLine is a bit quirky :
        * it returns the content of a line MINUS the newline.
        * it returns null only for the END of the stream.
        * it returns an empty String if two newlines appear in a row.
        */
        while (( line = input.readLine()) != null){
          contents.append(line);
          contents.append(System.getProperty("line.separator"));
        }
      }
      finally {
        input.close();
      }
    }
    catch (IOException ex){
      ex.printStackTrace();
    }
    
    return contents.toString();
  }

  /**
  * Change the contents of text file in its entirety, overwriting any
  * existing text.
  *
  * This style of implementation throws all exceptions to the caller.
  *
  * @param aFile is an existing file which can be written to.
  * @throws IllegalArgumentException if param does not comply.
  * @throws FileNotFoundException if the file does not exist.
  * @throws IOException if problem encountered during write.
  */
  static public void setContents(File aFile, String aContents)
                                 throws FileNotFoundException, IOException {
    if (aFile == null) {
      throw new IllegalArgumentException("File should not be null.");
    }
    if (!aFile.exists()) {
      throw new FileNotFoundException ("File does not exist: " + aFile);
    }
    if (!aFile.isFile()) {
      throw new IllegalArgumentException("Should not be a directory: " + aFile);
    }
    if (!aFile.canWrite()) {
      throw new IllegalArgumentException("File cannot be written: " + aFile);
    }

    //use buffering
    Writer output = new BufferedWriter(new FileWriter(aFile));
    try {
      //FileWriter always assumes default encoding is OK!
      output.write( aContents );
    }
    finally {
      output.close();
    }
  }

  /** Simple test harness.   */
  public static void main (String... aArguments) throws IOException {
    File testFile = new File("C:\\Temp\\blah.txt");
    System.out.println("Original file contents: " + getContents(testFile));
    setContents(testFile, "The content of this file has been overwritten...");
    System.out.println("New file contents: " + getContents(testFile));
  }
} 
 
 
 
 
source:  http://www.javapractices.com/topic/TopicAction.do?Id=42

Monday, 7 October 2013

JOGL2


Yet Another Tutorial on JOGL 2.0

Including Nehe JOGL Port

1.  Introduction to JOGL

OpenGL is a cross-platform, language-independent, industrial standard API for producing 3D (and 2D) computer graphics. Graphics cards that claim OpenGL-compliance make use of the hardware acceleration when possible to speed up the graphics rendering process. OpenGL competes with Direct3D on Microsoft Windows platform. The OpenGL mother site is at http://www.opengl.org.
The JOGL (Java Bindings for the OpenGL) allows Java applications to access the OpenGL API for graphics programming. In other words, it is simply a wrapper library for Java application to use OpenGL API. JOGL is open-source and currently maintained by "JogAmp" (Java on Graphics, Audio, Media and Processing) @ http://jogamp.org. JogAMP provides JOGL (3D graphics), JOAL (Java Bindings for OpenAL for 3D Audio) and JOCL (Java Bindings for OpenCL - a Common Language for Graphics Processors).
Alternatives to JOGL include open-source LWJGL (Light-Weight Java Game Library) @ http://lwjgl.org.
This tutorial assumes that you have sufficient knowledge on OpenGL, but new to JOGL. To learn OpenGL, find a good OpenGL book (e.g., the Red book "OpenGL Programming Guide" or Blue Book "OpenGL Superbible"). Nehe production maintains an excellent OpenGL Tutorials (@ http://nehe.gamedev.net). You may also read my OpenGL tutorials.
JOGL 2 supports OpenGL 1.3 to 4.0 and OpenGL ES 1.x and 2.x. JOGL integrates with the AWT, Swing and SWT. It also provides its own native windowing toolkit called NEWT.
This guide is meant for JOGL 2.0 (tested on rc8), which is not compatible with the older (and obsoleted) JOGL 1.x. For JOGL 1.x, read "A Tutorial on JOGL 1.1".

2.  Setting Up JOGL 2.0_rc8

Reference: "Downloading and installing JOGL" @ http://jogamp.org/wiki/index.php/Downloading_and_installing_JOGL.
Step 0: Install JDK
Install JDK, an IDE such as Eclipse/NetBeans or a programming text editor. You need a working Java programming environment to write JOGL programs.
Step 1: Download JOGL
Download the latest "stable" release from JogAMP @ http://jogamp.org/deployment/jogamp-current/archive (or from JogAMP @ http://jogamp.org ⇒ Builds/Downloads ⇒ Current ⇒ zip). Select "jogamp-all-platforms.7z", which contains the JOGL and gluegen JAR-files, Java Native Library (JNI) for all the platforms (e.g., Win32, Win64, Linux, Mac OS), and source-files. You are also recommended to download the "javadocs" and "demos".
Step 2: Setup JOGL
  1. Unzip "jogamp-all-platforms.7z" (you can unzip ".7z" file using WinRAR or possibly WinZIP?).
    • The jogl's and gluegen's jar-files are kept in the "jar" sub-directory.
    • The Java Native JNI Libraries ("*.dll" for Windows, "*.so" for Linux, or "*.jnilib" for MacOS) are kept in the "lib" sub-directories.
  2. Create a JOGL binary directory, says "jogl-2.0" - I shall denote the binary directory as $JOGL_HOME. Create sub-directories "jar", "lib", "src", "javadoc" under the $JOGL_HOME.
    Copy the necessary jar-file, native libraries of your operating platform, and source-files into the appropriate sub-directories.
    For example, for Win32, copy "jar\gluegen-rt.jar", "jar\jogl.all.jar" into "jar"; "lib\windows-i586\gluegen-rt.dll", "lib\windows-i586\jogl_desktop.dll", "lib\windows-i586\nativewindow_awt.dll", "lib\windows-i586\nativewindow_win32.dll", "lib\windows-i586\newt.dll" into "lib"; and "gluegen-java-src.zip", "jogl-java-src.zip" into "src". Unzip the javadocs downloaded into "javadoc".
Read the "jogl.README.txt".
This step is optional, but it is good to organize the JOGL JAR-files and Java Native Libraries for your operating platform in a single directory.
Step 3a: Customize for Eclipse 3.7.2
  1. Create a User Library: We shall first create a Eclipse's User Library called "jogl-2.0", which specifies the jar-files, native libraries, javadoc, and source files for the JOGL API. All the JOGL projects can then include this user library in its build path.
    1. From "Window" menu ⇒ Preferences ⇒ Java ⇒ Build Path ⇒ User Libraries ⇒ New ⇒ In "User library name", enter "jogl-2.0".
    2. In "User Library" dialog ⇒ Select "jogl-2.0" ⇒ Add JAR... ⇒ Navigate to "$JOGL_HOME\jar", and select "gluegen-rt.jar" and "jogl.all.jar".
    3. Expand the "jogl.all.jar" node, select "Native library location: (none)" ⇒ "Edit..." ⇒ External Folder... ⇒ select "$JOGL_HOME\lib" to provide the path for the native library code (such as "jogl_desktop.dll" for Windows).
      Repeat for "gluegen-rt.jar" (for "gluegen-rt.dll").
    4. (Optional But Recommended) Expand the "jogl.all.jar" node again ⇒ Select "Javadoc location" ⇒ "Edit..."
      • Specify the javadoc's path (either file: or http:) in "Javadoc URL" if you use an unzip version of the javadoc.
      • Specify the javadoc's archive file (either zip or jar) in "Javadoc in archive" if you use a zip file.
      Choose "Validate", which search for an "index.html" file.
      This is needed for Eclipse to display javadoc information about classes and methods.
    5. (Optional But Recommended) You may provide the source files by editing "Source attachment" ⇒ "Edit..." ⇒ "External File..." ⇒ Select the source file in zip form. Source is needed only if you are interested to debug into the JOGL source codes.
  2. Include the User Library: For EACH JAVA PROJECT created that uses JOGL, right-click on the project ⇒ "Build Path" ⇒ "Add Libraries" ⇒ Select "User Library" ⇒ Check "jogl-2.0".
Read "Java Native Library (JNI) Error" if you encounter error "SEVERE: java.lang.UnsatisfiedLinkError: no xxx in java.library.path".
Step 3b: Customize for NetBeans 7.0
There was a so-called "NetBeans OpenGL Pack", but it seems to be out-dated and does not support JOGL 2 (?!).
We shall create our own JOGL Library as follows:
  1. Create a JOGL Library:
    1. From "Tool" ⇒ "Library" ⇒ Click "New Libraries..." ⇒ Enter "jogl2.0".
    2. Click "Add JAR/Folder..." ⇒ Select "jogl.all.jar" and "gluegen-rt.jar".
    3. Under the "JavaDoc" tab ⇒ Select the JOGL's javadoc. You could use the zip version for better performance.
    4. Under the "Source" tab ⇒ Select the JOGL's source. You could use the zip version for better performance.
  2. Include the JOGL Library:
    1. For EACH of the JOGL project, include the JOGL library. Right-click on the project ⇒ "Properties" ⇒ "Library" ⇒ Under "Compile" tab ⇒ "Add Libraries..." ⇒ Choose the library "jogl2.0" created earlier.
    2. You also need to include the native library path for each of the project. Right-click the project ⇒ "Set Configuration" ⇒ "Customize..." ⇒ "Run" ⇒ In "VM options", enter "-Djava.library.path=xxx", where xxx is directory path (e.g., d:\bin\jogl2.0\lib), that contains the Java Native JNI Libraries ("*.dll" for Windows, "*.so" for Linux or "*.jnilib" for MacOS).
Read "Java Native Library (JNI) Error" if you encounter error "SEVERE: java.lang.UnsatisfiedLinkError: no xxx in java.library.path".
Step 3c: Customize for JDK/Editor
You need to modify two environment variables - CLASSPATH and PATH. Read "Environment Variables For Java Applications" on how to set these environment variables.
Modify the CLASSPATH environment variable to include the full-path filenames of "jogl.all.jar" and "gluegen-rt.jar", for example,
shell> set classpath=.;$JOGL_HOME\lib\jogl.all.jar;$JOGL_HOME\lib\gluegen-rt.jar
where $JOGL_HOME denotes the JOGL installed directory. Take note that you should include the current working directory '.'.
Modified the PATH environment variable to include the full path to the JOGL's "lib" directory for accessing the native libraries (e.g., "jogl_xxx.dll", "gluegen-rt.dll"), for example,
shell> set path=$JOGL_HOME\lib;......
Alternatively, you could include the directory path of the native libraries in Java system's property "java.library.path", via the VM command-line option -Djava.library.path=pathname, for example,
shell> java -Djava.library.path=d:\bin\jogl2.0\lib myjoglapp
Read "Java Native Library (JNI) Error" if you encounter error "SEVERE: java.lang.UnsatisfiedLinkError: no xxx in java.library.path".

3.  Getting Started with JOGL 2.0_rc8

3.1  OpenGL Drawable: GLCanvas and GLJPanel

An OpenGL drawable is a surface (or canvas) for graphics rendering. JOGL provides two drawables in package javax.media.opengl.awt: GLCanvas and GLJPanel.
  1. GLCanvas: A heavyweight AWT component which is a subclass of java.awt.Canvas.
    You can create a GLCanvas via the default constructor GLCanvas(), which construct a new GLCanvas component with a default set of OpenGL capabilities, using the default OpenGL capabilities selection mechanism, on the default screen device. For example,
    GLCanvas canvas = new GLCanvas();
    JFrame frame = new JFrame();         // or AWT's Frame
    frame.getContentPane().add(canvas);  // add Component
    canvas.addGLEventListener(.....);
  2. GLJPanel: A lightweight Swing component which is a subclass of javax.swing.JPanel.
    Again, You can create a GLJPanel via the default constructor GLJPanel(), which construct a new GLJPanel component with a default set of OpenGL capabilities, using the default OpenGL capabilities selection mechanism. For example,
    GLJPanel canvas = new GLJPanel();
    JFrame frame = new JFrame();
    frame.getContentPane().add(canvas);  // or frame.setContentPane(canvas);
    canvas.addGLEventListener(.....);
The GLCanvas is a heavyweight AWT component which supports hardware acceleration. It is designed as the primary widget for JOGL applications. On the other hand, GLJPanel is a swing-compatible lightweight component, which supports hardware acceleration but is not as fast as GLCanvas. GLJPanel is intended to provide 100% swing integration when the heavyweight GLCanvas cannot be used. Both the GLCanvas and GLJPanel implement a common interface GLAutoDrawable (which in turn implements the interface GLDrawable). These interfaces define the common behaviors expected on GLCanvas and GLJPanel, so that applications can switch between them with minimal code changes.
Beside supporting AWT, Swing and SWT, JOGL 2 also provide its own Native Window Toolkit called NEWT via drawable GLWindow (in package com.jogamp.newt.opengl). I shall discuss NEWT later.

3.2  GLEventListener and GLAutoDrawable

The interface GLEventListener (in package javax.media.opengl) declares the following 4 OpenGL event handlers:
  1. init(GLAutoDrawable drawable): called by the drawable immediately after the OpenGL context is initialized. It can be used to perform one-time initialization tasks such as setting up of lights and display lists. init() runs only once.
  2. dispose(GLAutoDrawable drawable): called by the drawable before the OpenGL context is destroyed. It can be used to release all OpenGL resources, such as memory buffers.
  3. display(GLAutoDrawable drawable): called by the drawable to render OpenGL graphics. It is the most important method.
  4. reshape(GLAutoDrawable drawable, int x, int y, int width, int height): called by the drawable when it is first set to visible, and during the first repaint after the it has been resized. It is used to set the view port and projection mode, and view volume.
All these methods are call-back methods. When an OpenGL event is posted on the event-queue, the graphics sub-system calls back the corresponding handler. An OpenGL renderer shall implement the GLEventListener interface.
Recall that GLCanvas and GLJPanel are GLAutoDrawable. The interface GLAutoDrawable defines these abstract methods to add or remove a GLEventListener:
public void addGLEventListener(GLEventListener listener)
public void removeGLEventListener(GLEventListener listener)
For example,
GLCanvas canvas = new GLCanvas();
canvas.addGLEventListener(renderer);  // add a GLEventListener called renderer
   // renderer shall provides these handlers
   //   init(GLAutoDrawable drawable)
   //   destroy(GLAutoDrawable drawable)
   //   display(GLAutoDrawable drawable)
   //   reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
Whenever an OpenGL event is fired (e.g., init, display), GLCanvas or GLJPanel invokes the corresponding handler of all its registered GLEventListener(s) (such as init() and display()) with itself as the argument for GLAutoDrawable, as illustrated.

3.3  Animator

To perform animation, we need an animator to drive the drawable's display() method in a loop to refresh the display regularly. JOGL provides two animator classes: Animator and FPSAnimator (in package com.jogamp.opengl.util). The commonly-used FPSAnimator can drive the display() of the given drawable at the specified number of frame per seconds (fps). For example,
// Construct a drawable
GLCanvas canvas = new GLCanvas();   // or GLJPanle
// Construct an FPS animator, which drives drawable's display() at the specified frames per second
FPSAnimator animator = new FPSAnimator(canvas, 60);
 
animator.start();       // start the animator
animator.pause();       // pause the animator if started
animator.resume();      // resume the animator if paused
animator.stop();        // stop the animator
animator.isStarted();   // started?
animator.isAnimating(); // started and not pause?
animator.isPause();     // started and pause?
The commonly-used constructors are:
FPSAnimator(GLAutoDrawable drawable, int fps)
      // Creates an FPSAnimator with a given target frames-per-second value 
      //  and an initial drawable to animate.
FPSAnimator(GLAutoDrawable drawable, int fps, boolean scheduleAtFixedRate)
      // Creates an FPSAnimator with a given target frames-per-second value, 
      //  an initial drawable to animate, 
      //  and a flag indicating whether to use fixed-rate scheduling.
Animator(GLAutoDrawable drawable)
      // Creates a new Animator for a particular drawable.

3.4  OpenGL Graphics Context

In order to perform rendering, an so-called OpenGL rendering context is required. You can retrieve the graphics context from a drawable as follow:
javax.media.opengl.GL  gl = drawable.getGL();
javax.media.opengl.GL2 gl = drawable.getGL().getGL2();  // up to OpenGL 3.0
javax.media.opengl.GL3 gl = drawable.getGL().getGL3();  // up to OpenGL 3.1
javax.media.opengl.GL4 gl = drawable.getGL().getGL4();  // up to OpenGL 4
......
// Others: GL2GL3, GL2bc, GL4bc, GLES1, GLES2, GL2ES1, GL2ES2
[TODO] To Revise.

3.5  JOGL 2.0 Program Templates

GLCanvas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import com.jogamp.opengl.util.FPSAnimator;
import static javax.media.opengl.GL.*;  // GL constants
import static javax.media.opengl.GL2.*; // GL2 constants
 
/**
 * JOGL 2.0 Program Template (GLCanvas)
 * This is a "Component" which can be added into a top-level "Container".
 * It also handles the OpenGL events to render graphics.
 */
@SuppressWarnings("serial")
public class JOGL2Setup_GLCanvas extends GLCanvas implements GLEventListener {
   // Define constants for the top-level container
   private static String TITLE = "JOGL 2.0 Setup (GLCanvas)";  // window's title
   private static final int CANVAS_WIDTH = 640;  // width of the drawable
   private static final int CANVAS_HEIGHT = 480; // height of the drawable
   private static final int FPS = 60; // animator's target frames per second
 
   /** The entry main() method to setup the top-level container and animator */
   public static void main(String[] args) {
      // Run the GUI codes in the event-dispatching thread for thread safety
      SwingUtilities.invokeLater(new Runnable() {
         @Override
         public void run() {
            // Create the OpenGL rendering canvas
            GLCanvas canvas = new JOGL2Setup_GLCanvas();
            canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
 
            // Create a animator that drives canvas' display() at the specified FPS.
            final FPSAnimator animator = new FPSAnimator(canvas, FPS, true);
 
            // Create the top-level container
            final JFrame frame = new JFrame(); // Swing's JFrame or AWT's Frame
            frame.getContentPane().add(canvas);
            frame.addWindowListener(new WindowAdapter() {
               @Override
               public void windowClosing(WindowEvent e) {
                  // Use a dedicate thread to run the stop() to ensure that the
                  // animator stops before program exits.
                  new Thread() {
                     @Override
                     public void run() {
                        if (animator.isStarted()) animator.stop();
                        System.exit(0);
                     }
                  }.start();
               }
            });
            frame.setTitle(TITLE);
            frame.pack();
            frame.setVisible(true);
            animator.start(); // start the animation loop
         }
      });
   }
 
   // Setup OpenGL Graphics Renderer
 
   private GLU glu;  // for the GL Utility
 
   /** Constructor to setup the GUI for this Component */
   public JOGL2Setup_GLCanvas() {
      this.addGLEventListener(this);
   }
 
   // ------ Implement methods declared in GLEventListener ------
 
   /**
    * Called back immediately after the OpenGL context is initialized. Can be used
    * to perform one-time initialization. Run only once.
    */
   @Override
   public void init(GLAutoDrawable drawable) {
      GL2 gl = drawable.getGL().getGL2();      // get the OpenGL graphics context
      glu = new GLU();                         // get GL Utilities
      gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // set background (clear) color
      gl.glClearDepth(1.0f);      // set clear depth value to farthest
      gl.glEnable(GL_DEPTH_TEST); // enables depth testing
      gl.glDepthFunc(GL_LEQUAL);  // the type of depth test to do
      gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // best perspective correction
      gl.glShadeModel(GL_SMOOTH); // blends colors nicely, and smoothes out lighting
 
      // ----- Your OpenGL initialization code here -----
   }
 
   /**
    * Call-back handler for window re-size event. Also called when the drawable is
    * first set to visible.
    */
   @Override
   public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
      GL2 gl = drawable.getGL().getGL2();  // get the OpenGL 2 graphics context
 
      if (height == 0) height = 1;   // prevent divide by zero
      float aspect = (float)width / height;
 
      // Set the view port (display area) to cover the entire window
      gl.glViewport(0, 0, width, height);
 
      // Setup perspective projection, with aspect ratio matches viewport
      gl.glMatrixMode(GL_PROJECTION);  // choose projection matrix
      gl.glLoadIdentity();             // reset projection matrix
      glu.gluPerspective(45.0, aspect, 0.1, 100.0); // fovy, aspect, zNear, zFar
 
      // Enable the model-view transform
      gl.glMatrixMode(GL_MODELVIEW);
      gl.glLoadIdentity(); // reset
   }
 
   /**
    * Called back by the animator to perform rendering.
    */
   @Override
   public void display(GLAutoDrawable drawable) {
      GL2 gl = drawable.getGL().getGL2();  // get the OpenGL 2 graphics context
      gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear color and depth buffers
      gl.glLoadIdentity();  // reset the model-view matrix
 
      // ----- Your OpenGL rendering code here (Render a white triangle for testing) -----
      gl.glTranslatef(0.0f, 0.0f, -6.0f); // translate into the screen
      gl.glBegin(GL_TRIANGLES); // draw using triangles
         gl.glVertex3f(0.0f, 1.0f, 0.0f);
         gl.glVertex3f(-1.0f, -1.0f, 0.0f);
         gl.glVertex3f(1.0f, -1.0f, 0.0f);
      gl.glEnd();
   }
 
   /**
    * Called back before the OpenGL context is destroyed. Release resource such as buffers.
    */
   @Override
   public void dispose(GLAutoDrawable drawable) { }
}
Try running the above program, which will show a white triangle on a black screen.
In this template:
  • I follow the design of "Component-based Architecture for Rich Internet Applications (RIA)", where the GUI "Component" (GLCanvas or GLJPanel) and "Container" (JFrame, Frame, JApplet, Applet) are clearly separated. The "Component" can be easily plugged into any of the "Container".
  • The main class extends GLCanvas (Component) to provide the OpenGL graphics rendering canvas. It also implements GLEventListener and provides handlers for init(), display(), dispose() and reshape().
  • The main() method:
    • Allocates a GLCanvas component.
    • Allocates an Animator to drive the display() method of the GLCanvas in a loop to refresh the display.
    • Allocates a top-level container (Swing's JFrame or AWT's Frame), and adds the GLCanvas component into the container..
Using AWT's Frame as Top-Level Container
The above template uses Swing's JFrame as the top-level container. To use AWT's Frame as the top-level window, modify the main() method as follows:
/** The entry main() method to setup the top-level container and animator */
public static void main(String[] args) {
   GLCanvas canvas = new GLCanvas();
   ......
   final Frame frame = new Frame(); // instead of Swing's JFrame
   frame.add(canvas);               // instead of Swing's frame.setContentPane()
   .......
}
[TODO] Check whether GLCanvas is better to use with AWT's Frame or Swing's JFrame if there is no other light-weight components.
Separating the Component and Container Classes
Alternatively, you could separate the renderer Component and the top-level Container into two classes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import static javax.media.opengl.GL.*;  // GL constants
import static javax.media.opengl.GL2.*; // GL2 constants
 
/**
 * JOGL 2.0 Program Template (GLCanvas)
 * This is a "Component" which can be added into a top-level "Container".
 * It also handles the OpenGL events to render graphics.
 */
@SuppressWarnings("serial")
public class JOGL2Setup_Renderer extends GLCanvas implements GLEventListener {
   private GLU glu;  // for the GL Utility
 
   /** Constructor to setup the GUI for this Component */
   public JOGL2Setup_Renderer() {
      this.addGLEventListener(this);
   }
 
   // ------ Implement methods declared in GLEventListener ------
 
   /**
    * Called back immediately after the OpenGL context is initialized. Can be used
    * to perform one-time initialization. Run only once.
    */
   @Override
   public void init(GLAutoDrawable drawable) {
      GL2 gl = drawable.getGL().getGL2();      // get the OpenGL graphics context
      glu = new GLU();                         // get GL Utilities
      gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // set background (clear) color
      gl.glClearDepth(1.0f);      // set clear depth value to farthest
      gl.glEnable(GL_DEPTH_TEST); // enables depth testing
      gl.glDepthFunc(GL_LEQUAL);  // the type of depth test to do
      gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // best perspective correction
      gl.glShadeModel(GL_SMOOTH); // blends colors nicely, and smoothes out lighting
 
      // ----- Your OpenGL initialization code here -----
   }
 
   /**
    * Call-back handler for window re-size event. Also called when the drawable is
    * first set to visible.
    */
   @Override
   public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
      GL2 gl = drawable.getGL().getGL2();  // get the OpenGL 2 graphics context
 
      if (height == 0) height = 1;   // prevent divide by zero
      float aspect = (float)width / height;
 
      // Set the view port (display area) to cover the entire window
      gl.glViewport(0, 0, width, height);
 
      // Setup perspective projection, with aspect ratio matches viewport
      gl.glMatrixMode(GL_PROJECTION);  // choose projection matrix
      gl.glLoadIdentity();             // reset projection matrix
      glu.gluPerspective(45.0, aspect, 0.1, 100.0); // fovy, aspect, zNear, zFar
 
      // Enable the model-view transform
      gl.glMatrixMode(GL_MODELVIEW);
      gl.glLoadIdentity(); // reset
   }
 
   /**
    * Called back by the animator to perform rendering.
    */
   @Override
   public void display(GLAutoDrawable drawable) {
      GL2 gl = drawable.getGL().getGL2();  // get the OpenGL 2 graphics context
      gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear color and depth buffers
      gl.glLoadIdentity();  // reset the model-view matrix
 
      // ----- Your OpenGL rendering code here (render a white triangle for testing) -----
      gl.glTranslatef(0.0f, 0.0f, -6.0f); // translate into the screen
      gl.glBegin(GL_TRIANGLES); // draw using triangles
         gl.glVertex3f(0.0f, 1.0f, 0.0f);
         gl.glVertex3f(-1.0f, -1.0f, 0.0f);
         gl.glVertex3f(1.0f, -1.0f, 0.0f);
      gl.glEnd();
   }
 
   /**
    * Called back before the OpenGL context is destroyed. Release resource such as buffers.
    */
   @Override
   public void dispose(GLAutoDrawable drawable) { }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.media.opengl.awt.GLCanvas;
import com.jogamp.opengl.util.FPSAnimator;
 
/**
 * JOGL 2.0 Program Template (GLCanvas)
 * This is the top-level "Container", which allocates and add GLCanvas ("Component")
 * and animator.
 */
@SuppressWarnings("serial")
public class JOGL2Setup_RendererMain extends JFrame {
   // Define constants for the top-level container
   private static String TITLE = "JOGL 2.0 Setup (GLCanvas)";  // window's title
   private static final int CANVAS_WIDTH = 640;  // width of the drawable
   private static final int CANVAS_HEIGHT = 480; // height of the drawable
   private static final int FPS = 60; // animator's target frames per second
 
   /** Constructor to setup the top-level container and animator */
   public JOGL2Setup_RendererMain() {
      // Create the OpenGL rendering canvas
      GLCanvas canvas = new JOGL2Setup_Renderer();
      canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
 
      // Create a animator that drives canvas' display() at the specified FPS.
      final FPSAnimator animator = new FPSAnimator(canvas, FPS, true);
 
      // Create the top-level container frame
      this.getContentPane().add(canvas);
      this.addWindowListener(new WindowAdapter() {
         @Override
         public void windowClosing(WindowEvent e) {
            // Use a dedicate thread to run the stop() to ensure that the
            // animator stops before program exits.
            new Thread() {
               @Override
               public void run() {
                  if (animator.isStarted()) animator.stop();
                  System.exit(0);
               }
            }.start();
         }
      });
      this.setTitle(TITLE);
      this.pack();
      this.setVisible(true);
      animator.start(); // start the animation loop
   }
 
   /** The entry main() method */
   public static void main(String[] args) {
      // Run the GUI codes in the event-dispatching thread for thread safety
      SwingUtilities.invokeLater(new Runnable() {
         @Override
         public void run() {
            new JOGL2Setup_RendererMain();  // run the constructor
         }
      });
   }
}
In this approach, all the graphics rendering codes are kept in the renderer (Component) class. The main (Container) class can be left untouched.
GLJPanel
To use the light-weight GLJPanel instead of the heavy-weight GLCanvas, simply change all reference of GLCanvas to GLJPanel.
public class JOGL2Setup_GLJPanel extends GLJPanel implements GLEventListener {
   ......
   /** The entry main() method to setup the top-level container and animator */
   public static void main(String[] args) {
      // Run the GUI codes in the event-dispatching thread for thread safety
      SwingUtilities.invokeLater(new Runnable() {
         @Override
         public void run() {
            // Create the OpenGL rendering canvas
            GLJPanel canvas = new JOGL2Setup_GLJPanel();
            ......
         }
      }
   }
   ......
}
GLJPanel canvas = new GLJPanel();  // instead of GLCanvas
Running as an Applet
As we followed the Component-based Architecture in our class design, we can plug the GLCanvas Component into other top-level Container, such as JApplet or Applet easily.
To run the program as an applet, you can simply add an applet launching class (as follow) to launch the main renderer class. Recall that an applet extends javax.swing.JApplet (or java.awt.Frame) and is managed via methods init() (instead of main() of an application), start(), stop() and destroy().
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import java.lang.reflect.InvocationTargetException;
import javax.media.opengl.awt.GLCanvas;
import javax.swing.JApplet;
import javax.swing.SwingUtilities;
import com.jogamp.opengl.util.FPSAnimator;
 
/**
 * JOGL 2.0 Applet Template (with GLCanvas and Swing JApplet)
 * This is the top-level "Container", which allocates and add GLCanvas ("Component")
 * and animator.
 */
@SuppressWarnings("serial")
public class JOGL2Setup_Applet extends JApplet {
   // Define constants for top-level container
   private static final int FPS = 60; // animator's target frames per second
 
   FPSAnimator animator;
 
   @Override
   public void init() {
      // Run the GUI codes in the event-dispatching thread for thread safety
      try {
         SwingUtilities.invokeAndWait(new Runnable() {
            @Override
            public void run() {
               // Create the OpenGL rendering canvas
               GLCanvas canvas = new JOGL2Setup_GLCanvas();
               getContentPane().add(canvas);
 
               // Create a animator that drives canvas' display() at the specified FPS.
               animator = new FPSAnimator(canvas, FPS, true);
               animator.start(); // start the animation loop
            }
         });
      } catch (InvocationTargetException e) {
         e.printStackTrace();
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
   }
 
   @Override
   public void destroy() {
      if (animator.isStarted()) animator.stop();
   }
 
   @Override
   public void start() {
      animator.start();
   }
 
   @Override
   public void stop() {
      if (animator.isStarted()) animator.stop();
   }
}
The main() method in the renderer class is ignored by applet.
Running in Full-Screen Mode
Games are often run in full-screen mode without decoration (title, status, scroll bars). The JOGL 2.0 program template for full screen mode operation is as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAnimatorControl;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import com.jogamp.opengl.util.FPSAnimator;
import static javax.media.opengl.GL.*;  // GL constants
import static javax.media.opengl.GL2.*; // GL2 constants
 
/**
 * JOGL 2.0 Program Template (GLCanvas) in Full Screen Mode with ESC to quit
 * This is a "Component" which can be added into a top-level "Container".
 * It also handles the OpenGL events to render graphics.
 */
@SuppressWarnings("serial")
public class JOGL2Setup_GLCanvasFullScreen extends GLCanvas
         implements GLEventListener, KeyListener {
   // Define constants for top-level container
   private static final int FPS = 60; // animator's target frames per second
 
   /** The entry main() method to setup the top-level container and animator */
   public static void main(String[] args) {
      // Run the GUI codes in the event-dispatching thread for thread safety
      SwingUtilities.invokeLater(new Runnable() {
         @Override
         public void run() {
            // Create the OpenGL rendering canvas
            GLCanvas canvas = new JOGL2Setup_GLCanvasFullScreen();
 
            // Create a animator that drives canvas' display() at the specified FPS.
            FPSAnimator animator = new FPSAnimator(canvas, FPS, true);
 
            // Create the top-level container frame
            JFrame frame = new JFrame(); // Swing's JFrame or AWT's Frame
            frame.getContentPane().add(canvas);
            frame.setUndecorated(true);     // no decoration such as title bar
            frame.setExtendedState(Frame.MAXIMIZED_BOTH);  // full screen mode
            frame.setVisible(true);
            animator.start(); // start the animation loop
         }
      });
   }
 
   // Setup OpenGL Graphics Renderer
 
   private GLU glu;  // for the GL Utility
 
   /** Constructor to setup the GUI for this Component */
   public JOGL2Setup_GLCanvasFullScreen() {
      this.addGLEventListener(this);   // for handling GLEvents
      this.addKeyListener(this); // for Handling KeyEvents
      this.setFocusable(true);
      this.requestFocus();
   }
 
   // ------ Implement methods declared in GLEventListener ------
 
   /**
    * Called back immediately after the OpenGL context is initialized. Can be used
    * to perform one-time initialization. Run only once.
    */
   @Override
   public void init(GLAutoDrawable drawable) {
      GL2 gl = drawable.getGL().getGL2();      // get the OpenGL graphics context
      glu = new GLU();                         // get GL Utilities
      gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // set background (clear) color
      gl.glClearDepth(1.0f);      // set clear depth value to farthest
      gl.glEnable(GL_DEPTH_TEST); // enables depth testing
      gl.glDepthFunc(GL_LEQUAL);  // the type of depth test to do
      gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // best perspective correction
      gl.glShadeModel(GL_SMOOTH); // blends colors nicely, and smoothes out lighting
 
      // ----- Your OpenGL initialization code here -----
   }
 
   /**
    * Call-back handler for window re-size event. Also called when the drawable is
    * first set to visible.
    */
   @Override
   public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
      GL2 gl = drawable.getGL().getGL2();  // get the OpenGL 2 graphics context
 
      if (height == 0) height = 1;   // prevent divide by zero
      float aspect = (float)width / height;
 
      // Set the view port (display area) to cover the entire window
      gl.glViewport(0, 0, width, height);
 
      // Setup perspective projection, with aspect ratio matches viewport
      gl.glMatrixMode(GL_PROJECTION);  // choose projection matrix
      gl.glLoadIdentity();             // reset projection matrix
      glu.gluPerspective(45.0, aspect, 0.1, 100.0); // fovy, aspect, zNear, zFar
 
      // Enable the model-view transform
      gl.glMatrixMode(GL_MODELVIEW);
      gl.glLoadIdentity(); // reset
   }
 
   /**
    * Called back by the animator to perform rendering.
    */
   @Override
   public void display(GLAutoDrawable drawable) {
      GL2 gl = drawable.getGL().getGL2();  // get the OpenGL 2 graphics context
      gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear color and depth buffers
      gl.glLoadIdentity();  // reset the model-view matrix
 
      // ----- Your OpenGL rendering code here (render a white triangle for testing) -----
      gl.glTranslatef(0.0f, 0.0f, -6.0f); // translate into the screen
      gl.glBegin(GL_TRIANGLES); // draw using triangles
         gl.glVertex3f(0.0f, 1.0f, 0.0f);
         gl.glVertex3f(-1.0f, -1.0f, 0.0f);
         gl.glVertex3f(1.0f, -1.0f, 0.0f);
      gl.glEnd();
   }
 
   /**
    * Called back before the OpenGL context is destroyed. Release resource such as buffers.
    */
   @Override
   public void dispose(GLAutoDrawable drawable) { }
 
   // ------ Implement methods declared in KeyListener ------
 
   @Override
   public void keyTyped(KeyEvent e) {}
 
   @Override
   public void keyPressed(KeyEvent e) {
      int keyCode = e.getKeyCode();
      switch (keyCode) {
         case KeyEvent.VK_ESCAPE: // quit
            // Use a dedicate thread to run the stop() to ensure that the
            // animator stops before program exits.
            new Thread() {
               @Override
               public void run() {
                  GLAnimatorControl animator = getAnimator();
                  if (animator.isStarted()) animator.stop();
                  System.exit(0);
               }
            }.start();
            break;
      }
   }
 
   @Override
   public void keyReleased(KeyEvent e) {}
}
To operate in full-screen mode, set the frame to:
final JFrame frame = new JFrame();
frame.setUndecorated(true);  // no decoration such as title and scroll bars
frame.setExtendedState(Frame.MAXIMIZED_BOTH);  // full screen mode
......
The "window-close" button is no longer available in the full-screen mode. Hence, we use the ESC key to exit the program. The renderer, hence, also implements the KeyListener interface and provide KeyEvent handlers, such as keyPressed() for processing the ESC key..
Note: Read the "Graphics Programming" section on how to switch between full-screen mode and windowed mode, if desired.

3.6  Example 1: Rotating 2D Shapes

Modify the GLEventListener handlers init(), display() and reshape() of the template (GLCanvas or GLJPanel) as follows:
public class JOGL2Ex1Rotate2D extends GLJCanvas implements GLEventListener {
   ......
   ......
   private float angle = 0.0f;  // rotation angle of the triangle

   /** Called back by the drawable to render OpenGL graphics */
   @Override
   public void display(GLAutoDrawable drawable) {
      render(drawable);
      update();
   }
   
   // Render a triangle
   private void render(GLAutoDrawable drawable) {
      // Get the OpenGL graphics context
      GL2 gl = drawable.getGL().getGL2();
      // Clear the color and the depth buffers
      gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      // Reset the view (x, y, z axes back to normal)
      gl.glLoadIdentity();   

      // Draw a triangle
      float sin = (float)Math.sin(angle);
      float cos = (float)Math.cos(angle);
      gl.glBegin(GL_TRIANGLES);
         gl.glColor3f(1.0f, 0.0f, 0.0f);   // Red
         gl.glVertex2d(-cos, -cos);
         gl.glColor3f(0.0f, 1.0f, 0.0f);   // Green
         gl.glVertex2d(0.0f, cos);
         gl.glColor3f(0.0f, 0.0f, 1.0f);   // Blue
         gl.glVertex2d(sin, -sin);
      gl.glEnd();
   }
   
   // Update the angle of the triangle after each frame
   private void update() {
      angle += 0.01f;
   }
   
   @Override
   public void init(GLAutoDrawable drawable) { }  // set to empty

   @Override
   public void dispose(GLAutoDrawable drawable) { }  // set to empty

   @Override
   public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { }  // set to empty

   ......
   ......
}
TRY:
  1. Using GLJPanel on Swing's JFrame.
  2. Use GLCanvas on AWT's Frame.
  3. Use GLCanvas on AWT's Applet.
  4. Using GLJPanel on Swing's JApplet.
Observe and compare the results.

3.7  GLEventListener Handlers

init(): called by the drawable immediately after the OpenGL graphics context is initialized. It can be used to perform one-time initialization tasks such as setting up of lights and display lists. The init() runs only once.
   /** Called after context is initialized, for one-time initialization tasks */
   @Override
   public void init(GLAutoDrawable drawable) {
      // Get the OpenGL graphics context
      GL2 gl = drawable.getGL().getGL2();
      // Get GL Utilities after the GL context created.
      // glu = GLU.createGLU();
      // Enable smooth shading, which blends colors nicely, and smoothes out lighting.
      gl.glShadeModel(GLLightingFunc.GL_SMOOTH);
      // Set background color in RGBA. Alpha: 0 (transparent) 1 (opaque) 
      gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
      // Setup the depth buffer and enable the depth testing
      gl.glClearDepth(1.0f);         // clear z-buffer to the farthest
      gl.glEnable(GL.GL_DEPTH_TEST); // enables depth testing
      gl.glDepthFunc(GL.GL_LEQUAL);  // the type of depth test to do
      // Do the best perspective correction
      gl.glHint(GL2ES1.GL_PERSPECTIVE_CORRECTION_HINT, GL.GL_NICEST);
      
      // ----- Your OpenGL initialization code here -----
      // ......
   }

reshape(): called by the drawable when the drawable is first set to visible, and during the first repaint after the canvas has been resized.
   /** Called for the first-time display and after display's size changes. 
       To set up the view port, projection mode and view volume. */
   @Override
   public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
      // Get the OpenGL graphics context
      GL2 gl = drawable.getGL().getGL2();
      
      height = (height == 0) ? 1 : height;  // Prevent divide by zero
      float aspect = (float)width / height; // Compute aspect ratio
      
      // Set view port to cover full screen 
      gl.glViewport(0, 0, width, height);
      
      // Set up the projection matrix - choose perspective view
      gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);  
      gl.glLoadIdentity();    // reset
      // Angle of view (fovy) is 45 degrees (in the up y-direction). Based on this
      // canvas's aspect ratio. Clipping z-near is 0.1f and z-near is 100.0f.
      glu.gluPerspective(45.0f, aspect, 0.1f, 100.0f); // fovy, aspect, zNear, zFar
      
      // Switch to the model-view transform
      gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
      gl.glLoadIdentity();    // reset
   }

display(): called by the drawable to perform OpenGL graphics rendering.
   /** Called to render graphics */
   @Override
   public void display(GLAutoDrawable drawable) {
      // Get the OpenGL graphics context
      GL2 gl = drawable.getGL().getGL2();
      // Clear the color and the depth buffers
      gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
      // Reset the view (x, y, z axes back to normal)
      gl.glLoadIdentity();
      
      // ----- Your OpenGL rendering code here -----
      // ......
   }

disposed(): called by the drawbale before the OpenGL context is destroyed. It can be used to release all OpenGL resources, such as memory buffers.
@Override
public void disposed(GLAutoDrawable drawable) { 
   // Hardly used.
}

3.8  Example 2: Rotating 3D Shapes

The following example show a color-pyramid and color-cube (Nehe Lesson #5).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;
import com.jogamp.opengl.util.FPSAnimator;
import static javax.media.opengl.GL.*;  // GL constants
import static javax.media.opengl.GL2.*; // GL2 constants
 
/**
 * JOGL 2.0 Example 2: Rotating 3D Shapes (GLCanvas)
 */
@SuppressWarnings("serial")
public class JOGL2Ex2Rotate3D_GLCanvas extends GLCanvas implements GLEventListener {
   // Define constants for the top-level container
   private static String TITLE = "Rotating 3D Shapes (GLCanvas)";  // window's title
   private static final int CANVAS_WIDTH = 320;  // width of the drawable
   private static final int CANVAS_HEIGHT = 240; // height of the drawable
   private static final int FPS = 60; // animator's target frames per second
 
   /** The entry main() method to setup the top-level container and animator */
   public static void main(String[] args) {
      // Run the GUI codes in the event-dispatching thread for thread safety
      SwingUtilities.invokeLater(new Runnable() {
         @Override
         public void run() {
            // Create the OpenGL rendering canvas
            GLCanvas canvas = new JOGL2Ex2Rotate3D_GLCanvas();
            canvas.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
 
            // Create a animator that drives canvas' display() at the specified FPS.
            final FPSAnimator animator = new FPSAnimator(canvas, FPS, true);
 
            // Create the top-level container
            final JFrame frame = new JFrame(); // Swing's JFrame or AWT's Frame
            frame.getContentPane().add(canvas);
            frame.addWindowListener(new WindowAdapter() {
               @Override
               public void windowClosing(WindowEvent e) {
                  // Use a dedicate thread to run the stop() to ensure that the
                  // animator stops before program exits.
                  new Thread() {
                     @Override
                     public void run() {
                        if (animator.isStarted()) animator.stop();
                        System.exit(0);
                     }
                  }.start();
               }
            });
            frame.setTitle(TITLE);
            frame.pack();
            frame.setVisible(true);
            animator.start(); // start the animation loop
         }
      });
   }
 
   // Setup OpenGL Graphics Renderer
 
   private GLU glu;  // for the GL Utility
   private float anglePyramid = 0;    // rotational angle in degree for pyramid
   private float angleCube = 0;       // rotational angle in degree for cube
   private float speedPyramid = 2.0f; // rotational speed for pyramid
   private float speedCube = -1.5f;   // rotational speed for cube
 
   /** Constructor to setup the GUI for this Component */
   public JOGL2Ex2Rotate3D_GLCanvas() {
      this.addGLEventListener(this);
   }
 
   // ------ Implement methods declared in GLEventListener ------
 
   /**
    * Called back immediately after the OpenGL context is initialized. Can be used
    * to perform one-time initialization. Run only once.
    */
   @Override
   public void init(GLAutoDrawable drawable) {
      GL2 gl = drawable.getGL().getGL2();      // get the OpenGL graphics context
      glu = new GLU();                         // get GL Utilities
      gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // set background (clear) color
      gl.glClearDepth(1.0f);      // set clear depth value to farthest
      gl.glEnable(GL_DEPTH_TEST); // enables depth testing
      gl.glDepthFunc(GL_LEQUAL);  // the type of depth test to do
      gl.glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // best perspective correction
      gl.glShadeModel(GL_SMOOTH); // blends colors nicely, and smoothes out lighting
   }
 
   /**
    * Call-back handler for window re-size event. Also called when the drawable is
    * first set to visible.
    */
   @Override
   public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
      GL2 gl = drawable.getGL().getGL2();  // get the OpenGL 2 graphics context
 
      if (height == 0) height = 1;   // prevent divide by zero
      float aspect = (float)width / height;
 
      // Set the view port (display area) to cover the entire window
      gl.glViewport(0, 0, width, height);
 
      // Setup perspective projection, with aspect ratio matches viewport
      gl.glMatrixMode(GL_PROJECTION);  // choose projection matrix
      gl.glLoadIdentity();             // reset projection matrix
      glu.gluPerspective(45.0, aspect, 0.1, 100.0); // fovy, aspect, zNear, zFar
 
      // Enable the model-view transform
      gl.glMatrixMode(GL_MODELVIEW);
      gl.glLoadIdentity(); // reset
   }
 
   /**
    * Called back by the animator to perform rendering.
    */
   @Override
   public void display(GLAutoDrawable drawable) {
      GL2 gl = drawable.getGL().getGL2();  // get the OpenGL 2 graphics context
      gl.glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear color and depth buffers
 
      // ----- Render the Pyramid -----
      gl.glLoadIdentity();                 // reset the model-view matrix
      gl.glTranslatef(-1.6f, 0.0f, -6.0f); // translate left and into the screen
      gl.glRotatef(anglePyramid, -0.2f, 1.0f, 0.0f); // rotate about the y-axis
 
      gl.glBegin(GL_TRIANGLES); // of the pyramid
 
      // Font-face triangle
      gl.glColor3f(1.0f, 0.0f, 0.0f); // Red
      gl.glVertex3f(0.0f, 1.0f, 0.0f);
      gl.glColor3f(0.0f, 1.0f, 0.0f); // Green
      gl.glVertex3f(-1.0f, -1.0f, 1.0f);
      gl.glColor3f(0.0f, 0.0f, 1.0f); // Blue
      gl.glVertex3f(1.0f, -1.0f, 1.0f);
 
      // Right-face triangle
      gl.glColor3f(1.0f, 0.0f, 0.0f); // Red
      gl.glVertex3f(0.0f, 1.0f, 0.0f);
      gl.glColor3f(0.0f, 0.0f, 1.0f); // Blue
      gl.glVertex3f(1.0f, -1.0f, 1.0f);
      gl.glColor3f(0.0f, 1.0f, 0.0f); // Green
      gl.glVertex3f(1.0f, -1.0f, -1.0f);
 
      // Back-face triangle
      gl.glColor3f(1.0f, 0.0f, 0.0f); // Red
      gl.glVertex3f(0.0f, 1.0f, 0.0f);
      gl.glColor3f(0.0f, 1.0f, 0.0f); // Green
      gl.glVertex3f(1.0f, -1.0f, -1.0f);
      gl.glColor3f(0.0f, 0.0f, 1.0f); // Blue
      gl.glVertex3f(-1.0f, -1.0f, -1.0f);
 
      // Left-face triangle
      gl.glColor3f(1.0f, 0.0f, 0.0f); // Red
      gl.glVertex3f(0.0f, 1.0f, 0.0f);
      gl.glColor3f(0.0f, 0.0f, 1.0f); // Blue
      gl.glVertex3f(-1.0f, -1.0f, -1.0f);
      gl.glColor3f(0.0f, 1.0f, 0.0f); // Green
      gl.glVertex3f(-1.0f, -1.0f, 1.0f);
 
      gl.glEnd(); // of the pyramid
 
      // ----- Render the Color Cube -----
      gl.glLoadIdentity();                // reset the current model-view matrix
      gl.glTranslatef(1.6f, 0.0f, -7.0f); // translate right and into the screen
      gl.glRotatef(angleCube, 1.0f, 1.0f, 1.0f); // rotate about the x, y and z-axes
 
      gl.glBegin(GL_QUADS); // of the color cube
 
      // Top-face
      gl.glColor3f(0.0f, 1.0f, 0.0f); // green
      gl.glVertex3f(1.0f, 1.0f, -1.0f);
      gl.glVertex3f(-1.0f, 1.0f, -1.0f);
      gl.glVertex3f(-1.0f, 1.0f, 1.0f);
      gl.glVertex3f(1.0f, 1.0f, 1.0f);
 
      // Bottom-face
      gl.glColor3f(1.0f, 0.5f, 0.0f); // orange
      gl.glVertex3f(1.0f, -1.0f, 1.0f);
      gl.glVertex3f(-1.0f, -1.0f, 1.0f);
      gl.glVertex3f(-1.0f, -1.0f, -1.0f);
      gl.glVertex3f(1.0f, -1.0f, -1.0f);
 
      // Front-face
      gl.glColor3f(1.0f, 0.0f, 0.0f); // red
      gl.glVertex3f(1.0f, 1.0f, 1.0f);
      gl.glVertex3f(-1.0f, 1.0f, 1.0f);
      gl.glVertex3f(-1.0f, -1.0f, 1.0f);
      gl.glVertex3f(1.0f, -1.0f, 1.0f);
 
      // Back-face
      gl.glColor3f(1.0f, 1.0f, 0.0f); // yellow
      gl.glVertex3f(1.0f, -1.0f, -1.0f);
      gl.glVertex3f(-1.0f, -1.0f, -1.0f);
      gl.glVertex3f(-1.0f, 1.0f, -1.0f);
      gl.glVertex3f(1.0f, 1.0f, -1.0f);
 
      // Left-face
      gl.glColor3f(0.0f, 0.0f, 1.0f); // blue
      gl.glVertex3f(-1.0f, 1.0f, 1.0f);
      gl.glVertex3f(-1.0f, 1.0f, -1.0f);
      gl.glVertex3f(-1.0f, -1.0f, -1.0f);
      gl.glVertex3f(-1.0f, -1.0f, 1.0f);
 
      // Right-face
      gl.glColor3f(1.0f, 0.0f, 1.0f); // magenta
      gl.glVertex3f(1.0f, 1.0f, -1.0f);
      gl.glVertex3f(1.0f, 1.0f, 1.0f);
      gl.glVertex3f(1.0f, -1.0f, 1.0f);
      gl.glVertex3f(1.0f, -1.0f, -1.0f);
 
      gl.glEnd(); // of the color cube
 
      // Update the rotational angle after each refresh.
      anglePyramid += speedPyramid;
      angleCube += speedCube;
   }
 
   /**
    * Called back before the OpenGL context is destroyed. Release resource such as buffers.
    */
   @Override
   public void dispose(GLAutoDrawable drawable) { }
}
TRY:
  1. Modify the program to run as an applet.
  2. Modify the program to run in full screen mode.

3.9  JOGL's NEWT (Native Windowing Toolkit) - GLWindow

Besides relying on AWT/Swing, JOGL provides its own windowing toolkit called NEWT. The base class for NEWT is GLWindow. To allocate a GLWindow:
// Get the default OpenGL profile, reflecting the best for your running platform
GLProfile glp = GLProfile.getDefault();
// Specifies a set of OpenGL capabilities, based on your profile.
GLCapabilities caps = new GLCapabilities(glp);
// Allocate a GLWindow and add GLEventListener
GLWindow window = GLWindow.create(caps);
window.addGLEventListener(......);
Let's rewrite Example 1 using JOGL's NEWT.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import com.jogamp.newt.event.WindowAdapter;
import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.opengl.util.FPSAnimator;
 
public class JOGL2NewtDemo implements GLEventListener {  // Renderer
   private static String TITLE = "JOGL 2 with NEWT";  // window's title
   private static final int WINDOW_WIDTH = 640;  // width of the drawable
   private static final int WINDOW_HEIGHT = 480; // height of the drawable
   private static final int FPS = 60; // animator's target frames per second
 
   private double theta = 0.0f;  // rotational angle
 
   /** Constructor */
   public JOGL2NewtDemo() {}
 
   /** The entry main() method */
   public static void main(String[] args) {
       // Get the default OpenGL profile, reflecting the best for your running platform
       GLProfile glp = GLProfile.getDefault();
       // Specifies a set of OpenGL capabilities, based on your profile.
       GLCapabilities caps = new GLCapabilities(glp);
       // Create the OpenGL rendering canvas
       GLWindow window = GLWindow.create(caps);
 
       // Create a animator that drives canvas' display() at the specified FPS.
       final FPSAnimator animator = new FPSAnimator(window, FPS, true);
 
       window.addWindowListener(new WindowAdapter() {
          @Override
          public void windowDestroyNotify(WindowEvent arg0) {
             // Use a dedicate thread to run the stop() to ensure that the
             // animator stops before program exits.
             new Thread() {
                @Override
                public void run() {
                   animator.stop(); // stop the animator loop
                   System.exit(0);
                }
             }.start();
          };
       });
 
       window.addGLEventListener(new JOGL2NewtDemo());
       window.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
       window.setTitle(TITLE);
       window.setVisible(true);
       animator.start();
   }
 
   /** Called back by the drawable to render OpenGL graphics */
   @Override
   public void display(GLAutoDrawable drawable) {
       render(drawable);
       update();
   }
 
   /** Render the shape (triangle) */
   private void render(GLAutoDrawable drawable) {
       GL2 gl = drawable.getGL().getGL2();
 
       gl.glClear(GL.GL_COLOR_BUFFER_BIT);
 
       // Draw a triangle
       float sine = (float)Math.sin(theta);
       float cosine = (float)Math.cos(theta);
       gl.glBegin(GL.GL_TRIANGLES);
       gl.glColor3f(1, 0, 0);
       gl.glVertex2d(-cosine, -cosine);
       gl.glColor3f(0, 1, 0);
       gl.glVertex2d(0, cosine);
       gl.glColor3f(0, 0, 1);
       gl.glVertex2d(sine, -sine);
       gl.glEnd();
   }
 
   /** Update the rotation angle after each frame refresh */
   private void update() {
       theta += 0.01;
   }
 
   /** Called back immediately after the OpenGL context is initialized */
   @Override
   public void init(GLAutoDrawable drawable) { }
 
   /** Called back before the OpenGL context is destroyed. */
   @Override
   public void dispose(GLAutoDrawable drawable) { }
 
   /** Called back by the drawable when it is first set to visible,
   and during the first repaint after the it has been resized. */
   @Override
   public void reshape(GLAutoDrawable drawable, int x, int y, int weight, int height) { }
}

3.10  OpenGL Profile and Capabilities

[TODO] Revised
You can create drawables to support different OpenGL profiles and capabilities:
  1. First, construct a GLProfile, which specifies the target profile of your application, e.g., OpenGL2, OpenGL3, OpenGL4, OpenGL|ES1, OpenGL|ES2, etc. The profiles are beyond the scope of this tutorial. Read "JOGL 2 - OpenGL Profiles explained" if you are interested. We shall use the following statement to get the default profile, which best reflects your running platform.
    // Get the default OpenGL profile, reflecting the best for your running platform
    GLProfile glp = GLProfile.getDefault();
  2. Next, construct a GLCapabilities, based on your chosen profile, which maintain a set of OpenGL capabilities.
    // Specifies a set of OpenGL capabilities, based on your profile.
    GLCapabilities caps = new GLCapabilities(glp);
  3. Now, you can construct your desired drawing canvas: GLCanvas for AWT, GLJPanel for Swing, and GLWindow for Newt. All these canvas are GLDrawable.
    // Allocate a GLDrawable, based on your OpenGL capabilities.
    // Using GLCanvas for AWT 
    GLCanvas canvas = new GLCanvas(caps);
    this.add(canvas);            // "this" is a subclass of AWT's Frame
       
    // Using GLJPanel for Swing
    GLJPanel panel = new GLJPanel(caps);
    this.setContentPane(panel);  // "this" is a subclass of Swing's JFrame
       
    // Using GLWindow for Newt
    GLWindow window = GLWindow.create(caps);
    window.setVisible(true);

4.  Nehe's JOGL 2 Port

I have ported some of the Nehe's lessons into JOGL. Refer to Nehe for the problem descriptions.
Setting Up
Download Source Codes: "JOGL2Nehe01to08.zip".
  • Nehe's Lesson #1 "Setting Up":
    - Using GLCanvas: JOGL2Setup_GLCanvas.java.
    - Using GLJPanel: JOGL2Setup_GLJPanel.java.
    - Run as an applet with GLCanvas: JOGL2Setup_Applet.java.
    - Run in full-screen mode: JOGL2Setup_GLCanvasFullScreen.
Expected output: blank black screen.
OpenGL Basics
I consider Lessons #2 - #8 as OpenGL basic lessons, that are extremely important! I use GLCanvas on Swing's JFrame for all these exercises, as GLJPanel does not seem to run properly.
Download Source Codes: "JOGL2Nehe01To08.zip".
  • Nehe's Lesson #2 "Basic Shape": JOGL2Nehe02Basic2D.java.
  • Nehe's Lesson #3 "Color": J2Nehe03Color.java.
  • Nehe's Lesson #4 "Rotation": JOGL2Nehe04Rotation.java.
  • Nehe's Lesson #5 "3D Shape": JOGL2Nehe05Shape3D.java.
  • Nehe's Lesson #6 "Texture": JOGL2Nehe06Texture.java.
  • Nehe's Lesson #7 "Texture Filter, Lighting, and key-controlled": JOGL2Nehe07TextureFilterLightKey.java.
  • Nehe's Lesson #8 "Blending": JOGL2Nehe08Blending.java and JOGL2Nehe08Blending_FullScreen.java
      Click imge to run the applet (not working - JNLP not supported under my server?!)
OpenGL Intermediates
Download Source Code: "JOGL2NeheIntermediate.zip".
  • Nehe's Lesson #9 "Moving Bitmaps in 3D space": J2NeheEx09Stars.java.
  • Nehe's Lesson #10: Building and moving in a 3D world J2NeheEx10World3D.java.
  • Nehe's Lesson #11 "Waving Effect": J2NeheEx11Flag.java.
  • Nehe's Lesson #12 "Using Display List": J2NeheEx12DisplayList.java.
  • Nehe's Lesson #13 "2D Texts": J2NeheEx13Text2D.java.
  • Nehe's Lesson #14 "3D Texts": J2NeheEx14Text3D.java.
  • Nehe's Lesson #16 "Fog Effect": J2NeheEx16Fog.java.
  • Nehe's Lesson #18 "Quadrics": J2NeheEx18Quadrics.java.
  • Nehe's Lesson #19 "Particle Engine": (a) J2NeheEx19Particle.java, (b) J2NeheEx19Firework.java.
      
  • Nehe's Lesson #26 "Reflection": J2NeheEx26Reflection.java.

5.  More JOGL Ports/Examples

JOGL comes with many excellent demos. You can get the latest demo source codes from https://github.com/sgothel/ ⇒ "jogl demos" ⇒ "src" ⇒ "demos". However, many of these demos are not properly explained (?).
Gears/JGears
You can get the source codes "Gears.java" from JOGL demos; or get the latest code from https://github.com/sgothel/ ⇒ "jogl demos" ⇒ "src" ⇒ "demos" ⇒ "gears" ⇒ "Gears.java".
"Gears.java" run the JOGL's NEWT window. [TODO] more.
There is a variation called "JGears.java", which included 2 images and texts in the display.
[TODO] Photo-Cube
[TODO] Bouncing Balls inside a Cube
[TODO] JOGL Demos
[TODO] Redbook Examples

6.  Deploying JOGL Applications, Applets and Web Start Apps

Read "Java's Rich Internet Applications (RIA) - Applets & Web Start Apps".

6.1  Deploying JOGL 2.0 WebStart App

Jarring Up JOGL App
Jar-up your JOGL application's classes and relevant resources.
Preparing JNLP file
<?xml version="1.0" encoding="UTF-8"?>
<jnlp>
   <information>
      <title>My JOGL App</title>
      <vendor>My Company</vendor>
      <offline-allowed />
   </information>
   <resources>
      <j2se version="1.4+" href="http://java.sun.com/products/autodl/j2se" />
      <jar href="my_app.jar" main="true" />
      <extension name="jogl-all-awt" href="http://jogamp.org/deployment/v2.0-rc8/jogl-all-awt.jnlp" />
   </resources>
   <application-desc main-class="mydemo.myAppMain" />
</jnlp>
The above <extension> is meant for JOGL application. The necessary JOGL jar-files are provide by the jogamp server. Choose the appropriate JOGL version that you used to compile your application, e.g., "v2.0-rc8".

6.2  Deploying JOGL 2.0 Applet

Reference:
  1. Java Network Launch Protocol (JNLP) Support @ http://www.oracle.com/technetwork/java/javase/jnlp-136707.html
  2. JNLPAppletLauncher @ http://jogamp.org/applet-launcher/www/.
  3. Test page for JOGL Applets @ http://jogamp.org/deployment/jogamp-current/jogl-test-applets.html.
  4. JOGL: Applets @ http://jausoft.com/blog/2009/07/03/jogl-applets-part-1.
JNLP Applet (JDK 6u10)
Starting from JDK 6u10 Standard "JNLP Applets" are supported, in which the Java Plug-In (for web browser) provides support for launching applets directly from JNLP files. To launch an applet from a JNLP file, use the "jnlp_href" parameter in the <applet> tag.
For example, the following HTML file contains an applet which references JNLP file "my_applet.jnlp".
<applet width="300" height="300" >
<param name="jnlp_href" value="my_applet.jnlp">
</applet>
The JNLP file "my_applet.jnlp" is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<jnlp href="my_applet.jnlp">
   <information>
      <title>My Applet</title>
      <vendor>My Company</vendor>
      <offline-allowed />
   </information>
   <resources>
      <j2se version="1.6+" />
      <jar href="my_applet.jar" main="true" />
      <extension name="jogl-all-awt" href="http://jogamp.org/deployment/v2.0-rc8/jogl-all-awt.jnlp" />
   </resources>
   <applet-desc
      name="My Applet"
      main-class="mydemo.MyApplet"
      width="300"
      height="300">
   </applet-desc>
</jnlp>
The above extension is meant for JOGL app, where you should choose the appropriate JOGL version that you used to compile your application, e.g., "v2.0-rc8".
Applet Launcher (JDK 6u10)
JDK 1.6u10 has greatly improved the efficiency of Java applet, and it is now feasible and practical to deploy a huge Java program as an applet, via a so-called "Applet Launcher".
JNLP applet is support since JDK 6u14. However, you may need to fall back to the Applet-Launcher to support the older releases.
Depolying JOGL Applet as "Standard JNLP Applet" / "JNLPAppletLauncher"
We shall deploy JOGL applet as "JNLP Applet" if the web browser JRE Plug-in supports it (above JDK 6u14); otherwise, we fall back to JNLPAppletLauncher, as follow:
Prepare a JNLP file as follow:
<?xml version="1.0" encoding="utf-8"?>
<jnlp>
  <information>
    <title>JOGL Test</title>
    <vendor>SomeOne</vendor>
  </information>
  <resources>
      <j2se version="1.6+"/>
      <property name="sun.java2d.noddraw" value="true"/>
      <jar href="YourJoglApp.jar" main="true"/>
      <extension name="jogl-all-awt" href="http://jogamp.org/deployment/v2.0-rc8/jogl-all-awt.jnlp" />
  </resources>
 
  <applet-desc
      name="Test Applet"
      main-class="YourAppletClass"
      width="640"
      height="480">
  </applet-desc>
</jnlp>
In the <extension>'s href, set to the appropriate JOGL version that you used to compile your program, e.g., "v2.0-rc8" in my case.
Use the following <applet> tag with a reference to the JNLP file in parameter "jnlp_href":
<applet code="org.jdesktop.applet.util.JNLPAppletLauncher"
      width=600
      height=400
      archive=
      "http://jogamp.org/deployment/v2.0-rc8/jar/applet-launcher.jar,
       http://jogamp.org/deployment/v2.0-rc8/jar/nativewindow.all.jar,
       http://jogamp.org/deployment/v2.0-rc8/jar/gluegen-rt.jar,
       http://jogamp.org/deployment/v2.0-rc8/jar/jogl.all.jar,
       YourJOGLApp.jar">
   <param name="codebase_lookup" value="false">
   <param name="subapplet.classname" value="YourAppletClass">
   <param name="subapplet.displayname" value="JOGL Applet Test">
   <param name="noddraw.check" value="true">
   <param name="progressbar" value="true">
   <param name="jnlpNumExtensions" value="1">
   <param name="jnlpExtension1" value="http://jogamp.org/deployment/v2.0-rc8/jogl-core.jnlp">
   <param name="java_arguments" value="-Dsun.java2d.noddraw=true">
   <param name="jnlp_href" value="YourJnlpFile.jnlp">
</applet>
where:
  • Attribute "code" is pointing at "JNLPAppletLauncher", which is downloaded from http://jogamp.org/deployment/v2.0-rc8/jar/applet-launcher.jar, instead of your local server.
  • Attribute "archive" includes all the jar files for running JOGL program. Again, they are downloaded from the server. "archive" also include your JOGL JAR file.
  • Attributes "width" and "height" specify the width and height of your applet's display area inside the browser's window.
  • The name of your main applet is specified in the parameter "subapplet.classname".
  • The parameter "codebase_lookup" is set to false, as this applet does not need to fetch other files from your local server's code base path.
  • The parameter "noddraw.check" is set to true, to check if DirectDraw is enabled and, if so, will prompt the user to disable it for all applets. DirectDraw is incompatible with OpenGL. Disabling it is unlikely to slow down other non-3D applets significantly.
REFERENCES & RESOURCES
  1. JOGL mother site @ http://jogamp.org/jogl/www/; JOGL tutorial @ http://jogamp.org/wiki/index.php/Jogl_Tutorial; JOGL Wiki @ http://jogamp.org/wiki/index.php/Main_Page.
  2. JOGL Developer and master repository (including source and demos) @ https://github.com/sgothel/.
  3. OpenGL mother site @ www.opengl.org.
  4. Nehe OpenGL tutorials @ http://nehe.gamedev.net.
  5. OpenGL Programming Guide (Red book); OpenGL Superbible (Blue book)