Saturday, July 16, 2011

More Concise and More Powerful

Over a year ago I posted about the focus of Sgine to be extremely concise in creating 3d applications. I've always found it annoying that the barrier to entry writing 3d applications of any sort if overly complicated. I started Sgine with the belief that an engine could be created that abstracts without reducing the power of the system. Scala has been instrumental in making this possible.

Now, the point of this post is to announce that I'm finally back to the UI abstraction layer again. After nearly a year of re-architecting and adding new foundational concepts I'm finally back to the high-level abstraction that is the magic of Sgine.

In the post I mentioned above I was showing off just how concisely you can display an image in Sgine:

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

My goal in this re-write was to keep at least as concise as 0.1 and hopefully achieve something even better. I do believe I have accomplished something even more concise in the current iteration of development with only a single line of logic to display an image on the screen:

package org.sgine.ui

object ImageTest extends UI {
  this += Image("sgine.png")
}

There may be some slight revisions to this (ex. I'm considering extracting the base container out into a variable name "container" instead of mixing it into UI), but I honestly don't see any way I can make it any more concise than that. :)

For those of you that love pictures, here's the screenshot of what's displayed:



There hasn't been a lot of chatter on here lately, but now that I'm back on the UI abstraction layer there will be a lot more to see, so check back often.

Sunday, June 12, 2011

Sgine + VLC = Awesomeness

I have long been interested in being able to play video in OpenGL and if you look back at previous posts I've made here, as well as posts at matthicks.com you'll see most of my previous work has been around the use of JMC (one of the only cool things to come out of JavaFX 1.x). However, it had significant problems playing specific kinds of videos and was just generally buggy. In this new remix of Sgine I'm adding a new project that provides complete support for VLC through the use of the VLCJ project.

Here are a couple screenshots taken in my testing using "Better Off Ted":





Still very preliminary, but both sound and video are displaying flawlessly on the screen. The great features of VLC include the ability to play practically any video file or stream, record from a webcam, watch DVDs, play audio, and even record the desktop. This will open the door for lots of useful non-game applications utilizing Sgine I hope.

It will probably be a while before I commit this new project as I still have a lot of tweaking and customization to do before it's ready. Additionally, this will likely rely on the still undefined scenegraph model for this iteration so check back frequently as there's much more to come.

Friday, June 3, 2011

NeHe Tutorials

In an effort to validate and test the functionality of the OpenGL Generator and derived implementations I have started porting the NeHe tutorials over to Sgine. If you aren't familiar with the NeHe tutorials they are a great resource to learn the fundamentals of OpenGL. I recently finished porting the first chunk to Sgine and wanted to post pictures and links to source. I start here with Lesson 2 since Lesson 1 is all setup and doesn't really apply to what I'm trying to show.



Lesson 02



Sgine Source code




Lesson 03



Sgine Source code




Lesson 04



Sgine Source code




Lesson 05



Sgine Source code



I'm not sure how many more of the NeHe tutorials I'll port as they require a lot of boiler plate to properly represent the OpenGL aspects of the code and my main goal with Sgine is to minimize boiler plate and complexity. However, this does serve as a good test base for OpenGL functionality on both desktop and Android device.

I am currently in the process of defining a good texturing / image abstraction layer for the rendering paradigm and will likely be posting about that in the near future.

Sunday, May 29, 2011

Reloaded

Yes, it has been quite a while since the last post, but Sgine is anything but inactive. Pretty soon after that last post a decision was made to add support for Android to the core architecture of Sgine. As you might imagine this was no small undertaking and required some massive changes. So here we are several months later and Sgine has been re-designed from the ground up and I wanted to take a minute to discuss some of those changes.

First, there is a new OpenGL abstraction layer. No, this isn't abstracting you from the details of OpenGL, but rather the OpenGL implementation. Obviously there's a great reason for this decision, and here's where we come back to our inclusion of Android. Android uses OpenGL ES and LWJGL (our desktop rendering platform) uses standard OpenGL. Now, in order to write applications that will run on the desktop and on Android we need a point of convergence to build from and that point is OpenGL. Unfortunately though they are incredibly similar, they are still very different in many ways. This required a unification layer and ultimately a code generator to dynamically link between Android GLES and LWJGL. I'd love to say at this point it's 100% finished, but honestly I expect there's still going to be modifications happening to this layer for a while.

The result of this work is the ability to import org.sgine.opengl.GL._ and get access to a consistent OpenGL layer that will work on desktop and handheld alike. What does this look like? Well, quite simple really. The following is a recreation of Lesson 2 of the NeHe tutorial in Sgine:
class Lesson02 extends GLDisplay {
  private val triangleVertices = Array(0.0f, 1.0f, 0.0f,
                                       -1.0f, -1.0f, 0.0f,
                                       1.0f, -1.0f, 0.0f)
  private var triangleVertexBuffer: FloatBuffer = _

