Archives for July 2009

Using LWJGL with Griffon

LWJGL (Light-weight Java Game Library) is a game library that is the basis for many graphics libraries including jMonkeyEngine. You might be wondering why I'm covering LWJGL in a separate post when it is used in jMonkeyEngine which I covered several weeks ago. Though there is some overlap, each fits a specific need.

I'd describe the relationship like this: OpenGL/JOGL is a bicycle, LWJGL is a Vespa, and jME is a Harley. OpenGL is great if you want to touch the bare metal, LWJGL if you want to tweak and customize, jME if you singular goal is to make a game.

Getting started

  • Download LWJGL and drop the lwjgl.jar in your lib directory.
  • Find the native files for your operating system and extract them into lib/native
  • Download jME 2.0 Distribution. We aren't doing that much advanced stuff so we only need jme.jar, jinput.jar, and jme-awt.jar. Drop these into your lib directory.
  • Modify your Config.groovy file to contain the following:
     
    griffon {
       app {
        javaOpts = ["-Djava.library.path=${basedir}/lib/native"]
       }
    }
    

Linking our model and view

Our model and view are going to be fairly basic and initiate a model property called canvas that is added to the view. We don't need to do anything in our controller.

SimpleLWJGLModel.groovy

 
import groovy.beans.Bindable
 
class SimpleLWJGLModel {
   @Bindable canvas = new SimpleCanvas()
}

SimpleLWJGLView.groovy

 
application(title:'SimpleLWJGL',
  size:[300,300],
  resizable:false,
  locationByPlatform:true,
  iconImage: imageIcon('/griffon-icon-48x48.png').image,
  iconImages: [imageIcon('/griffon-icon-48x48.png').image,
               imageIcon('/griffon-icon-32x32.png').image,
               imageIcon('/griffon-icon-16x16.png').image]
) {
    widget(model.canvas)
}

Drawing on our canvas

Here we draw a rotating quad.

 
import org.lwjgl.LWJGLException
import org.lwjgl.opengl.AWTGLCanvas
import org.lwjgl.opengl.Display
import org.lwjgl.opengl.GL11

public class SimpleCanvas extends AWTGLCanvas {
 
    float angle = 0
 
    public SimpleCanvas() throws LWJGLException {
      // Launch a thread to repaint the canvas 60 fps
      Thread.start{
          while (true) {
            if (isVisible()) {
              repaint()
            }
            Display.sync(60)
          }
      }
    }
 
    public void paintGL() {
	  GL11.with {
		  glClear(GL_COLOR_BUFFER_BIT)
		  glMatrixMode(GL_PROJECTION_MATRIX)
		  glLoadIdentity()
		  glOrtho(0, 640, 0, 480, 1, -1)
		  glMatrixMode(GL_MODELVIEW_MATRIX)
	 
		  glPushMatrix()
		  glTranslatef(320, 240, 0.0f)
		  glRotatef(angle, 0, 0, 1.0f)
		  glBegin(GL_QUADS)
		  glVertex2i(-50, -50)
		  glVertex2i(50, -50)
		  glVertex2i(50, 50)
		  glVertex2i(-50, 50)
		  glEnd()
		  glPopMatrix()
	  }
      angle += 1
 
      try {
        swapBuffers()
      } catch (Exception e) { }
    }   
}

One thing you might notice is that LWJGL requires a lot less setup than jME. Download the source here.

Griffon at The Strange Loop

I'm happy to report that my session entitled, "Griffon: Swing just got fun again" was accepted at The Strange Loop.

The Strange Loop is a developer conference taking place in St. Louis October 22nd and 23rd. The sessions are a nice mix of different technologies so it won't be hard to find something that interests you. Register by August 14th for half($75) of what it would you pay at the door.

Fellow Groovyists Hamley D'Arcy, Guillaume Laforge, and Jeff Brown will be presenting "Groovy Compiler Metaprogramming for Fun and Profit," "Groovy, to infinity and beyond!," and "Polyglot Web Development with Grails," respectively.

You can follow announcements from the conference on Twitter @strangeloop_stl or or on the website http://thestrangeloop.com.

Using jMonkeyEngine with Griffon

jMonkeyEngine is a scenegraph game engine with a vibrant community. It supports OpenGL functionality via LWJGL, sound via OpenAL, and keyboard/mouse/controller interactivity using JInput. In this post, we are going to embed a jME canvas in Griffon and draw a textured cube.

