VTK.Rendering allows SWT-based VTK view, without AWT tread.
gitlab #2
Change-Id: Ida8a60eb56c012ea96be874888d0e72559e76204
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>vtk.rendering.win32.win32.x86_64</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
--- /dev/null
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: VTK Rendering X86_64
+Bundle-SymbolicName: vtk.rendering.win32.win32.x86_64
+Bundle-Version: 8.2.0.qualifier
+Fragment-Host: vtk.rendering;bundle-version="8.2.0"
+Automatic-Module-Name: vtk.rendering.win32.win32.x86_64
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Eclipse-PlatformFilter: (& (osgi.ws=win32) (osgi.os=win32) (osgi.arch=x86_64))
--- /dev/null
+This folder contains deprecated plain native libraries for platform windows-amd64, please use the native JAR files in the jar folder.
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry exported="true" kind="lib" path="lib/gluegen-rt.jar"/>
+ <classpathentry exported="true" kind="lib" path="lib/jogl-all.jar"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>vtk.rendering</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.8
--- /dev/null
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: VTK Rendering
+Bundle-SymbolicName: vtk.rendering
+Bundle-Version: 8.2.0.qualifier
+Automatic-Module-Name: vtk.rendering
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
+Require-Bundle: org.eclipse.swt;bundle-version="3.106.0",
+ vtk;bundle-version="8.2.0"
+Bundle-ClassPath: lib/jogl-all.jar,
+ .,
+ lib/gluegen-rt.jar
+Export-Package: com.jogamp.common,
+ com.jogamp.common.jvm,
+ com.jogamp.common.net,
+ com.jogamp.common.net.asset,
+ com.jogamp.common.nio,
+ com.jogamp.common.os,
+ com.jogamp.common.type,
+ com.jogamp.common.util,
+ com.jogamp.common.util.awt,
+ com.jogamp.common.util.cache,
+ com.jogamp.common.util.locks,
+ com.jogamp.gluegen.runtime,
+ com.jogamp.gluegen.runtime.opengl,
+ com.jogamp.graph.curve,
+ com.jogamp.graph.curve.opengl,
+ com.jogamp.graph.curve.tess,
+ com.jogamp.graph.font,
+ com.jogamp.graph.geom,
+ com.jogamp.nativewindow,
+ com.jogamp.nativewindow.awt,
+ com.jogamp.nativewindow.egl,
+ com.jogamp.nativewindow.swt,
+ com.jogamp.nativewindow.util,
+ com.jogamp.nativewindow.windows,
+ com.jogamp.nativewindow.x11,
+ com.jogamp.newt,
+ com.jogamp.newt.awt,
+ com.jogamp.newt.awt.applet,
+ com.jogamp.newt.event,
+ com.jogamp.newt.event.awt,
+ com.jogamp.newt.opengl,
+ com.jogamp.newt.opengl.util,
+ com.jogamp.newt.opengl.util.stereo,
+ com.jogamp.newt.swt,
+ com.jogamp.newt.util,
+ com.jogamp.newt.util.applet,
+ com.jogamp.opengl,
+ com.jogamp.opengl.awt,
+ com.jogamp.opengl.egl,
+ com.jogamp.opengl.fixedfunc,
+ com.jogamp.opengl.glu,
+ com.jogamp.opengl.glu.gl2,
+ com.jogamp.opengl.glu.gl2es1,
+ com.jogamp.opengl.math,
+ com.jogamp.opengl.math.geom,
+ com.jogamp.opengl.swt,
+ com.jogamp.opengl.util,
+ com.jogamp.opengl.util.av,
+ com.jogamp.opengl.util.awt,
+ com.jogamp.opengl.util.gl2,
+ com.jogamp.opengl.util.glsl,
+ com.jogamp.opengl.util.glsl.fixedfunc,
+ com.jogamp.opengl.util.glsl.sdk,
+ com.jogamp.opengl.util.packrect,
+ com.jogamp.opengl.util.stereo,
+ com.jogamp.opengl.util.stereo.generic,
+ com.jogamp.opengl.util.texture,
+ com.jogamp.opengl.util.texture.awt,
+ com.jogamp.opengl.util.texture.spi,
+ com.jogamp.opengl.util.texture.spi.awt,
+ jogamp.common,
+ jogamp.common.jvm,
+ jogamp.common.os,
+ jogamp.common.os.elf,
+ jogamp.common.util,
+ jogamp.common.util.locks,
+ jogamp.graph.curve.opengl,
+ jogamp.graph.curve.opengl.shader,
+ jogamp.graph.curve.tess,
+ jogamp.graph.font,
+ jogamp.graph.font.typecast,
+ jogamp.graph.font.typecast.ot,
+ jogamp.graph.font.typecast.ot.mac,
+ jogamp.graph.font.typecast.ot.table,
+ jogamp.graph.font.typecast.t2,
+ jogamp.graph.font.typecast.tt.engine,
+ jogamp.graph.geom.plane,
+ jogamp.nativewindow,
+ jogamp.nativewindow.awt,
+ jogamp.nativewindow.jawt,
+ jogamp.nativewindow.jawt.macosx,
+ jogamp.nativewindow.jawt.windows,
+ jogamp.nativewindow.jawt.x11,
+ jogamp.nativewindow.windows,
+ jogamp.nativewindow.x11,
+ jogamp.nativewindow.x11.awt,
+ jogamp.newt,
+ jogamp.newt.awt,
+ jogamp.newt.awt.event,
+ jogamp.newt.driver,
+ jogamp.newt.driver.awt,
+ jogamp.newt.driver.linux,
+ jogamp.newt.driver.opengl,
+ jogamp.newt.driver.windows,
+ jogamp.newt.driver.x11,
+ jogamp.newt.event,
+ jogamp.newt.swt,
+ jogamp.newt.swt.event,
+ jogamp.opengl,
+ jogamp.opengl.awt,
+ jogamp.opengl.egl,
+ jogamp.opengl.es1,
+ jogamp.opengl.es3,
+ jogamp.opengl.gl2,
+ jogamp.opengl.gl4,
+ jogamp.opengl.glu,
+ jogamp.opengl.glu.error,
+ jogamp.opengl.glu.gl2.nurbs,
+ jogamp.opengl.glu.mipmap,
+ jogamp.opengl.glu.nurbs,
+ jogamp.opengl.glu.registry,
+ jogamp.opengl.glu.tessellator,
+ jogamp.opengl.openal.av,
+ jogamp.opengl.util,
+ jogamp.opengl.util.av,
+ jogamp.opengl.util.av.impl,
+ jogamp.opengl.util.glsl,
+ jogamp.opengl.util.glsl.fixedfunc,
+ jogamp.opengl.util.jpeg,
+ jogamp.opengl.util.pngj,
+ jogamp.opengl.util.pngj.chunks,
+ jogamp.opengl.util.stereo,
+ jogamp.opengl.windows.wgl,
+ jogamp.opengl.windows.wgl.awt,
+ jogamp.opengl.x11.glx,
+ vtk.rendering,
+ vtk.rendering.awt,
+ vtk.rendering.swt
--- /dev/null
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ lib/jogl-all.jar,\
+ lib/gluegen-rt.jar
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<project
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.simantics.g3d</groupId>
+ <artifactId>org.simantics.g3d.root</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>vtk</artifactId>
+ <packaging>eclipse-plugin</packaging>
+ <version>8.2.0-SNAPSHOT</version>
+
+</project>
\ No newline at end of file
--- /dev/null
+package vtk.rendering.awt;
+
+import java.awt.Canvas;
+import java.awt.Dimension;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+
+import vtk.vtkObject;
+import vtk.vtkRenderWindow;
+import vtk.rendering.vtkAbstractComponent;
+
+/**
+ * Provide AWT based vtk rendering component
+ *
+ * @authors Sebastien Jourdain - sebastien.jourdain@kitware.com
+ * Joachim Pouderoux - joachim.pouderoux@kitware.com
+ */
+public class vtkAwtComponent extends vtkAbstractComponent<Canvas> {
+ protected vtkInternalAwtComponent uiComponent;
+ protected boolean isWindowCreated;
+ protected Runnable onWindowCreatedCallback;
+
+ public vtkAwtComponent() {
+ this(new vtkRenderWindow());
+ }
+
+ public vtkAwtComponent(vtkRenderWindow renderWindowToUse) {
+ super(renderWindowToUse);
+ this.isWindowCreated = false;
+ this.uiComponent = new vtkInternalAwtComponent(this);
+ this.uiComponent.addComponentListener(new ComponentAdapter() {
+
+ public void componentResized(ComponentEvent arg0) {
+ Dimension size = vtkAwtComponent.this.uiComponent.getSize();
+ vtkAwtComponent.this.setSize(size.width, size.height);
+ }
+ });
+ }
+
+ public void Render() {
+ // Make sure we can render
+ if (inRenderCall || renderer == null || renderWindow == null) {
+ return;
+ }
+
+ // Try to render
+ try {
+ lock.lockInterruptibly();
+ inRenderCall = true;
+
+ // Initialize the window only once
+ if (!isWindowCreated) {
+ uiComponent.RenderCreate(renderWindow);
+ setSize(uiComponent.getWidth(), uiComponent.getHeight());
+ isWindowCreated = true;
+ }
+
+ // Trigger the real render
+ renderWindow.Render();
+
+ // Execute callback if need be
+ if(this.onWindowCreatedCallback != null) {
+ this.onWindowCreatedCallback.run();
+ this.onWindowCreatedCallback = null;
+ }
+ } catch (InterruptedException e) {
+ // Nothing that we can do except skipping execution
+ } finally {
+ lock.unlock();
+ inRenderCall = false;
+ }
+ }
+
+ public Canvas getComponent() {
+ return this.uiComponent;
+ }
+
+ public void Delete() {
+ this.lock.lock();
+
+ // We prevent any further rendering
+ inRenderCall = true;
+
+ if (this.uiComponent.getParent() != null) {
+ this.uiComponent.getParent().remove(this.uiComponent);
+ }
+ super.Delete();
+
+ // On linux we prefer to have a memory leak instead of a crash
+ if (!this.renderWindow.GetClassName().equals("vtkXOpenGLRenderWindow")) {
+ this.renderWindow = null;
+ } else {
+ System.out.println("The renderwindow has been kept around to prevent a crash");
+ }
+ this.lock.unlock();
+ vtkObject.JAVA_OBJECT_MANAGER.gc(false);
+ }
+
+ /**
+ * @return true if the graphical component has been properly set and
+ * operation can be performed on it.
+ */
+ public boolean isWindowSet() {
+ return this.isWindowCreated;
+ }
+
+ /**
+ * Set a callback that gets called once the window is properly created and can be
+ * customized in its settings.
+ *
+ * Once called the callback will be released.
+ *
+ * @param callback
+ */
+ public void setWindowReadyCallback(Runnable callback) {
+ this.onWindowCreatedCallback = callback;
+ }
+
+ /**
+ * Just allow class in same package to affect inRenderCall boolean
+ *
+ * @param value
+ */
+ protected void updateInRenderCall(boolean value) {
+ this.inRenderCall = value;
+ }
+}
--- /dev/null
+package vtk.rendering.awt;
+
+import java.awt.Canvas;
+import java.awt.Graphics;
+
+import vtk.vtkRenderWindow;
+
+public class vtkInternalAwtComponent extends Canvas {
+ protected native int RenderCreate(vtkRenderWindow renderWindow);
+
+ private static final long serialVersionUID = -7756069664577797620L;
+ private vtkAwtComponent parent;
+
+ public vtkInternalAwtComponent(vtkAwtComponent parent) {
+ this.parent = parent;
+ this.addMouseListener(this.parent.getInteractorForwarder());
+ this.addMouseMotionListener(this.parent.getInteractorForwarder());
+ this.addMouseWheelListener(this.parent.getInteractorForwarder());
+ this.addKeyListener(this.parent.getInteractorForwarder());
+ }
+
+ public void addNotify() {
+ super.addNotify();
+ parent.isWindowCreated = false;
+ parent.getRenderWindow().SetForceMakeCurrent();
+ parent.updateInRenderCall(false);
+ }
+
+ public void removeNotify() {
+ parent.updateInRenderCall(true);
+ super.removeNotify();
+ }
+
+ public void paint(Graphics g) {
+ parent.Render();
+ }
+
+ public void update(Graphics g) {
+ parent.Render();
+ }
+}
--- /dev/null
+package vtk.rendering.awt;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionAdapter;
+import java.util.concurrent.locks.ReentrantLock;
+
+import vtk.vtkCamera;
+import vtk.vtkGenericRenderWindowInteractor;
+import vtk.vtkInteractorStyle;
+import vtk.vtkInteractorStyleTrackballCamera;
+import vtk.vtkPanel;
+import vtk.vtkRenderWindow;
+import vtk.vtkRenderer;
+import vtk.rendering.vtkComponent;
+import vtk.rendering.vtkInteractorForwarder;
+
+/**
+ * Provide AWT based vtk rendering component using the vtkPanel class
+ * while exposing everything as a new rendering component.
+ *
+ * @author Sebastien Jourdain - sebastien.jourdain@kitware.com
+ *
+ * Notes: This class should be replaced down the road by the vtkAwtComponent
+ * but on some platform such as Windows the vtkAwtComponent
+ * produce a runtime error regarding invalid pixel format while
+ * the vtkPanelComponent which use vtkPanel works fine.
+ * For now, this class provide a good substitute with just a minor overhead.
+ */
+
+public class vtkPanelComponent implements vtkComponent<vtkPanel> {
+ protected vtkPanel panel;
+ protected ReentrantLock lock;
+ protected vtkGenericRenderWindowInteractor windowInteractor;
+ protected vtkInteractorForwarder eventForwarder;
+
+ public vtkPanelComponent() {
+ this.panel = new vtkPanel();
+ this.lock = new ReentrantLock();
+
+ // Init interactor
+ this.windowInteractor = new vtkGenericRenderWindowInteractor();
+ this.windowInteractor.SetRenderWindow(this.panel.GetRenderWindow());
+ this.windowInteractor.TimerEventResetsTimerOff();
+
+ this.windowInteractor.SetSize(200, 200);
+ this.windowInteractor.ConfigureEvent();
+
+ // Update style
+ vtkInteractorStyleTrackballCamera style = new vtkInteractorStyleTrackballCamera();
+ this.windowInteractor.SetInteractorStyle(style);
+
+ // Setup event forwarder
+ this.eventForwarder = new vtkInteractorForwarder(this);
+ this.windowInteractor.AddObserver("CreateTimerEvent", this.eventForwarder, "StartTimer");
+ this.windowInteractor.AddObserver("DestroyTimerEvent", this.eventForwarder, "DestroyTimer");
+
+ // Remove unwanted listeners
+ this.panel.removeKeyListener(this.panel);
+ this.panel.removeMouseListener(this.panel);
+ this.panel.removeMouseMotionListener(this.panel);
+ this.panel.removeMouseWheelListener(this.panel);
+
+ // Add mouse listener that update interactor
+ this.panel.addMouseListener(this.eventForwarder);
+ this.panel.addMouseMotionListener(this.eventForwarder);
+ this.panel.addMouseWheelListener(this.eventForwarder);
+
+ // Make sure we update the light position when interacting
+ this.panel.addMouseMotionListener(new MouseMotionAdapter() {
+ public void mouseDragged(MouseEvent e) {
+ panel.UpdateLight();
+ }
+ });
+ }
+
+ public void resetCamera() {
+ this.panel.resetCamera();
+ }
+
+ public void resetCameraClippingRange() {
+ this.panel.resetCameraClippingRange();
+ }
+
+ public vtkCamera getActiveCamera() {
+ return this.panel.GetRenderer().GetActiveCamera();
+ }
+
+ public vtkRenderer getRenderer() {
+ return this.panel.GetRenderer();
+ }
+
+ public vtkRenderWindow getRenderWindow() {
+ return this.panel.GetRenderWindow();
+ }
+
+ public vtkGenericRenderWindowInteractor getRenderWindowInteractor() {
+ return this.windowInteractor;
+ }
+
+ public void setInteractorStyle(vtkInteractorStyle style) {
+ this.getRenderWindowInteractor().SetInteractorStyle(style);
+ }
+
+ public void setSize(int w, int h) {
+ this.panel.setSize(w, h);
+ this.getRenderWindowInteractor().SetSize(w, h);
+ }
+
+ public vtkPanel getComponent() {
+ return this.panel;
+ }
+
+ public void Delete() {
+ this.panel.Delete();
+ }
+
+ public void Render() {
+ this.panel.Render();
+ }
+
+ public vtkInteractorForwarder getInteractorForwarder() {
+ return this.eventForwarder;
+ }
+
+ public ReentrantLock getVTKLock() {
+ return this.lock;
+ }
+}
--- /dev/null
+package vtk.rendering.swt;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+
+import com.jogamp.opengl.GLAutoDrawable;
+import com.jogamp.opengl.GLCapabilities;
+import com.jogamp.opengl.GLProfile;
+import com.jogamp.opengl.GLRunnable;
+import com.jogamp.opengl.swt.GLCanvas;
+
+import vtk.vtkObject;
+
+/**
+ * @author Joachim Pouderoux - joachim.pouderoux@kitware.com, Kitware SAS 2012
+ * @copyright This work was supported by CEA/CESTA
+ * Commissariat a l'Energie Atomique et aux Energies Alternatives,
+ * 15 avenue des Sablieres, CS 60001, 33116 Le Barp, France.
+ */
+public class vtkInternalSwtComponent extends GLCanvas implements Listener {
+
+ private vtkSwtComponent parent;
+
+ public static GLCapabilities GetGLCapabilities() {
+ GLCapabilities caps;
+ caps = new GLCapabilities(GLProfile.get(GLProfile.GL2GL3));
+ caps.setDoubleBuffered(true);
+ caps.setHardwareAccelerated(true);
+ caps.setSampleBuffers(false);
+ caps.setNumSamples(4);
+
+ caps.setAlphaBits(8);
+
+ return caps;
+ }
+
+ public vtkInternalSwtComponent(vtkSwtComponent parent, Composite parentComposite) {
+
+ super(parentComposite, SWT.NO_BACKGROUND, GetGLCapabilities(), null);
+ this.parent = parent;
+
+ vtkSwtInteractorForwarderDecorator forwarder = (vtkSwtInteractorForwarderDecorator) this.parent
+ .getInteractorForwarder();
+
+ this.addMouseListener(forwarder);
+ this.addKeyListener(forwarder);
+ this.addMouseMoveListener(forwarder);
+ this.addMouseTrackListener(forwarder);
+ this.addMouseWheelListener(forwarder);
+
+ this.addListener(SWT.Paint, this);
+ this.addListener(SWT.Close, this);
+ this.addListener(SWT.Dispose, this);
+ this.addListener(SWT.Resize, this);
+
+ this.IntializeRenderWindow();
+ }
+
+ protected void IntializeRenderWindow() {
+
+ // setCurrent(); // need to be done so SetWindowIdFromCurrentContext can
+ // get the current context!
+ // Context is not created until the first draw call. The renderer isn't
+ // initialized until the context is
+ // present.
+ invoke(false, new GLRunnable() {
+
+ @Override
+ public boolean run(GLAutoDrawable arg0) {
+ // This makes this thread (should be the main thread) current
+ getContext().makeCurrent();
+ parent.getRenderWindow().InitializeFromCurrentContext();
+ // Swapping buffers is handled by the vtkSwtComponent
+ parent.getRenderWindow().SwapBuffersOff();
+ return false;
+ }
+ });
+
+ // Swap buffers to trigger context creation
+ swapBuffers();
+ setAutoSwapBufferMode(false);
+ }
+
+ @Override
+ public void update() {
+ super.update();
+ if (isRealized()) {
+ parent.Render();
+ }
+ }
+
+ @Override
+ public void dispose() {
+ this.removeListener(SWT.Paint, this);
+ this.removeListener(SWT.Close, this);
+ this.removeListener(SWT.Dispose, this);
+ this.removeListener(SWT.Resize, this);
+
+ if (getContext().isCurrent()) {
+ getContext().release();
+ }
+ super.dispose();
+ }
+
+ @Override
+ public void handleEvent(Event event) {
+ switch (event.type) {
+ case SWT.Paint:
+ if (isRealized()) {
+ parent.Render();
+ }
+ break;
+ case SWT.Dispose:
+ parent.Delete();
+ vtkObject.JAVA_OBJECT_MANAGER.gc(false);
+ break;
+ case SWT.Close:
+ // System.out.println("closing");
+ break;
+ case SWT.Resize:
+ parent.setSize(getClientArea().width, getClientArea().height);
+ break;
+ }
+ }
+}
--- /dev/null
+package vtk.rendering.swt;
+
+import org.eclipse.swt.widgets.Composite;
+
+import com.jogamp.opengl.swt.GLCanvas;
+
+import vtk.vtkRenderWindow;
+import vtk.rendering.vtkAbstractComponent;
+
+/**
+ * Provide SWT based vtk rendering component
+ *
+ * @author Joachim Pouderoux - joachim.pouderoux@kitware.com, Kitware SAS 2012
+ * @copyright This work was supported by CEA/CESTA
+ * Commissariat a l'Energie Atomique et aux Energies Alternatives,
+ * 15 avenue des Sablieres, CS 60001, 33116 Le Barp, France.
+ */
+public class vtkSwtComponent extends vtkAbstractComponent<GLCanvas> {
+
+ protected vtkInternalSwtComponent uiComponent;
+ protected boolean isWindowCreated;
+
+ public vtkSwtComponent(Composite parentComposite) {
+ this(new vtkRenderWindow(), parentComposite);
+ }
+
+ public vtkSwtComponent(vtkRenderWindow renderWindowToUse, Composite parentComposite) {
+ super(renderWindowToUse);
+ this.eventForwarder = new vtkSwtInteractorForwarderDecorator(this, this.eventForwarder);
+ this.isWindowCreated = true;
+ this.uiComponent = new vtkInternalSwtComponent(this, parentComposite);
+
+ renderWindow.AddObserver("StartEvent", this, "startEvent");
+ renderWindow.AddObserver("EndEvent", this, "endEvent");
+ }
+
+ /**
+ * Set the size of the VTK component
+ * @param x width
+ * @param y height
+ */
+ @Override
+ public void setSize(int x, int y) {
+ x = x < 1 ? 1 : x;
+ y = y < 1 ? 1 : y;
+ super.setSize(x, y);
+ this.uiComponent.setSize(x, y);
+ this.uiComponent.redraw();
+ this.uiComponent.update();
+ }
+
+ /**
+ * Render the VTK component. Should not be called externally.
+ * Call update() to refresh the window content.
+ */
+ @Override
+ public void Render() {
+ // Make sure we can render
+ if (inRenderCall || renderer == null || renderWindow == null) {
+ return;
+ }
+
+ // Try to render
+ try {
+ lock.lockInterruptibly();
+ inRenderCall = true;
+ // Trigger the real render
+ renderWindow.Render();
+ } catch (InterruptedException e) {
+ // Nothing that we can do except skipping execution
+ } finally {
+ lock.unlock();
+ inRenderCall = false;
+ }
+ }
+
+ /**
+ * Redraw the VTK component
+ */
+ public void update() {
+ this.uiComponent.redraw();
+ this.uiComponent.update();
+ }
+
+ /**
+ * @return the encapsulated SWT component (a GLCanvas instance)
+ * @see vtk.rendering.vtkAbstractComponent#getComponent()
+ */
+ @Override
+ public GLCanvas getComponent() {
+ return this.uiComponent;
+ }
+
+ @Override
+ public void Delete() {
+ this.lock.lock();
+ // We prevent any further rendering
+ this.inRenderCall = true;
+ this.renderWindow = null;
+ super.Delete();
+ this.lock.unlock();
+ }
+
+ /**
+ * @return true if the graphical component has been properly set and
+ * operation can be performed on it.
+ */
+ public boolean isWindowSet() {
+ return this.isWindowCreated;
+ }
+
+ /**
+ * Just allow class in same package to affect inRenderCall boolean
+ *
+ * @param value
+ */
+ protected void updateInRenderCall(boolean value) {
+ this.inRenderCall = value;
+ }
+
+ /** This method is called by the VTK JNI code. Do not remove. */
+ void startEvent() {
+ if (!getComponent().getContext().isCurrent()) {
+ getComponent().getContext().makeCurrent();
+ }
+ }
+
+ /** This method is called by the VTK JNI code. Do not remove. */
+ void endEvent() {
+ if (getComponent().getContext().isCurrent()) {
+ getComponent().swapBuffers();
+ getComponent().getContext().release();
+ }
+ }
+}
--- /dev/null
+package vtk.rendering.swt;
+
+import java.awt.Label;
+
+import vtk.rendering.vtkComponent;
+import vtk.rendering.vtkInteractorForwarder;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.KeyEvent;
+import org.eclipse.swt.events.KeyListener;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.MouseTrackListener;
+import org.eclipse.swt.events.MouseWheelListener;
+
+/**
+ * Decorator class used to implement all Mouse/Key SWT listener and convert them
+ * into the vtkInteractorForwarder proper AWT event.
+ *
+ * @author Joachim Pouderoux - joachim.pouderoux@kitware.com, Kitware SAS 2012
+ * @copyright This work was supported by CEA/CESTA
+ * Commissariat a l'Energie Atomique et aux Energies Alternatives,
+ * 15 avenue des Sablieres, CS 60001, 33116 Le Barp, France.
+ */
+public class vtkSwtInteractorForwarderDecorator extends vtkInteractorForwarder
+implements MouseListener, MouseMoveListener, MouseTrackListener, MouseWheelListener, KeyListener {
+
+ vtkInteractorForwarder forwarder;
+ Label dummyComponent;
+
+ public vtkSwtInteractorForwarderDecorator(vtkComponent<?> component, vtkInteractorForwarder forwarder) {
+ super(component);
+ dummyComponent = new Label();
+ this.forwarder = forwarder;
+ }
+
+ public static int convertModifiers(int mods) {
+ int modifiers = 0;
+ if ((mods & SWT.SHIFT) != 0) modifiers |= java.awt.Event.SHIFT_MASK;
+ if ((mods & SWT.CTRL) != 0) modifiers |= java.awt.Event.CTRL_MASK;
+ if ((mods & SWT.ALT) != 0) modifiers |= java.awt.Event.ALT_MASK;
+ return modifiers;
+ }
+
+ public java.awt.event.KeyEvent convertKeyEvent(org.eclipse.swt.events.KeyEvent e) {
+ return new java.awt.event.KeyEvent(dummyComponent, 0, (long)e.time, convertModifiers(e.stateMask), e.keyCode, e.character);
+ }
+
+ public java.awt.event.MouseEvent convertMouseEvent(org.eclipse.swt.events.MouseEvent e) {
+ int button = 0;
+ if ((e.button == 1) || (e.stateMask & SWT.BUTTON1) != 0) button = java.awt.event.MouseEvent.BUTTON1;
+ else if ((e.button == 2) || (e.stateMask & SWT.BUTTON2) != 0) button = java.awt.event.MouseEvent.BUTTON2;
+ else if ((e.button == 3) || (e.stateMask & SWT.BUTTON3) != 0) button = java.awt.event.MouseEvent.BUTTON3;
+ return new java.awt.event.MouseEvent(dummyComponent, 0, (long)e.time, convertModifiers(e.stateMask), e.x, e.y, e.count, false, button);
+ }
+
+ public java.awt.event.MouseWheelEvent convertMouseWheelEvent(org.eclipse.swt.events.MouseEvent e) {
+ return new java.awt.event.MouseWheelEvent(dummyComponent, 0, e.time, convertModifiers(e.stateMask), e.x, e.y, 0, false, java.awt.event.MouseWheelEvent.WHEEL_UNIT_SCROLL, 1, e.count);
+ }
+
+ public void keyPressed(KeyEvent e) {
+ super.keyPressed(convertKeyEvent(e));
+ }
+
+ public void keyReleased(KeyEvent e) {
+ super.keyReleased(convertKeyEvent(e));
+ }
+
+ public void mouseEnter(MouseEvent e) {
+ super.mouseEntered(convertMouseEvent(e));
+ }
+
+ public void mouseExit(MouseEvent e) {
+ super.mouseExited(convertMouseEvent(e));
+ }
+
+ public void mouseMove(MouseEvent e) {
+ if (((e.stateMask & SWT.BUTTON1) == 0)
+ && ((e.stateMask & SWT.BUTTON2) == 0)
+ && ((e.stateMask & SWT.BUTTON3) == 0)) {
+ super.mouseMoved(convertMouseEvent(e));
+ } else {
+ super.mouseDragged(convertMouseEvent(e));
+ }
+ }
+
+ public void mouseDown(MouseEvent e) {
+ super.mousePressed(convertMouseEvent(e));
+ }
+
+ public void mouseUp(MouseEvent e) {
+ super.mouseReleased(convertMouseEvent(e));
+ }
+
+ public void mouseScrolled(MouseEvent e) {
+ super.mouseWheelMoved(convertMouseWheelEvent(e));
+ }
+
+ public void mouseHover(MouseEvent e) {
+ }
+
+ public void mouseDoubleClick(MouseEvent e) {
+ }
+}
--- /dev/null
+package vtk.rendering;
+
+import java.util.concurrent.locks.ReentrantLock;
+
+import vtk.vtkAxesActor;
+import vtk.vtkCamera;
+import vtk.vtkGenericRenderWindowInteractor;
+import vtk.vtkInteractorStyle;
+import vtk.vtkInteractorStyleTrackballCamera;
+import vtk.vtkOrientationMarkerWidget;
+import vtk.vtkRenderWindow;
+import vtk.vtkRenderer;
+
+/**
+ * Abstract class that bring most of the VTK logic to any rendering component
+ * regardless its origin. (awt, swt, sing, ...)
+ *
+ * @param <T>
+ * The concrete type of the graphical component that will contains
+ * the vtkRenderWindow.
+ *
+ * @authors Sebastien Jourdain - sebastien.jourdain@kitware.com, Kitware Inc 2012
+ * Joachim Pouderoux - joachim.pouderoux@kitware.com, Kitware SAS 2012
+ * @copyright This work was supported by CEA/CESTA
+ * Commissariat a l'Energie Atomique et aux Energies Alternatives,
+ * 15 avenue des Sablieres, CS 60001, 33116 Le Barp, France.
+ */
+public abstract class vtkAbstractComponent<T> implements vtkComponent<T> {
+ protected vtkRenderWindow renderWindow;
+ protected vtkRenderer renderer;
+ protected vtkCamera camera;
+ protected vtkGenericRenderWindowInteractor windowInteractor;
+ protected vtkInteractorForwarder eventForwarder;
+ protected ReentrantLock lock;
+ protected boolean inRenderCall;
+
+ public vtkAbstractComponent() {
+ this(new vtkRenderWindow());
+ }
+
+ public vtkAbstractComponent(vtkRenderWindow renderWindowToUse) {
+ this.inRenderCall = false;
+ this.renderWindow = renderWindowToUse;
+ this.renderer = new vtkRenderer();
+ this.windowInteractor = new vtkGenericRenderWindowInteractor();
+ this.lock = new ReentrantLock();
+
+ // Init interactor
+ this.windowInteractor.SetRenderWindow(this.renderWindow);
+ this.windowInteractor.TimerEventResetsTimerOff();
+
+ this.windowInteractor.SetSize(200, 200);
+ this.windowInteractor.ConfigureEvent();
+
+ // Update style
+ vtkInteractorStyleTrackballCamera style = new vtkInteractorStyleTrackballCamera();
+ this.windowInteractor.SetInteractorStyle(style);
+
+ // Setup event forwarder
+ this.eventForwarder = new vtkInteractorForwarder(this);
+ this.windowInteractor.AddObserver("CreateTimerEvent", this.eventForwarder, "StartTimer");
+ this.windowInteractor.AddObserver("DestroyTimerEvent", this.eventForwarder, "DestroyTimer");
+
+ // Link renderWindow with renderer
+ this.renderWindow.AddRenderer(this.renderer);
+
+ // Keep camera around to prevent its creation/deletion in Java world
+ this.camera = this.renderer.GetActiveCamera();
+ }
+
+ public ReentrantLock getVTKLock() {
+ return this.lock;
+ }
+
+ public void resetCamera() {
+ if (renderer == null) {
+ return; // Nothing to do we are deleted...
+ }
+
+ try {
+ lock.lockInterruptibly();
+ renderer.ResetCamera();
+ } catch (InterruptedException e) {
+ // Nothing that we can do
+ } finally {
+ this.lock.unlock();
+ }
+ }
+
+ public void resetCameraClippingRange() {
+ if (renderWindow == null) {
+ return; // Nothing to do we are deleted...
+ }
+
+ try {
+ this.lock.lockInterruptibly();
+ renderer.ResetCameraClippingRange();
+ } catch (InterruptedException e) {
+ // Nothing that we can do
+ } finally {
+ this.lock.unlock();
+ }
+ }
+
+ public vtkCamera getActiveCamera() {
+ return this.camera;
+ }
+
+ public vtkRenderer getRenderer() {
+ return this.renderer;
+ }
+
+ public vtkRenderWindow getRenderWindow() {
+ return this.renderWindow;
+ }
+
+ public vtkGenericRenderWindowInteractor getRenderWindowInteractor() {
+ return this.windowInteractor;
+ }
+
+ public void setInteractorStyle(vtkInteractorStyle style) {
+ if (this.windowInteractor != null) {
+ this.lock.lock();
+ this.windowInteractor.SetInteractorStyle(style);
+ this.lock.unlock();
+ }
+ }
+
+ public void setSize(int w, int h) {
+ if (renderWindow == null || windowInteractor == null) {
+ return; // Nothing to do we are deleted...
+ }
+
+ try {
+ lock.lockInterruptibly();
+ renderWindow.SetSize(w, h);
+ windowInteractor.SetSize(w, h);
+ } catch (InterruptedException e) {
+ // Nothing that we can do
+ } finally {
+ this.lock.unlock();
+ }
+ }
+
+ public void Delete() {
+ this.lock.lock();
+ this.renderer = null;
+ this.camera = null;
+ this.windowInteractor = null;
+ // removing the renderWindow is let to the superclass
+ // because in the very special case of an AWT component
+ // under Linux, destroying renderWindow crashes.
+ this.lock.unlock();
+ }
+
+ public vtkInteractorForwarder getInteractorForwarder() {
+ return this.eventForwarder;
+ }
+
+ public abstract T getComponent();
+
+ /**
+ * Generic helper method used to attach orientation axes to a vtkComponent
+ *
+ * @param vtkComponent<?>
+ */
+ public static void attachOrientationAxes(vtkComponent<?> component) {
+ // only build this once, because it creates its own renderer.
+ // Extra renderers causes issues with resetting.
+ vtkAxesActor axes = new vtkAxesActor();
+ vtkOrientationMarkerWidget axesWidget = new vtkOrientationMarkerWidget();
+
+ axesWidget.SetOutlineColor(0.9300, 0.5700, 0.1300);
+ axesWidget.SetOrientationMarker(axes);
+ axesWidget.SetInteractor(component.getRenderWindowInteractor());
+ axesWidget.SetDefaultRenderer(component.getRenderer());
+ axesWidget.SetViewport(0.0, 0.0, .2, .2);
+ axesWidget.EnabledOn();
+ axesWidget.InteractiveOff();
+ }
+}
--- /dev/null
+package vtk.rendering;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+
+/**
+ * This class implement vtkEventInterceptor with no event interception at all.
+ *
+ * @see {@link MouseMotionListener} {@link MouseListener} {@link MouseWheelListener}
+ * {@link KeyListener}
+ *
+ * @author Sebastien Jourdain - sebastien.jourdain@kitware.com, Kitware Inc 2013
+ */
+
+public class vtkAbstractEventInterceptor implements vtkEventInterceptor {
+
+ public boolean keyPressed(KeyEvent e) {
+ return false;
+ }
+
+ public boolean keyReleased(KeyEvent e) {
+ return false;
+ }
+
+ public boolean keyTyped(KeyEvent e) {
+ return false;
+ }
+
+ public boolean mouseDragged(MouseEvent e) {
+ return false;
+ }
+
+ public boolean mouseMoved(MouseEvent e) {
+ return false;
+ }
+
+ public boolean mouseClicked(MouseEvent e) {
+ return false;
+ }
+
+ public boolean mouseEntered(MouseEvent e) {
+ return false;
+ }
+
+ public boolean mouseExited(MouseEvent e) {
+ return false;
+ }
+
+ public boolean mousePressed(MouseEvent e) {
+ return false;
+ }
+
+ public boolean mouseReleased(MouseEvent e) {
+ return false;
+ }
+
+ public boolean mouseWheelMoved(MouseWheelEvent e) {
+ return false;
+ }
+}
--- /dev/null
+package vtk.rendering;
+
+import java.util.concurrent.locks.ReentrantLock;
+
+import vtk.vtkCamera;
+import vtk.vtkGenericRenderWindowInteractor;
+import vtk.vtkInteractorStyle;
+import vtk.vtkRenderWindow;
+import vtk.vtkRenderer;
+
+/**
+ * Generic API for any new VTK based graphical components.
+ *
+ * @param <T>
+ * The concrete type of the graphical component that will contains
+ * the vtkRenderWindow.
+ *
+ * @author Sebastien Jourdain - sebastien.jourdain@kitware.com, Kitware Inc 2012
+ * @copyright This work was supported by CEA/CESTA
+ * Commissariat a l'Energie Atomique et aux Energies Alternatives,
+ * 15 avenue des Sablieres, CS 60001, 33116 Le Barp, France.
+ */
+
+public interface vtkComponent<T> {
+
+ /**
+ * @return the lock that is used to prevent concurrency inside this
+ * rendering component. This lock can also be used outside to make
+ * sure any VTK processing happen in a save manner.
+ */
+ ReentrantLock getVTKLock();
+
+ /**
+ * Adjust the camera position so any object in the scene will be fully seen.
+ */
+ void resetCamera();
+
+ /**
+ * Update the clipping range of the camera
+ */
+ void resetCameraClippingRange();
+
+ /**
+ * @return the active camera of the renderer
+ */
+ vtkCamera getActiveCamera();
+
+ /**
+ * @return a reference to the Renderer used internally
+ */
+ vtkRenderer getRenderer();
+
+ /**
+ * Useful for screen capture or exporter.
+ *
+ * @return a reference to the RenderWindow used internally
+ */
+ vtkRenderWindow getRenderWindow();
+
+ /**
+ * vtkWindowInteractor is useful if you want to attach 3DWidget into your
+ * view.
+ *
+ * @return a reference to the vtkWindowInteractor used internally
+ */
+ vtkGenericRenderWindowInteractor getRenderWindowInteractor();
+
+ /**
+ * Shortcut method to bind an vtkInteractorStyle to our interactor.
+ *
+ * @param style
+ */
+ void setInteractorStyle(vtkInteractorStyle style);
+
+ /**
+ * Update width and height of the given component
+ *
+ * @param w
+ * @param h
+ */
+ void setSize(int w, int h);
+
+ /**
+ * @return the concrete implementation of the graphical container such as
+ * java.awt.Canvas / java.swing.JComponent /
+ * org.eclipse.swt.opengl.GLCanvas
+ */
+ T getComponent();
+
+ /**
+ * Remove any reference from Java to vtkObject to allow the VTK Garbage
+ * collector to free any remaining memory. This is specially needed for
+ * internal hidden reference to vtkObject.
+ */
+ void Delete();
+
+ /**
+ * Request a render.
+ */
+ void Render();
+
+ /**
+ * @return the vtkInteractor Java event converter.
+ */
+ vtkInteractorForwarder getInteractorForwarder();
+}
--- /dev/null
+package vtk.rendering;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+
+/**
+ * This interface defines what should be implemented to intercept interaction
+ * events and create custom behavior.
+ *
+ * @see {@link MouseMotionListener} {@link MouseListener} {@link MouseWheelListener}
+ * {@link KeyListener}
+ *
+ * @author Sebastien Jourdain - sebastien.jourdain@kitware.com, Kitware Inc 2012
+ * @copyright This work was supported by CEA/CESTA
+ * Commissariat a l'Energie Atomique et aux Energies Alternatives,
+ * 15 avenue des Sablieres, CS 60001, 33116 Le Barp, France.
+ */
+public interface vtkEventInterceptor {
+
+ /**
+ * @param e
+ * event
+ * @return true if the event has been consumed and should not be forwarded
+ * to the vtkInteractor
+ */
+ boolean keyPressed(KeyEvent e);
+
+ /**
+ * @param e
+ * event
+ * @return true if the event has been consumed and should not be forwarded
+ * to the vtkInteractor
+ */
+ boolean keyReleased(KeyEvent e);
+
+ /**
+ * @param e
+ * event
+ * @return true if the event has been consumed and should not be forwarded
+ * to the vtkInteractor
+ */
+ boolean keyTyped(KeyEvent e);
+
+ /**
+ * @param e
+ * event
+ * @return true if the event has been consumed and should not be forwarded
+ * to the vtkInteractor
+ */
+ boolean mouseDragged(MouseEvent e);
+
+ /**
+ * @param e
+ * event
+ * @return true if the event has been consumed and should not be forwarded
+ * to the vtkInteractor
+ */
+ boolean mouseMoved(MouseEvent e);
+
+ /**
+ * @param e
+ * event
+ * @return true if the event has been consumed and should not be forwarded
+ * to the vtkInteractor
+ */
+ boolean mouseClicked(MouseEvent e);
+
+ /**
+ * @param e
+ * event
+ * @return true if the event has been consumed and should not be forwarded
+ * to the vtkInteractor
+ */
+ boolean mouseEntered(MouseEvent e);
+
+ /**
+ * @param e
+ * event
+ * @return true if the event has been consumed and should not be forwarded
+ * to the vtkInteractor
+ */
+ boolean mouseExited(MouseEvent e);
+
+ /**
+ * @param e
+ * event
+ * @return true if the event has been consumed and should not be forwarded
+ * to the vtkInteractor
+ */
+ boolean mousePressed(MouseEvent e);
+
+ /**
+ * @param e
+ * event
+ * @return true if the event has been consumed and should not be forwarded
+ * to the vtkInteractor
+ */
+ boolean mouseReleased(MouseEvent e);
+
+ /**
+ * @param e
+ * event
+ * @return true if the event has been consumed and should not be forwarded
+ * to the vtkInteractor
+ */
+ boolean mouseWheelMoved(MouseWheelEvent e);
+}
--- /dev/null
+package vtk.rendering;
+
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
+import java.lang.reflect.Field;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Helper class used to implement all Mouse/Key Java listener and convert them
+ * into the vtkInteractor proper event.
+ *
+ * @authors Sebastien Jourdain - sebastien.jourdain@kitware.com, Kitware Inc 2012
+ * Joachim Pouderoux - joachim.pouderoux@kitware.com, Kitware SAS 2012
+ * @copyright This work was supported by CEA/CESTA
+ * Commissariat a l'Energie Atomique et aux Energies Alternatives,
+ * 15 avenue des Sablieres, CS 60001, 33116 Le Barp, France.
+ */
+public class vtkInteractorForwarder implements MouseListener, MouseMotionListener, MouseWheelListener, KeyListener {
+ final public static int MOUSE_BUTTON_1 = 1;
+ final public static int MOUSE_BUTTON_2 = 2;
+ final public static int MOUSE_BUTTON_3 = 4;
+ final public static int MOUSE_MODIFIER_SHIFT = 1;
+ final public static int MOUSE_MODIFIER_CTRL = 2;
+ final public static int MOUSE_MODIFIER_ALT = 4;
+
+ private int lastX;
+ private int lastY;
+ private int ctrlPressed;
+ private int shiftPressed;
+ private vtkComponent<?> component;
+ private double updateRate, updateRateRelease;
+ private double scaleFactor = 1;
+ private ScheduledExecutorService scheduler;
+ private Runnable eventTick;
+ private vtkEventInterceptor eventInterceptor;
+
+ public vtkInteractorForwarder(vtkComponent<?> component) {
+ this.component = component;
+ this.lastX = this.lastY = this.ctrlPressed = 0;
+ this.updateRate = 5.0;
+ this.updateRateRelease = 0.01;
+ this.scaleFactor = vtkInteractorForwarder.getDisplayScale();
+
+ this.eventTick = new Runnable() {
+
+ public void run() {
+ vtkInteractorForwarder.this.component.getVTKLock().lock();
+ vtkInteractorForwarder.this.component.getRenderWindowInteractor().TimerEvent();
+ vtkInteractorForwarder.this.component.getVTKLock().unlock();
+ }
+ };
+
+ // Schedule time events
+ this.scheduler = Executors.newSingleThreadScheduledExecutor();
+ }
+
+ /**
+ * Provide a custom event interceptor
+ *
+ * @param eventInterceptor
+ */
+ public void setEventInterceptor(vtkEventInterceptor eventInterceptor) {
+ this.eventInterceptor = eventInterceptor;
+ }
+
+ /**
+ * @return the custom event interceptor if any otherwise return null
+ */
+ public vtkEventInterceptor getEventInterceptor() {
+ return eventInterceptor;
+ }
+
+ /**
+ * Method called by VTK to start a timer
+ */
+ public void StartTimer() {
+ this.scheduler.scheduleAtFixedRate(this.eventTick, 10, 10, TimeUnit.MILLISECONDS);
+ }
+
+ /**
+ * Method called by VTK to stop a timer
+ */
+ public void DestroyTimer() {
+ this.scheduler.shutdown();
+ }
+
+ /**
+ * Allow the user to change the update rate
+ *
+ * @param updateRate
+ * @param updateRateRelease
+ */
+ public void setUpdateRate(double updateRate, double updateRateRelease) {
+ this.updateRate = updateRate;
+ this.updateRateRelease = updateRateRelease;
+ }
+
+ /**
+ * @return the update rate that is currently used
+ */
+ public double getUpdateRate() {
+ return updateRate;
+ }
+
+ /**
+ * @return the update rate after release that is currently used
+ */
+ public double getUpdateRateRelease() {
+ return updateRateRelease;
+ }
+
+ public void mousePressed(MouseEvent e) {
+ if (component == null || component.getRenderer() == null) {
+ return;
+ }
+
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mousePressed(e)) {
+ return;
+ }
+
+ // Update scale factor if needed
+ this.scaleFactor = 1;
+ if (e.getComponent().getGraphicsConfiguration() != null) {
+ this.scaleFactor = vtkInteractorForwarder.getGraphicDeviceScale(e.getComponent().getGraphicsConfiguration().getDevice());
+ }
+
+ try {
+ component.getVTKLock().lockInterruptibly();
+ component.getRenderWindow().SetDesiredUpdateRate(this.updateRate);
+ lastX = (int)(e.getX() * scaleFactor);
+ lastY = (int)(e.getY() * scaleFactor);
+ ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0;
+ shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0;
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, '0', 0, "0");
+ switch (e.getButton()) {
+ case MouseEvent.BUTTON3:
+ component.getRenderWindowInteractor().RightButtonPressEvent();
+ break;
+ case MouseEvent.BUTTON2:
+ component.getRenderWindowInteractor().MiddleButtonPressEvent();
+ break;
+ case MouseEvent.BUTTON1:
+ default:
+ component.getRenderWindowInteractor().LeftButtonPressEvent();
+ break;
+ }
+ } catch (InterruptedException interupt) {
+ // Nothing to do
+ } finally {
+ component.getVTKLock().unlock();
+ }
+ }
+
+ public void mouseReleased(MouseEvent e) {
+ if (component == null || component.getRenderer() == null) {
+ return;
+ }
+
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mouseReleased(e)) {
+ return;
+ }
+
+ try {
+ component.getVTKLock().lockInterruptibly();
+ component.getRenderWindow().SetDesiredUpdateRate(this.updateRateRelease);
+ lastX = (int)(e.getX() * scaleFactor);
+ lastY = (int)(e.getY() * scaleFactor);
+ ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0;
+ shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0;
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, '0', 0, "0");
+ switch (e.getButton()) {
+ case MouseEvent.BUTTON3:
+ component.getRenderWindowInteractor().RightButtonReleaseEvent();
+ break;
+ case MouseEvent.BUTTON2:
+ component.getRenderWindowInteractor().MiddleButtonReleaseEvent();
+ break;
+ case MouseEvent.BUTTON1:
+ default:
+ component.getRenderWindowInteractor().LeftButtonReleaseEvent();
+ break;
+ }
+ } catch (InterruptedException interupt) {
+ // Nothing to do
+ } finally {
+ component.getVTKLock().unlock();
+ }
+ }
+
+ public void mouseMoved(MouseEvent e) {
+ if (component == null || component.getRenderer() == null) {
+ return;
+ }
+
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mouseMoved(e)) {
+ return;
+ }
+
+ try {
+ component.getVTKLock().lockInterruptibly();
+ component.getRenderWindow().SetDesiredUpdateRate(this.updateRateRelease);
+ lastX = (int)(e.getX() * scaleFactor);
+ lastY = (int)(e.getY() * scaleFactor);
+ ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0;
+ shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0;
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, '0', 0, "0");
+ component.getRenderWindowInteractor().MouseMoveEvent();
+ } catch (InterruptedException interupt) {
+ // Nothing to do
+ } finally {
+ component.getVTKLock().unlock();
+ }
+ }
+
+ public void mouseDragged(MouseEvent e) {
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mouseDragged(e)) {
+ return;
+ }
+
+ this.mouseMoved(e);
+ }
+
+ public void mouseEntered(MouseEvent e) {
+ if (component == null || component.getRenderer() == null) {
+ return;
+ }
+
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mouseEntered(e)) {
+ return;
+ }
+
+ try {
+ component.getVTKLock().lockInterruptibly();
+ component.getRenderWindow().SetDesiredUpdateRate(this.updateRateRelease);
+ lastX = (int)(e.getX() * scaleFactor);
+ lastY = (int)(e.getY() * scaleFactor);
+ ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0;
+ shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0;
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, '0', 0, "0");
+ component.getRenderWindowInteractor().EnterEvent();
+ } catch (InterruptedException interupt) {
+ // Nothing to do
+ } finally {
+ component.getVTKLock().unlock();
+ }
+ }
+
+ public void mouseExited(MouseEvent e) {
+ if (component == null || component.getRenderer() == null) {
+ return;
+ }
+
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mouseExited(e)) {
+ return;
+ }
+
+ try {
+ component.getVTKLock().lockInterruptibly();
+ component.getRenderWindow().SetDesiredUpdateRate(this.updateRateRelease);
+ lastX = (int)(e.getX() * scaleFactor);
+ lastY = (int)(e.getY() * scaleFactor);
+ ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0;
+ shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0;
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, '0', 0, "0");
+ component.getRenderWindowInteractor().LeaveEvent();
+ } catch (InterruptedException interupt) {
+ // Nothing to do
+ } finally {
+ component.getVTKLock().unlock();
+ }
+ }
+
+ public void mouseClicked(MouseEvent e) {
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mouseClicked(e)) {
+ return;
+ }
+ }
+
+ public void mouseWheelMoved(MouseWheelEvent e) {
+ if (component == null || component.getRenderer() == null) {
+ return;
+ }
+
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.mouseWheelMoved(e)) {
+ return;
+ }
+
+ try {
+ component.getVTKLock().lockInterruptibly();
+ component.getRenderWindow().SetDesiredUpdateRate(this.updateRateRelease);
+ lastX = (int)(e.getX() * scaleFactor);
+ lastY = (int)(e.getY() * scaleFactor);
+ ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0;
+ shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0;
+ if (e.getWheelRotation() > 0) {
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, '0', 0, "0");
+ component.getRenderWindowInteractor().MouseWheelBackwardEvent();
+ }
+ else if (e.getWheelRotation() < 0) {
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, '0', 0, "0");
+ component.getRenderWindowInteractor().MouseWheelForwardEvent();
+ }
+ } catch (InterruptedException interupt) {
+ // Nothing to do
+ } finally {
+ component.getVTKLock().unlock();
+ }
+ }
+
+ public void keyPressed(KeyEvent e) {
+ if (component == null || component.getRenderer() == null) {
+ return;
+ }
+
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.keyPressed(e)) {
+ return;
+ }
+
+ try {
+ component.getVTKLock().lockInterruptibly();
+ component.getRenderWindow().SetDesiredUpdateRate(this.updateRateRelease);
+ ctrlPressed = (e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK ? 1 : 0;
+ shiftPressed = (e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK ? 1 : 0;
+ char keyChar = e.getKeyChar();
+ component.getRenderWindowInteractor().SetEventInformationFlipY(lastX, lastY, ctrlPressed, shiftPressed, keyChar, 0, String.valueOf(keyChar));
+ component.getRenderWindowInteractor().KeyPressEvent();
+ component.getRenderWindowInteractor().CharEvent();
+ } catch (InterruptedException interupt) {
+ // Nothing to do
+ } finally {
+ component.getVTKLock().unlock();
+ }
+ }
+
+ public void keyReleased(KeyEvent e) {
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.keyReleased(e)) {
+ return;
+ }
+ }
+
+ public void keyTyped(KeyEvent e) {
+ // Allow user to override some behavior
+ if (this.eventInterceptor != null && this.eventInterceptor.keyTyped(e)) {
+ return;
+ }
+ }
+
+ public static int getDisplayScale() {
+ GraphicsDevice graphicsDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
+ return getGraphicDeviceScale(graphicsDevice);
+ }
+
+ public static int getGraphicDeviceScale(GraphicsDevice device) {
+ try {
+ Field field = device.getClass().getDeclaredField("scale");
+ if (field != null) {
+ field.setAccessible(true);
+ Object scale = field.get(device);
+ if (scale instanceof Integer) {
+ return ((Integer) scale).intValue();
+ }
+ System.out.println("Invalid scale type: " + scale);
+ }
+ } catch (Exception e) {
+ // Don't care, at least we tried.
+ }
+ return 1;
+ }
+}