Wednesday, June 23, 2010

JLaunch + Sgine

As I mentioned in my previous post I've been working on a simplified deployment system for Java applications and I've made some pretty good strides. To that end I wanted to share my current progress by finally posting a working applet here to show:



Using a bit of JavaScript the applet will launch when you click on the static image. This is still a very early version, but my goal is to release JLaunch as an open-source project that provides a wizard to simplify creating deployments. The system currently supports two methods of launching. The first is a static void main(args) method that it invokes that gives over complete control to display a new Frame or whatever it is configured to do. The second is the referenced class providing a "createCanvas" method that returns a java.awt.Canvas instead that gets put into the applet for you upon instantiation. The latter instance is what is being used in the above example and is implemented by default in StandardDisplay, so any classes that extend that don't even have to think about it.

For example, see the code for the TestImage class being used:

package org.sgine.ui

import org.sgine.core.Resource

import org.sgine.render.Debug
import org.sgine.render.StandardDisplay

object TestImage extends StandardDisplay with Debug {
 def setup() = {
  val component = new Image(Resource("puppies.jpg"))
  scene += component
 }
}

I also inherit Debug which disables vertical-sync and shows the framerate in the top-left of the screen. To sum up, the above two lines of logic can be launched as an application (since StandardDisplay provides a main method that is inherited) or as an applet via JLaunch. Pretty awesome huh? :)

One last noteworthy item is that the jlaunch.jar is 14kb and the pack200 version is a total of 5kb. This, I believe, is a good representation of what the startup time of applets should be.

Wednesday, June 16, 2010

Layout Management

For any UI application layout management is an absolute essential. In 3D game development I have yet to see any sort of layout management and though I can think of a few uses they are pretty few and far between. However, with the goals of Sgine to provide both a 3D UI as well as a full scenegraph infrastructure layout management is a very important thing.

What's particularly cool about layout management in Sgine is that it's not just for UI elements and it's not just for vertical and horizontal. That's right, you can use layout managers to lay out 3D objects in 3D space.

The layout management infrastructure is now in place, but still has a long way to go to provide a full set of advanced layout techniques. For now, here's a simple example laying out two Buttons:

package org.sgine.ui

import org.sgine.core.Direction

import org.sgine.render.StandardDisplay

import org.sgine.ui.layout.BoxLayout

object TestLayout extends StandardDisplay {
 def setup() = {
  val container = new LayoutContainer()
  container.layout := BoxLayout(Direction.Vertical, 10)
  container += new Button("Test Button 1")
  container += new Button("Test Button 2")
  scene += container
 }
}

What do you get for those five lines of logic? This:



You are not required to specify the layout as it will default to BoxLayout(Direction.Vertical, 0), but in order to show how easy configuring the layout function I decided to show a custom example. Custom layout functions can be provided that simply follow: Function1[NodeContainer, Unit].

Tuesday, June 15, 2010

Concise and Powerful

One of my biggest complaints and one of the things I've been criticized about most is my hatred for the complexities of using the majority of 3D engines today. To this end I've strived in Sgine to provide a much more simplistic and concise engine without sacrificing the power you would expect from a 3D engine.