  private val quadVertices = Array(-1.0f, -1.0f, 0.0f,
                                   1.0f, -1.0f, 0.0f,
                                   -1.0f, 1.0f, 0.0f,
                                   1.0f, 1.0f, 0.0f)
  private var quadVertexBuffer: FloatBuffer = _

  def create() = {
    glShadeModel(GL_SMOOTH)
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f)
    glClearDepth(1.0f)
    glEnable(GL_DEPTH_TEST)
    glDepthFunc(GL_LEQUAL)

    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()

    // Create Triangle
    var bb = ByteBuffer.allocateDirect(triangleVertices.length * 4)
    bb.order(ByteOrder.nativeOrder())
    triangleVertexBuffer = bb.asFloatBuffer()
    triangleVertexBuffer.put(triangleVertices)
    triangleVertexBuffer.position(0)

    // Create Quad
    bb = ByteBuffer.allocateDirect(quadVertices.length * 4)
    bb.order(ByteOrder.nativeOrder())
    quadVertexBuffer = bb.asFloatBuffer()
    quadVertexBuffer.put(quadVertices)
    quadVertexBuffer.position(0)
  }

  def resize(width: Int, height: Int) = {
    glViewport(0, 0, width, height)

    gluPerspective(45.0f, width.toFloat / height.toFloat, 0.1f, 100.0f)

    glMatrixMode(GL_MODELVIEW)
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
  }

  def render() = {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glLoadIdentity()
    glTranslatef(-1.5f, 0.0f, -6.0f)

    glVertexPointer(3, GL_FLOAT, 0, triangleVertexBuffer)
    glEnableClientState(GL_VERTEX_ARRAY)
    glDrawArrays(GL_TRIANGLE_STRIP, 0, triangleVertices.length / 3)
    glDisableClientState(GL_VERTEX_ARRAY)

    glTranslatef(3.0f, 0.0f, 0.0f)
    glVertexPointer(3, GL_FLOAT, 0, quadVertexBuffer)
    glEnableClientState(GL_VERTEX_ARRAY)
    glDrawArrays(GL_TRIANGLE_STRIP, 0, quadVertices.length / 3)
    glDisableClientState(GL_VERTEX_ARRAY)
  }
}

object Lesson02 {
  def main(args: Array[String]): Unit = {
    val lesson02 = new Lesson02()
    val controller = LWJGLController(lesson02, 1024, 768, "NeHe Lesson 02")
  }
}

As you can see from the original tutorial the OpenGL code is surprisingly similar. It would have been almost identical if GLES supported fixed function pipeline (old-school GL).

Hopefully in the near future many more of the NeHe tutorials will be ported to Sgine as examples of how to do OpenGL coding using Sgine, but this is a good start. If you want to see the current status check out the org.sgine.opengl.nehe project.

This leads to the next major change in Sgine. The framework / engine was becoming too large for a single project and thanks to the awesomeness that is SBT (Simple Build Tool) the project has now been split into a multi-project that is built and published individually and with better dependency separation. This will allow projects to take advantages of parts of Sgine without having to utilize the entire framework.

Now, as might be obvious from previous posts I've made, I'm a big fan of simplicity and smaller more concise blocks of code. The above snippet for Lesson 2 had two major flaws:
  1. The number of lines of code is incredibly high to draw a triangle and quad to the screen.
  2. Having to directly use OpenGL seems incredibly tedious when you need to do even something as simple as drawing a triangle and quad to the screen.

This leads to the next layer of abstraction in Sgine. We now have a render abstraction that hides the details of the rendering platform to the developer. This means we can both plug in a different rendering platform later (can you say ray-tracing?) as well as reduce the complexity of standard rendering tasks in a well defined object oriented structure.

The following code is Lesson 2 using the new rendering framework:
object RendererTest extends RenderApplication {
  private val triangleMatrix = Matrix4.Identity.translate(x = -1.5, z = -6.0)
  private val triangleShape = Shape(Vertices.triangle())
  private val quadMatrix = Matrix4.Identity.translate(x = 1.5, z = -6.0)
  private val quadShape = Shape(Vertices.quad())

  def update() = {
  }

  def render() = {
    renderer.loadMatrix(triangleMatrix)
    triangleShape.render()
    renderer.loadMatrix(quadMatrix)
    quadShape.render()
  }

  def dispose() = {
    triangleShape.dispose()
    quadShape.dispose()
  }
}

I presume it's pretty obvious what this code is doing apart from the call to the Vertices methods. The Vertices triangle and quad methods have default args that define the size of the shape to be -1 to 1 both vertically and horizontally and generates the the triangle vertices to display.

