GLIMGUI released

March 26, 2014

Ages ago I wrote a nice article about how I searched for a simple GUI system for a game that I was working at the time. I ended up writing my own GUI system that was using the IMGUI approach and I am still very happy with this. It indirectly inspired @the_vrld to create Quickie which is an IMGUI system for my favourite 2D game framework LÖVE.

In the article I had written that I plan to release a simple library that can be used as a starting point for more advanced IMGUI explorations. Turns out I never did publish it so here we go:

Grab the code from: https://bitbucket.org/MartinFelis/glimgui.

It is licensed under the MIT license and as said very basic but with ~500 lines it should also be very easy to adjust and extend it. It is written in plain C and only depends on OpenGL and glut. Only ASCII strings are supported but if you have a fully featured unicode rendering function available it should be very easy to plug it in (look at glimgui_printxy(float x, float y, const char str*, ...)).

Here are some screenshots (very basic but easy-peasy to pimp): main_menu options

And here the full source code for the UI including the button logic that was used for the screenshots:

void draw_ui () {
  glimgui_prepare ();

  // Drawing of the GUI

  // We have two GUIs that are indicated by the global gui_layout value
  if (gui_layout == 0) {
    glimgui_label (99, "Main Menu", 20, 20, 1, 1); 

    if (glimgui_button (1, "Some Button", 220, 100, 180, 50)) {
      printf ("Some Button was pressed!\n");
    }

    if (glimgui_button (2, "Options", 220, 180, 180, 50)) {
      glimgui_clear();
      gui_layout = 1;
      printf ("Switching to Options!\n");
    }

    if (glimgui_button (3, "Quit", 220, 380, 180, 50)) {
      printf ("Quit!\n");
      glutDestroyWindow(window_id);
    }
  } else {
    glimgui_label (99, "Options", 20, 20, 1, 1); 

    if (glimgui_button (1, "Some Other Button", 220, 100, 180, 50)) {
      printf ("Some Other Button was pressed!\n");
    }

    glimgui_label (98, "Enter your name:", 150, 180, 1, 50);

    static char name[32] = { "IMGUI fan\0" };

    if (glimgui_lineedit (2, name, 16, 290, 195, -1, 20)) {
      printf ("Changed name value: '%s'\n", name);
    }

    glimgui_label (97, "Enter your age:", 150, 210, 1, 50);

    static char age[32] = { "99\0" };

    if (glimgui_lineedit (3, age, 3, 290, 225, -1, 20)) {
      printf ("Changed age value: '%s'\n", age);
    }

    if (glimgui_button (4, "Back", 220, 380, 180, 50)) {
      printf ("Switching back!\n");
      glimgui_clear();
      gui_layout = 0;
    }
  }

  glimgui_finish ();
}

Nice, ey?

Tags

MeshUp!

January 11, 2012

Last week I started working on a small, yet powerful visualization tool for animations or more generally spoken for any multi-body simulations. It is based on skeletal animation and magic and is called MeshUp!.

The frames for the skeleton are defined in a JSON file (thanks to jsoncpp this was relatively easy to implement). In the same file meshes can be attached to the frames (e.g. some random monkey head to the “Head” frame, etc.) and are then moved with the head bone.

The meshes themselves are Wavefront OBJ files that can be exported by nearly every 3d content creation package. I wrote the importer in about 2 hours which surprised me. I feared that to be a lot more of a hassle.

Furthermore it finally made me play around with Quaternions a bit more. Turns out that they are not as hard and are actually quite efficient. Before that I used some matrix calculations for the rotations but with the Quaternions I basically have the same usage but about 10% performance gain (not that it would matter, but it surprised me a little). The biggest problems I had, was that in my computer animation reference book a formula for a conversion had a typo. Thanks to test driven development this was easy to debug and will not occur in the future! Yay!

Oh, also it is coordinate system agnostic. Meaning you can use whatever angle convention you like! ZYX Euler? Sure! YZX Euler? Why not? Just define the proper coordinate system and rotation order in the model file and that’s it!

I published MeshUp! at bitbucket account. You can download the source at:

https://bitbucket.org/MartinFelis/meshup

So far I havent’t decided on a license. Any suggestions?

 

Tags

