From: Marko Luukkainen Date: Mon, 13 May 2019 12:06:02 +0000 (+0300) Subject: VTK.Rendering plug-in + win64 fragment X-Git-Tag: v1.43.0~263 X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F97%2F2897%2F1;p=simantics%2F3d.git VTK.Rendering plug-in + win64 fragment VTK.Rendering allows SWT-based VTK view, without AWT tread. gitlab #2 Change-Id: Ida8a60eb56c012ea96be874888d0e72559e76204 --- diff --git a/vtk.rendering.win32.win32.x86_64/.classpath b/vtk.rendering.win32.win32.x86_64/.classpath new file mode 100644 index 00000000..eca7bdba --- /dev/null +++ b/vtk.rendering.win32.win32.x86_64/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/vtk.rendering.win32.win32.x86_64/.project b/vtk.rendering.win32.win32.x86_64/.project new file mode 100644 index 00000000..5b951697 --- /dev/null +++ b/vtk.rendering.win32.win32.x86_64/.project @@ -0,0 +1,28 @@ + + + vtk.rendering.win32.win32.x86_64 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/vtk.rendering.win32.win32.x86_64/.settings/org.eclipse.jdt.core.prefs b/vtk.rendering.win32.win32.x86_64/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..0c68a61d --- /dev/null +++ b/vtk.rendering.win32.win32.x86_64/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +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 diff --git a/vtk.rendering.win32.win32.x86_64/META-INF/MANIFEST.MF b/vtk.rendering.win32.win32.x86_64/META-INF/MANIFEST.MF new file mode 100644 index 00000000..309c36e5 --- /dev/null +++ b/vtk.rendering.win32.win32.x86_64/META-INF/MANIFEST.MF @@ -0,0 +1,9 @@ +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)) diff --git a/vtk.rendering.win32.win32.x86_64/README.txt b/vtk.rendering.win32.win32.x86_64/README.txt new file mode 100644 index 00000000..47572ee3 --- /dev/null +++ b/vtk.rendering.win32.win32.x86_64/README.txt @@ -0,0 +1 @@ +This folder contains deprecated plain native libraries for platform windows-amd64, please use the native JAR files in the jar folder. diff --git a/vtk.rendering.win32.win32.x86_64/build.properties b/vtk.rendering.win32.win32.x86_64/build.properties new file mode 100644 index 00000000..34d2e4d2 --- /dev/null +++ b/vtk.rendering.win32.win32.x86_64/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . diff --git a/vtk.rendering.win32.win32.x86_64/gluegen-rt.dll b/vtk.rendering.win32.win32.x86_64/gluegen-rt.dll new file mode 100644 index 00000000..d02d2ccf Binary files /dev/null and b/vtk.rendering.win32.win32.x86_64/gluegen-rt.dll differ diff --git a/vtk.rendering.win32.win32.x86_64/joal.dll b/vtk.rendering.win32.win32.x86_64/joal.dll new file mode 100644 index 00000000..f07d1a4e Binary files /dev/null and b/vtk.rendering.win32.win32.x86_64/joal.dll differ diff --git a/vtk.rendering.win32.win32.x86_64/jocl.dll b/vtk.rendering.win32.win32.x86_64/jocl.dll new file mode 100644 index 00000000..1f6121a4 Binary files /dev/null and b/vtk.rendering.win32.win32.x86_64/jocl.dll differ diff --git a/vtk.rendering.win32.win32.x86_64/jogl_cg.dll b/vtk.rendering.win32.win32.x86_64/jogl_cg.dll new file mode 100644 index 00000000..a4952a48 Binary files /dev/null and b/vtk.rendering.win32.win32.x86_64/jogl_cg.dll differ diff --git a/vtk.rendering.win32.win32.x86_64/jogl_desktop.dll b/vtk.rendering.win32.win32.x86_64/jogl_desktop.dll new file mode 100644 index 00000000..191dc441 Binary files /dev/null and b/vtk.rendering.win32.win32.x86_64/jogl_desktop.dll differ diff --git a/vtk.rendering.win32.win32.x86_64/jogl_mobile.dll b/vtk.rendering.win32.win32.x86_64/jogl_mobile.dll new file mode 100644 index 00000000..9213fd35 Binary files /dev/null and b/vtk.rendering.win32.win32.x86_64/jogl_mobile.dll differ diff --git a/vtk.rendering.win32.win32.x86_64/nativewindow_awt.dll b/vtk.rendering.win32.win32.x86_64/nativewindow_awt.dll new file mode 100644 index 00000000..b73f0348 Binary files /dev/null and b/vtk.rendering.win32.win32.x86_64/nativewindow_awt.dll differ diff --git a/vtk.rendering.win32.win32.x86_64/nativewindow_win32.dll b/vtk.rendering.win32.win32.x86_64/nativewindow_win32.dll new file mode 100644 index 00000000..354f22fe Binary files /dev/null and b/vtk.rendering.win32.win32.x86_64/nativewindow_win32.dll differ diff --git a/vtk.rendering.win32.win32.x86_64/newt.dll b/vtk.rendering.win32.win32.x86_64/newt.dll new file mode 100644 index 00000000..cdf227cd Binary files /dev/null and b/vtk.rendering.win32.win32.x86_64/newt.dll differ diff --git a/vtk.rendering.win32.win32.x86_64/soft_oal.dll b/vtk.rendering.win32.win32.x86_64/soft_oal.dll new file mode 100644 index 00000000..93974250 Binary files /dev/null and b/vtk.rendering.win32.win32.x86_64/soft_oal.dll differ diff --git a/vtk.rendering/.classpath b/vtk.rendering/.classpath new file mode 100644 index 00000000..b9bcee7a --- /dev/null +++ b/vtk.rendering/.classpath @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/vtk.rendering/.gitignore b/vtk.rendering/.gitignore new file mode 100644 index 00000000..ae3c1726 --- /dev/null +++ b/vtk.rendering/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/vtk.rendering/.project b/vtk.rendering/.project new file mode 100644 index 00000000..c698cc64 --- /dev/null +++ b/vtk.rendering/.project @@ -0,0 +1,28 @@ + + + vtk.rendering + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/vtk.rendering/.settings/org.eclipse.jdt.core.prefs b/vtk.rendering/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..0c68a61d --- /dev/null +++ b/vtk.rendering/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +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 diff --git a/vtk.rendering/META-INF/MANIFEST.MF b/vtk.rendering/META-INF/MANIFEST.MF new file mode 100644 index 00000000..6ee0bfe1 --- /dev/null +++ b/vtk.rendering/META-INF/MANIFEST.MF @@ -0,0 +1,140 @@ +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 diff --git a/vtk.rendering/build.properties b/vtk.rendering/build.properties new file mode 100644 index 00000000..ca7d753a --- /dev/null +++ b/vtk.rendering/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + lib/jogl-all.jar,\ + lib/gluegen-rt.jar diff --git a/vtk.rendering/lib/gluegen-rt.jar b/vtk.rendering/lib/gluegen-rt.jar new file mode 100644 index 00000000..742fdb26 Binary files /dev/null and b/vtk.rendering/lib/gluegen-rt.jar differ diff --git a/vtk.rendering/lib/jogl-all.jar b/vtk.rendering/lib/jogl-all.jar new file mode 100644 index 00000000..f73174f9 Binary files /dev/null and b/vtk.rendering/lib/jogl-all.jar differ diff --git a/vtk.rendering/pom.xml b/vtk.rendering/pom.xml new file mode 100644 index 00000000..6dee25c0 --- /dev/null +++ b/vtk.rendering/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + + org.simantics.g3d + org.simantics.g3d.root + 1.0.0-SNAPSHOT + + + vtk + eclipse-plugin + 8.2.0-SNAPSHOT + + \ No newline at end of file diff --git a/vtk.rendering/src/vtk/rendering/awt/vtkAwtComponent.java b/vtk.rendering/src/vtk/rendering/awt/vtkAwtComponent.java new file mode 100644 index 00000000..974a561d --- /dev/null +++ b/vtk.rendering/src/vtk/rendering/awt/vtkAwtComponent.java @@ -0,0 +1,127 @@ +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 { + 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; + } +} diff --git a/vtk.rendering/src/vtk/rendering/awt/vtkInternalAwtComponent.java b/vtk.rendering/src/vtk/rendering/awt/vtkInternalAwtComponent.java new file mode 100644 index 00000000..08bba081 --- /dev/null +++ b/vtk.rendering/src/vtk/rendering/awt/vtkInternalAwtComponent.java @@ -0,0 +1,41 @@ +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(); + } +} diff --git a/vtk.rendering/src/vtk/rendering/awt/vtkPanelComponent.java b/vtk.rendering/src/vtk/rendering/awt/vtkPanelComponent.java new file mode 100644 index 00000000..79cbf2a5 --- /dev/null +++ b/vtk.rendering/src/vtk/rendering/awt/vtkPanelComponent.java @@ -0,0 +1,128 @@ +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 { + 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; + } +} diff --git a/vtk.rendering/src/vtk/rendering/swt/vtkInternalSwtComponent.java b/vtk.rendering/src/vtk/rendering/swt/vtkInternalSwtComponent.java new file mode 100644 index 00000000..2d73b3d5 --- /dev/null +++ b/vtk.rendering/src/vtk/rendering/swt/vtkInternalSwtComponent.java @@ -0,0 +1,127 @@ +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; + } + } +} diff --git a/vtk.rendering/src/vtk/rendering/swt/vtkSwtComponent.java b/vtk.rendering/src/vtk/rendering/swt/vtkSwtComponent.java new file mode 100644 index 00000000..7d79189d --- /dev/null +++ b/vtk.rendering/src/vtk/rendering/swt/vtkSwtComponent.java @@ -0,0 +1,135 @@ +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 { + + 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(); + } + } +} diff --git a/vtk.rendering/src/vtk/rendering/swt/vtkSwtInteractorForwarderDecorator.java b/vtk.rendering/src/vtk/rendering/swt/vtkSwtInteractorForwarderDecorator.java new file mode 100644 index 00000000..28178862 --- /dev/null +++ b/vtk.rendering/src/vtk/rendering/swt/vtkSwtInteractorForwarderDecorator.java @@ -0,0 +1,105 @@ +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) { + } +} diff --git a/vtk.rendering/src/vtk/rendering/vtkAbstractComponent.java b/vtk.rendering/src/vtk/rendering/vtkAbstractComponent.java new file mode 100644 index 00000000..e68bd467 --- /dev/null +++ b/vtk.rendering/src/vtk/rendering/vtkAbstractComponent.java @@ -0,0 +1,181 @@ +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 + * 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 implements vtkComponent { + 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(); + } +} diff --git a/vtk.rendering/src/vtk/rendering/vtkAbstractEventInterceptor.java b/vtk.rendering/src/vtk/rendering/vtkAbstractEventInterceptor.java new file mode 100644 index 00000000..b63f3e46 --- /dev/null +++ b/vtk.rendering/src/vtk/rendering/vtkAbstractEventInterceptor.java @@ -0,0 +1,64 @@ +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; + } +} diff --git a/vtk.rendering/src/vtk/rendering/vtkComponent.java b/vtk.rendering/src/vtk/rendering/vtkComponent.java new file mode 100644 index 00000000..d9d72de4 --- /dev/null +++ b/vtk.rendering/src/vtk/rendering/vtkComponent.java @@ -0,0 +1,106 @@ +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 + * 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 { + + /** + * @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(); +} diff --git a/vtk.rendering/src/vtk/rendering/vtkEventInterceptor.java b/vtk.rendering/src/vtk/rendering/vtkEventInterceptor.java new file mode 100644 index 00000000..1f388f40 --- /dev/null +++ b/vtk.rendering/src/vtk/rendering/vtkEventInterceptor.java @@ -0,0 +1,111 @@ +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); +} diff --git a/vtk.rendering/src/vtk/rendering/vtkInteractorForwarder.java b/vtk.rendering/src/vtk/rendering/vtkInteractorForwarder.java new file mode 100644 index 00000000..af8a6e36 --- /dev/null +++ b/vtk.rendering/src/vtk/rendering/vtkInteractorForwarder.java @@ -0,0 +1,389 @@ +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; + } +}