
Step:
If you already have a class and don't want to define the class as subclass of OGL, please use OGL object to call OpenGL functions.
Differences are:
This program uses callback mechanism for "reshape", "keyboard" event handling. But, of course, you can use awt event mechanism instead.
This sample uses a Panel for rendering, then you can add some other
components to the panel. This time, I added a Button. If you push
the button, the direction of rotation is reversed.
Complete program is here.
1. Very Small Example
This program is very simple. The class is a subclass of OGL and it
draws a rectangle on a Frame directly.
NOTE: The rectangle is drawn only once. The frame won't be repainted.
import jsparrow.gl.*;
import java.awt.Frame;
public class MinOGL extends OGL {
public void start() {
Frame frame = new Frame();
frame.setSize(300, 300);
frame.setVisible(true);
try {
Thread.sleep(500);
} catch (InterruptedException e) { }
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
jsCreateContext(frame);
glViewport(0, 0, 300, 300);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-5.0f, 5.0f, -5.0f, 5.0f, -10.0f, 10.0f);
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT);
glRectf(-2.5f, -2.5f, 2.5f, 2.5f);
glFlush();
}
public static void main(String argv[]) {
MinOGL min = new MinOGL();
min.start();
}
}
Source code of right side is an example of using OGLConstants interface.
import jsparrow.gl.*;
import java.awt.Frame;
public class MinOGL2 {
public void start() {
Frame frame = new Frame();
frame.setSize(300, 300);
frame.setVisible(true);
try {
Thread.sleep(500);
} catch (InterruptedException e) { }
OGL o = new OGL();
o.glutInitDisplayMode(o.GLUT_SINGLE | o.GLUT_RGB);
o.jsCreateContext(frame);
o.glViewport(0, 0, 300, 300);
o.glMatrixMode(o.GL_PROJECTION);
o.glLoadIdentity();
o.glOrtho(-5.0f, 5.0f, -5.0f, 5.0f, -10.0f, 10.0f);
o.glMatrixMode(o.GL_MODELVIEW);
o.glClear(o.GL_COLOR_BUFFER_BIT);
o.glRectf(-2.5f, -2.5f, 2.5f, 2.5f);
o.glFlush();
}
public static void main(String argv[]) {
MinOGL2 min = new MinOGL2();
min.start();
}
}
import jsparrow.gl.*;
import java.awt.Frame;
public class MinOGL3 implements OGLConstants {
public void start() {
Frame frame = new Frame();
frame.setSize(300, 300);
frame.setVisible(true);
try {
Thread.sleep(500);
} catch (InterruptedException e) { }
OGL o = new OGL();
o.glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
o.jsCreateContext(frame);
o.glViewport(0, 0, 300, 300);
o.glMatrixMode(GL_PROJECTION);
o.glLoadIdentity();
o.glOrtho(-5.0f, 5.0f, -5.0f, 5.0f, -10.0f, 10.0f);
o.glMatrixMode(GL_MODELVIEW);
o.glClear(GL_COLOR_BUFFER_BIT);
o.glRectf(-2.5f, -2.5f, 2.5f, 2.5f);
o.glFlush();
}
public static void main(String argv[]) {
MinOGL3 min = new MinOGL3();
min.start();
}
}
2. GUI Application Sample
Next sample is a Window base application with GUI. It draws a red
teapot at center of a canvas.
Left side is a JSparrow and Right side is a C code. There are very few differences.
Java Program with JSparrow
import jsparrow.gl.*;
import java.awt.*;
import java.awt.event.*;
public class TeapotCanvas extends OGLCanvas {
public void init() {
float ambient[] = {0.2f, 0.2f, 0.2f, 1.0f};
float diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
float specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
float position[] = {1.0f, 1.0f, 1.0f, 0.0f};
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glFrontFace(GL_CW);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glEnable(GL_DEPTH_TEST);
}
public void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float mat[] = {1.0f, 0.0f, 0.0f, 1.0f};
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat);
glutSolidTeapot(1.0);
glFlush();
}
public void reshape(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-3.0f, 3.0f, -3.0f, 3.0f, -10.0f, 10.0f);
glMatrixMode(GL_MODELVIEW);
}
public void keyboard(char key, int x, int y) {
switch (key) {
case 27:
System.exit(0);
}
}
int main() {
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB
| GLUT_DEPTH);
OGLContext context = jsCreateContextAuto();
glutInitWindowSize(200, 200);
jsInitFunc("init", this, context);
glutReshapeFunc("reshape", this, context);
glutDisplayFunc("display", this, context);
glutKeyboardFunc("keyboard", this, context);
return 0;
}
public static void main (String argv[]) {
TeapotCanvas canvas = new TeapotCanvas();
canvas.main();
Frame frame = new Frame("teapot");
frame.add(canvas);
frame.pack();
frame.show();
}
}
C Program
#include <GL/glut.h>
void init() {
GLfloat ambient[] = {0.2, 0.2, 0.2, 1.0};
GLfloat diffuse[] = {1.0, 0.0, 0.0, 1.0};
GLfloat specular[] = {1.0, 1.0, 1.0, 1.0};
GLfloat position[] = {5.0, 5.0, 5.0, 0.0};
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glFrontFace(GL_CW);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glEnable(GL_DEPTH_TEST);
}
void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
GLfloat mat[] = {1.0, 0.0, 0.0, 1.0};
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat);
glutSolidTeapot(1.0);
glFlush();
}
void reshape(int w, int h) {
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-3.0, 3.0, -3.0, 3.0, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
}
void keyboard(unsigned char key, int x, int y) {
switch (key) {
case 27:
exit(0);
}
}
int main(int argc, char **argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB
| GLUT_DEPTH);
glutInitWindowSize(200, 200);
glutCreateWindow(argv[0]);
init();
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutKeyboardFunc(keyboard);
glutMainLoop();
return 0;
}