OpenGL is dead! Long live OpenGL! (a.k.a. IFTPOP 0.0.2a)

November 20, 2011

I think finally tracked the error that made the game crash on some computers. The culprit is OpenGL, more specifically OpenGL 1.X. Since the introduction of OpenGL 2.0 in 2004 there have been a few changes in the way how to do graphics (“it’s called shader baby!”). As my current reference of OpenGL (the OpenGL Super Bible, 5th ed.) tries to break free from the old legacy code (“fixed function pipeline”) I ended up being dependent on this new stuff.

Sorry about that. But if it does not run, you probably should get a new computer anyways.

At least some good news: errors are now nicely reported with a message box. Should your graphics card be incompatible, you will beinformed properly.

Get it from here: iftpop_0.0.2a

A new version with better graphics (OpenGL 2.X!) is coming along as I now finally fixed this error.

Tags

Custom Shaders and Material in Horde3D

November 15, 2011

To simplify scene management and visual effects I looked at various open-source graphic engines that I might use. I briefly looked at the usual suspects such as Ogre3D and Irrlicht until I found Horde3D, which convinced me by its simple looking API and the compiled library was much smaller than of the others. It also seemed to feature various capabilities that might be interesting (scene graph, shadow mapping) or nice to have things (picking, blur, hdr, etc.).

However being an old-school OpenGL programmer, that mostly draws simple geometries such as cubes, spheres, and similar, it is not quite the way I am used to do stuff. Furthermore, the shaders in the examples seemed much more advanced than I need for now, so I am currently trying to make things more basic. Eventually I want to use the scene graph to do some procedural animation and that I am going to do with these simple geometries. Using more sophisticated models created with blender should not be too hard once I got it running.

So far I incorporated Horde3D to my code and using assets from the example to get some experience with Horde3D and implemented a simple shader. As I had the OpenGL Superbible laying around I thought it would be nice to implement the good old Ambient-Diffuse-Specular lighting model (so far only on a per-vertex basis).

Here are some screenshots of the different steps I took:

Now I can easily specify the material in the XML-files that Horde3D is using. Also, I learned a great deal about Horde3D.

Hopefully I’ll soon be able to draw simple procedurally generated geometries and can then start to look at the animations.

Tags

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()
  }
}

Tags

Scala + LWJGL = Running Program

September 22, 2011

scala + lwjglI thought I would try to get the Lightweight Java Game Library (LWJGL) running in Scala as both are really hip nowadays. Turns out that there is not much available on teh internets that works. Most of them use the “Simple Build Tool” (sbt) which I did not find simple at all. Also they have a new version 0.10.x which is incompatible to the Scala+LWJGL examples which use sbt version 0.7.x. Yay!

Anyhow, I used the Scala code from http://lwjgl.org/forum/index.php?topic=3416.0 and finally managed to get it run without any “simple” tools or other dependencies. Here is how:

  1. Download the current LWJGL release (as of writing: 2.7.1). This should give you a zip file with a few jars, dlls and so files.
  2. Download and install Scala from http://www.scala-lang.org/ (as of writing: 2.9.1)
  3. Create the folders “lwjglproject/lib” and “lwjglproject/src”
  4. Extract all .jars to “lwjglproject/lib”. When using Windows do so with the dlls, on Linux put the .so files there and Mac users probably don’t have to do anything (that’s what I’m always being told)
  5. Create a source file “lwjglproject/src/lwjgl.scala” with contents from the example (also available further down)
  6. Compile the code with
    scalac -classpath ./lib/lwjgl.jar src/lwjgl.scala

    this should  give you some .class files

  7. Run the example by executing
    scala -classpath lib/lwjgl.jar -Djava.library.path=./lib Main
  8. Enjoy

Oh, and if you want to run the program directly with java to have to specify the path to scala-library.jar and add the (current) “lwjglproject” path to the classpath:

java -classpath .:lib/lwjgl.jar:/lib/scala-library.jar -Djava.library.path=./lib Main

Here is the code for the example:

import org.lwjgl._
import opengl.{Display,GL11,DisplayMode}
import GL11._
import input._
import math._
 
object Main{
	val GAME_TITLE = "My Game"
	val FRAMERATE = 60
	val width = 640
	val height = 480
 
	val player = new Player(0,0,0);
 