For those of you who like pictures, it's not much, but here's a screenshot:


One final thing to note is that Sgine is going back to providing its own math library. Simplex3d has been great, but the needs of Sgine are moderately different from the goals of Simplex3d and for both performance and simplicity we are rolling our own.

The new rendering framework and math library are still in early development, but more is coming fast. Once the rendering framework is complete there will be one last layer of abstraction above that: the scenegraph. The scenegraph envisioned will be extremely similar to the scenegraph that Sgine 0.1 provided (pre-refactor), the major difference being performance improvements and relying the rendering framework relying on the OpenGL abstraction. The end goal is still to provide an extremely performant, yet easy to use 3d engine in Scala.

Stay tuned, more will be coming soon.

Wednesday, September 8, 2010

Beans Should Be Deprecated - The Future of Object Architecture With Properties (Part 2 of 2)

In part 1 we discussed the basics of properties in Sgine, how to listen for events, what a delegate property is, how to filter properties, transactions with properties, and animation. In this part we will conclude our tutorial of properties in Sgine with a discussion of paths in properties, binding support, property containers, dependent property, and advanced property.

Path-based Properties


In Sgine there is a unique path system. However, this is not a typical path system because it represents object paths, not filesystem paths. In the org.sgine.path package there is a class called OPath (object path) that can represent the hierarchical path to an object. So, for example, take the following code:
import org.sgine.property.MutableProperty

class Person {
    val addresses = new MutableProperty[Addresses]
}

class Addresses {
    val billing = new MutableProperty[Address]
    val shipping = new MutableProperty[Address]
}

class Address {
    val line1 = new MutableProperty[String]
}

Now, presume I have a reference to an instance of a person object, and I want to listen for any changes to address line1 on the shipping address. This is difficult as "addresses" is mutable, "shipping" is mutable, and "line1" is mutable. So, if I do the following:
person.addresses().shipping().line1.listeners += shippingLine1Changed _
I may get a NullPointerException because something isn't initialized, or I may connect up, but when any one of the mutable chains in-between break I'm now referencing the wrong data. This is where OPath comes in. I can pass a root reference and a path as a String and it can resolve the underlying object and return Option[T]. So for example, if I want to resolve the value as above with an OPath I can invoke:
val o = OPath.resolve[String](person, "addresses().shipping().line1()")
The value of "o" will be Some[String] representing value of line1 or None if any point in the hierarchy is not able to be resolved.

Now, back to properties. The PathProperty works with OPath instances (calling resolve like above simply resolves the value, but an OPath instance is a long-term reference to that path that receives events when anything changes). So if we wanted to create a property and know when the value of line1 in the shipping address has changed we could do the following:
val shippingLine1 = new PathProperty[String](OPath(person, "addresses().shipping().line1()"))
shippingLine1.listeners += shippingLine1Changed _

Your listener would look like this:
private def shippingLine1Changed(evt: PropertyChangeEvent[String]) = {
    ... shipping line1 has changed ...
}

Binding


I mentioned earlier that events were probably the most used feature in properties, but binding is likely a close second. The premise of binding is fairly simple. You have two values and you want one or both to replicate the value of the other. Newer frameworks like Flex and JavaFX make heavy use of binding and do a decent job of it. However, there's a lot that Sgine provides that they have no ability to do. Alas, I'm getting ahead of myself. Let's first take a look at a simple example. Consider the standard UI usage of binding. We have a CRUD app that manages people, so we have a text field that when updated needs to modify the name of the specific person we are working with. We must first modify our Person class to support binding:
import org.sgine.property.BindingProperty
import org.sgine.property.MutableProperty

class Person {
    val name = new MutableProperty[String] with BindingProperty[String]
}
Now, presuming we have a text field with signature like the following:
class TextField {
    val text = new MutableProperty[String] with BindingProperty[String]
}
We can simply take our Person's name and bind it to the text field's text property:
person.name bind nameField.text
Now any changes that occur to the nameField will automatically be applied back to person.name. This is the simple case and pretty much the extent to which most binding systems function. However, as I stated before, in Sgine binding support goes well beyond that.

The first problem you often run into with standard binding functionality is that you can only bind the same type of properties together. For example, in the previous case we were binding the name of a person to the text value of a text field. These both were String representations, but what if we wanted to do something like have an "age" property that is bound to a "birthday" property? We have an Int that wants to link up to a Calendar? This brings us to translation bindings.

Translation Binding


Translation binding is very similar to standard binding except there is a translation step that must occur to get the value ready for use in the target.

Lets look at the age / birthday example:
import java.util.Calendar

import org.sgine.property.BindingProperty
import org.sgine.property.MutableProperty

class Person {
    val age = new MutableProperty[Int] with BindingProperty[Int]
    val birthday = new MutableProperty[Calendar] with BindingProperty[Calendar]

