Well, I tried momoko_fans context system and in my case I couldn't overcome the exception:
Exception in thread "AWT-EventQueue-1" java.lang.NullPointerException
at com.jme.renderer.lwjgl.LWJGLCamera.doFrustumChange(LWJGLCamera.java:193)
your workaround for this issue doesn't work for me...
I have to thank you anyway, because I didn't give my original solution and I found a workaround XD
I will explain in case this will help someone in the future.
As I already wrote first problem was with
yUpCamera. In the
RenParticleEditor this method is called in the constructor, because it assumes that canvas will be immediately displayed. In my case the tab that contains the canvas is not initially active. And because canvas are not visible,
impl.getRenderer() returns
null in the constructor.
A workaround for this is to wrap
yUpCamera in a thread that waits for the
impl.getRenderer() to return the renderer.
private class CameraScheduller extends Thread {
public CameraScheduller() {
super();
}
public void run() {
yUpCamera();
}
private void yUpCamera() {
Camera cam = null;
while (cam == null)
try {
cam = impl.getCamera();
Thread.sleep(100);
}
catch (InterruptedException e)
{}
camhand.worldUpVector.set(Vector3f.UNIT_Y);
cam.getLocation().set(0, 850, -850);
camhand.recenterCamera();
grid.getLocalRotation().fromAngleAxis(0, Vector3f.UNIT_X);
grid.updateRenderState();
prefs.putBoolean("yUp", true);
}
}
public void yUpCamera() {
new CameraScheduller().start();
}
The last thing is to call this thread in the JTabbedPane listener when the tab with canvas is activated.
tabbedPane.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent changeEvent) {
// check if we selected the canvas pane
if (statePanel.equals(tabbedPane.getComponentAt(tabbedPane.getSelectedIndex())))
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
clusteringStatePanel.setupCamera();
}
catch (Exception e) {
e.printStackTrace();
}
}
});
}
});
Second problem occurs with
doResize - it throws
java.lang.NullPointerException in
GL11.glViewport.
This one was really tough! The only solution I found is to hide all the canvas except the one that will be resized, than resize the canvas and finally show the canvas that were hidden.
I will post only the essential parts of the code. First of all you will have to store references to all canvas in a way that they can be accessed for a canvas itself. I solved it creating a singleton factory that stores all the canvas that it has created.
Than you created two methods:
public static void setSingleViewerVisible(UUID viewerUUID) {
for (ClusteringViewer clusteringViewer : getClusteringViewers())
if (clusteringViewer.viewerUUID.equals(viewerUUID))
clusteringViewer.setCanvasVisible(true);
else
clusteringViewer.setCanvasVisible(false);
}
public static void setAllViewersVisible(boolean visible) {
for (ClusteringViewer clusteringViewer : getClusteringViewers())
clusteringViewer.setCanvasVisible(visible);
}
The lest step is to modify the
doResize:
protected void doResize() {
if (impl != null)
if (impl.getCamera() != null) {
// hide canvas in all instances but the one that is being resized
ClusteringViewerFactory.setSingleViewerVisible(parentUUID);
Callable<Void> resize = new Callable<Void>() {
public Void call() {
// resize the canvas
impl.resizeCanvas(glCanvas.getWidth(), glCanvas.getHeight());
impl.getCamera().setFrustumPerspective(45.0f, (float) glCanvas.getWidth() / (float) glCanvas.getHeight(), 1, 10000);
// show all canvas
Callable<Void> resizeFinished = new Callable<Void>() {
public Void call()
{
ClusteringViewerFactory.setAllViewersVisible(true);
return null;
}
};
GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).enqueue(resizeFinished);
return null;
}
};
GameTaskQueueManager.getManager().getQueue(GameTaskQueue.RENDER).enqueue(resize);
}
}
Hope this helps someone, because I wasted whole day working it out....