[Odejava] OO Issues - take 2

Hi All,

First off - I feel Odejava is coming along very nicely - especially with
Jani’s new collision objects.

I have been doing some more Xith3D <–> Ode work recently and would like
to suggest a slight improvement on the way the integration between those
API’s is organised based on my observations.

I found the OdejavaToXith3D class quite confusing. It does two tasks -
one is that it creates Xith3D representations of Ode objects, and the
second is that it updates the Xith3D objects with the correct new
coordinates of their bound bodies.

What I find confusing is that there are several linked lists and the
userData method of TransformGroup is used.

I think that the updating probably should be kept separate of the object
generation code and also it would be nice to decouple some of the
binding code from Xith3D and make it an abstract library which would
enhance readability and make it easier to support other display
libraries such as jMe.

So here goes:


There is a new package:
        org.odejava.display.*

Basically it has an object named "DisplayBin" which stores all "Bound"
display objects (for example a Xith3D TG bound to an Ode Body).  Calling
updateAll will update the display objects transform based on the Ode
one.

These bound objects are in a class named "BoundDisplayObjects" which
simply stores the DisplayObject and OdeTransformable (ie. body or geom).

DisplayObject is an interface which Xith3D and any other display API can
implement to use with Ode.


This package has some abstract classes and interfaces.  Here are their
stubs  and partial implementations.

/**
 *  Container of BoundDisplayObjectS
 */
public class DisplayBin {

   protected List displayObjects = new ArrayList();

   // some List methods such as add, remove, iterator ...

   /**
    * Calls update on all contained BoundDisplayObjectS
    */
   public void updateAll();

}

/**
 * Represents an abstract Display Object that is bound to
 * an Ode Body or Geom (the OdeTransformable).
 */
public class BoundDisplayObject {

    protected DisplayObject displayObject;
    protected OdeTransformable odeObject;
    
    public BoundDisplayObject (DisplayObject displayObject,    
                                         OdeTransformable odeObject) {
        ...
   }

    public void update () {
       displayObject.setPosition(odeObject.getPosition());
       displayObject.setQuaternion(odeObject.getQuaternion());
    }

}

/**
 * Interface for the DisplayObject
 */
public interface DisplayObject {

        setPosition(Vector3f);
        setQuaternion(Quat4f);

}



As you can see - to add support for a new graphical library all that is
needed is to create an object which implements DisplayObject - in the
case of Xith3D this is obviously TransformGroup.

I believe OdejavaToXith3D could be retrofitted to support this
abstraction so the API doesn’t break this time. Most of OdejavaToXith3D
wouldn’t be touched - only methods which do what this package would do
(i.e. the ones using these variables).

    // Result lists, updated by createTransformGroups() method
    LinkedList geomTransformGroup;
    LinkedList bodyTransformGroup;

Ultimately I’d like to see those methods totaly removed - but they could
be deprecated for now.

So then there is a mere two classes any graphics library must implement

  • the DisplayObject interface (which is dead simple) and some way to
    generate it’s objects from the Ode ones.

If the response to this proposal is positive, I will do the modification
within 24 hours and have it in CVS. As I said - the API won’t break
(just some deprecation) so don’t worry about your code breaking.

I await your comments.

Regards,

Will.

Will, I’m quite short of time for Odejava in the near days but I skimmed your post and here are my toughts:

  1. setting suggested methods to deprecated is fine
  2. if nothing breaks, go for it
  3. old OdejavaToXith3d should be removed after some time

This also sounds good: separating the creation of the graphical side of Odejava objects and updating Odejava object pos/quats to renderer should be divided to different classes…

I’ll be glad to check your code later this weekend!

The org.odejava.display package has been written, fully javadoc’d and now committed.

The Xith3D implementation is coded, just waiting for me to javadoc it and commit.

As I expected, it was quite easy to maintain backward compatability this time. Several methods were deprecated and we should plan to remove them in a few weeks once everyone has switched over.

Will.

