ImagePainter + Texture2D = NPE issue

@nehon, merci, j’essaie de faire au mieux ^^
C’est pas faux, on pense français puis on tente de traduire alors qu’on devrait penser anglais directement :stuck_out_tongue:

héhé :slight_smile:

So for the test case the following code is just the renderToTexture with imagepainter code added not really my code but the npe is here ^^.
[java]/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
    */
    package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f;
import com.jme3.renderer.Camera;
import com.jme3.renderer.ViewPort;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.texture.FrameBuffer;
import com.jme3.texture.Image.Format;
import com.jme3.texture.Texture;
import com.jme3.texture.Texture2D;
import com.zero_separation.plugins.imagepainter.ImagePainter;

/**
*

  • @author Florent
    */

public class Main extends SimpleApplication implements ActionListener {

private static final String TOGGLE_UPDATE = "Toggle Update";
private Geometry offBox;
private float angle = 0;
private ViewPort offView;
Texture2D myTexture;

ImagePainter ip;

//for delay
float myUpdateTimer = 0;
float myUpdateTime = 10; //with 10 sec the texture is displayed a lot of times

public static void main(String[] args){
    Main app = new Main();
    app.start();
}

public Texture2D setupOffscreenView(){
    Camera offCamera = new Camera(512, 512);

    offView = renderManager.createPreView("Offscreen View", offCamera);
    offView.setClearFlags(true, true, true);
    offView.setBackgroundColor(ColorRGBA.DarkGray);

    // create offscreen framebuffer
    FrameBuffer offBuffer = new FrameBuffer(512, 512, 1);

    //setup framebuffer's cam
    offCamera.setFrustumPerspective(45f, 1f, 1f, 1000f);
    offCamera.setLocation(new Vector3f(0f, 0f, -5f));
    offCamera.lookAt(new Vector3f(0f, 0f, 0f), Vector3f.UNIT_Y);

    //setup framebuffer's texture
    Texture2D offTex = new Texture2D(512, 512, Format.RGBA8);
    offTex.setMinFilter(Texture.MinFilter.Trilinear);
    offTex.setMagFilter(Texture.MagFilter.Bilinear);

    //setup framebuffer to use texture
    offBuffer.setDepthBuffer(Format.Depth);
    offBuffer.setColorTexture(offTex);
    
    //set viewport to render to offscreen framebuffer
    offView.setOutputFrameBuffer(offBuffer);

    // setup framebuffer's scene
    Box boxMesh = new Box(Vector3f.ZERO, 1,1,1);
    Material material = assetManager.loadMaterial("Interface/Logo/Logo.j3m");
    offBox = new Geometry("box", boxMesh);
    offBox.setMaterial(material);

    // attach the scene to the viewport to be rendered
    offView.attachScene(offBox);
    
    
    //ip = new ImagePainter(offTex.getImage());
    
    return offTex;
}

@Override
public void simpleInitApp() {
    cam.setLocation(new Vector3f(3, 3, 3));
    cam.lookAt(Vector3f.ZERO, Vector3f.UNIT_Y);

    //setup main scene
    Geometry quad = new Geometry("box", new Box(Vector3f.ZERO, 1,1,1));

    myTexture = setupOffscreenView();

    Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
    mat.setTexture("ColorMap", myTexture);
    quad.setMaterial(mat);
    rootNode.attachChild(quad);
    inputManager.addMapping(TOGGLE_UPDATE, new KeyTrigger(KeyInput.KEY_SPACE));
    inputManager.addListener(this, TOGGLE_UPDATE);
}

@Override
public void simpleUpdate(float tpf){
    
    Quaternion q = new Quaternion();
    
    if (offView.isEnabled()) {
        angle += tpf;
        angle %= FastMath.TWO_PI;
        q.fromAngles(angle, 0, angle);
        
        offBox.setLocalRotation(q);
        offBox.updateLogicalState(tpf);
        offBox.updateGeometricState();
        myUpdateTimer += tpf;
        if (myUpdateTimer >= myUpdateTime) {
            myUpdateTimer = 0;
            ip = new ImagePainter(myTexture.getImage());
            ip.paintRect(0, 0, 20, 20, ColorRGBA.Green, ImagePainter.BlendMode.SET);
        }
    }
}

@Override
public void onAction(String name, boolean isPressed, float tpf) {
    if (name.equals(TOGGLE_UPDATE) && isPressed) {
        offView.setEnabled(!offView.isEnabled());
    }
}

}[/java]

I’ve found two other possible ways to avoid the problem in my game(need a try) but it doesn’t explains why the npe occurs with that method.

1 Like

great, I’m gonna look into it.

The two other ways don’t succeed for now…GrrrRRrrr.

Do you found something on your side @nehon?

Sorry I didn’t, I’ll look into it.

Actually, it seems that when you render a texture in a framebuffer the CPU side buffer is never filled (which makes sense, all is on the GPU).
I’m afraid you can’t do what you want like this.

What you could do though is to render the background of the map (like you do right now), and instead of writing pixel to it with the image painter, have a transparent cpu overlay texture (on a quad) where you render the additional things with the image painter.

1 Like

Hey, you’re right, it makes sense indeed…

O_o, yeah, but why i didn’t found it myself, good idea :).

Edit: And it works pretty well without a lot of additionnal work. Thank you very much for the search and especially for the tip :D.

Actually could’nt we make some kind of assertions or similar, that would give a clean exception when trying to get that buffer of a gpu only image?

Eg

    public List getData() {
        if(data == null){
             throw new RuntimeException("No data buffer present, is image Gpu only? (eg frambuffer?)");
        }
        return data;
    }
1 Like
@Empire Phoenix said: Actually could'nt we make some kind of assertions or similar, that would give a clean exception when trying to get that buffer of a gpu only image?

Eg

[code]
public List getData() {
if(data == null){
throw new RuntimeException(“No data buffer present, is image Gpu only? (eg frambuffer?)”);
}
return data;
}

[/code]


yep that looks fine