Getting started

  • Download LWJGL and drop the lwjgl.jar in your lib directory.
  • Find the native files for your operating system and extract them into lib/native
  • Download jME 2.0 Distribution. We aren't doing that much advanced stuff so we only need jme.jar, jinput.jar, and jme-awt.jar. Drop these into your lib directory.
  • Modify your Config.groovy file to contain the following:
    griffon {
            app {
                javaOpts = ["-Djava.library.path=${basedir}/lib/native"]
            }
             extensions {
                jarUrls = []
                jnlpUrls = ["lwjgl.jnlp"]
            }
        }
    
  • Add this jnlp file to griffon-app/conf/webstart: lwjgl.jnlp.
     
  • Switch the order in Application.groovy to the following:
        mvcGroups {
            '<Your app name>' {
                model = 'YOURAPP-Model'
                controller = 'YOURAPP-Controller'
                view = 'YOURAPP-View'            
            }
        }
    It's important that the controller be initialized before the view because the controller will initialize our canvas.

Linking our model and view

JmeSwingModel.groovy

import groovy.beans.Bindable

class JmeSwingModel {
   @Bindable canvas
   @Bindable impl
   @Bindable display
   int height = 640
   int width = 480
}

JmeSwingView.groovy

application(title:'Griffon jME Swing',
  pack:true,
  resizable:false,
  //location:[50,50],
  locationByPlatform:true,
  iconImage: imageIcon('/griffon-icon-48x48.png').image,
  iconImages: [imageIcon('/griffon-icon-48x48.png').image,
               imageIcon('/griffon-icon-32x32.png').image,
               imageIcon('/griffon-icon-16x16.png').image]
) {
    widget(model.canvas)
}

 Initializing our canvas

JmeSwingController.groovy

import com.jme.input.KeyInput
import java.awt.event.KeyListener
import com.jme.input.InputHandler
import com.jme.system.DisplaySystem
import com.jmex.awt.lwjgl.LWJGLCanvas
import com.jme.system.canvas.JMECanvas
import java.awt.event.ComponentListener
import com.jmex.awt.input.AWTMouseInput
import com.jme.system.lwjgl.LWJGLSystemProvider
import com.jme.system.canvas.JMECanvasImplementor
import com.jmex.awt.lwjgl.LWJGLAWTCanvasConstructor

class JmeSwingController {
    // these will be injected by Griffon
    def model
    def view

    void mvcGroupInit(Map args) {
		// make the canvas:
		model.display = DisplaySystem.getDisplaySystem(LWJGLSystemProvider.LWJGL_SYSTEM_IDENTIFIER);
		model.display.registerCanvasConstructor("AWT", LWJGLAWTCanvasConstructor.class);
		model.canvas = (LWJGLCanvas)model.display.createCanvas(model.width, model.height);
		model.canvas.setUpdateInput(true);
		model.canvas.setTargetRate(60);			
		
		// Setup key and mouse input
		KeyInput.setProvider(KeyInput.INPUT_AWT);
		KeyListener kl = (KeyListener) KeyInput.get();
		model.canvas.addKeyListener(kl);
		AWTMouseInput.setup(model.canvas, false);

		// Important! Here is where we add the guts to the panel:
		model.impl = new MyImplementor(model.width, model.height);
		model.canvas.setImplementor(model.impl);
		model.canvas.setBounds(0, 0, model.width, model.height);
    }
}

Drawing on our canvas

MyImplementor is bit of code that draws our world.

import com.jme.bounding.BoundingBox;
import com.jme.image.Texture;
import com.jme.input.InputHandler;
import com.jme.input.KeyInput;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Renderer;
import com.jme.scene.shape.Box;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.system.canvas.JMECanvas;
import com.jme.system.canvas.JMECanvasImplementor;
import com.jme.system.canvas.SimpleCanvasImpl;
import com.jme.system.lwjgl.LWJGLSystemProvider;
import com.jme.util.GameTaskQueueManager;
import com.jme.util.TextureManager;
import com.jmex.awt.input.AWTMouseInput;
import com.jmex.awt.lwjgl.LWJGLAWTCanvasConstructor;
import com.jmex.awt.lwjgl.LWJGLCanvas;

public class MyImplementor extends SimpleCanvasImpl {