    age bind(birthday, determineAge)

    private def determineAge(c: Calendar) = {
     if (c != null) {
         val now = Calendar.getInstance
         val age = now.get(Calendar.YEAR) - c.get(Calendar.YEAR)
         now.set(Calendar.YEAR, c.get(Calendar.YEAR))
         if (now before c) {
             age - 1
         } else {
             age
         }
     } else {
      -1
     }
    }
}
We simply bind birthday to age, but at the same time provide a function to convert from a Calendar to an Int. Now every time birthday changes, age gets updated.

Path-based Binding


As we've already discussed, OPath in Sgine represents an object-path to a value within a hierarchical structure. We've already seen it used to resolve values directly and with PathProperty. Now we're going to look at one of the most powerful uses of OPath, and that's for binding. Often you want to bind to a hierarchical value that may or may not exist at time of instantiation. The solution to this generally is to add a listener, to wait until it has been defined, and then add the binding. Later though, the reference structure may change or be set back to null and you find yourself with a binding to something that is no longer being used. With path-based bindings you can bind to a hierarchical structure and no longer concern yourself with the details of parts changing in-between. Every time the path changes the binding will be updated.

For example:
import org.sgine.path.OPath

import org.sgine.property.BindingProperty
import org.sgine.property.MutableProperty

class Person {
    val lastName = new MutableProperty[String] with BindingProperty[String]
    val spouse = new MutableProperty[Person] with BindingProperty[Person]
}
Now, consider that this person has stated they want their lastName to be bound to that of their spouse's. We could do this:
person.lastName bind person.spouse().lastName
But it's possible they are not yet married, and it's also possible that the spouse might change. If we do a path-based binding instead, no matter if they are married now or change spouses in the future, the binding will remain pointing to their spouse's lastName:
person.lastName bindPath OPath(person, "spouse().lastName()")
Though a little hard to grasp at first, the benefits of such functionality significantly reduce the amount of handling that must be added in order to deal with multi-level mutability.

Property Container


Properties by themselves are quite useful little beasts, but add PropertyContainer to this mix and the benefits multiply. One of the troubles you have with the standard bean scenario is introspecting the contents of that bean in order to find out what values it contains in order to make use of it. Inevitably Reflection is used to determine the fields or methods that make up that bean. PropertyContainer eliminates the need for manual Reflection.

The ability to know what properties exist for a specific instance can be very useful. Rather than pushing back the necessity to use Reflection onto the developer, PropertyContainer dynamically introspects the instance in order to determine what properties are available and by what name they can be referenced. For example:
import org.sgine.property.MutableProperty
import org.sgine.property.container.PropertyContainer

class Person extends PropertyContainer {
    val name = new MutableProperty[String]
}
Now, I can iterate over all the properties of my "person" with:
for (prop <- person.properties) {
    ...
}
I can also do a lookup of a property by name:
val name = person("name")
Another very useful feature to PropertyContainers is that they are also Listenable instances, so they can receive events. This gives you the ability to listen for events on the container and receive events for the children. See the following example:
import org.sgine.property.ListenableProperty
import org.sgine.property.MutableProperty
import org.sgine.property.container.PropertyContainer

class Person extends PropertyContainer {
    val name = new MutableProperty[String] with ListenableProperty[String] {
        override val parent = Person.this
    }
}
It's important to notice here the only revision that needed take place is that "name" provide a reference to the Person instance via the "parent" property. This is used to propagate the event up. This can allow a complete hierarchical structure to propagate all the way up to the top. Now we can add a listener with the following:
import org.sgine.event.EventHandler
import org.sgine.event.Recursion

import org.sgine.property.event.PropertyChangeEvent

val person = new Person()
person.listeners += EventHandler(propertyChanged, recursion = Recursion.Children)

private def propertyChanged(evt: PropertyChangeEvent[_]) = {
    ... property changed ...
}
The above example will be invoked if any child throws a PropertyChangeEvent. Finally, beyond the static PropertyContainer we also may need to add and remove properties dynamically. This is where MutablePropertyContainer comes in. MutablePropertyContainer, as the name suggests, allows dynamically adding and removing properties on the fly rather than relying on Reflection in order to determine names and references.

Dependent Properties

DependentProperty allows for the default value to point to another property instead of the initial value of that property. For example:
import org.sgine.property.DependentProperty
import org.sgine.property.MutableProperty

class Person {
    val name = new MutableProperty[String] with DependentProperty[String] {
        val dependency = Person.defaultName
    }
}

object Person {
    val defaultName = new MutableProperty[String]("Anonymous")
}
The value of person.name is defaulted to point to whatever the value of Person.defaultName is. Even if the value of "defaultName" should change after initialization it will continue to point to it until the value of the "name" property itself has been changed. This is particularly useful for stylization as it allows default styles to exist but without removing the ability to explicitly override.

