Scala + LWJGL + AWT = Resizable OpenGL Window

September 28, 2011

Following up on my previous post, I played around a bit more with Scala and LWJGL. What bothered me is that the standard examples for LWJGL and Scala had no resizable windows. But this is no more the case! It took me a bit to figure out how to translate various bloated Java examples to Scala but I am happy with the result.

Here is the code (btw.: does someone know how to make WP-Syntax a bit nicer looking?):

/**
 * Example program to get a resizable window using LWJGL + AWT in Scala.
 *
 * This code is public domain. Feel free to use it for anything you like.
 */
package org.fysx.lwjgltools
 
import java.awt._
import java.awt.event.{ComponentEvent, ComponentAdapter, WindowAdapter, WindowEvent}
import java.util.concurrent.atomic.{AtomicReference, AtomicBoolean}
 
import org.lwjgl._
import opengl.{Display,GL11,DisplayMode}
import GL11._
import input._
import math._
import org.lwjgl.opengl.AWTGLCanvas
 
class LWJGLFrame(text: String) extends Frame(text) {
  // tells us whether the screen was resized
  var resized = new AtomicBoolean()
  // the canvas on which the OpenGL context will be drawn
  var canvas = new Canvas()
  // this will store the new size after a resize
  var newCanvasSize = new AtomicReference[Dimension]
  // will be true if we received a window close request
  var closeRequested = false
  // used when resizing
  var newDim = new Dimension()
  // used for some animation
  var c = 0.0f
  var delta_c = 0.01f
 
  // added constructor in case we did not specify a String to LWJGLFrame()
  def this() {
    this("")
  }
 
  // add listener to the resize event
  canvas.addComponentListener (new ComponentAdapter() {
    override def componentResized(e: ComponentEvent) = {
//      println ("new size")
      newCanvasSize.set(canvas.getSize())
    }
  })
 
  // add the canvas our LWJGLFrame
  add(canvas, BorderLayout.CENTER)
 
  // add listener to the window close event
  addWindowListener(new WindowAdapter() {
    override def windowClosing (e: WindowEvent) = {
//      println ("close requested")
      closeRequested = true
    }
  })
 
  // adjust OpenGL context for change of the window size
  def resize() {
    newDim = newCanvasSize.getAndSet(null)
 
    if ( newDim != null ) {
//      println ("updating viewport")
      GL11.glViewport(0, 0, newDim.width, newDim.height)
    }
  }
 
  // perform the actual drawing
  def render() {
    c = c + delta_c
    if (c > 1.0f || c < 0.0f) delta_c = delta_c * -1.f
 
    GL11.glClearColor (0, 0, 0, 0)
    GL11.glClear(GL11.GL_COLOR_BUFFER_BIT)
 
    glColor3f (1.0f, 1.0f, 1.0f)
    glBegin(GL_TRIANGLES)
    glColor3f (0.25f, 1-c, 0.25f)
    glVertex3f (-0.5f, -0.75f, 0.0f)
    glColor3f (0.5f, 0.25f, 1.0f-c)
    glVertex3f (0.5f, -0.75f, 0.0f)
    glColor3f (c, 0.5f, 0.25f)
    glVertex3f (0.f, 0.75f, 0.0f)
    glEnd
  }
 
  // handle keyboard and other events
  def logic() {
    import Keyboard._
 
    if (isKeyDown(KEY_I)) println ("Key I was pressed!")
  }
 
  // starts the OpenGL loop
  def run() {
//    println ("executing run()")
    try {
      // setup of the Display (connect it to the canvas)
      Display.setParent(canvas)
      try {
        Display.create()
      } catch {
        case e: LWJGLException => {
          e.printStackTrace()
          println (e.getMessage())
        }
      }
 
      Display.setVSyncEnabled(true)
 
      // the actual main loop
      while (!Display.isCloseRequested() && !closeRequested) {
        resize()
        Display.update()
 
        logic()
 
        render()
 
        Display.sync(60)
      }
 
      // we're done so we have to destroy the Display
      Display.destroy()
    }
  }
}
 
object Main {
  // actual entry point of the program
  def main(args: Array[String]) {
    var lwjglframe = new LWJGLFrame ("Scala + LWJGL + AWT = resizable window")
 
    lwjglframe.setMinimumSize(new Dimension(320, 240))
    lwjglframe.setSize(new Dimension(640, 480))
    lwjglframe.setVisible(true)
 
    lwjglframe.run()
 
    lwjglframe.dispose()
  }
}