How to Render a GLCanvas inside jME3

Hi,

I’m trying to render an existing GLCanvas (javax.media.opengl.awt.GLCanvas) inside the jME3-Scene.
The GLCanvas is placed inside a JPanel and this JPanel inside a JFrame. The code of the initial Situation looks like:


java.awt.Dimension size = new Dimension(620, 900);
 
// Magic Method that returns the GLCanvas as a java.awt.Component
java.awt.Component comp;
comp = someThirdPartyApp.getCanvas();
 
/* INITIALIZATION BEGIN */
 
// create JPanel and configure it
javax.swing.JPanel panel;
panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
panel.setPreferredSize(size);
panel.setMinimumSize(size);
panel.setMaximumSize(size);
panel.setSize(size);
panel.setBounds(0, 0, size.width, size.height);
panel.setBackground(Color.red);
 
// Add the GLCanvas which is in the comp variable to the JPanel
panel.add(comp, BorderLayout.CENTER);
panel.setVisible(true);
 
// create JFrame and configure it
javax.swing.JFrame frame;
frame = new JFrame();
frame.setBackground(Color.PINK);
frame.setUndecorated(true);
frame.setPreferredSize(size);
frame.setMinimumSize(size);
frame.setMaximumSize(size);
frame.setSize(size);
frame.setBounds(0, 0, size.width, size.height);
// Add the panel to the frame
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
 
// Cast the Component to a GLCanvas Object
javax.media.opengl.awt.GLCanvas glCanvas;
glCanvas = (GLCanvas) comp;

// Getting the jogl context of that glCanvas 
javax.media.opengl.GL gl = null;
while( (gl=glCanvas.getGL()) == null) {
        try {
                Thread.sleep(50);
        } catch (InterruptedException ex) {
                Logger.getLogger(Game.class.getName()).log(Level.SEVERE, null, ex);
        }
}

Running this part of the code shows the contents of the GLCanvas in the JFrame. But it’s not rendered in jME right now (just going sure that it works until this step)

Now I have three different approaches to achieve what I’m trying to do:

  1. Render the JPanel…
  2. Render the JFrame…
  3. Render the GLCanvas…
    …into a com.jme3.texture.Texture2D and place it on a Geometry-Object.
    I sadly didn’t get it working yet. Here is what I’ve done (this code follows the above code-lines ):

// hide the Frame again (Context is only created if the canvas is visible, so hide it after creation. have to work on this)
frame.setVisible(false);

// Definition of a Geometry wich will use the created Texture2D as a Material
Box viewerMesh = new Box( size.x/200f, size.y/200f, 0f);
Geometry plane = new Geometry("Viewer Plane", viewerMesh);
// Set initial Material to green Color
Material backgroundColor = new Material(assetManager,
		"Common/MatDefs/Misc/Unshaded.j3md");       // create a simple material
backgroundColor.setColor("Color", ColorRGBA.Green);  // set color of material to green
plane.setMaterial(backgroundColor);     // set the plane's material
plane.setLocalTranslation(new Vector3f(0f, 0f, 5f));  // Set Position
rootNode.attachChild(plane);

/* INITIALIZATION END */

/* This is done in the update-loop */
updatePlane();

These are the used methods:


public void UpdatePlane() {
       java.awt.image.BufferedImage bImage;

       // 1. approach JPanel-> Texture2D
       bImage = createImage(panel);
       
       // 2. approach JFrame -> Texture2D
       bImage = createImage(frame);
       
       // 3. approach GLCanvas -> Texture2D
       

       // Conversion of BufferedImage to com.jme3.texture.Image
       // works, tested with the monkey.png as Texture for a Geometry
       com.jme3.texture.Image image;
       image = awtLoader.load(bImage, false); 
       Texture2D planeTexture = new Texture2D(image);
       Material planeMat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
       planeMat.setTexture("ColorMap", planeTexture);
       plane.setMaterial(planeMat);
}

private BufferedImage createImage(JPanel panel) {        
	if(panel==null) {
	    return null;
	}
	
	int w = panel.getWidth();
	int h = panel.getHeight();
	BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
	Graphics2D g = bi.createGraphics();
	//panel.paintAll(g);
	panel.printAll(g);
	//panel.getComponent(0).print(g);
        g.dispose();
	return bi;
}

private BufferedImage createImage(JFrame frame) {
	if(frame==null) {
	    return null;
	}
	
	int w = frame.getWidth();
	int h = frame.getHeight();
	BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
	Graphics2D g = bi.createGraphics();
	frame.paintAll(g);
	//frame.printAll(g);
	g.dispose();
	return bi;
}

Results:

  1. approach with JFrame: the plane has a black Texture
  2. approach with JPanel: the plane shows the red JPanel but not its containing GLCanvas
  3. approach TODO

I would prefer not using a JFrame or JPanel at all, because it’s overhead which I’ll don’t need at all.

I did something similar with a native C++ OpenGL application whose framebuffer I highjacked and converted to a Texture2D. But I had access to the source code of the native app and could modify where the opengl output was rendered to. In this case I only have the GLCanvas and not much experience with jogl in combination jME3. If I could set the render output of the jogl GLCanvas, I should be able to use it for creating a texture.

Has anyone tried something similar ?
Any help would be appreciated.

Thank you!
Nosezeichen

I have done a similar thing… the solution is to create a material, assign a texture to it and just copy from the buffered image to that texture… I can see you doing this… but be sure that 1) you create the material, the texture and the image just once during the init and 2) you copy the data to the image on every new frame so that the picture gets updated. I remember once I had an issue that the image was still not updated on every frame and I had to reassign the image to the texture or the texture to the material or something like that, I do not remember exactly… does this help you a bit?