AdvancedProperty

In the examples above there is a lot of mixing of traits to achieve the desired functionality, but in most cases there is no reason not to make all of this functionality available. For simplification the AdvancedProperty combines all the standard functionality that might be desired in a property without sacrificing performance. The traits that AdvancedProperty mixes in by default are:
  • MutableProperty
  • DepedentProperty
  • ListenableProperty
  • NamedProperty
  • BindingProperty
  • AnimatingProperty
  • EventDelegationProperty
  • CombiningProperty
Simply instantiating AdvancedProperty is much easier than concerning yourself with every possibly trait that might be needed on a given property and in general there's nothing lost by doing so. AdvancedProperty does not contain all the available traits for properties, but additional traits can be mixed in as needed. To use AdvancedProperty is quite simple:
import org.sgine.property.AdvancedProperty

class Person {
    val name = new AdvancedProperty[String]("")
}
This gives you all the functionality you are likely to need in "name". If you are taking advantage of PropertyContainer you can use the following signature instead:
import org.sgine.property.AdvancedProperty
import org.sgine.property.container.PropertyContainer

class Person extends PropertyContainer {
    val name = new AdvancedProperty[String]("", this)
}

Conclusion

This has been a lengthy tutorial about the functionality that is provided in Sgine's Property system, but hopefully provides the foundation necessary for you to start taking advantage of Properties in your projects. The focus of Sgine is very much toward 3d engine development, but much of the foundation is geared toward general usage. To that end it is my desire that functionality such as the Property system may be leveraged in diverse systems that may have nothing to do with graphical programming at all. Though this was a lengthy examination of properties it did not go over every feature and trait available in Sgine. For additional information please refer to the ScalaDocs for Sgine.

Beans Should Be Deprecated - The Future of Object Architecture With Properties (Part 1 of 2)

In my previous post I discussed the case for Properties and the basics of how they work. In this post I will dive into the specific workings of Properties in Sgine and how to use the various features it provides.

This post is all about Properties in Sgine for use primarily with Scala. However, I know many people, for whatever reason, are still using Java. For those people I would like to point you to this post I made a year previous regarding Properties in Java and the implementation of Properties in the open-source project xjava.

Basics


In Sgine Property is a trait that extends Function0[T] (getter) and Function1[T, Property[T]] (setter). This basic foundation allows better compliance of use along with functional delegation. Here's a simple example class implementation of a Property:

import org.sgine.property.Property

import scala.reflect.Manifest

class SimpleProperty[T](protected implicit val manifest: Manifest[T]) extends Property[T] {
    private var _value: T = _

    def apply() = _value

    def apply(value: T): Property[T] = {
        _value = value

        this
    }
}

This is relatively straight-forward to the way properties were discussed in the previous article with one glaring difference. The use of Manifest is a very cool feature in Scala that Sgine takes extensive use of. If you're not familiar with Manifest I suggest reading more here. If you are familiar with erasure Generics in Java you'll know that Generic type information is not available at runtime, it is purely a compile-time feature to maintain static-typing. However, there are many cases where having that information at runtime is extremely useful and that's exactly what scala.reflect.Manifest gives you. Fortunately though, the only case in which this knowledge will be necessary is if you need to extend Properties, which will never be necessary for the majority of developers.

Now that we have our SimpleProperty class we want to use it:

class Person {
    val name = new SimpleProperty[String]()
}

val person = new Person()
person.name("John Doe")
val name = person.name()

Now that we understand how easy it is to create properties, lets put that knowledge aside for now. As I stated, you'll probably never need to do this, but hopefully this helps you understand how easy it is to do if you should desire to do so.

Moving on, Sgine already supplies all the functionality demonstrated in SimpleProperty in org.sgine.property.MutableProperty. This class is the base for most of the standard mutable Property functionality in Sgine.

The above example requires the creation of your own Property class, but you can use the built-in MutableProperty:

import org.sgine.property.MutableProperty

class Person {
    val name = new MutableProperty[String]()
}

val person = new Person()
person.name("John Doe")
val name = person.name()

Because setting name via apply:
person.name("John Doe")
Is not the most intuitive to realize it is setting the value of the Property, there are a couple additional convenience methods in Property that invoke the same functionality but may be more readable in code.

The first is ":=" so you can write:
person.name := "John Doe"
This is what I personally prefer when setting the value of a Property as it is quite clear that I am intentionally modifying the value of person.name.

Additionally you can use "value" for both getting and setting:
person.name.value = "John Doe"    // Setter
val name = person.name.value    // Getter