        private Quaternion rotQuat;
        private float angle = 0;
        private Vector3f axis;
        private Box box;
        private InputHandler input;

        public MyImplementor(int width, int height) {
            super(width, height);
        }

        public void simpleSetup() {

            // Normal Scene setup stuff...
            rotQuat = new Quaternion();
            axis = new Vector3f(1, 1, 0.5f);
            axis.normalizeLocal();

            Vector3f max = new Vector3f(5, 5, 5);
            Vector3f min = new Vector3f(-5, -5, -5);

            box = new Box("Box", min, max);
            box.setModelBound(new BoundingBox());
            box.updateModelBound();
            box.setLocalTranslation(new Vector3f(0, 0, -10));
            box.setRenderQueueMode(Renderer.QUEUE_SKIP);
            rootNode.attachChild(box);

            box.setRandomColors();

            TextureState ts = renderer.createTextureState();
            ts.setEnabled(true);
            ts.setTexture(TextureManager.loadTexture(this.getClass().getClassLoader().getResource(
                            "Monkey.jpg"),
                    Texture.MinificationFilter.BilinearNearestMipMap,
                    Texture.MagnificationFilter.Bilinear));

            rootNode.setRenderState(ts);

            input = new InputHandler();
        }

        public void simpleUpdate() {
            input.update(tpf);

            // Code for rotating the box... no surprises here.
            if (tpf < 1) {
                angle = angle + (tpf * 25);
                if (angle > 360) {
                    angle = 0;
                }
            }
            rotQuat.fromAngleNormalAxis(angle * FastMath.DEG_TO_RAD, axis);
            box.setLocalRotation(rotQuat);

        }
    }

 Download the source here

Using Processing with Griffon

Processing is a great graphics language that reminds me alot of old-school BASIC/turtle graphics. It's built on top of Java so it's only natural that we'd eventually try it with Griffon.

Getting Started

  • Download processing from http://processing.org/download.
  • Regardless of your operating system, grab the Windows version WITHOUT Java.
  • Find the core.jar file and drop it in the lib directory of your project.

Extend PApplet

The following is a slightly tweaked example from processingjs.org
 

import processing.core.*;

public class Embedded extends PApplet {
// Global variables

    float radius = 50.0f;
    int X, Y;
    int nX, nY;
    int delay = 16;

// Setup the Processing Canvas
    void setup() {
        size(400, 400);
        strokeWeight(10);
        frameRate(15);
        X = width / 2;
        Y = width / 2;
        nX = X;
        nY = Y;
    }

// Main draw loop
    void draw() {

        radius = radius + sin((float) (frameCount / 4));

        // Track circle to new destination
        X += (nX - X) / delay;
        Y += (nY - Y) / delay;

        // Fill canvas grey
        background(100);

        // Set fill-color to blue
        fill(0, 121, 184);

        // Set stroke-color white
        stroke(255);

        // Draw circle
        ellipse(X, Y, radius, radius);
    }

// Set circle's next destination
    void mouseMoved() {
        nX = mouseX;
        nY = mouseY;
    }
}

Linking your view and model to Processing

Proce55ingModel.groovy

import groovy.beans.Bindable
import processing.core.PApplet

class Proce55ingModel {
   @Bindable pApplet = new Embedded()
}

Proce55ingView.groovy

application(title:'Proce55ing',
  size:[400,400],
  //location:[50,50],
  locationByPlatform:true,
  iconImage: imageIcon('/griffon-icon-48x48.png').image,
  iconImages: [imageIcon('/griffon-icon-48x48.png').image,
               imageIcon('/griffon-icon-32x32.png').image,
               imageIcon('/griffon-icon-16x16.png').image]
) {
    widget(model.pApplet)
}

Final touches

Proce55ingController.groovy

class Proce55ingController {
    // these will be injected by Griffon
    def model
    def view

    void mvcGroupInit(Map args) {	
        // ensures animation is started and that vars properly set
        model.pApplet.init()
		
    }
    /*
    def action = { evt = null ->
    }
    */
}

Screenshot of pulsing circles.

Because it is very procedural like OpenGL, a builder might be improbable.

Groovy's duck-typing and the fact that Processing uses floats for its non-integral numeric type means that some values will need to be cast. With a few casts, you can use any of the examples on processingjs.org

Download the source code here.