Xith3D display objects implementation committed - now all that is waiting is for the retro-fitted OdejavaToXith3D.

Once I’ve done that I’ll write a brief tutorial on how to use the new library :slight_smile:

Will.

Updated OdejavaToXith3D committed.

I ran all public Odejava tests and they worked.

There are some deprecated methods which we should plan to remove in the near future (say 2-4 weeks).

I also altered SimpleExample to use the new code. Here’s the diff so you know what needs to be changed (it isn’t much, but I think it looks a bit neater - as does the code “under the hood”).


Index: src/org/odejava/xith3d/test/SimpleExample.java
===================================================================
RCS file: /cvs/odejava/odejava-xith3d/src/org/odejava/xith3d/test/SimpleExample.java,v
retrieving revision 1.2
diff -u -r1.2 SimpleExample.java
--- src/org/odejava/xith3d/test/SimpleExample.java      28 Dec 2003 13:46:27 -0000      1.2
+++ src/org/odejava/xith3d/test/SimpleExample.java      11 Mar 2004 12:12:58 -0000
@@ -45,6 +45,9 @@
 // Import odejava to xith binder
 import org.odejava.xith3d.OdejavaToXith3D;
  
+import org.odejava.display.*;
+import org.odejava.xith3d.Xith3DDisplayObject;
+
 // Import ode example world
 import org.odejava.test.simple.HighLevelApiExample;
  
@@ -66,10 +69,12 @@
        BranchGroup scene;
  
        // Odejava to xith helper class
-       OdejavaToXith3D odejavaToXith = new OdejavaToXith3D();
+       OdejavaToXith3D odejavaToXith;
+
+
        // Each TransformGroup contains xith shapes, these are constantly updated
        // by Odejava. TransformGroup's userData contains object Odejava.body
-       LinkedList bodyTransformGroups;
+       DisplayBin boundObjects = new DisplayBin();
  
        // View
        Vector3f viewLocation = new Vector3f(5f, 7f, 3f);
@@ -162,13 +167,12 @@
                // Set user defined Shapes
                Shape3D shape;
  
+               odejavaToXith = new OdejavaToXith3D(boundObjects);
+
                // Create transform groups based on given Odejava object
                odejavaToXith.createTransformGroups(odeSimple.getGeoms());
