package icy.vtk; import icy.gui.dialog.IdConfirmDialog; import icy.gui.dialog.MessageDialog; import icy.gui.frame.progress.FailedAnnounceFrame; import icy.system.IcyExceptionHandler; import icy.system.IcyHandledException; import icy.system.thread.ThreadUtil; import icy.util.OpenGLUtil; import icy.util.ReflectionUtil; import java.awt.Graphics; import java.util.concurrent.locks.ReentrantLock; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLContext; import javax.media.opengl.GLEventListener; import javax.media.opengl.GLProfile; import javax.media.opengl.awt.GLJPanel; import jogamp.opengl.GLDrawableHelper; import vtk.vtkCamera; import vtk.vtkGenericOpenGLRenderWindow; import vtk.vtkGenericRenderWindowInteractor; import vtk.vtkLight; import vtk.vtkRenderWindow; import vtk.vtkRenderWindowInteractor; import vtk.vtkRenderer; import vtk.vtkTIFFWriter; import vtk.vtkWindowToImageFilter; public class VtkJoglPanel extends GLJPanel { class GLEventImpl implements GLEventListener { @Override public void init(GLAutoDrawable drawable) { if (!windowset) { windowset = true; // Make sure the JOGL Context is current GLContext ctx = drawable.getContext(); if (!ctx.isCurrent()) ctx.makeCurrent(); // Init VTK OpenGL RenderWindow rw.SetMapped(1); rw.SetPosition(0, 0); setSize(drawable.getWidth(), drawable.getHeight()); rw.OpenGLInit(); // init light if (!lightingset) { lightingset = true; ren.AddLight(lgt); lgt.SetPosition(cam.GetPosition()); lgt.SetFocalPoint(cam.GetFocalPoint()); } } } @Override public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { setSize(width, height); } @Override public void display(GLAutoDrawable drawable) { render(); } @Override public void dispose(GLAutoDrawable drawable) { delete(); } } /** * */ private static final long serialVersionUID = 8821516677188995191L; protected vtkGenericOpenGLRenderWindow rw; protected vtkRenderer ren; protected vtkRenderWindowInteractor wi; protected vtkCamera cam; protected vtkLight lgt; protected ReentrantLock lock; protected GLEventImpl glEventImpl; protected int lastX; protected int lastY; protected boolean windowset; protected boolean lightingset; protected int interactionMode; protected boolean rendering; private boolean failed; public VtkJoglPanel() { super(new GLCapabilities(GLProfile.getDefault())); rw = new vtkGenericOpenGLRenderWindow(); // init render window rw.SetIsDirect(1); rw.SetSupportsOpenGL(1); rw.SetIsCurrent(true); // FIXME: smoothing is broken with VTK 6.3 // rw.SetPointSmoothing(1); // rw.SetLineSmoothing(1); // rw.SetPolygonSmoothing(1); // rw.SetMultiSamples(4); // init window interactor wi = new vtkGenericRenderWindowInteractor(); wi.SetRenderWindow(rw); wi.ConfigureEvent(); ren = new vtkRenderer(); ren.SetLightFollowCamera(1); cam = null; lgt = new vtkLight(); // set ambient color to white lgt.SetAmbientColor(1d, 1d, 1d); lock = new ReentrantLock(); glEventImpl = new GLEventImpl(); windowset = false; lightingset = false; rendering = false; failed = false; addGLEventListener(glEventImpl); rw.AddRenderer(ren); cam = ren.GetActiveCamera(); // super.setSize(200, 200); // rw.SetSize(200, 200); // not compatible with OpenGL 3 ? (new VTK OpenGL backend require OpenGL 3.2) if (!OpenGLUtil.isOpenGLSupported(3)) { if (!IdConfirmDialog .confirm( "Warning", "Your graphics card driver does not support OpenGL 3, you may experience issues or crashes with VTK.\nDo you want to try anyway ?", IdConfirmDialog.YES_NO_OPTION, getClass().getName() + ".notCompatibleDialog")) throw new IcyHandledException("Your graphics card driver is not compatible with OpenGL 3 !"); } } /** * @deprecated Use {@link #disposeInternal()} instead */ @Deprecated public void Delete() { delete(); } protected void delete() { if (rendering) { rw.SetAbortRender(1); // wait a bit while rendering ThreadUtil.sleep(500); // still rendering --> exit if (rendering) return; } lock.lock(); try { // prevent any further rendering rendering = true; // if (getParent() != null) // getParent().remove(this); // release internal VTK objects ren = null; cam = null; lgt = null; // On linux we prefer to have a memory leak instead of a crash if (!rw.GetClassName().equals("vtkXOpenGLRenderWindow")) { rw = null; } else { System.out.println("The renderwindow has been kept arount to prevent a crash"); } // call it only once in parent as this can take a lot of time // vtkObjectBase.JAVA_OBJECT_MANAGER.gc(false); } finally { // removing the renderWindow is let to the superclass // because in the very special case of an AWT component // under Linux, destroying renderWindow crashes. lock.unlock(); } } /** * Disable method, use {@link #disposeInternal()} instead to release VTK and OpenGL resources */ @Override protected void dispose() { // prevent disposal on removeNotify as window externalization produce remove/add operation. // --> don't forget to call disposeInternal when needed } /** * Release VTK and OGL objects.<br> * Call it when you know you won't use anymore the VTK OGL panel */ public void disposeInternal() { super.dispose(); // remove the GL event listener to avoid memory leak removeGLEventListener(glEventImpl); try { // hacky fix to avoid the infamous memory leak from ThreadLocal from GLPanel ! final GLDrawableHelper helper = (GLDrawableHelper) ReflectionUtil.getFieldObject(this, "helper", true); final ThreadLocal threadLocal = (ThreadLocal) ReflectionUtil.getFieldObject(helper, "perThreadInitAction", true); threadLocal.remove(); } catch (Throwable t) { // ignore } } /** * @deprecated Use {@link #lock()} instead */ @Deprecated public void Lock() { lock(); } /** * @deprecated Use {@link #unlock()} instead */ @Deprecated public void UnLock() { unlock(); } /** * @deprecated Use {@link #getRenderer()} instead */ @Deprecated public vtkRenderer GetRenderer() { return getRenderer(); } /** * @deprecated Use {@link #getRenderWindow()} instead */ @Deprecated public vtkRenderWindow GetRenderWindow() { return getRenderWindow(); } public vtkRenderer getRenderer() { return ren; } public vtkRenderWindow getRenderWindow() { return rw; } public vtkCamera getCamera() { return cam; } public vtkLight getLight() { return lgt; } public vtkRenderWindowInteractor getInteractor() { return wi; } /** * return true if currently rendering */ public boolean isRendering() { return rendering; } @Override public void setBounds(int x, int y, int width, int height) { super.setBounds(x, y, width, height); if (windowset) { final int[] size = rw.GetSize(); // set size only if needed if ((size[0] != width) || (size[1] != height)) { lock(); try { wi.SetSize(width, height); rw.SetSize(width, height); sizeChanged(); } finally { unlock(); } } } } /** * Called when window render size changed (helper for this specific event) */ public void sizeChanged() { // nothing here but can be overridden } /** * @deprecated Use {@link #render()} instead. */ @Deprecated public void Render() { render(); } /** * Do rendering */ public void render() { if (rendering) return; rendering = true; lock(); try { rw.Render(); } finally { unlock(); rendering = false; } } // public synchronized void Render() // { // // already rendering or rendering windows not defined --> exit // if ((rendering) || (rw == null)) // return; // // nothing to do --> exit // if (ren.VisibleActorCount() == 0) // return; // // rendering = true; // // try // { // if (windowset == 0) // { // // set the window id and the active camera // cam = ren.GetActiveCamera(); // // if (lightingset == 0) // { // ren.AddLight(lgt); // lgt.SetPosition(cam.GetPosition()); // lgt.SetFocalPoint(cam.GetFocalPoint()); // lightingset = 1; // } // // windowset = 1; // setSize(getWidth(), getHeight()); // } // // lock(); // rw.Render(); // unlock(); // } // finally // { // rendering = false; // } // } public boolean isWindowSet() { return windowset; } public void lock() { lock.lock(); } public void unlock() { lock.unlock(); } /** * @deprecated do nothing now */ @Deprecated public void InteractionModeRotate() { // } /** * @deprecated do nothing now */ @Deprecated public void InteractionModeTranslate() { // } /** * @deprecated do nothing now */ @Deprecated public void InteractionModeZoom() { // } /** * @deprecated Use {@link #updateLight()} instead */ @Deprecated public void UpdateLight() { updateLight(); } public void updateLight() { lgt.SetPosition(cam.GetPosition()); lgt.SetFocalPoint(cam.GetFocalPoint()); } public void resetCameraClippingRange() { lock(); try { ren.ResetCameraClippingRange(); } finally { unlock(); } } public void resetCamera() { lock(); try { ren.ResetCamera(); } finally { unlock(); } } @Override public void paint(Graphics g) { // previous failed --> do nothing now if (failed) return; try { super.paint(g); } catch (Throwable t) { // it can happen with older video cards failed = true; new FailedAnnounceFrame("An error occured while initializing OpenGL !\n" + "You may try to update your graphics card driver to fix this issue.", 0); IcyExceptionHandler.handleException(t, true); } } /** * @deprecated Use {@link #doHardCopy(String, int)} instead */ @Deprecated public void HardCopy(String filename, int mag) { doHardCopy(filename, mag); } public void doHardCopy(String filename, int mag) { lock(); vtkWindowToImageFilter w2if = new vtkWindowToImageFilter(); w2if.SetInput(rw); w2if.SetMagnification(mag); w2if.Update(); vtkTIFFWriter writer = new vtkTIFFWriter(); writer.SetInputConnection(w2if.GetOutputPort()); writer.SetFileName(filename); writer.Write(); unlock(); } }