3. Animation Sample
This is a sample of animation program. An animation thread calls
repaint() method of panel. awt component doesn't generate paint event.
So we have to make a subclass of Component and override paint() method.
With this program, MyPanel class is it.
import jsparrow.gl.*;
import java.awt.*;
import java.awt.event.*;
public class AnimationOGL extends OGL implements ActionListener, Runnable {
MyPanel panel;
Thread thread;
float angle, direction = 1.0f;
public void init() {
float ambient[] = {0.2f, 0.2f, 0.2f, 1.0f};
float diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
float specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
float position[] = {1.0f, 1.0f, 1.0f, 0.0f};
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glLightfv(GL_LIGHT0, GL_POSITION, position);
glFrontFace(GL_CW);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_AUTO_NORMAL);
glEnable(GL_NORMALIZE);
glEnable(GL_DEPTH_TEST);
}
public void display() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
float mat[] = new float[] {0.0f, 1.0f, 0.0f, 1.0f};
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat);
glPushMatrix();
glRotatef(angle, 0.0f, 1.0f, 0.0f);
glutSolidTorus(0.9, 1.7, 20, 20);
glPopMatrix();
swapBuffers();
}
public void reshape(int w, int h) {
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-3.0f, 3.0f, -3.0f, 3.0f, -10.0f, 10.0f);
glMatrixMode(GL_MODELVIEW);
}
public void actionPerformed(ActionEvent e) {
direction *= -1;
}
public void run() {
while (thread != null) {
angle += 5.0f * direction;
if (angle > 360.0f) angle = 0.0f;
panel.repaint();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
void main() {
panel = new MyPanel(this);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
OGLContext context = jsCreateContextAuto(panel);
jsInitFunc("init", this, context);
jsReshapeFunc("reshape", this, context);
jsDisplayFunc("display", this, context);
Button button = new Button("Reverse");
button.addActionListener(this);
panel.add(button);
Frame frame = new Frame("TorusPanel");
frame.setSize(300, 300);
frame.add(panel);
frame.setVisible(true);
thread = new Thread(this);
thread.start();
}
public static void main (String argv[]) {
AnimationOGL ogl = new AnimationOGL();
ogl.main();
}
}
class MyPanel extends Panel {
OGL ogl;
MyPanel(OGL o) {
ogl = o;
}
public void update(Graphics g) {
paint(g);
}
public void paint(Graphics g) {
ogl.callDisplayFuncs(this);
}
}
4. Multi-thread Sample
This is a sample of multi thread rendering. The threads of this
program are not awt threads. If my threads call repaint() method of
Canvas, those events are scheduled in the thread of the canvas. Not
in my own thread. Then, rendering will be executed in single canvas
thread.
The threads of this program draw rectangles directly on canvas.
import jsparrow.gl.*;
import java.awt.Canvas;
import java.awt.Frame;
public class MultiThread implements Runnable, OGLConstants {
OGL o = new OGL();
Thread thread;
Canvas canvas;
float step, distance;
int time;
float angle = 0.0f;
OGLContext context;
public MultiThread(Canvas canvas, float step,
float distance, int time) {
this.canvas = canvas;
this.step = step;
this.distance = distance;
this.time = time;
}
public void run() {
while (thread != null) {
if (context == null) {
context = o.jsCreateContext(canvas);
if (context == null) {
Thread.yield();
continue;
}
o.glViewport(0, 0, 300, 300);
o.glMatrixMode(GL_PROJECTION);
o.glLoadIdentity();
o.glOrtho(-10.0f, 10.0f, -10.0f, 10.0f,
-10.0f, 10.0f);
o.glMatrixMode(GL_MODELVIEW);
}
if (o.jsMakeCurrent(canvas, context)) {
o.glPushMatrix();
o.glRotatef(angle, 0.0f, 0.0f, 1.0f);
o.glTranslatef(distance, 0.0f, 0.0f);
o.glColor3f(1.0f, 1.0f, 1.0f);
o.glRectf(-1.0f, -1.0f, 1.0f, 1.0f);
o.glPopMatrix();
angle += step;
if (angle > 360.0f) {
angle = 0.0f;
}
o.glPushMatrix();
o.glRotatef(angle, 0.0f, 0.0f, 1.0f);
o.glTranslatef(distance, 0.0f, 0.0f);
o.glColor3f(0.0f, 0.0f, 0.7f);
o.glRectf(-1.0f, -1.0f, 1.0f, 1.0f);
o.glPopMatrix();
o.glFlush();
o.jsMakeCurrent(null, null);
try {
Thread.sleep(time);
} catch (InterruptedException e) {
}
}
}
}
public void start() {
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
public static void main(String argv[]) {
Canvas c = new Canvas();
c.setSize(300, 300);
Frame frame = new Frame("MultiThread");
frame.add(c);
frame.pack();
frame.show();
MultiThread t1 = new MultiThread(c, 7.0f, 7.0f, 200);
MultiThread t2 = new MultiThread(c, -5.0f, -5.0f, 300);
t1.start();
t2.start();
}
}
5. GLU NURBS sample
This is a Java version of sample program from the "Red Book",
surface.c. It uses NURBS.
In JSparrow, NURBS can be used in a similar way. Almost same.
Like this:
Java Program with JSparrow
GLUnurbsObj theNurb;
.
.
public void nurbsError(int errorCode) {
String estring;
estring = gluErrorString(errorCode);
System.out.println("Nurbs Error: " + estring);
System.exit(0);
}
.
.
theNurb = gluNewNurbsRenderer();
gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0f);
gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);
gluNurbsCallback(theNurb, GLU_ERROR, "nurbsError");
.
.
gluBeginSurface(theNurb);
gluNurbsSurface(theNurb,
8, knots, 8, knots,
4 * 3, 3, ctlpoints,
4, 4, GL_MAP2_VERTEX_3);
gluEndSurface(theNurb);
C Program
GLUnurbsObj *theNurb;
.
.
void CALLBACK nurbsError(GLenum errorCode) {
const GLubyte *estring;
estring = gluErrorString(errorCode);
fprintf (stderr, "Nurbs Error: %s\n", estring);
exit (0);
}
.
.
theNurb = gluNewNurbsRenderer();
gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25.0);
gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);
gluNurbsCallback(theNurb, GLU_ERROR, nurbsError);
.
.
gluBeginSurface(theNurb);
gluNurbsSurface(theNurb,
8, knots, 8, knots,
4 * 3, 3, &ctlpoints[0][0][0],
4, 4, GL_MAP2_VERTEX_3);
gluEndSurface(theNurb);

jsparrow@zak.att.ne.jp