WaterRenderPass causes NullPointerException in LWJGLDisplaySystem

Hi,



i have a new problem. I make a program that has a SimpleCanvasImpl class. In this class I load a new class which extends SimplePassGame. In this class I want to create a projectedGrid water. But I always get an issue from LWJGLDisplaySystem.



Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
        at com.jme.renderer.lwjgl.LWJGLTextureRenderer.<init>(LWJGLTextureRenderer.java:104)
        at com.jme.system.lwjgl.LWJGLDisplaySystem.createTextureRenderer(LWJGLDisplaySystem.java:327)
        at com.jmex.effects.water.WaterRenderPass.initialize(WaterRenderPass.java:205)
        at com.jmex.effects.water.WaterRenderPass.<init>(WaterRenderPass.java:182)
        at jmetool.createWater.setupWater(createWater.java:58)
        at jmetool.jmeClass.einbinden(jmeClass.java:680)
        at jmetool.LiveNode.addToNode(LiveNode.java:249)
        at jmetool.Main$2.actionPerformed(Main.java:204)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:387)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:242)
        at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:236)
        at java.awt.Component.processMouseEvent(Component.java:6134)
        at javax.swing.JComponent.processMouseEvent(JComponent.java:3265)
        at java.awt.Component.processEvent(Component.java:5899)
        at java.awt.Container.processEvent(Container.java:2023)
        at java.awt.Component.dispatchEventImpl(Component.java:4501)
        at java.awt.Container.dispatchEventImpl(Container.java:2081)
        at java.awt.Component.dispatchEvent(Component.java:4331)
        at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4301)
        at java.awt.LightweightDispatcher.processMouseEvent(Container.java:3965)
        at java.awt.LightweightDispatcher.dispatchEvent(Container.java:3895)
        at java.awt.Container.dispatchEventImpl(Container.java:2067)
        at java.awt.Window.dispatchEventImpl(Window.java:2458)
        at java.awt.Component.dispatchEvent(Component.java:4331)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:599)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)




Does anybody know why this is and how solve this problem?

Greetz

You propably need to make sure to create the WaterRenderPass inside the opengl thread.

I'm not quite sure if there is a separate opengl thread in your case or in which thread the opengl context is available.

I was reading this in another thread too, but I can't manage what I have to do for this.



Could you explain what I have to do to create the WaterRenderPass?





In JME 2 I'm currently mazed. Things that runs in JME 1 easily doesn't do that in JME 2, like the problem with the WaterRenderPass. Im JME 1 I maked programs in exactly the same way and there run it. Could it maybe be, that the problem with the WaterRenderPass comes from the Canvas in which it should run? I had to register the Canvas whith LWJGLAWTCanvasContructor what I didn't have to in JME 1.

can you post a minimalistic runnable example to reproduce the problem ?

no, I think it's impossible to make a minimalistic example but I try explain what I've done:


  • I've a main class which extends JFrame. In this class I've a canvas.
  • Also I've a class which extends SimpleCanvasImpl, which is shown in the canvas of main. From this class I call functions which are in another class. By calling the functions I send BasicPassManager and Camera to the other class.



    If this don't help I upload a .rar of my code.

Try to create the waterrenderpass inside a callable which is sent to the GameTaskQueueManager.



        Callable<?> exe = new Callable<Object>() {
            public Object call() {
                water = new WaterRenderPass(...)
                return null;
            }
        };
        GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).enqueue(exe);



You might have to update and render the queue in your SimeplCanvas.doUpdate() and doRender() Methods if it not already done.


GameTaskQueueManager.getManager().getQueue(GameTaskQueue.UPDATE).execute();
GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).execute();

no, that doesn't help  :frowning:



My class to create the water looks now:



public void setupWater(Node root, float hoeheGross, float hoeheKlein, float speedGross, float speedKlein, BasicPassManager pManager, final Camera cam, Skybox skybox)
    {
        System.out.println(cam.getLocation());

        Callable<?> exe = new Callable<Object>() {
            public Object call() {
                waterPass= new WaterRenderPass(cam, 4, true, true);
                return null;
            }
        };
        GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).enqueue(exe);

        waterPass.setClipBias(0.5f);
        waterPass.setWaterMaxAmplitude(5.0f);
        // setting to default value just to show
        waterPass.setWaterPlane(new Plane(new Vector3f(0.0f, 1.0f,0.0f), 0.0f));

        WaterHeightGenerator water = new WaterHeightGenerator();
        water.setHeightbig(hoeheGross);
        water.setHeightsmall(hoeheKlein);
        water.setSpeedbig(speedGross);
        water.setSpeedsmall(speedKlein);

        projectedGrid = new ProjectedGrid("ProjectedGrid", cam, 100, 70, 0.01f,water);

        waterPass.setWaterEffectOnSpatial(projectedGrid);
        root.attachChild(projectedGrid);

       
        waterPass.setReflectedScene(scene);
        waterPass.setSkybox(skybox);
        pManager.add(waterPass);
    }




My updatefunction of the SimpleCanvasImpl:


public void simpleUpdate()
    {
        pManager.updatePasses(tpf);
        InputSystem.update();
        input.update(tpf);
        GameTaskQueueManager.getManager().getQueue(GameTaskQueue.UPDATE).execute();
    }




And my renderfunction of the SimpleCanvasImpl:


public void simpleRender()
    {
        pManager.renderPasses(getRenderer());
        GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).execute();
    }

hmm can you post the exception again now ? it has to work because i'm out of ideas…

The new exception is a NullPointerException by the call of waterPass.setClipBias(0.5f) caus the WaterRenderPass isn't initialized.



If you are out of ideas, what should I then say. This problem sucks really.

NullPointerException, thats a completely different problem tho.



Its because GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).enqueue(exe); just adds the creation of the waterrender pass to the queue.

It is executed asynchronously  in another thread.



try this instead, to wait add the callable to the queue and wait until it is fninished.


GameTaskQueueManager.getManager().render(exe).get();



This might result in a deadlock if the opengl thread is not yet running at the time you call setupWater().

If that is the case, you could wrap the whole setupWater() call  in a Callable and then not call get(), so that the callable gets executed as soon as your application starts.
In the latter case, add a root.updateRenderstate() at the end of the setupWater() method tho.

Your post brought me to another idea. I create the WaterRenderPass now at the programstart and send the created WaterRenderPass to the setupWater() function. Now it runs. I know, it's not a very clean solution but it functions.



Thanks Core-Dumb for your effort.