	var finished = false
	var angle = 0.0f
	var rotation = 0.0f
 
	def main(args:Array[String]){
		var fullscreen = false
		for(arg <- args){
			arg match{
				case "-fullscreen" =>
					fullscreen = true
			}
		}
 
		init(fullscreen)
		run
	}
 
	def init(fullscreen:Boolean){
 
		println("init Display")
		Display.setTitle(GAME_TITLE)
		Display.setFullscreen(fullscreen)
		Display.setVSyncEnabled(true)
		Display.setDisplayMode(new DisplayMode(width,height))
		Display.create
 
		println("init gl")
		glEnable(GL_DEPTH_TEST);
		glEnable(GL_LIGHTING)
		glEnable(GL_LIGHT0)
		adjustcam
	}
 
	def adjustcam(){
		val v = Display.getDisplayMode.getWidth.toFloat/Display.getDisplayMode.getHeight.toFloat
		printf("v:%f",v)
		glMatrixMode(GL_PROJECTION)
		glLoadIdentity
		glFrustum(-v,v,-1,1,1,100)
		glMatrixMode(GL_MODELVIEW)
	}
 
	def cleanup(){
		Display.destroy
	}
 
	def run(){
		while(!finished){
			Display.update
 
			logic
			render
 
			Display.sync(FRAMERATE)
		}
	}
 
	def logic(){
	    // in scala we can locally import all methods from Keyboard.
	    import Keyboard._
 
		if(isKeyDown(KEY_ESCAPE))
			finished = true
		if(Display.isCloseRequested)
			finished = true
 
		// rx and rx store our keyboard input as direction  
		var ry = 0
		var rx = 0
 
		// keys are IKJL for up down left right
 
		if(isKeyDown(KEY_I))
			ry += 1
		if(isKeyDown(KEY_K))
			ry -= 1
		if(isKeyDown(KEY_J))
			rx -= 1
		if(isKeyDown(KEY_L))
			rx += 1
 
		// this makes the direction relative to the camera position
		// it is a simple rotation matrix you may know from linear algebra
		val ax = rx*cos(-rotation.toRadians)-ry*sin(-rotation.toRadians)
		val ay = rx*sin(-rotation.toRadians)+ry*cos(-rotation.toRadians)
 
		player.x += 0.1f*ax.toFloat
		player.y += 0.1f*ay.toFloat
 
		// this rotates our camera around the center
		angle += 2.0f % 360
		rotation += 0.2f
	}
 
	def renderGrid(size : Int){
	    // this creates the nice looking background.
		glDisable(GL_LIGHTING)
		glBegin(GL_LINES)
		for(i <- -size to size){
			glVertex2i(i,-size)
			glVertex2i(i, size)
			glVertex2i(-size,i)
			glVertex2i( size,i)
		}
		glEnd
		glEnable(GL_LIGHTING)
	}
 
	def render(){
		glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glLoadIdentity
 
		glTranslatef(0,0,-20)
		glRotatef(-70,1,0,0)
		glRotatef(rotation,0,0,1)
 
		glPushMatrix
		player.applyPos
		//rotate the player just for fun
		glRotatef(angle, 0, 0, 1.0f)
		player.draw
		glPopMatrix
 
		//without background, motion is not visible
		// a green grid is nice and retro
		glColor3f(0,1,0)
		renderGrid(10000)
	}
}
 
class Player(nx:Float,ny:Float,nz:Float){
	var x:Float = nx
	var y:Float = ny
	var z:Float = nz
 
	def applyPos {
	    glTranslatef(x,y,z)
	}
 
	def draw = {
		glColor3f(1, 0, 0)
		glBegin(GL_TRIANGLE_FAN)
		glNormal3d( 0, 0, 1);	glVertex3d(0,0,0.5)
		glNormal3d(-1,-1, 1);	glVertex2d(-0.5, -0.5)
		glNormal3d( 1,-1, 1);	glVertex2d(0.5, -0.5)
		glNormal3d( 1, 1, 1);	glVertex2d(0.5, 0.5)
		glNormal3d(-1, 1, 1);	glVertex2d(-0.5, 0.5)
		glNormal3d(-1,-1, 1);	glVertex2d(-0.5, -0.5)
		glEnd
	}
}

Tags