When I was a developer on the jME (http://www.jmonkeyengine.com) project it is what led me to write "StandardGame" as far too commonly developers would end up with basically the same "Game" implementation for all their games, but it either consisted of a lot of copy and paste from other projects or a lot of re-writing the same code each time a new project was created.

If you look at previous posts the code has always been moderately simple and no more than a dozen or so lines of code to accomplish a basic task. However, I still had visions for improving further.

Perhaps I've gone a bit overboard in my agenda to simplify, but I've created a new trait in Sgine called "StandardDisplay" that is the spiritual successor to the ideas I put forth in jME years before. With Scala and Sgine a lot of possibilities for simplification have been opened up that were never possible before, such as putting the main method in a trait so it need not be explicitly defined. Further, one of the big problems with JRE applications today is deployment. Whether you want an Applet, a WebStart application, a desktop application, or all three it is a great deal of pain to get the end result you want. One of the goals of StandardDisplay is to be able to simply extend and execute in any display model you desire. Couple this with the idea of a deployment generation system I have yet to write and deployment of applications can be a simple afterthought instead of a major headache holding you back from getting your projects out.

Okay, I've droned on long enough without some actual code to show. If you've read this blog from the beginning you'll remember the very first post I made with an actual example with the following code to display an image of my dogs:

package org.sgine.render

import org.sgine.math.Matrix4

import javax.imageio._

import org.lwjgl.opengl.GL11._

object TestRenderer {
 def main(args: Array[String]): Unit = {
  val r = Renderer.createFrame(1024, 768, "Test Renderer")
  
  val t = new Texture(700, 366)
  TextureUtil(t, ImageIO.read(getClass.getClassLoader.getResource("resource/puppies.jpg")), 0, 0, 700, 366)
  
  val m = Matrix4().translate(z = -1000.0)
  val i = Image(t)
  val fps = FPS(1.0)
  
  r.renderable := RenderList(MatrixState(m) :: i :: fps :: Nil)
  
  println("Renderer started!")
 }
}

That concept has firmed up a lot since then with the scenegraph system and the UI package to more recently look like:

package org.sgine.ui

import org.sgine.core.Resource

import org.sgine.render.Renderer
import org.sgine.render.scene.RenderableScene

import org.sgine.scene.GeneralNodeContainer
import org.sgine.scene.ext.ResolutionNode

object TestImage {
 def main(args: Array[String]): Unit = {
  val r = Renderer.createFrame(1024, 768, "Test RenderScene")
  
  val scene = new GeneralNodeContainer() with ResolutionNode
  scene.setResolution(1024, 768)
  
  val component = new Image()
  component.source := Resource("puppies.jpg")
  scene += component
  
  r.renderable := RenderableScene(scene)
 }
}

Though much more concise and simplified I still was not satisfied. After all, I just wanted to display a picture of my puppies on the screen. Enter StandardDisplay:

package org.sgine.ui

import org.sgine.core.Resource

import org.sgine.render.StandardDisplay

object TestImage extends StandardDisplay {
 def setup() = {
  val component = new Image(Resource("puppies.jpg"))
  scene += component
 }
}

That's right, two lines of actual logic code to display an Image with puppies. Yes, this technically could have been reduced to a single line, but the goal was concise, not showing how I used to write code in Perl. ;)

This can be executed as an application since StandardDisplay trait contains a "main" method that calls "start" and the only requirement is that a "setup" method be implemented. You can go much further than this if desired to customize and configure how and what you want to display but this is all that is required to get going.

There is still a lot of work to be done to support Applets, WebStart, etc. but the core is functional and pretty impressive if I do say so myself. :)

Sunday, June 13, 2010

MediaPlayer Component

Getting JMC from JavaFX 1.3 to work within Sgine took a bit longer than I anticipated. In JavaFX 1.2 it was a simple matter of calling paintVideoFrame and using a BufferedImage to draw onto and then convert to a texture. Fortunately for performance in JavaFX 1.3 they changed to working with NIO buffers instead, but unfortunately that created a much bigger headache trying to figure out how to access and properly use it since there is absolutely no documentation and the source code is not freely available. However, after several days of poking around it has finally paid off. There are still some optimizations that should be done but on my machine I'm able to watch H.264 video at 4,000fps in synchronous mode (direct rendering in OpenGL) and 5,200fps in asynchronous mode (pushing data to the buffer in another thread via PBO).

Here's a screenshot of the working example:


Here's the source required to run the video:
package org.sgine.ui

import org.sgine.core.Resource

import org.sgine.render.Renderer
import org.sgine.render.scene.RenderableScene

import org.sgine.scene.GeneralNodeContainer
import org.sgine.scene.ext.ResolutionNode

object TestMediaPlayer {
 def main(args: Array[String]): Unit = {
  val r = Renderer.createFrame(640, 480, "Test MediaPlayer")
  
  val scene = new GeneralNodeContainer() with ResolutionNode
  scene.setResolution(640, 480)
  
  val component = new MediaPlayer()
  val url = new java.net.URL("http://sun.edgeboss.net/download/sun/media/1460825906/1460825906_2956241001_big-buck-bunny-640x360.flv")
  component.source := Resource(url)
  scene += component
  
  r.renderable := RenderableScene(scene)
  
  component.play()
 }
}

As always the goal is to keep the API as simple as possible and hopefully 27 total lines of code is simplistic enough. :)

There's still much left to do as far as introspection and control of video playing as well as controls to allow user interaction with the player, but we've finally got a fast and reliable means of playing all popular audio and video formats and I will probably divert back to more important work for a while. :)

Wednesday, June 9, 2010

Video Player

I've been pretty busy lately and haven't had time to work on Sgine as much as I'd liked, so I figured I needed to have something pretty awesome to show for my next post. Hopefully video playing is still considered awesome as that's the best I could do.

I'm leveraging the JMC system that JavaFX uses for video playing and integrating it to render directly to LWJGL.

It's not really ready for prime-time as I've got a lot of things still to do to increase the framerate and integrate it as an actual component, but for now I have a screenshot with the promise of more to come soon:

Scala Engine for high-performance interactive applications.