Usage aside, Properties are quite simple in concept and though every implementation has its own details you must understand, you hopefully have a good foundation to start with. In the next sections we will be building upon this foundation with specific functionality that Sgine provides to make Properties that much more powerful and effective.

Events


Events in properties are arguably the most useful feature in any properties framework and definitely the most requested feature to any properties system. Sgine provides a complete Event system that is general purpose apart from properties, but is utilized in the properties system to provide a simple, yet complete event system.

The relevant trait we'll use for event handling is ListenableProperty. Here's a sample of setup:
import org.sgine.property.ListenableProperty
import org.sgine.property.MutableProperty

class Person {
    val name = new MutableProperty[String] with ListenableProperty[String]
}

Notice we simply had to mix-in the ListenableProperty to our MutableProperty and now we've got event support in our "name" property.

Here's an example to listen for change of "name":
val person = new Person()
person.name.listeners += nameChanged _

Notice here that we simply reference the "listeners" instance of "name" and invoke "+=" to add our listener.

The definition of our listener "nameChanged":
private def nameChanged(evt: PropertyChangeEvent[String]) = {
    println("Name Changed!")
}

Like I stated previously, the event is extremely powerful and can do some really awesome things, but for the purposes of this tutorial we'll keep it to simply mentioning that we can reference as our "listener" any method/function that takes an Event and returns Unit. In the above code we are explicitly wanting to receive PropertyChangeEvents for Strings and the internal event system will filter all other events from getting to our listener method.

Now every time we change "name" an event will be thrown to "nameChanged".

Another tutorial needs to be written in the future to explain the features and functionality provided in the event system, but you now have the basic knowledge to listen for events in properties.

Delegate Properties


DelegateProperty is an alternative base property to MutableProperty. Instead of maintaining a value internally within the property itself, it delegates to outside functions for getting and setting values. This is most useful when dealing with existing code. Consider the following example:
import org.sgine.property.DelegateProperty

class Window {
    private val frame = new javax.swing.JFrame()

    val title = new DelegateProperty[String](frame.getTitle _, frame.setTitle _)
}
This example is a simple wrapper around Swing's JFrame, and though we could create a title property, listen to changes, and then apply them to the underlying JFrame it would be quite a bit of effort (and a lot more code) to do so. Instead, since all we want to do is replicate the functionality from JFrame's getTitle/setTitle methods we can just delegate to and from those methods. This allows us to utilize all the features of properties while relying on existing functions.

This can also be useful for more complex scenarios where determining the value requires some internal processing. You simply specify your getter to point to a private method/function that does the work and you're finished. The setter function is an optional parameter and if unspecified will throw an UnsupportedOperationException if invoked.

Filtering


FilteredProperty provides the ability to modify an incoming value before it gets applied to the property itself. See the following example usage:
import org.sgine.property.FilteredProperty
import org.sgine.property.MutableProperty

class Person {
    val name = new MutableProperty[String] with FilteredProperty[String] {
        val filter = (s: String) => if (s == null) "" else s
    }
}
This simple example converts nulls to a blank String. This allows you to work with "name" without ever being worried about its value being null.

Another usage of this would be to disallow specific values by throwing an Exception:
import org.sgine.property.FilteredProperty
import org.sgine.property.MutableProperty

class Person {
    val name = new MutableProperty[String] with FilteredProperty[String] {
        val filter = (s: String) => if (s == null) throw new NullPointerException("This property does not allow null!") else s
    }
}
Now, this is creating boiler-plate code, and we don't like boiler-plate code. Lets do this in a more reusable way:
import org.sgine.property.FilteredProperty

trait NullsAreBadFilteredProperty[T] extends FilteredProperty[T] {
    val filter = (value: T) => {
        if (value == null) {
            throw new NullPointerException("This property does not allow null!")
        } else {
            value
        }
    }
}
Now I can simply mix-in my new trait wherever I want to disallow nulls:
import org.sgine.property.MutableProperty

class Person {
    val name = new MutableProperty[String] with NullsAreBadFilteredProperty[String]
}

Transactional Properties


TransactionalProperty is the property equivalent of a database transaction. When a the property is created it maintains a reference to its initial value and the current value. At any time the value can be committed in order to roll forward the initial value to the current value or it may be reverted in order to roll back the current value to the initial value. Finally, when a TransactionalProperty is committed a PropertyTransactionEvent is thrown for the property that represents the original value and the new value.
import org.sgine.property.MutableProperty
import org.sgine.property.TransactionalProperty

class Person {
    val name = new MutableProperty[String]("") with TransactionalProperty[String]
}

Simple usage:
val person = new Person()
person.name := "John Doe"
person.name.revert() // Reverts the value back to ""
person.name := "Jane Doe"
person.name.commit() // Commits "Jane Doe"

Animation