-               // Get result (dynamic objects)
-               bodyTransformGroups = odejavaToXith.getBodyTransformGroup();
-
-               // Add bodyTransformGroup (dynamic objects) into scene
-               odejavaToXith.addTransformGroupToScene(scene, bodyTransformGroups);
+
+               Xith3DDisplayObject.addToScene(boundObjects, scene);
        }
  
        /**
@@ -184,7 +188,7 @@
                                // step simulation
                                odeSimple.step();
                                // update xith objects based on Odejava bodies
-                               odejavaToXith.updateBodyTGs(bodyTransformGroups);
+                               boundObjects.updateAll();
                                // render view
                                view.renderOnce();
                                rendering = false;


Test runs fine using the new methods.

Tomorrow I shall write a small tutorial :slight_smile:

Cheers,

Will.

[quote]Updated OdejavaToXith3D committed.

Test runs fine using the new methods.

Tomorrow I shall write a small tutorial :slight_smile:
[/quote]
Uber! Uber! It looks nice. I shall get back to Odejava in the weekend and check these out.

Will, your org.odejava.display classes are neat addition. I noticed that the interface OdeTransformable contains these:
public Vector3f getPosition();
public Quat4f getQuaternion();
public AxisAngle4f getAxisAngle ();

I’d recommed that these are changed to
public void getPosition(Vector3f result);
public void getAxisAngle (AxisAngle4f result);
public void getQuaternion(Quat4f result);

I know this is not as clean solution but it is neccessary in order to avoid massive amounts of new object creations.

If you have e.g. 200 bodies then you are creating 400 new objects per each frame and if you have 50 fps then you get 20000 new objects (Vector3f and Quat4f) per second and this means extra work for GC. Of course you can use incgc but the right solution is to avoid “mass” object creations if possible.

If you run plain Odejava without any renderer it won’t ever need to run garbace collector.

This is an easy fix, let me know what you think or just do the changes to CVS.

Cheers, Jani!

[quote]I noticed that the interface OdeTransformable contains these:
public Vector3f getPosition();
public Quat4f getQuaternion();
public AxisAngle4f getAxisAngle ();

I’d recommed that these are changed to
public void getPosition(Vector3f result);
public void getAxisAngle (AxisAngle4f result);
public void getQuaternion(Quat4f result);
[/quote]
I suggest a slight change:
public Vector3f getPosition(Vector3f result);
public AxisAngle4f getAxisAngle (AxisAngle4f result);
public Quat4f getQuaternion(Quat4f result);

Then the parameter could be optionally null and the calls could be chained. In general ‘get’ methods should return a value. :slight_smile:

Ok, I’ll make the changes and have them also return the value for conveniance.

The Body and Geom classes will be updated as well.

Will.

I have added the overloaded methods as suggested.

In Body (not Geom) there are a few methods which I think should be depreacted as they are really redundant. These are ones which use float arrays rather than javax.vecmath classes.

eg.
public void getPosition(float[] result)

Any compelling reason to keep them?

Will.

Ick… another ‘get’ method that doesn’t return the result :).

I was using the previously but I think it’s cleaner to remove them as there should not be any compelling reason why one would not like to use ‘real’ objects like Vector3f, Quat4f…

[quote]Ick… another ‘get’ method that doesn’t return the result :).
[/quote]
I know what you mean, even vecmath and Xith contain these ‘get’ methods that return void :frowning: Don’t know if there exists any patterns for this kind of problem, I’ve never needed to concern too much about object creation problems before, even on large projects.

This ‘avoid new, reuse objects as much as you can’ make API dirtier but we all know it’s best to do it on places where it affects performance. This getPosition and getQuaternion (also other getters) are the “hotspots” of object creations because they are accessed excessively (multiple times per Body per step).

How about separating proper bean getter from the gc friendly solution like this:

// dirtier but GC friendly solution
// @param result The vector where position is to be copied
public void position(Vector3f result)

// proper bean styled getter
// Javadoc note: creates new object, do not use excessively
public Vector3f getPosition()

Of course your solution would be fine also:
public Vector3f getPosition(Vector3f result);
but it would contain one extra if clause and one extra return clause. (ok the speed difference is minimal). But when you use these you need to pass null every time you want vector3f created.

I’d go for two separate methods than to merge both solutions into one method. I noticed Will committed the “merged” method, can we change this to two separate methods? I’m sure there will be couple other places aswell where this is needed.

Jani,

What I have committed is formats 2 and 3 that you just posted.

#2 we should definitely keep IMHO, and #3 seems to make more sense than #1

The #3’s have a javadoc comment saying that they use the passed object. I guess the #2’s could mention that they create a new object.

Will.

Note that you can still avoid ‘new’.
Just return the same object that was passed in as a parameter. I think it makes the ‘get’ function more consistent. If you decide that the method is/isn’t going to generate too much garbage you can make the parameter required/optional without changing too much code.

Sometimes I name methods differently when they fill in some datastructure as opposed to returning the value. Sometimes a ‘fill’ prefix or ‘init’ or similar.

ok - good advice on the “fill” prefix :slight_smile:

For Odejava - these are the changes I made:

https://odejava.dev.java.net/source/browse/odejava/odejava/src/org/odejava/Body.java?r1=1.16&r2=1.17

Each method has two overloads - one which reuses an object, one which does not.

Will.

all of the demos are updated now.

Please test them for errors :slight_smile: I have and I didn’t see any.

IMPORTANT

The methods deprecated in this thread will be removed in the future. Please upgrade now (it’s easy - max 5 lines to changes).

Will.

cop this - package level docs for the display package.

Want to know how to add a binding for the display library of your choice like Java3D? Well look no further :slight_smile:

It’s actually very simple.

Will.