I tried to write a insert statement with Spring JDB Template for an PostgreSQL Database. My insert string looked like this:
final String sql = "INSERT INTO products (prod_name, prod_key, artifact_id,
group_id, link, src, prod_type) VALUES ('?','?','?','?','?','?','?')";
And I got this Exception:
PreparedStatementCallback; SQL []; The column index is out of range: 1,
number of columns: 0.; nested exception is org.postgresql.util.PSQLException:
The column index is out of range: 1, number of columns: 0.
Solve:
The Problem was that I used ” ‘ ” inside of the sql string close to
the “?”. After I removed the ” ‘ ” strings it worked perfectly.
Wednesday, 27 November 2013
How to convert java.util.date to java.sql.date?
public class MainClass {
public static void main(String[] args) {
java.util.Date utilDate = new java.util.Date();
java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
System.out.println("utilDate:" + utilDate);
System.out.println("sqlDate:" + sqlDate);
}
}
explains it. The link is http://www.java2s.com/Tutorial/Java/0040__Data-Type/ConvertfromajavautilDateObjecttoajavasqlDateObject.htm
Source: http://stackoverflow.com/questions/530012/how-to-convert-java-util-date-to-java-sql-date
Wednesday, 13 November 2013
Passing clicked value from jsp to jsp/servlet
We can pass the value from jsp to servlet using,
Passing clicked value from jsp to jsp/servlet:
We have to pass the clicked value as get parameter in the href link like below,
Servlet code:
In the below sample program javadomain (small letters) will be clicked, then the same value passed from jsp to servlet and there javadomain(small letters) are converted to JAVADOMAIN (UPPER CASE) then the new upper case values are passed from servlet to jsp.
Program:
main.jsp:
Output:
Source: http://javadomain.in/passing-clicked-value-from-jsp-to-jspservlet/
Thanks for reading this post……..!!!
request.getParameter("text"); //servlet code to get the jsp valuewhere text is the name of the input fields (text field).
Passing clicked value from jsp to jsp/servlet:
We have to pass the clicked value as get parameter in the href link like below,
<a href="/Myservlet?input=javadomain">MyServlet is the name of the servlet.
Servlet code:
request.getParameter("input");So javadomain will be passed from jsp to servlet.
In the below sample program javadomain (small letters) will be clicked, then the same value passed from jsp to servlet and there javadomain(small letters) are converted to JAVADOMAIN (UPPER CASE) then the new upper case values are passed from servlet to jsp.
Program:
main.jsp:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <html> <head> <title>Small Letters</title> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <meta name="GENERATOR" content="Rational Application Developer"> </head> <body> <a href="/Blog/ToCapLetters?a=javadomain">javadomain</a> </body> </html>final.jsp:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <html> <head> <title>Capital Letters</title> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <meta name="GENERATOR" content="Rational Application Developer"> </head> <body> <% HttpSession session1 = request.getSession(); String capitalValue = session1.getAttribute("clicked_value").toString(); out.println(capitalValue); %> </body> </html>ToCapLetters.java: (servlet file)
import java.io.IOException; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * Servlet implementation class ToCapLetters */ @WebServlet("/ToCapLetters") public class ToCapLetters extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public ToCapLetters() { super(); // TODO Auto-generated constructor stub } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String value = request.getParameter("a"); String value_capital = value.toUpperCase(); HttpSession session = request.getSession(); session.setAttribute("clicked_value", value_capital); RequestDispatcher rd = request.getRequestDispatcher("./final.jsp"); rd.forward(request,response); } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // TODO Auto-generated method stub } }
Output:
Source: http://javadomain.in/passing-clicked-value-from-jsp-to-jspservlet/
Thanks for reading this post……..!!!
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
Published by Rodrigo Sasaki on 06/06/2013 | Leave a response
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
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:
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:
And now the printed value is: 10000000000000000000000000000000.
As we can see, all the 1s became 0s and the initial 0 became 1.
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:
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:
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 ^
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:
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:
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:
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.
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:
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.
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:
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:
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
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
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 0 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.
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 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)); } |
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:
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:
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:
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 } |
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)); } |
public static void main(String[] args){ int n = 0b1010; System.out.println(n); // Prints 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)); } |
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 ShiftingIf 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 )); } |
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 00100000000000000000000000000001On 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 byte3And 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 byte3All 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 ; } } |
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
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.
- Scanner - allows reading files in a compact way
- BufferedReader - readLine
- BufferedWriter - write + newLine
- 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)
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.
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 insignificant programming notes... | HOME
TABLE OF CONTENTS (HIDE)
1. Introduction to JOGL
2. Setting Up JOGL 2.0_rc8
3. Getting Started with JOGL 2.0_rc8
3.1 OpenGL Drawable: GLCanvas and GLJPanel
3.2 GLEventListener and GLAutoDrawable
3.3 Animator
3.4 OpenGL Graphics Context
3.5 JOGL 2.0 Program Templates
3.6 Example 1: Rotating 2D Shapes
3.7 GLEventListener Handlers
3.8 Example 2: Rotating 3D Shapes
3.9 JOGL's NEWT (Native Windowing Toolkit) - GLWindow
3.10 OpenGL Profile and Capabilities
4. Nehe's JOGL 2 Port
5. More JOGL Ports/Examples
6. Deploying JOGL Applications, Applets and Web Start Apps
6.1 Deploying JOGL 2.0 WebStart App
6.2 Deploying JOGL 2.0 Applet
2. Setting Up JOGL 2.0_rc8
3. Getting Started with JOGL 2.0_rc8
3.1 OpenGL Drawable: GLCanvas and GLJPanel
3.2 GLEventListener and GLAutoDrawable
3.3 Animator
3.4 OpenGL Graphics Context
3.5 JOGL 2.0 Program Templates
3.6 Example 1: Rotating 2D Shapes
3.7 GLEventListener Handlers
3.8 Example 2: Rotating 3D Shapes
3.9 JOGL's NEWT (Native Windowing Toolkit) - GLWindow
3.10 OpenGL Profile and Capabilities
4. Nehe's JOGL 2 Port
5. More JOGL Ports/Examples
6. Deploying JOGL Applications, Applets and Web Start Apps
6.1 Deploying JOGL 2.0 WebStart App
6.2 Deploying JOGL 2.0 Applet
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
- Unzip "
jogamp-all-platforms.7z
" (you can unzip ".7z
" file using WinRAR or possibly WinZIP?).- The
jogl
's andgluegen
'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.
- The
- 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 thejavadocs
downloaded into "javadoc
".
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
- 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.- From "Window" menu ⇒ Preferences ⇒ Java ⇒ Build Path ⇒ User Libraries ⇒ New ⇒ In "User library name", enter "
jogl-2.0
". - In "User Library" dialog ⇒ Select "
jogl-2.0
" ⇒ Add JAR... ⇒ Navigate to "$JOGL_HOME\jar
", and select "gluegen-rt.jar
" and "jogl.all.jar
". - 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
"). - (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.
index.html
" file.
This is needed for Eclipse to display javadoc information about classes and methods. - (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.
- From "Window" menu ⇒ Preferences ⇒ Java ⇒ Build Path ⇒ User Libraries ⇒ New ⇒ In "User library name", enter "
- 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
".
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:
- Create a JOGL Library:
- From "Tool" ⇒ "Library" ⇒ Click "New Libraries..." ⇒ Enter "
jogl2.0
". - Click "Add JAR/Folder..." ⇒ Select "
jogl.all.jar
" and "gluegen-rt.jar
". - Under the "JavaDoc" tab ⇒ Select the JOGL's javadoc. You could use the zip version for better performance.
- Under the "Source" tab ⇒ Select the JOGL's source. You could use the zip version for better performance.
- From "Tool" ⇒ "Library" ⇒ Click "New Libraries..." ⇒ Enter "
- Include the JOGL Library:
- 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. - 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).
- 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 "
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.jarwhere
$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 myjoglappRead "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 packagejavax.media.opengl.awt
: GLCanvas
and GLJPanel
.GLCanvas
: A heavyweight AWT component which is a subclass ofjava.awt.Canvas
.
You can create aGLCanvas
via the default constructorGLCanvas()
, which construct a newGLCanvas
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(.....);
GLJPanel
: A lightweight Swing component which is a subclass ofjavax.swing.JPanel
.
Again, You can create aGLJPanel
via the default constructorGLJPanel()
, which construct a newGLJPanel
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(.....);
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 interfaceGLEventListener
(in package javax.media.opengl
) declares the following 4 OpenGL event handlers:init(GLAutoDrawable drawable)
: called by thedrawable
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.dispose(GLAutoDrawable drawable)
: called by thedrawable
before the OpenGL context is destroyed. It can be used to release all OpenGL resources, such as memory buffers.display(GLAutoDrawable drawable)
: called by thedrawable
to render OpenGL graphics. It is the most important method.reshape(GLAutoDrawable drawable, int x, int y, int width, int height)
: called by thedrawable
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.
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'sdisplay()
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) { } } |
In this template:
- I follow the design of "Component-based Architecture for Rich Internet Applications (RIA)", where the GUI "
Component
" (GLCanvas
orGLJPanel
) 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 implementsGLEventListener
and provides handlers forinit()
,display()
,dispose()
andreshape()
. - The
main()
method:- Allocates a
GLCanvas
component. - Allocates an
Animator
to drive thedisplay()
method of theGLCanvas
in a loop to refresh the display. - Allocates a top-level container (Swing's
JFrame
or AWT'sFrame
), and adds theGLCanvas
component into the container..
- Allocates a
Using AWT's Frame as Top-Level Container
The above template uses Swing'sJFrame
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 rendererComponent
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 } }); } } |
Component
) class. The main (Container
) class can be left untouched.GLJPanel
To use the light-weightGLJPanel
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 theGLCanvas
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(); } } |
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) {} } |
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 theGLEventListener
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:
- Using
GLJPanel
on Swing'sJFrame
. - Use
GLCanvas
on AWT'sFrame
. - Use
GLCanvas
on AWT'sApplet
. - Using
GLJPanel
on Swing'sJApplet
.
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. Theinit()
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) { } } |
- Modify the program to run as an applet.
- 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 isGLWindow
. 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] RevisedYou can create drawables to support different OpenGL profiles and capabilities:
- 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();
- 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);
- Now, you can construct your desired drawing canvas:
GLCanvas
for AWT,GLJPanel
for Swing, andGLWindow
for Newt. All these canvas areGLDrawable
.// 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":
- UsingGLCanvas
:JOGL2Setup_GLCanvas.java
.
- UsingGLJPanel
:JOGL2Setup_GLJPanel.java
.
- Run as an applet withGLCanvas
:JOGL2Setup
_Applet.java
.
- Run in full-screen mode:JOGL2Setup_GLCanvasFullScreen
.
OpenGL Basics
I consider Lessons #2 - #8 as OpenGL basic lessons, that are extremely important! I useGLCanvas
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
andJOGL2Nehe08Blending_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:- Java Network Launch Protocol (JNLP) Support @ http://www.oracle.com/technetwork/java/javase/jnlp-136707.html
- JNLPAppletLauncher @ http://jogamp.org/applet-launcher/www/.
- Test page for JOGL Applets @ http://jogamp.org/deployment/jogamp-current/jogl-test-applets.html.
- 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 fromhttp://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 tofalse
, 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
- 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.
- JOGL Developer and master repository (including source and demos) @ https://github.com/sgothel/.
- OpenGL mother site @ www.opengl.org.
- Nehe OpenGL tutorials @ http://nehe.gamedev.net.
- OpenGL Programming Guide (Red book); OpenGL Superbible (Blue book)
Latest version tested: JOGL 2.0_rc8, JDK 1.7.2, Eclispe 3.7.2
Last modified: May, 2012
Last modified: May, 2012
Feedback, comments, corrections, and errata can be sent to Chua Hock-Chuan (ehchua@ntu.edu.sg) | HOME
source: http://www3.ntu.edu.sg/home/ehchua/programming/opengl/JOGL2.0.html
source: http://www3.ntu.edu.sg/home/ehchua/programming/opengl/JOGL2.0.html
Subscribe to:
Posts (Atom)