Friday, April 3, 2009

OpenGL in Clojure

After much struggling I finally got a simple OpenGL example working in Clojure!

Here's a port of the JOGL example in Wikipedia to Clojure:
;This is a Clojure port of the JOGL example in Wikipedia
;Author: Curran Kelleher
;License: Public Domain
;dependencies: jogl.jar, gluegen-rt.jar

;for the REPL (use C-x C-e):
(comment
;these are the default paths of the jars in Ubuntu
(add-classpath "file:/usr/share/java/jogl.jar")
(add-classpath "file:/usr/share/java/gluegen-rt.jar")
)

(import '(java.awt Frame)
'(java.awt.event WindowListener WindowAdapter KeyListener KeyEvent)
'(javax.media.opengl GLCanvas GLEventListener GL GLAutoDrawable)
'(javax.media.opengl.glu GLU)
'(com.sun.opengl.util Animator))
(def rotateT 0)
(def glu (new GLU))
(def canvas (new GLCanvas))
(def frame (new Frame "Jogl 3D Shape/Rotation"))
(def animator (new Animator canvas))
(defn exit "Stops animation and closes the OpenGL frame." []
(.stop animator)
(.dispose frame))

(.addGLEventListener
canvas
(proxy [GLEventListener] []
(display
[#^GLAutoDrawable drawable]
(doto (.getGL drawable)
(.glClear (. GL GL_COLOR_BUFFER_BIT))
(.glClear (. GL GL_DEPTH_BUFFER_BIT))
(.glLoadIdentity)
(.glTranslatef 0 0 -5)

(.glRotatef rotateT 1 0 0)
(.glRotatef rotateT 0 1 0)
(.glRotatef rotateT 0 0 1)
(.glRotatef rotateT 0 1 0)

(.glBegin (. GL GL_TRIANGLES))

; Front
(.glColor3f 0 1 1)
(.glVertex3f 0 1 0)
(.glColor3f 0 0 1)
(.glVertex3f -1 -1 1)
(.glColor3f 0 0 0)
(.glVertex3f 1 -1 1)


; Right Side Facing Front
(.glColor3f 0 1 1)
(.glVertex3f 0 1 0)
(.glColor3f 0 0 1)
(.glVertex3f 1 -1 1)
(.glColor3f 0 0 0)
(.glVertex3f 0 -1 -1)

; Left Side Facing Front
(.glColor3f 0 1 1)
(.glVertex3f 0 1 0)
(.glColor3f 0 0 1)
(.glVertex3f 0 -1 -1)
(.glColor3f 0 0 0)
(.glVertex3f -1 -1 1)

;Bottom
(.glColor3f 0 0 0)
(.glVertex3f -1 -1 1)
(.glColor3f 0.1 0.1 0.1)
(.glVertex3f 1 -1 1)
(.glColor3f 0.2 0.2 0.2)
(.glVertex3f 0 -1 -1)

(.glEnd))
(def rotateT (+ 0.2 rotateT)))

(displayChanged [drawable m d])

(init
[#^GLAutoDrawable drawable]
(doto (.getGL drawable)
(.glShadeModel (. GL GL_SMOOTH))
(.glClearColor 0 0 0 0)
(.glClearDepth 1)
(.glEnable (. GL GL_DEPTH_TEST))
(.glDepthFunc (. GL GL_LEQUAL))
(.glHint (. GL GL_PERSPECTIVE_CORRECTION_HINT)
(. GL GL_NICEST)))
(.addKeyListener
drawable
(proxy [KeyListener] []
(keyPressed
[e]
(when (= (.getKeyCode e) (. KeyEvent VK_ESCAPE))
(exit))))))

(reshape
[#^GLAutoDrawable drawable x y w h]
(when (> h 0)
(let [gl (.getGL drawable)]
(.glMatrixMode gl (. GL GL_PROJECTION))
(.glLoadIdentity gl)
(.gluPerspective glu 50 (/ w h) 1 1000)
(.glMatrixMode gl (. GL GL_MODELVIEW))
(.glLoadIdentity gl))))))

(doto frame
(.add canvas)
(.setSize 640 480)
(.setUndecorated true)
(.setExtendedState (. Frame MAXIMIZED_BOTH))
(.addWindowListener
(proxy [WindowAdapter] []
(windowClosing [e] (exit))))
(.setVisible true))
(.start animator)
(.requestFocus canvas)


Here's a shell script that will run it:
#!/bin/sh
java -cp $CLOJURE_EXT/clojure.jar:/usr/share/java/jogl.jar:/usr/share/java/gluegen-rt.jar clojure.main joglExample.clj

The libraries can be installed in Ubuntu with
sudo apt-get install libjogl-java

Here's the refactored Java example from Wikipedia:
import javax.media.opengl.GL;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.glu.GLU;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.media.opengl.GLCanvas;
import java.awt.Frame;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import com.sun.opengl.util.Animator;

public class joglExample implements GLEventListener, KeyListener {
float rotateT = 0.0f;
static GLU glu = new GLU();
static GLCanvas canvas = new GLCanvas();
static Frame frame = new Frame("Jogl 3D Shape/Rotation");
static Animator animator = new Animator(canvas);
public void display(GLAutoDrawable gLDrawable) {
final GL gl = gLDrawable.getGL();
gl.glClear(GL.GL_COLOR_BUFFER_BIT);
gl.glClear(GL.GL_DEPTH_BUFFER_BIT);
gl.glLoadIdentity();
gl.glTranslatef(0.0f, 0.0f, -5.0f);

gl.glRotatef(rotateT, 1.0f, 0.0f, 0.0f);
gl.glRotatef(rotateT, 0.0f, 1.0f, 0.0f);
gl.glRotatef(rotateT, 0.0f, 0.0f, 1.0f);
gl.glRotatef(rotateT, 0.0f, 1.0f, 0.0f);

gl.glBegin(GL.GL_TRIANGLES);

// Front
gl.glColor3f(0.0f, 1.0f, 1.0f);
gl.glVertex3f(0.0f, 1.0f, 0.0f);
gl.glColor3f(0.0f, 0.0f, 1.0f);
gl.glVertex3f(-1.0f, -1.0f, 1.0f);
gl.glColor3f(0.0f, 0.0f, 0.0f);
gl.glVertex3f(1.0f, -1.0f, 1.0f);

// Right Side Facing Front
gl.glColor3f(0.0f, 1.0f, 1.0f);
gl.glVertex3f(0.0f, 1.0f, 0.0f);
gl.glColor3f(0.0f, 0.0f, 1.0f);
gl.glVertex3f(1.0f, -1.0f, 1.0f);
gl.glColor3f(0.0f, 0.0f, 0.0f);
gl.glVertex3f(0.0f, -1.0f, -1.0f);

// Left Side Facing Front
gl.glColor3f(0.0f, 1.0f, 1.0f);
gl.glVertex3f(0.0f, 1.0f, 0.0f);
gl.glColor3f(0.0f, 0.0f, 1.0f);
gl.glVertex3f(0.0f, -1.0f, -1.0f);
gl.glColor3f(0.0f, 0.0f, 0.0f);
gl.glVertex3f(-1.0f, -1.0f, 1.0f);

// Bottom
gl.glColor3f(0.0f, 0.0f, 0.0f);
gl.glVertex3f(-1.0f, -1.0f, 1.0f);
gl.glColor3f(0.1f, 0.1f, 0.1f);
gl.glVertex3f(1.0f, -1.0f, 1.0f);
gl.glColor3f(0.2f, 0.2f, 0.2f);
gl.glVertex3f(0.0f, -1.0f, -1.0f);

gl.glEnd();

rotateT += 0.2f;
}

public void displayChanged(GLAutoDrawable gLDrawable,
boolean modeChanged, boolean deviceChanged) {
}

public void init(GLAutoDrawable gLDrawable) {
GL gl = gLDrawable.getGL();
gl.glShadeModel(GL.GL_SMOOTH);
gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
gl.glClearDepth(1.0f);
gl.glEnable(GL.GL_DEPTH_TEST);
gl.glDepthFunc(GL.GL_LEQUAL);
gl.glHint(GL.GL_PERSPECTIVE_CORRECTION_HINT,
GL.GL_NICEST);
gLDrawable.addKeyListener(this);
}

public void reshape(GLAutoDrawable gLDrawable, int x,
int y, int width, int height) {
GL gl = gLDrawable.getGL();
if(height <= 0) {
height = 1;
}
float h = (float)width / (float)height;
gl.glMatrixMode(GL.GL_PROJECTION);
gl.glLoadIdentity();
glu.gluPerspective(50.0f, h, 1.0, 1000.0);
gl.glMatrixMode(GL.GL_MODELVIEW);
gl.glLoadIdentity();
}

public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ESCAPE) {
exit();
}
}

public void keyReleased(KeyEvent e) {
}

public void keyTyped(KeyEvent e) {
}

public static void exit(){
animator.stop();
frame.dispose();
System.exit(0);
}

public static void main(String[] args) {
canvas.addGLEventListener(new joglExample());
frame.add(canvas);
frame.setSize(640, 480);
frame.setUndecorated(true);
frame.setExtendedState(Frame.MAXIMIZED_BOTH);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
exit();
}
});
frame.setVisible(true);
animator.start();
canvas.requestFocus();
}
}


Here's a shell script that will run it:
#!/bin/sh
javac -cp /usr/share/java/jogl.jar:/usr/share/java/gluegen-rt.jar joglExample.java
java -cp ./:/usr/share/java/jogl.jar:/usr/share/java/gluegen-rt.jar joglExample

Enjoy!

Links:
Gears demo in Clojure
Wikipedia JOGL demo

8 comments:

Hair inhibitor cream said...

I didn't fully understand the concept....

Vigaplus natural ed pills said...

Very innovative concept. Things are really useful and important to the related people. Thanks.

Best low sperm count pills review said...

Things are really useful and important to the related people...not for me though...

Best hair loss pills review said...

Things are really useful and important to the related people..

Duramale premature ejaculation pills said...

This is well understandable concept....Many of us can apply it and get benefitted..

dan_lee said...

so this is the reason that I have so many errors with games, all of then give me the same error "OpenGl is missing, please install the correct programm and Buy Viagra" I don't know why this last part.

saim said...

Hey its been really a very good and informative post to read on. I will keep these points in my mind from now onwards, hope will not commit mistakes





natural supplements

HawkEye said...

Attempt not impossibilities.
Locksmith Washington DC