Smoother FengGUI integration in jME

Hi!!



darkfrog and I were having a conversation over at the FengGUI forum about a transparency issue with FengGUI. Basically, at the current state, FengGUI fails to render above transparent spatials when using the SimpleGame-setting in jME, because they are kept in the QUEUE_TRANSPARENT bucket which is processed after simpleRender() (display.getRenderer().displayBackBuffer() which is behind render(-1.0f) in BaseGame.start()).



That's why I would like to come up with a smoother way to integrate FengGUI in jME. The best way would probably to wrap FengGUI in a SceneElement that is put in QUEUE_ORTHOGONAL, because this bucket is processed at the very end of the update cycle and already sets up the model view and projection matrix to draw 2D stuff. Is that a good idea? Do you have an advice from a jME professional to a jME noob on how to best accomplish that?



Thanks!



Johannes

How does FengUI display things? With a texture? Or by writing to the screen buffer?

I believe it writes to the screen buffer.

why not just have it in a separate pass (like with SimplePassGame).  Seems like a bad use of the scenegraph to force your gui to be part of your scene.

darkfrog said:

I believe it writes to the screen buffer.

ortho queue seems really wrong then

yep, a pass should be fine, but I believe he asked how to integrate in SimpleGame... can you integrate a pass after the queue processing in SimpleGame?

yipp, a separate pass would be the cleaner way to go instead of keeping FengGUI directly in the scenegraph.



The SimpleGame requirement was actually just a starting point for me to get going from a fail-safe basis. In fact, I dont know darkfrogs setting at all, so it might be that he is fine with having an additonal FengGUI rendering pass.



From what I know about rendering passes is that they just render the scene (entirely or partially depends on the task) in the off (e.g. on a texture) in order to use the result in later rendering passes. I believe that's what you do to cast shadows and render reflections. But I confess I never did that before, so I was wondering if someone could tell me a brief recipe on how to best render FengGUI in a separate pass with jME?  :slight_smile:



Johannes

Wait, is this transparency issue the thing that makes ComboBox not work in BasicGameState?  Transparency for the Frame works fine though… just as soon as I make a ComboBox it freezes.



I'm using StandardGame, BasicGameState… making my own FengGUIGameState when I hit that problem.



I'll fiddle with it for a while longer, and if I can't fix it, then I'll post the code in a day or so.





Just making a ComboBox causes it to freeze, even if I don't add it to anything!



Inside my GameState; Freezes!

Exception in thread "main" java.lang.NullPointerException

at org.lwjgl.opengl.GL11.glGenTextures(GL11.java:1317)

at org.fenggui.render.lwjgl.LWJGLTextureLoader.createTextureID(LWJGLTextureLoader.java:83)

at org.fenggui.render.lwjgl.LWJGLTextureLoader.getTexture(LWJGLTextureLoader.java:215)

at org.fenggui.render.lwjgl.LWJGLBinding.getTexture(LWJGLBinding.java:60)

at org.fenggui.xml.theme.DefaultTheme.setUp(DefaultTheme.java:168)

at org.fenggui.xml.theme.StandardTheme.setUp(StandardTheme.java:67)

at org.fenggui.StandardWidget.setupTheme(StandardWidget.java:73)

at org.fenggui.ComboBox.<init>(ComboBox.java:108)  setupTheme(ComboBox.class);

at gui.FengGUIGameState.initGUI(FengGUIGameState.java:107)

at gui.FengGUIGameState.<init>(FengGUIGameState.java:77)



Outside GameState! Distorts frame.

Exception in thread "main" java.lang.NullPointerException

at org.lwjgl.opengl.GL11.glGenTextures(GL11.java:1317)

at org.fenggui.render.lwjgl.LWJGLTextureLoader.createTextureID(LWJGLTextureLoader.java:83)

at org.fenggui.render.lwjgl.LWJGLTextureLoader.getTexture(LWJGLTextureLoader.java:215)

at org.fenggui.render.lwjgl.LWJGLBinding.getTexture(LWJGLBinding.java:60)

at org.fenggui.xml.theme.DefaultTheme.setUp(DefaultTheme.java:168)

at org.fenggui.xml.theme.StandardTheme.setUp(StandardTheme.java:67)

at org.fenggui.StandardWidget.setupTheme(StandardWidget.java:73)

at org.fenggui.ComboBox.<init>(ComboBox.java:108)

at BS.init(BS.java:94)

at BS.main(BS.java:133)



In both case all I did was: ComboBox list = new ComboBox();

Nothing else!



Ack! Now im getting distorted frames without ComboBox…  ok, I had no probs with FengGUI till I started using threads… so I'm thinking I'm just screwing that up…

Yes, but this time we cannot solve this by setting useDepthTest to true apparently, because we got transparent objects in the scene. And the transparent objects are always drawn above FengGUI.

@EmperorLiam, you have to create your components for FengGUI in the OpenGL thread.  Everything in FengGUI seems to be direct LWJGL calls so you need to wrap it in an invocation to GameTaskQueue.  That will solve your problem, what Schabby is referring to is my problem that he still hasn't solved.  :stuck_out_tongue:

Its' been a few years since I looked at the mechanics behind OpenGL, but what if FengGUI was rendered into the "QUEUE_TRANSPARENT bucket", wouldn't it then be rendered last like you want?



I figured out that FengGUI needed to be rendered in the OpenGL thread last night, but thanks for telling me a good way to go about doing that DarkFrog!



Gnarf90, DarkFrog's tutorials also have more info on StandardGame and GameTaskQueueManager:

