(Yet another) Java Scene Graph

I’ve decided to release the source for the scene graph I’ve been working on for while. The code can be found on google code.

Its a fast and simple scene graph with little overhead. Some of the features supported:
-multipass rendering
-render to texture using pbo
-shaders
-cube maps
-view frustum culling against bounding spheres
-state sorting
-front to back and back to front sorting using radix sort
-optimisations on shapes with either static state, model matrix or vertex data

I have a few (very shallow) comments on the code.

  1. IMMIDIATE --> IMMEDIATE :stuck_out_tongue:

In GLState.applyDiff(…) there are bugs in the logic:


                if (polygonOffsetFillEnabled != state.polygonOffsetFillEnabled) {
                        polygonOffsetFillEnabled = state.polygonOffsetFillEnabled;
                        if (polygonOffsetFillEnabled) {
                                glEnable(GL_POLYGON_OFFSET_FILL);
                                if (polygonOffsetFactor != state.polygonOffsetFactor
                                                || polygonOffsetUnits != state.polygonOffsetUnits) {
                                        polygonOffsetFactor = state.polygonOffsetFactor;
                                        polygonOffsetUnits = state.polygonOffsetUnits;
                                        glPolygonOffset(polygonOffsetFactor, polygonOffsetUnits);
                                }
                        } else {
                                glDisable(GL_POLYGON_OFFSET_FILL);
                        }
                }

now glPolygonOffset(polygonOffsetFactor, polygonOffsetUnits); is only called when a bunch of conditions apply. So when only polygonOffsetFactor is changed, the difference won’t be applied.

Now this is just one example, but the same bug is everywhere in GLState.applyDiff(…), like:

if (depthTestEnabled != state.isDepthTestEnabled()) {
                        depthTestEnabled = state.isDepthTestEnabled();
                        
                        if (depthTestEnabled) {
                                glEnable(GL_DEPTH_TEST);
                                if (depthFunc != state.getDepthFunc()) {
                                        depthFunc = state.getDepthFunc();
                                        glDepthFunc(depthFunc.get());
                                }
                        } else {
                                glDisable(GL_DEPTH_TEST);                       
                        }
                }

\

Which has the same problem with glDepthFunc(...); - The value is only applied when depthTestEnabled was toggled.

Or maybe I did just miss something?

IMHO it should be like:


     boolean depthTestToggle = depthTestEnabled != state.isDepthTestEnabled();
     if (depthTestToggle) {
            depthTestEnabled = state.isDepthTestEnabled();
                        
            if (depthTestEnabled) {
                     glEnable(GL_DEPTH_TEST);
            } else {
                     glDisable(GL_DEPTH_TEST);                       
            }
       }

       boolean depthFuncChanged = depthFunc != state.getDepthFunc();
       if(depthFuncChanged && depthTestEnabled)
       { 
             depthFunc = state.getDepthFunc();
             glDepthFunc(depthFunc.get());
       }

Thanks Riven! This is in fact a bug. Checked in a fix in SVN.

Nice to see someone taking the time to find some bugs :slight_smile:

…and I know I can’t spell :slight_smile:

(!) same problem in GLState.applyLight(…)

further, about code readability, consider these two logically identical code listings:


void stuff()
{
   if(someFlag)
   {
      // do
      // lots
      // of
      // complex
      // things
   }
   else
   {
       throw new IllegalStateException("Problem");
   }
}

vs.


void stuff()
{
   if(!someFlag)
       throw new IllegalStateException("Problem");

   // do
   // lots
   // of
   // complex
   // things
}

Or, like this:


for(.....)
{
       if(....) {
            if(....) {
                  // stuff!
                  // stuff!
                  // stuff!
                  // stuff!
                  // stuff!
                  // stuff!
            }
       }
}

vs.


for(.....)
{
       if( ! ....)
           continue;
       if( ! ....)
           continue;

       // stuff!
       // stuff!
       // stuff!
       // stuff!
       // stuff!
       // stuff!
}

I find that reducing the indentation level in your sourcecode makes it easier to read, and easier do fix. After all it was Linus who said that if you have more than 3 indentation levels (in your method) you’re screwed anyway. I tend to strongly agree with that, but he also said that Linux is so fast, it does an infinite loop in 2 seconds… so go figure.

Another nice idea might be to make your methods max 10-15 lines. Split those massive methods into nice little chunks, with self descriptive names. The JIT will also take advantage of that, btw.

It is interesting, I’m going to watch your source code. Thank you very much for releasing it. I have some questions:

  • Why is it bound to LWJGL? :frowning:
  • Why are there only DLLs under the lib directory???
  • Is your source code not cross-platform?
  • Why do you use vecmath whereas it produces a lot of garbage? (it often bothers the garbage collector)

If it’s LWJGL, it is cross platform. And why not bind it to LWJGL? Got to bind it to something.

Cas :slight_smile:

Maybe it would be better to write something that abstracts the OpenGL binding to drive it easier to use another binding.

Or maybe not. Not every 3D rendering library on the planet needs to be abstracted to such a degree. Some are, some aren’t. Life goes on.

Because I’ve used LWJGL for a long time, and I like it. I see no advantage in supporting both LWJGL and JOGL. It is good enough that it works on one of them.

I am interested in creating either a DirectX renderer or a new DirectX scene graph. This is something want to look into in the future.

Because I use windows and I had the files available when I uploaded to SVN. I might provide the other binaries later. They are only needed to run the single test that is included.

I don’t know. Haven’t tested it on anything but windows. I assume it is since all my code is Java and LWJGL is cross-platform.

Because it is a full featured, mature and will tested vecmath library. It do produce some garbage in some cases, like inverting a matrix. This is not big problom in most situations. I also think there is more garbage friendly implementation that one can use simply by replacing the jar (not completely sure about this). The vecmath source code is open. It can be fixed if this turns out to be a problem.

Making it cross platform is not the most important goal of this project. Although it would be nice to get it running on max. Don’t care if it runs on linux :stuck_out_tongue:

The only vecmath.jar replacement I’ve seen is this one:

http://www.objectclub.jp/download/vecmath_e

but it’s pretty much defunct and doesn’t claim any garbage improvements. However, as you say the original vecmath is now open source so you could always fix that one.

You might also consider OpenMali (https://openmali.dev.java.net/) which apparantly contains a reworked vecmath. Never used it myself so can’t say if it’s any better.

Kev

Yes, I was thinking of Kenji Hiranabe’s javax.vecmath implementation. I thought Xith3D used it a long time ago because performance was better. But maybe it was used just because it was free.

OpenMaLi contains both original Sun’s Vecmath reimplementation (evolved version of Kenji Hiranabe’s implementation with reduced memory allocation and under BSD license) and their own version (called Vecmath2, but it’s not successor to Sun’s Vecmath, it’s just different project).

About the DLLs… I don’t see any problem here, it uses LWJGL so it’s crossplatform, you can compile it yourself and it will most likely work out of the box. Not everyone have access to various OSes and care about other platforms. Though I don’t like when there is no technical problem to support other platforms and it’s refused by author… even when the support is contributed. Which I believe is not this case.

About JOGL, you can port it yourself. I find it quite ridiculous to have abstraction for different OpenGL bindings, as in the end it’s about the same calls to underlying OpenGL library… And you can even mix LWJGL and JOGL’s contexts if needed.