Animation may be a little confusing of a name here since we're dealing with properties and not images, but AnimatingProperty works with a PropertyAnimator to allow "animation" from the current value to the newly applied value over time. Obviously this is of primary benefit in the case of a user-interface, but can be applicable to other uses as well.

Here is a simple example to animate linearly from 0.0 to 5.0 over five seconds:
import org.sgine.property.AnimatingProperty
import org.sgine.property.MutableProperty
import org.sgine.property.animate.LinearNumericAnimator

class Location {
    val x = new MutableProperty[Double](0.0) with AnimatingProperty[Double]
    x.animator = new LinearNumericAnimator(1.0)    // Move 1.0 per second
}

val location = new Location()
location.x := 5.0    // Begin animation from 0.0 to 5.0
location.x.waitForTarget()    // Convenience method to wait for target value to be reached
We're using LinearNumericAnimator, a built-in animator to work with Double properties, to animate 1.0 per second. If you are familiar with Flex or JavaFX this is similar in purpose to what they call "Effects". However, in those frameworks an Effect is defined apart from the property being modified and is simply activated upon it. Though this means writing explicit code for every movement you wish to make it is perfectly acceptable most of the time. However, this does create the potential problem of multiple effects being enacted on the same value at the same time. For example, a box is displayed in the center of the screen with two buttons. The first button moves the box to the left side of the screen and the second button moves the box to the right side of the screen. This is perfectly fine until you try hitting one right after another. If you don't add explicit support to cancel the first effect you will run into what I call "effect fighting". This is the scenario where two effects are trying to modify the same property to two different targets. The visual result of the box example is the box jumping to the left, then the right, then left, and so on with each effect attempting to update the position. Particularly in the case of Sgine, being a fully multi-threaded and thread-safe 3d engine this was of great concern. PropertyAnimator simplifies and abstracts the process, preventing effect fighting from occurring.

Consider another scenario. In the Location class we created above, if it were being managed in a layout manager of some sort, the layout manager wouldn't necessarily know anything about animation. By virtue of the fact that the layout manager modifies the "x" property, instead of immediately jumping to the new position, animation would occur.

LinearNumericAnimator is just one built-in PropertyAnimator. EasingNumericAnimator similarly works with Double properties, but uses easing functions instead of linear motion. Numbers are not the only things that can be animated though. The EasingColorAnimator works similarly to EasingNumericAnimator, but works on Colors. At the time of this writing those are the only built-in PropertyAnimators, but writing your own PropertyAnimator is a simple matter of providing your own implementation of the following method signature:
def apply(current: T, target: T, elapsed: Double): T

Easings with animation is generally more elegant than simple linear animation. Sgine has a full listing of easing functions supported:
  • BackIn / BackOut / BackInOut
  • BounceIn / BounceOut / BounceInOut
  • CircularIn / CircularOut / CircularInOut
  • CubicIn / CubicOut / CubicInOut
  • ElasticIn / ElasticOut / ElasticInOut
  • ExponentialIn / ExponentialOut / ExponentialInOut
  • LinearIn / LinearOut / LinearInOut
  • QuadraticIn / QuadraticOut / QuadraticInOut
  • QuarticIn / QuarticOut / QuarticInOut
  • QuinticIn / QuinticOut / QuinticInOut
  • SineIn / SineOut / SineInOut

This concludes part 1 of this tutorial. Please continue on to part 2 for the conclusion.

Tuesday, August 31, 2010

The Advantages of Using Properties Instead of Getters/Setters in Java and Scala

There have been a few concepts I've been pushing for most of my programming career, and one of the top items on that list is Properties. This is a topic I've been meaning to delve into for a while, and have previously, but as this is an incredibly important part of the core of Sgine I would like to take some time to state the case for Properties. This post is all about why Properties are useful and ultimately why Sgine uses them. The next post, Properties - Tutorial, will go into great detail about how to use Properties within the context of Sgine. Properties as a term is bandied about in many different forms, so first a definition is in order.

Definition


In the context of this discussion a Property is the concept of a wrapper class around a value as an alternative to the standard private field, public getter/setter. For example in Java:
public class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

person.setName("John Doe");
String name = person.getName();

The property alternative:
public class Person {
    public final name = new Property<String>(null);
}

person.name.set("John Doe");
String name = person.name.get();

A basic Property class in Java might look something like:
public class Property<T> {
    private T value;

    public void set(T value) {
        this.value = value;
    }

    public T get() {
        return value;
    }
}

Or in Scala:
class Person {
    private var _name: String = _

    def name = _name

    def name_=(name: String) = _name = name
}

person.name = "John Doe"
val name = person.name

The property alternative:
class Person {
    val name = new Property[String](null)
}

person.name := "John Doe"
val name = person.name()

A basic Property class in Scala might look something like:
class Property[T] {
    private var value: T = _