http://www.jmonkeyengine.com/wiki/doku.php?id=simplegame_to_standardgame

http://www.jmonkeyengine.com/wiki/doku.php?id=standardgame_gamestates_and_multithreading_a_new_way_of_thinking

Hello,

I have the same problem. How can I wrap it in an invocation to GameTaskQueue. I'm an absolutely newbie in JME  , so a piece of code would help.

All of the instantiation stuff is done in the constructor of FengGameState:


      GameTaskQueueManager.getManager().update(new Callable<Object>() {
         public Object call() throws Exception {
            FengGameState state = new FengGameState();
            GameStateManager.getInstance().attachChild(state);
            state.setActive(true);
            return null;
         }
      });



It's important to note that you need to have support for GameTaskQueue in your game for this to work.  If you're using StandardGame that support is already there.
you have to create your components for FengGUI in the OpenGL thread.  Everything in FengGUI seems to be direct LWJGL calls so you need to wrap it in an invocation to GameTaskQueue.


yeah, textures are uploaded to the video memory already in the initialization phase. That's why you get this kind of error there. I will make that an item in the FAQ.

EDIT: @EmperorLiam: When I replied to your post there was only the first line of your final post, that's why my answer seems to be a bit far off  :)

  That will solve your problem, what Schabby is referring to is my problem that he still hasn't solved.  tongue


hehe, yes, I am confident that we will solve that problem soon.

You better, or I'll be forced to write "FrogGUI" - pronounced "froggy". :wink:

lol

For all of you who have trouble with FengGUI being drawn above your transparent objects, I post some quick and dirty hack below that wraps FengGUI in a spatial. When setting the FengGUISpation to ORTH_QUEUE (setRenderQueueMode(Renderer.QUEUE_ORTHO)), it will be put in the ortho bucket which ensures that it is drawn at the end of the update cycle. This solves the occlusion problem.


class FengGUISpatial extends Quad
   {

      @Override
      public void draw(Renderer r)
      {
         
         if(!r.isProcessingQueue())
         {
            r.checkAndAdd(this);
            return;
         }
         
         // drawing FengGUI
         disp.display();
         
         
      }

      public void onDraw(Renderer r)
      {
         super.onDraw(r);
      }
      
      @Override
      public void findCollisions(Spatial scene, CollisionResults results)
      {
      }

      @Override
      public void findPick(Ray toTest, PickResults results)
      {
      }

      @Override
      public boolean hasCollision(Spatial scene, boolean checkTriangles)
      {
         return false;
      }

      @Override
      public void setModelBound(BoundingVolume modelBound)
      {
      }

      @Override
      public void updateModelBound()
      {
      }

      @Override
      public int getType()
      {
         return 0;
      }

      @Override
      public void updateWorldBound()
      {
      }

   }



However, although it should work, it is certainly not the cleanest solution. We will continue to work on drawing FengGUI in a separate render pass. But for the time being, this hack will hopefully suffice.

I just wanted to update this thread in case someone has the same issues.



Making a fengGUI pass is actually quite simple, however there is one caveat; it must be added before a shadow pass.  This means that the shadow pass must be last, and the fengGUI pass must be second to last.  There is probably a render state that needs to be reset, however I couldn't figure out what it was from empirical debugging.  This workaround does seem to solve the renderQueue( Transparent ) problem also, so thats a plus.



here's the code that I used to make a fengGUI pass



import com.jme.image.Texture;
import com.jme.math.Vector3f;
import com.jme.renderer.Renderer;
import com.jme.renderer.pass.Pass;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import org.fenggui.Display;
import org.fenggui.render.Binding;


// This should probably extend GameState so jME can easily enable and disable
public class FengPass extends Pass {
   
   
    private Display display;

    private TextureState defaultTextureState = null;
   
   
    public Feng_MessageWindow() {
       
        display = new org.fenggui.Display( new org.fenggui.render.lwjgl.LWJGLBinding() );

        // Create default texture state to reset from jME to fengGUI
        Texture defTex = TextureState.getDefaultTexture().createSimpleClone();
        defTex.setScale( Vector3f.UNIT_XYZ.clone() );
        defaultTextureState = DisplaySystem.getDisplaySystem().getRenderer().createTextureState();
        defaultTextureState.setTexture( defTex );

       // Make fengGUI stuff...
    }


   
   
   
   
    // jME State Methods
    @Override
    public void doUpdate( float timePerFrame ) {
    }
   
    @Override
    public void doRender( Renderer renderer ) {
        defaultTextureState.apply();
        display.display();
    }
   
    @Override
    public void cleanUp() {
    }
   
   
}

Hey Schabby,



For the time being, I'm using your solution! Hoping you'll find the best way to render FengGUI as soon as possible!



Good luck to you!

The pass method or the Quad??



If you use the path method let me know if there are any issues;  I haven't found any problems yet so maybe it is the holy grail of jME/fengGUI integration.  But I would like to know if there is something I have missed (I haven't tested it with Bloom and some other stuff).

Hi guys,



I have an issue with both approaches (rendering to a Quad or using a pass):

If I render FengGUI before the shadow pass, the shadows appear over the GUI; And if I render FengGUI after the shadow pass, FengGUI only appears where there’s shadow  :frowning:



Please take a look at the images to get a better picture of what’s going on…

I’m using the current stable version of both JME and FengGUI



Rendering FengGUI before the shadow pass:





Rendering FengGUI after the shadow pass:





Any ideas?

Thanks