Spatial and RenderStates

Have you thought about using the NullObject pattern for Spatial’s render states? It would make the code a fair bit simpler. Also, is it possible for a Spatial’s parent’s render states to change while it’s being rendered? If not, then perhaps it’s not necessary to cache the parent’s render states in the set() method.


public void setStates() {
   if (parent != null) {
      parentStateList = parent.getRenderStateList();
   }
   for (int i = 0; i < renderStateList.length; i++) {
      if (renderStateList[i] != null && renderStateList[i].isEnabled()) {
         renderStateList[i].set();
      }
   }
}

public void unsetStates() {
   for (int i = 0; i < renderStateList.length; i++) {
      if (renderStateList[i] != null) {
         if(isRoot) {
            renderStateList[i].unset();
         } else if (parentStateList[i] != null) {
            renderStateList[i].unset();
            if(i == RenderState.RS_LIGHT) {
               parentStateList[i].unset();
            }
            parentStateList[i].set();
         } else {
            renderStateList[i].unset();
         }
      }
   }
}



To this:

public void setStates() {
   for (int i = 0; i < renderStateList.length; i++) {
      if (renderStateList[i].isEnabled()) {
         renderStateList[i].set();
      }
   }
}

public void unsetStates() {
   for (int i = 0; i < renderStateList.length; i++) {
      renderStateList[i].unset();
      if (!isRoot) {
         if (i == RenderState.RS_LIGHT) {
            parent.getRenderStateList()[i].unset();
         }
         parentStateList[i].set();
      }
   }
}

How is this a bug? :slight_smile:

Just move it to Suggestions–Features and be done with it. Go mod powers! :stuck_out_tongue:



ahem On topic, I agree that it’s a good suggestion. It’s easy to implement ( ? ) and cleans the code up a bit.

Ah, sorry about picking the wrong forum.

why are you removing the checking of nulls?

Well, he’s not removing them, he’s suggesting we move them. :smiley:



However, I still don’t see the benefit of this. If you could go into further detail we can discuss this.

The benefit is that you don’t have to care about the internal State of a RenderState, no check! no null pointer…

use it normally, set and unset without caring about any null setting.



NullObject only means a kind of implementation of the RenderState that does absolutely nothing. Such object can be a singleton (a unique and static instance) with the following implementation

final void set() { return; }

final void unset() { return; }



if you want to know if the parent RenderState is used, you just have to check if the renderState is equals to the NullRenderState, exactly as the the null check

Yes, the suggestion was partly based in the fact that I didn’t realize nulls meant inheriting the parent’s state.

Are a parent’s render states meant to apply only to its immediate children, or to the entire sub-tree? If a grandchild, so to speak, overrides a grandparent’s render state, subsequent grandchildren don’t seem to inherit the grandparent’s render state.



I could well be misunderstanding something (wouldn’t be the first time!).


TestTextureState green = new TestTextureState("green");
TestTextureState red = new TestTextureState("red");

TestNode root = new TestNode("Root");
root.setRenderState(green);
root.addExpectedRenderStateAtDrawTime(green);

TestNode child = new TestNode("Child");
child.addExpectedRenderStateAtDrawTime(green);
root.attachChild(child);

TestNode grandchild1 = new TestNode("Grandchild 1");
grandchild1.setRenderState(red);
grandchild1.addExpectedRenderStateAtDrawTime(red);
child.attachChild(grandchild1);

TestNode grandchild2 = new TestNode("Grandchild 2");
grandchild2.addExpectedRenderStateAtDrawTime(green);
child.attachChild(grandchild2);

TestNode grandchild3 = new TestNode("Grandchild 3");
grandchild3.addExpectedRenderStateAtDrawTime(green);
child.attachChild(grandchild3);

DisplaySystem displaySystem = DisplaySystem.getDisplaySystem("TEST");
Renderer renderer = displaySystem.getRenderer();
renderer.setCamera(new TestCamera());
renderer.draw(root);



This is the output:

INFO: Node created.
Apr 8, 2004 10:12:33 AM com.jme.RenderStateTraversalTest$TestNode setRenderState
INFO: Node "Root" .setRenderState(texture:"green")
Apr 8, 2004 10:12:33 AM com.jme.scene.Node <init>
INFO: Node created.
Apr 8, 2004 10:12:33 AM com.jme.scene.Node attachChild
INFO: Child (Child) attached to this node (Root)
Apr 8, 2004 10:12:33 AM com.jme.scene.Node <init>
INFO: Node created.
Apr 8, 2004 10:12:33 AM com.jme.RenderStateTraversalTest$TestNode setRenderState
INFO: Node "Grandchild 1" .setRenderState(texture:"red")
Apr 8, 2004 10:12:33 AM com.jme.scene.Node attachChild
INFO: Child (Grandchild 1) attached to this node (Child)
Apr 8, 2004 10:12:33 AM com.jme.scene.Node <init>
INFO: Node created.
Apr 8, 2004 10:12:33 AM com.jme.scene.Node attachChild
INFO: Child (Grandchild 2) attached to this node (Child)
Apr 8, 2004 10:12:33 AM com.jme.scene.Node <init>
INFO: Node created.
Apr 8, 2004 10:12:33 AM com.jme.scene.Node attachChild
INFO: Child (Grandchild 3) attached to this node (Child)
Apr 8, 2004 10:12:33 AM com.jme.renderer.AbstractCamera <init>
INFO: Camera created.
Apr 8, 2004 10:12:33 AM com.jme.RenderStateTraversalTest$TestTextureState set
INFO: TextureState "green" set
Apr 8, 2004 10:12:33 AM com.jme.RenderStateTraversalTest$TestNode draw
INFO: Node "Root" draw() called with active render states [texture:"green"].
Apr 8, 2004 10:12:33 AM com.jme.RenderStateTraversalTest$TestNode draw
INFO: Node "Child" draw() called with active render states [texture:"green"].
Apr 8, 2004 10:12:33 AM com.jme.RenderStateTraversalTest$TestTextureState set
INFO: TextureState "red" set
Apr 8, 2004 10:12:33 AM com.jme.RenderStateTraversalTest$TestNode draw
INFO: Node "Grandchild 1" draw() called with active render states [texture:"red"].
Apr 8, 2004 10:12:33 AM com.jme.RenderStateTraversalTest$TestTextureState unset
INFO: TextureState "red" unset
Apr 8, 2004 10:12:33 AM com.jme.RenderStateTraversalTest$TestNode draw
SEVERE: Node "Grandchild 2" draw() called with incorrect render states. Expected [texture:"green"] but found []
Apr 8, 2004 10:12:33 AM com.jme.RenderStateTraversalTest$TestNode draw
SEVERE: Node "Grandchild 3" draw() called with incorrect render states. Expected [texture:"green"] but found []
Apr 8, 2004 10:12:33 AM com.jme.RenderStateTraversalTest$TestTextureState unset
INFO: TextureState "green" unset

Hmm, odd, b/c we have a similar test (TestSceneGraph) and at least on first glance it appears to be functioning as expected.



Edit: Hmm, spoke too soon, just retested and it’s not working anymore. :frowning: Examining code…

I submitted a small revision to the build script a while ago that runs JUnit tests at compilation time to prevent this sort of regression - I’ll send the test that I wrote for this particular case if you want it.

JUnit tests will definitely prove useful, but not my bailiwick at the moment. Mojo will have to chime in on what he wants to do here.



As far as the bug, it was introduced with the parent states fix for lights. I’ve examined newer Eberly code than what we used to build Spatial and such and have discovered that he now uses stacks for tracking renderstates down the tree. This makes a ton of sense. There are some other great concepts in there too… I’d like us to rejigger Spatial to follow a similar tact (which among other things would solve your reported bug,) but I’ll have to wait until tonight to get approval from Mojo.

Not right now, I’m sick of us fucking around with existing code this early. Let’s get the API to a feature rich state and we can discuss all this. We have many systems that need to be written before we go in changing everything for the hell of it. There is a release later on that will be dedicated to such things + documentation. I’m also not going to implement a process to base code changes rather than “It’d be cool if…”.



However, if there is in deed a bug, then yes, those should be fixed. But fixed to the existing system rather than rewriting it. So, yes, bug fixes are priority one, and I’ll fix the render state issue. Although I don’t see the bug at first glance. What am I looking for?

Bug fixed and checked in.

Unfortunately the fix seems to have caused (or uncovered perhaps) a new issue. Try running testmd2… Also, if you add a simple check for parent != null to fix the npe, the whole scene (fps counter and all) disappears about the time it should be showing the death scene. Any ideas?

whoops, sorry about that, found the problem and fixed it. I’m going to check the other tests then check the fix back in.

Ok, checked in the fix. I somewhat undid some of the crap I threw in for the light fix (I wasn’t real happy by the way I “fixed” it originally anyways). I basically wrote a work around, I need to handle the problem in the light state itself. The place you’ll notice is in camera man. The spot light is no longer shining on the model, just the camera’s view.