    def :=(value: T) = this.value = value

    def apply() = value
}

Since this blog is about Sgine, a 3d engine in Scala, I will be showing all further example code only in Scala though much of this still applies directly to Java.

Advantages


This is all well and good, but for all practical appearances it's about the same as classic getter/setter pattern. Why would you want to break convention and use Properties instead?

In the examples above there isn't much practical difference between the two methodologies. Performance-wise they are identical. Properties reduce the amount of code in your class by a pretty large margin if you consider one line:
val name = new Property[String](null)

Instead of three (or seven in the case of Java):
private var _name: String = _
def name = _name
def name_=(name: String) = _name = name

However, the typical response here is that with today's IDEs they will generate the getter/setters for you automagically, so what does that matter? To some degree I agree with this, but it is still clutter added to your classes that make managing your source code that much more complicated down the road. I will agree though that this in and of itself is not a convincing reason to break convention so lets get on to the real reason.

Ultimately it comes down to one major reason to use the Property concept instead of methods, and that is encapsulation. Given the above Person example with a "name", how would you handle a check upon assignment to make sure the name is no more than 255 characters, and if it is, to chop off the extra characters?

Perhaps something like:
class Person {
    private var _name: String = _

    def name = _name

    def name_=(name: String) = {
        val filtered = ...filter name...
        _name = filtered
    }
}

That's simple enough, but what if you want to add an "address" field as well and limit it to 255 characters? Sure, you can simplify by creating a "filter" method you can invoke, but no matter how you swing it, you end up with boiler-plate code to accomplish your task. The reason this happens is because methods don't have the ability to encapsulate and extend functionality the way that an object does. So for the above example I could simply create a FilteredProperty trait that can be mixed in:
trait FilteredProperty extends Property[String] {
    abstract override :=(value: String) = {
        val filtered = ...filter value...
        super.:=(filtered)
    }
}

Now you simply make a very slight change to your person class to get the benefits of filtering:
class Person {
    val name = new Property[String](null) with FilteredProperty
}

Hopefully you are beginning to see the advantages here. In order to add functionality to your simply extend Property functionality to provide what you want and then mix it together in your resulting Property instance. Not only does this remove any need for boilerplate code, but it makes reading the source code for classes extremely easy as a single line of code describes the make-up of that property.

Here are a few examples of things you can do well with Properties:
  • Events: Adding event listeners to a property is one of the most common uses for a Property system as event handling in a standard Bean scenario involves a lot of boiler-plate code. Here's a simple example of usage:
    person.name.listeners += nameChanged _
    
    private def nameChanged(evt: PropertyChangeEvent[String]) = {
        ... property has changed ...
    }

    As is hopefully obvious, any changes to person.name will result in the invocation of the nameChanged method.
  • Binding: Synchronizing two properties together via binding is probably the second most common reasons Properties are used. This is something that takes quite a bit of effort to support, but by leveraging Properties the functionality can be written once and then re-used everywhere desired. Here's a simple example of usage:
    person1.name bind person2.name

    Sure, that's incredibly simple, but now any changes to person2's name will result in person1's name being updated as well.
  • Translation: The ability to translate incoming values is a very broad topic, whether you are converting Strings to Ints, translating to another language upon set, or simply modifying all applied data to follow a specific standard Properties can provide all of the functionality by simple extension and mix-in.
  • Filtering: Applying a filter may represent limiting of a String to 255 characters as discussed above, or it may include throwing an Exception if invalid data is attempted to be passed (ex. Attempting to set null on a Property that should not be null).
  • Transactions: Simple transaction support may consist of an uncommitted value along with commit and rollback methods. This would allow simple management of objects in a user-interface and the ability to know if the object has uncommitted values and what they are so you are only applying changes to the database instead of sweeping updates.
  • Animation: Also called "adjusters", this is the ability to move from one value to another over time. This is most commonly applied to numbers. For example, a AnimatingProperty trait may start at 0.0 but when the value is set to 100.0 instead of applying it directly, it is applied over time and possibly with an easing function.
  • Delegation: This allows the ability delegate getting/setting functionality to another method, function, or value.

There is a great deal more that can be done with Properties, but this is hopefully a nice glimpse to what is possible.

History


As much as I'd love to claim responsibility for the idea of properties, alas, it is not my own and here are a few URLs to other posts about properties (including some older ones from me):

http://joda-beans.sourceforge.net/
http://www.javalobby.org/java/forums/t88090.html?start=50#92123353
http://www.javalobby.org/java/forums/t90756.html
http://www.javalobby.org/java/forums/m92123242.html
http://www.matthicks.com/2009/06/have-beans-been-holding-us-back.html
http://www.matthicks.com/2009/07/death-of-beans.html
Scala Engine for high-performance interactive applications.