]> gerrit.simantics Code Review - simantics/3d.git/commitdiff
Alpha-version of jME-bindings for g3d.
authorluukkainen <luukkainen@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Fri, 5 Jul 2013 11:10:43 +0000 (11:10 +0000)
committerluukkainen <luukkainen@ac1ea38d-2e2b-0410-8846-a27921b304fc>
Fri, 5 Jul 2013 11:10:43 +0000 (11:10 +0000)
refs #4378

git-svn-id: https://www.simantics.org/svn/simantics/3d/trunk@27693 ac1ea38d-2e2b-0410-8846-a27921b304fc

28 files changed:
org.simantics.g3d.jme/.classpath [new file with mode: 0644]
org.simantics.g3d.jme/.project [new file with mode: 0644]
org.simantics.g3d.jme/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.g3d.jme/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.g3d.jme/build.properties [new file with mode: 0644]
org.simantics.g3d.jme/plugin.xml [new file with mode: 0644]
org.simantics.g3d.jme/src/org/simantics/g3d/jme/Activator.java [new file with mode: 0644]
org.simantics.g3d.jme/src/org/simantics/g3d/jme/common/AbstractJMENodeMap.java [new file with mode: 0644]
org.simantics.g3d.jme/src/org/simantics/g3d/jme/common/JMENodeMap.java [new file with mode: 0644]
org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/AxesActor.java [new file with mode: 0644]
org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/AxesActor2.java [new file with mode: 0644]
org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/AxisActor.java [new file with mode: 0644]
org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/DualHeadArrowActor.java [new file with mode: 0644]
org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/MeshNode.java [new file with mode: 0644]
org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/TubeActor.java [new file with mode: 0644]
org.simantics.g3d.jme/src/org/simantics/g3d/jme/system/SWTApplication.java [new file with mode: 0644]
org.simantics.g3d.jme/src/org/simantics/g3d/jme/system/SWTCanvas.java [new file with mode: 0644]
org.simantics.g3d.jme/src/org/simantics/g3d/jme/system/SimpleSWTApplication.java [new file with mode: 0644]
org.simantics.g3d.jme/src/org/simantics/g3d/jme/test/JMETestViewPart.java [new file with mode: 0644]
org.simantics.g3d.jme/src/org/simantics/g3d/jme/utils/JmeUtil.java [new file with mode: 0644]
org.simantics.opencascade.jme/.classpath [new file with mode: 0644]
org.simantics.opencascade.jme/.project [new file with mode: 0644]
org.simantics.opencascade.jme/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
org.simantics.opencascade.jme/META-INF/MANIFEST.MF [new file with mode: 0644]
org.simantics.opencascade.jme/build.properties [new file with mode: 0644]
org.simantics.opencascade.jme/src/org/simantics/opencascade/jme/Activator.java [new file with mode: 0644]
org.simantics.opencascade.jme/src/org/simantics/opencascade/jme/JmeOCCTTool.java [new file with mode: 0644]
org.simantics.opencascade.jme/src/org/simantics/opencascade/jme/JmeSolidObject.java [new file with mode: 0644]

diff --git a/org.simantics.g3d.jme/.classpath b/org.simantics.g3d.jme/.classpath
new file mode 100644 (file)
index 0000000..8a8f166
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/org.simantics.g3d.jme/.project b/org.simantics.g3d.jme/.project
new file mode 100644 (file)
index 0000000..424c0e2
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.g3d.jme</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.g3d.jme/.settings/org.eclipse.jdt.core.prefs b/org.simantics.g3d.jme/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..c107b6a
--- /dev/null
@@ -0,0 +1,8 @@
+#Wed Aug 08 16:41:22 EEST 2012\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
+org.eclipse.jdt.core.compiler.compliance=1.6\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.6\r
diff --git a/org.simantics.g3d.jme/META-INF/MANIFEST.MF b/org.simantics.g3d.jme/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..59de283
--- /dev/null
@@ -0,0 +1,22 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Jme
+Bundle-SymbolicName: org.simantics.g3d.jme;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.simantics.g3d.jme.Activator
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.simantics.g3d;bundle-version="1.0.0",
+ org.simantics.g3d.ontology;bundle-version="1.0.0",
+ com.jme;bundle-version="1.0.0",
+ javax.vecmath;bundle-version="1.5.2",
+ org.simantics.db;bundle-version="1.1.0",
+ org.simantics.db.common;bundle-version="1.1.0",
+ org.simantics.objmap2;bundle-version="1.0.0",
+ org.eclipse.ui.views;bundle-version="3.6.0"
+Bundle-ActivationPolicy: lazy
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Export-Package: org.simantics.g3d.jme.common,
+ org.simantics.g3d.jme.shape,
+ org.simantics.g3d.jme.system,
+ org.simantics.g3d.jme.utils
diff --git a/org.simantics.g3d.jme/build.properties b/org.simantics.g3d.jme/build.properties
new file mode 100644 (file)
index 0000000..6f20375
--- /dev/null
@@ -0,0 +1,5 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               .,\\r
+               plugin.xml\r
diff --git a/org.simantics.g3d.jme/plugin.xml b/org.simantics.g3d.jme/plugin.xml
new file mode 100644 (file)
index 0000000..d175276
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<?eclipse version="3.4"?>\r
+<plugin>\r
+   <extension\r
+         point="org.eclipse.ui.views">\r
+      <view\r
+            allowMultiple="false"\r
+            class="org.simantics.g3d.jme.test.JMETestViewPart"\r
+            icon="platform:/plugin/com.famfamfam.silk/icons/bug.png"\r
+            id="org.simantics.g3d.jme.testview"\r
+            name="JME Test"\r
+            restorable="true">\r
+      </view>\r
+   </extension>\r
+\r
+</plugin>\r
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/Activator.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/Activator.java
new file mode 100644 (file)
index 0000000..49e768f
--- /dev/null
@@ -0,0 +1,50 @@
+package org.simantics.g3d.jme;\r
+\r
+import org.eclipse.ui.plugin.AbstractUIPlugin;\r
+import org.osgi.framework.BundleContext;\r
+\r
+/**\r
+ * The activator class controls the plug-in life cycle\r
+ */\r
+public class Activator extends AbstractUIPlugin {\r
+\r
+       // The plug-in ID\r
+       public static final String PLUGIN_ID = "org.simantics.g3d.jme"; //$NON-NLS-1$\r
+\r
+       // The shared instance\r
+       private static Activator plugin;\r
+       \r
+       /**\r
+        * The constructor\r
+        */\r
+       public Activator() {\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)\r
+        */\r
+       public void start(BundleContext context) throws Exception {\r
+               super.start(context);\r
+               plugin = this;\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)\r
+        */\r
+       public void stop(BundleContext context) throws Exception {\r
+               plugin = null;\r
+               super.stop(context);\r
+       }\r
+\r
+       /**\r
+        * Returns the shared instance\r
+        *\r
+        * @return the shared instance\r
+        */\r
+       public static Activator getDefault() {\r
+               return plugin;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/common/AbstractJMENodeMap.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/common/AbstractJMENodeMap.java
new file mode 100644 (file)
index 0000000..162fbb3
--- /dev/null
@@ -0,0 +1,415 @@
+package org.simantics.g3d.jme.common;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.Stack;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.ReadRequest;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.g3d.ontology.G3D;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.RenderListener;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.g3d.scenegraph.base.NodeListener;\r
+import org.simantics.g3d.scenegraph.base.ParentNode;\r
+import org.simantics.objmap.graph.IMapping;\r
+import org.simantics.objmap.graph.IMappingListener;\r
+import org.simantics.utils.datastructures.MapList;\r
+import org.simantics.utils.datastructures.MapSet;\r
+import org.simantics.utils.datastructures.Pair;\r
+\r
+import com.jme3.app.Application;\r
+import com.jme3.scene.Spatial;\r
+\r
+public abstract class AbstractJMENodeMap<E extends IG3DNode> implements JMENodeMap, IMappingListener, NodeListener, RenderListener {\r
+\r
+       protected Session session;\r
+       protected IMapping mapping;\r
+       protected Application app;\r
+//     protected InteractiveVtkPanel panel;\r
+       \r
+       protected MapList<E, Spatial> nodeToActor = new MapList<E, Spatial>();\r
+       protected Map<Spatial,E> actorToNode = new HashMap<Spatial, E>();\r
+\r
+       protected ParentNode<E> rootNode;\r
+       \r
+       public AbstractJMENodeMap(Session session, IMapping mapping, Application app, ParentNode<E> rootNode) {\r
+               this.session = session;\r
+               this.mapping = mapping;\r
+               this.rootNode = rootNode;\r
+               this.app = app;\r
+//             this.panel = panel;\r
+//             panel.addListener(this);\r
+               mapping.addMappingListener(this);\r
+               rootNode.addListener(this);\r
+       }\r
+       \r
+       protected abstract void addActor(E node);\r
+       protected abstract void removeActor(E node);\r
+       protected abstract void updateActor(E node,Set<String> ids);\r
+       \r
+       \r
+       public void repaint() {\r
+               \r
+       }\r
+       \r
+       public void populate() {\r
+               for (E node : rootNode.getNodes()) {\r
+                       receiveAdd(node, node.getParentRel(),true);\r
+               }\r
+               repaint();\r
+       }\r
+       \r
+       @Override\r
+       public IG3DNode getNode(Spatial prop) {\r
+               return actorToNode.get(prop);\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public Collection<Spatial> getRenderObjects(IG3DNode node) {\r
+               return nodeToActor.getValues((E)node);\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public ParentNode<IG3DNode> getRootNode() {\r
+               return (ParentNode<IG3DNode>)rootNode;\r
+       }\r
+       \r
+       @Override\r
+       public void commit() {\r
+               session.asyncRequest(new WriteRequest() {\r
+                       \r
+                       @Override\r
+                       public void perform(WriteGraph graph) throws DatabaseException {\r
+                               synchronized(syncMutex) {\r
+                                       graphUpdates = true;\r
+                                       mapping.updateDomain(graph);\r
+                                       graphUpdates = false;\r
+                               }\r
+                       }\r
+               });\r
+       }\r
+       \r
+       @Override\r
+       public boolean isChangeTracking() {\r
+               return changeTracking;\r
+       }\r
+       \r
+       @Override\r
+       public void setChangeTracking(boolean enabled) {\r
+               changeTracking = enabled;\r
+       }\r
+       \r
+       private boolean changeTracking = true;\r
+       \r
+       private Object syncMutex = new Object(); \r
+       \r
+\r
+       private List<Pair<E,String>> added = new ArrayList<Pair<E,String>>();\r
+       private List<Pair<E,String>> removed = new ArrayList<Pair<E,String>>();\r
+       //private List<Pair<E,String>> updated = new ArrayList<Pair<E,String>>();\r
+       private MapSet<E, String> updated = new MapSet<E, String>();//new MapSet.Hash<E, String>();\r
+\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public void updateRenderObjectsFor(IG3DNode node) {\r
+               List<Spatial> toDelete = new ArrayList<Spatial>();\r
+               for (Spatial prop : nodeToActor.getValues((E)node)) {\r
+//                     if (prop.GetVTKId() != 0) {\r
+//                             panel.GetRenderer().RemoveActor(prop);\r
+//                             //prop.Delete();\r
+//                             toDelete.add(prop);\r
+//                     }\r
+                       prop.removeFromParent();\r
+                       actorToNode.remove(prop);\r
+               }\r
+               nodeToActor.remove((E)node);\r
+               Collection<Spatial> coll = getActors((E)node);\r
+               if (coll == null)\r
+                       return;\r
+               for (Spatial prop : coll) {\r
+                       nodeToActor.add((E)node,prop);\r
+                       actorToNode.put(prop, (E)node);\r
+                       toDelete.remove(prop);\r
+               }\r
+               for (Spatial p : toDelete) {\r
+                       //p.Delete();\r
+               }\r
+       }\r
+       \r
+       protected abstract  Collection<Spatial> getActors(E node);\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       private void receiveAdd(E node, String id, boolean db) {\r
+               synchronized (syncMutex) {\r
+                       for (Pair<E, String> n : added) {\r
+                               if (n.first.equals(node))\r
+                                       return;\r
+                       }\r
+                       if (changeTracking) {\r
+                               mapping.rangeModified(node.getParent());\r
+                       }\r
+                       added.add(new Pair<E, String>(node, id));       \r
+               }\r
+               repaint();\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       private void receiveRemove(E node, String id, boolean db) {\r
+               synchronized (syncMutex) {\r
+                       for (Pair<E, String> n : removed) {\r
+                               if (n.first.equals(node))\r
+                                       return;\r
+                       }\r
+                       if (changeTracking && !db)\r
+                               mapping.rangeModified(node.getParent());\r
+                       removed.add(new Pair<E, String>(node, id));\r
+               }\r
+               repaint();\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       private void receiveUpdate(E node, String id, boolean db) {\r
+               synchronized (syncMutex) {\r
+//                     for (Pair<E, String> n : updated) {\r
+//                             if (n.first.equals(node))\r
+//                                     return;\r
+//                     }\r
+                       if (changeTracking && !db)\r
+                               mapping.rangeModified(node);\r
+                       //updated.add(new Pair<E, String>(node, id));\r
+                       updated.add(node, id);\r
+               }\r
+               repaint();\r
+       }\r
+       \r
+       private boolean graphUpdates = false;\r
+       private Set<Object> graphModified = new HashSet<Object>();\r
+       \r
+       @Override\r
+       public void domainModified() {\r
+               if (graphUpdates)\r
+                       return;\r
+               //System.out.println("domainModified");\r
+               session.asyncRequest(new ReadRequest() {\r
+                       \r
+                       @SuppressWarnings("unchecked")\r
+                       @Override\r
+                       public void run(ReadGraph graph) throws DatabaseException {\r
+                               graphUpdates = true;\r
+                               for (Object domainObject : mapping.getDomainModified()) {\r
+                                       Object rangeObject = mapping.get(domainObject);\r
+                                       if (rangeObject != null)\r
+                                               graphModified.add(rangeObject);\r
+                               }\r
+                               mapping.updateRange(graph);\r
+                               graphModified.clear();\r
+                               graphUpdates = false;\r
+                               if (mapping.isRangeModified())\r
+                                       commit();\r
+                       }\r
+               });\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void rangeModified() {\r
+               //System.out.println("rangeModified");\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void postRender() {\r
+               \r
+       }\r
+       \r
+       List<Pair<E, String>> rem = new ArrayList<Pair<E,String>>();\r
+       List<Pair<E, String>> add = new ArrayList<Pair<E,String>>();\r
+       MapSet<E, String> mod = new MapSet<E, String>();//new MapSet.Hash<E, String>();\r
+       Set<E> propagation = new HashSet<E>();\r
+       Stack<E> stack = new Stack<E>();\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public synchronized void preRender() {\r
+               rem.clear();\r
+               add.clear();\r
+               mod.clear();\r
+               propagation.clear();\r
+               \r
+               synchronized (syncMutex) {\r
+                       rem.addAll(removed);\r
+                       add.addAll(added);\r
+                       //mod.addAll(updated);\r
+                       for (E e : updated.getKeys()) {\r
+                               for (String s : updated.getValues(e))\r
+                                       mod.add(e, s);\r
+                       }\r
+                       \r
+                       removed.clear();\r
+                       added.clear();\r
+                       updated.clear();\r
+               }\r
+               \r
+               for (Pair<E, String> n : rem) {\r
+                       stopListening(n.first);\r
+                       removeActor(n.first);\r
+               \r
+               }\r
+               \r
+               for (Pair<E, String> n : add) {\r
+                       addActor(n.first);\r
+                       listen(n.first);\r
+               }\r
+               \r
+               for (E e : mod.getKeys()) {\r
+                       Set<String> ids = mod.getValues(e);\r
+                       if (ids.contains(G3D.URIs.hasPosition) || ids.contains(G3D.URIs.hasOrientation)) {\r
+                               if (!propagation.contains(e))\r
+                                       propagation.add(e);\r
+                       }\r
+               }\r
+               \r
+               if (propagation.size() > 0) {\r
+                       stack.clear();\r
+                       stack.addAll(propagation);\r
+                       propagation.clear();\r
+                       while (!stack.isEmpty()) {\r
+                               E node = stack.pop();\r
+                               if (propagation.contains(node))\r
+                                       continue;\r
+                               propagation.add(node);\r
+                               for (NodeListener l : node.getListeners()) {\r
+                                       if (l == this) {\r
+                                               //changeTracking = false;\r
+                                               //l.propertyChanged(node, G3D.URIs.hasPosition);\r
+                                               //changeTracking = true;\r
+                                       } else {\r
+                                               l.propertyChanged(node, G3D.URIs.hasPosition);\r
+                                       }\r
+                               }\r
+                               if (node instanceof ParentNode) {\r
+                                       stack.addAll(((ParentNode<E>)node).getNodes());\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               for (E e : mod.getKeys()) {\r
+                       Set<String> ids = mod.getValues(e);\r
+                       updateActor(e,ids);\r
+               }\r
+               \r
+               for (Pair<E, String> n : rem) {\r
+                       for (NodeListener l : nodeListeners)\r
+                               l.nodeRemoved(null, n.first, n.second);\r
+               }\r
+               for (Pair<E, String> n : add) {\r
+                       for (NodeListener l : nodeListeners)\r
+                               l.nodeAdded(n.first.getParent(), n.first, n.second);\r
+               }\r
+//             for (Pair<E, String> n : mod) {\r
+//                     for (NodeListener l : nodeListeners)\r
+//                             l.propertyChanged(n.first, n.second);\r
+//             }\r
+               for (E e : mod.getKeys()) {\r
+                       for (NodeListener l : nodeListeners)\r
+                               for (String s : mod.getValues(e))\r
+                                       l.propertyChanged(e, s);\r
+               }\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       private void listen(INode node) {\r
+               node.addListener(this);\r
+               if (node instanceof ParentNode<?>) {\r
+                       ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
+                       for (INode n : parentNode.getNodes())\r
+                               listen(n);\r
+               }\r
+       }\r
+       \r
+       private void stopListening(INode node) {\r
+               node.removeListener(this);\r
+               if (node instanceof ParentNode<?>) {\r
+                       @SuppressWarnings("unchecked")\r
+                       ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
+                       for (INode n : parentNode.getNodes())\r
+                               stopListening(n);\r
+               }\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public void propertyChanged(INode node, String id) {\r
+               //receiveUpdate((E)node, id, graphUpdates);\r
+               receiveUpdate((E)node, id, graphModified.contains(node));\r
+               \r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public <T extends INode> void nodeAdded(ParentNode<T> node, INode child,\r
+                       String rel) {\r
+               //receiveAdd((E)child, rel ,graphUpdates);\r
+               receiveAdd((E)child, rel ,graphModified.contains(node));\r
+               \r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public <T extends INode> void nodeRemoved(ParentNode<T> node, INode child,\r
+                       String rel) {\r
+               //receiveRemove((E)child, rel, graphUpdates);\r
+               receiveRemove((E)child, rel, graphModified.contains(node));\r
+       }\r
+       \r
+       @Override\r
+       public void delete() {\r
+               changeTracking = false;\r
+               //panel.removeListener(this);\r
+               mapping.removeMappingListener(this);\r
+\r
+               List<E> nodes = new ArrayList<E>(nodeToActor.getKeySize());\r
+               nodes.addAll(nodeToActor.getKeys());\r
+               for (E node : nodes) {\r
+                       node.removeListener(this);\r
+                       removeActor(node);\r
+                       node.cleanup();\r
+               }\r
+               for (Spatial prop : actorToNode.keySet()) {\r
+                       prop.removeFromParent();\r
+                       //if (prop.GetVTKId() != 0) \r
+                       //      prop.Delete();\r
+               }\r
+               actorToNode.clear();\r
+               nodeToActor.clear();\r
+               \r
+       }\r
+       \r
+       \r
+       private List<NodeListener> nodeListeners = new ArrayList<NodeListener>();\r
+       @Override\r
+       public void addListener(NodeListener listener) {\r
+               nodeListeners.add(listener);\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void removeListener(NodeListener listener) {\r
+               nodeListeners.remove(listener);\r
+               \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/common/JMENodeMap.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/common/JMENodeMap.java
new file mode 100644 (file)
index 0000000..bc7f740
--- /dev/null
@@ -0,0 +1,9 @@
+package org.simantics.g3d.jme.common;\r
+\r
+import org.simantics.g3d.scenegraph.NodeMap;\r
+\r
+import com.jme3.scene.Spatial;\r
+\r
+public interface JMENodeMap extends NodeMap<Spatial>{\r
+\r
+}\r
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/AxesActor.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/AxesActor.java
new file mode 100644 (file)
index 0000000..05f15ee
--- /dev/null
@@ -0,0 +1,39 @@
+package org.simantics.g3d.jme.shape;\r
+\r
+import com.jme3.app.Application;\r
+import com.jme3.material.Material;\r
+import com.jme3.math.ColorRGBA;\r
+import com.jme3.math.Vector3f;\r
+import com.jme3.scene.Geometry;\r
+import com.jme3.scene.Mesh;\r
+import com.jme3.scene.Node;\r
+import com.jme3.scene.debug.Arrow;\r
+\r
+public class AxesActor extends Node {\r
+       \r
+       Application app;\r
+       \r
+       public AxesActor(Application app, double size) {\r
+               this.app = app;\r
+                putArrow(Vector3f.ZERO, Vector3f.UNIT_X.mult((float)size), ColorRGBA.Red);\r
+            putArrow(Vector3f.ZERO, Vector3f.UNIT_Y.mult((float)size), ColorRGBA.Green);\r
+            putArrow(Vector3f.ZERO, Vector3f.UNIT_Z.mult((float)size), ColorRGBA.Blue);\r
+       }\r
+       \r
+       public Geometry putShape(Mesh shape, ColorRGBA color){\r
+        Geometry g = new Geometry("shape", shape);\r
+        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");\r
+        mat.getAdditionalRenderState().setWireframe(true);\r
+        mat.setColor("Color", color);\r
+        g.setMaterial(mat);\r
+        this.attachChild(g);\r
+        return g;\r
+    }\r
+\r
+    public void putArrow(Vector3f pos, Vector3f dir, ColorRGBA color){\r
+        Arrow arrow = new Arrow(dir);\r
+        arrow.setLineWidth(4); // make arrow thicker\r
+        putShape(arrow, color).setLocalTranslation(pos);\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/AxesActor2.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/AxesActor2.java
new file mode 100644 (file)
index 0000000..2c106c9
--- /dev/null
@@ -0,0 +1,60 @@
+package org.simantics.g3d.jme.shape;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+import org.simantics.g3d.shape.Color4d;\r
+import org.simantics.g3d.shape.Cone;\r
+import org.simantics.g3d.shape.Cylinder;\r
+import org.simantics.g3d.shape.Sphere;\r
+\r
+import com.jme3.app.Application;\r
+\r
+public class AxesActor2 extends MeshNode {\r
+       \r
+       public AxesActor2(Application app, double size) {\r
+               super(app);\r
+               \r
+               int res = 16;\r
+               \r
+               org.simantics.g3d.shape.Mesh cone_x = Cone.create(size*0.3, res);\r
+               org.simantics.g3d.shape.Mesh cone_y = Cone.create(size*0.3, res);\r
+               org.simantics.g3d.shape.Mesh cone_z = Cone.create(size*0.3, res);\r
+               cone_x.rotate(MathTools.getQuat(new AxisAngle4d(0,0,-1,Math.PI*0.5)));\r
+               cone_z.rotate(MathTools.getQuat(new AxisAngle4d(1,0,0,Math.PI*0.5)));\r
+               cone_x.translate(new Vector3d(size,0,0));\r
+               cone_y.translate(new Vector3d(0,size,0));\r
+               cone_z.translate(new Vector3d(0,0,size));\r
+               \r
+               org.simantics.g3d.shape.Mesh tube_x = Cylinder.create(MathTools.ORIGIN, new Vector3d(size,0,0), size*0.1, res);\r
+               org.simantics.g3d.shape.Mesh tube_y = Cylinder.create(MathTools.ORIGIN, new Vector3d(0,size,0), size*0.1, res);\r
+               org.simantics.g3d.shape.Mesh tube_z = Cylinder.create(MathTools.ORIGIN, new Vector3d(0,0,size), size*0.1, res);\r
+               \r
+               org.simantics.g3d.shape.Mesh sphere = Sphere.create(size*0.3, res, res*2/3);\r
+               \r
+               Color4d x_col = new Color4d(1,0,0,1);\r
+               Color4d y_col = new Color4d(1,1,0,1);\r
+               Color4d z_col = new Color4d(0,1,0,1);\r
+               Color4d o_col = new Color4d(0,0,1,1);\r
+               \r
+               cone_x.setColor(x_col);\r
+               tube_x.setColor(x_col);\r
+               cone_y.setColor(y_col);\r
+               tube_y.setColor(y_col);\r
+               cone_z.setColor(z_col);\r
+               tube_z.setColor(z_col);\r
+               sphere.setColor(o_col);\r
+               \r
+               sphere.add(cone_x);\r
+               sphere.add(tube_x);\r
+               sphere.add(cone_y);\r
+               sphere.add(tube_y);\r
+               sphere.add(cone_z);\r
+               sphere.add(tube_z);\r
+               \r
+               setMesh(sphere);\r
+       }\r
+       \r
+       \r
+}\r
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/AxisActor.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/AxisActor.java
new file mode 100644 (file)
index 0000000..c6ddd58
--- /dev/null
@@ -0,0 +1,41 @@
+package org.simantics.g3d.jme.shape;\r
+\r
+import javax.vecmath.Vector3d;\r
+\r
+import com.jme3.app.Application;\r
+import com.jme3.material.Material;\r
+import com.jme3.math.ColorRGBA;\r
+import com.jme3.math.Vector3f;\r
+import com.jme3.scene.Geometry;\r
+import com.jme3.scene.Mesh;\r
+import com.jme3.scene.Node;\r
+import com.jme3.scene.debug.Arrow;\r
+\r
+public class AxisActor extends Node {\r
+       \r
+       Application app;\r
+       \r
+       public AxisActor(Application app, String name, Vector3d v) {\r
+               this.app = app;\r
+               Vector3f vec = new Vector3f((float)v.x, (float)v.y, (float)v.z);\r
+               putArrow(Vector3f.ZERO, vec, ColorRGBA.Red);\r
+           \r
+       }\r
+       \r
+       public Geometry putShape(Mesh shape, ColorRGBA color){\r
+        Geometry g = new Geometry("shape", shape);\r
+        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");\r
+        mat.getAdditionalRenderState().setWireframe(true);\r
+        mat.setColor("Color", color);\r
+        g.setMaterial(mat);\r
+        this.attachChild(g);\r
+        return g;\r
+    }\r
+\r
+    public void putArrow(Vector3f pos, Vector3f dir, ColorRGBA color){\r
+        Arrow arrow = new Arrow(dir);\r
+        arrow.setLineWidth(4); // make arrow thicker\r
+        putShape(arrow, color).setLocalTranslation(pos);\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/DualHeadArrowActor.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/DualHeadArrowActor.java
new file mode 100644 (file)
index 0000000..b81abee
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.g3d.jme.shape;\r
+\r
+import javax.vecmath.Vector3d;\r
+\r
+import com.jme3.app.Application;\r
+import com.jme3.material.Material;\r
+import com.jme3.math.ColorRGBA;\r
+import com.jme3.math.Vector3f;\r
+import com.jme3.scene.Geometry;\r
+import com.jme3.scene.Mesh;\r
+import com.jme3.scene.Node;\r
+import com.jme3.scene.debug.Arrow;\r
+\r
+public class DualHeadArrowActor extends Node {\r
+       \r
+       Application app;\r
+       \r
+       public DualHeadArrowActor(Application app, String name, Vector3d v) {\r
+               this.app = app;\r
+               Vector3f vec = new Vector3f((float)(v.x*0.5), (float)(v.y*0.5), (float)(v.z*0.5));\r
+               Vector3f vecN = new Vector3f(vec);\r
+               vecN.negate();\r
+               putArrow(vec, vec, ColorRGBA.Red);\r
+               putArrow(vec, vecN, ColorRGBA.Red);\r
+           \r
+       }\r
+       \r
+       public Geometry putShape(Mesh shape, ColorRGBA color){\r
+        Geometry g = new Geometry("shape", shape);\r
+        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");\r
+        mat.getAdditionalRenderState().setWireframe(true);\r
+        mat.setColor("Color", color);\r
+        g.setMaterial(mat);\r
+        this.attachChild(g);\r
+        return g;\r
+    }\r
+\r
+    public void putArrow(Vector3f pos, Vector3f dir, ColorRGBA color){\r
+        Arrow arrow = new Arrow(dir);\r
+        arrow.setLineWidth(4); // make arrow thicker\r
+        putShape(arrow, color).setLocalTranslation(pos);\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/MeshNode.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/MeshNode.java
new file mode 100644 (file)
index 0000000..b6baa79
--- /dev/null
@@ -0,0 +1,84 @@
+package org.simantics.g3d.jme.shape;\r
+\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.shape.Color4d;\r
+\r
+import com.jme3.app.Application;\r
+import com.jme3.material.Material;\r
+import com.jme3.math.ColorRGBA;\r
+import com.jme3.scene.Geometry;\r
+import com.jme3.scene.Mesh;\r
+import com.jme3.scene.VertexBuffer.Type;\r
+\r
+public class MeshNode extends Geometry {\r
+       Application app;\r
+       \r
+       \r
+       public MeshNode(Application app) {\r
+               this.app = app;\r
+       }\r
+       \r
+       public void setMesh(org.simantics.g3d.shape.Mesh mesh) {\r
+               \r
+               Mesh shape = new Mesh();\r
+               \r
+               float points[] = new float[mesh.getVertices().size()*3];\r
+               for (int i = 0; i < mesh.getVertices().size(); i++) {\r
+                       Vector3d v = mesh.getVertices().get(i);\r
+                       points[i * 3] = (float)v.x;\r
+                       points[i * 3+1] = (float)v.y;\r
+                       points[i * 3+2] = (float)v.z;\r
+               }\r
+               shape.setBuffer(Type.Position, 3, points);\r
+               \r
+               if (mesh.getNormals() == null)\r
+                       mesh.createNormals();\r
+               float normals[] = new float[mesh.getNormals().size()*3];\r
+               for (int i = 0; i < mesh.getNormals().size(); i++) {\r
+                       Vector3d v = mesh.getNormals().get(i);\r
+                       normals[i * 3] = (float)v.x;\r
+                       normals[i * 3+1] = (float)v.y;\r
+                       normals[i * 3+2] = (float)v.z;\r
+               }\r
+               shape.setBuffer(Type.Normal, 3, normals);\r
+               \r
+               int index[] = new int[mesh.getIndices().size()];\r
+               for (int i = 0; i < index.length; i++) {\r
+                       index[i] = mesh.getIndices().get(i);\r
+               }\r
+               shape.setBuffer(Type.Index, 3, index);\r
+               \r
+               if (mesh.getColors() != null) {\r
+                       float colors[] = new float[mesh.getColors().size()*4];\r
+                       for (int i = 0; i < mesh.getColors().size(); i++) {\r
+                               Color4d v = mesh.getColors().get(i);\r
+                               colors[i * 4] = (float)v.x;\r
+                               colors[i * 4+1] = (float)v.y;\r
+                               colors[i * 4+2] = (float)v.z;\r
+                               colors[i * 4+3] = (float)v.w;\r
+                       }\r
+                       shape.setBuffer(Type.Color, 4, colors);\r
+               }\r
+               \r
+               setMesh(shape);\r
+               updateModelBound();\r
+               \r
+               //Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");\r
+               Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");\r
+               \r
+               \r
+               if (true) {\r
+                       ColorRGBA color = new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);\r
+                       mat.setColor("Diffuse", color);\r
+                       mat.setColor("Ambient", color);\r
+                       mat.setColor("Specular", new ColorRGBA(1, 1, 1, 1));\r
+                       mat.setBoolean("UseMaterialColors", true);\r
+               }\r
+               if (mesh.getColors() != null)\r
+                       mat.setBoolean("UseVertexColor", true);\r
+               setMaterial(mat);\r
+           \r
+       }\r
+\r
+}\r
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/TubeActor.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/shape/TubeActor.java
new file mode 100644 (file)
index 0000000..fbdef41
--- /dev/null
@@ -0,0 +1,205 @@
+package org.simantics.g3d.jme.shape;\r
+\r
+import java.util.List;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+\r
+import com.jme3.app.Application;\r
+import com.jme3.material.Material;\r
+import com.jme3.math.ColorRGBA;\r
+import com.jme3.scene.Geometry;\r
+import com.jme3.scene.Mesh;\r
+import com.jme3.scene.VertexBuffer.Type;\r
+\r
+public class TubeActor extends Geometry {\r
+       \r
+       List<Vector3d> vertices;\r
+       List<ColorRGBA> colors;\r
+       List<Double> radiis;\r
+       Double radius = 1.0;\r
+       int resolution = 8;\r
+       \r
+       public TubeActor() {\r
+               super();\r
+       }\r
+       \r
+       public void setResolution(int resolution) {\r
+               if (resolution > 2)\r
+                       this.resolution = resolution;\r
+       }\r
+       \r
+       public void setVertices(List<Vector3d> vertices) {\r
+               this.vertices = vertices;\r
+       }\r
+\r
+       public void setColors(List<ColorRGBA> colors) {\r
+               this.colors = colors;\r
+       }\r
+       \r
+       public void setRadiis(List<Double> radiis) {\r
+               this.radiis = radiis;\r
+       }\r
+       \r
+       public void setRadius(Double radius) {\r
+               this.radius = radius;\r
+       }\r
+       \r
+       \r
+       \r
+       public void createTube(Application app) {\r
+               if (vertices.size() < 2 )\r
+                       throw new IllegalArgumentException("Tube must have at least two vertices");\r
+               \r
+               Vector3d t = new Vector3d();\r
+               \r
+               for (int i = 0; i < vertices.size() - 1; i++) {\r
+                       t.set(vertices.get(i+1));\r
+                       t.sub(vertices.get(i));\r
+                       if (t.lengthSquared() < 0.0001)\r
+                               throw new IllegalArgumentException("vertices at index " + i + " are too close to each other");\r
+               }\r
+               \r
+               float points[] = new float[vertices.size()*resolution*3];\r
+               float normals[] = new float[vertices.size()*resolution*3];\r
+               float clrs[] = null;\r
+               if (this.colors != null)\r
+                       clrs = new float[vertices.size()*resolution*4];\r
+               \r
+               for (int i = 0; i < vertices.size(); i++) {\r
+                       createCircle(i,points,normals, clrs);\r
+               }\r
+               \r
+               int index[] = new int[(vertices.size()-1)*resolution*6];\r
+               \r
+               createIndices(index);\r
+               \r
+               Mesh mesh = new Mesh();\r
+               mesh.setBuffer(Type.Index, 3, index);\r
+               mesh.setBuffer(Type.Position, 3, points);\r
+               mesh.setBuffer(Type.Normal, 3, normals);\r
+               if (clrs != null)\r
+                       mesh.setBuffer(Type.Color, 4, clrs);\r
+               setMesh(mesh);\r
+               updateModelBound();\r
+               \r
+               ColorRGBA color = new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f);\r
+               Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");\r
+               mat.setColor("Diffuse", color);\r
+               mat.setColor("Ambient", color);\r
+               mat.setColor("Specular", new ColorRGBA(1, 1, 1, 1));\r
+               mat.setBoolean("UseMaterialColors", true);\r
+               if (clrs != null)\r
+                       mat.setBoolean("UseVertexColor", true);\r
+               setMaterial(mat);\r
+               \r
+               vertices.clear();\r
+               if (colors != null)\r
+                       colors.clear();\r
+               if (radiis != null)\r
+                       radiis.clear();\r
+               \r
+       }\r
+       \r
+       private void createCircle(int i, float points[],float normals[], float clrs[]) {\r
+               final Vector3d up = new Vector3d(0,1,0);\r
+               final Vector3d up2 = new Vector3d(0,0,1);\r
+               ColorRGBA c = null;\r
+               if (clrs != null)\r
+                       c = this.colors.get(i);\r
+               Vector3d p = vertices.get(i);\r
+               Vector3d t = getTangent(i);\r
+               Vector3d n = new Vector3d();\r
+               if (up.dot(t) < 0.99) {\r
+                       n.cross(up, t);\r
+               } else {\r
+                       n.cross(up2, t);\r
+               }\r
+               n.normalize();\r
+               if (radiis != null) {\r
+                       n.scale(radiis.get(i));\r
+               } else {\r
+                       n.scale(radius);\r
+               }\r
+               \r
+               for (int index = 0; index < resolution; index ++) {\r
+                       Vector3d v;\r
+                       if (index == 0) {\r
+                               v = new Vector3d(n);\r
+                               \r
+                       } else {\r
+                               AxisAngle4d aa = new AxisAngle4d(t, (Math.PI * 2 * (double)index)/(double)resolution);\r
+                               v = new Vector3d();\r
+                               MathTools.rotate(MathTools.getQuat(aa), n, v);\r
+                       }\r
+                       int vIndex = (i*resolution + index)*3; \r
+                       points[vIndex+0] = (float)(p.x+v.x);\r
+                       points[vIndex+1] = (float)(p.y + v.y);\r
+                       points[vIndex+2] = (float)(p.z + v.z);\r
+                       v.normalize();\r
+                       normals[vIndex+0] = (float)(v.x);\r
+                       normals[vIndex+1] = (float)(v.y);\r
+                       normals[vIndex+2] = (float)(v.z);\r
+                       if (colors != null) {\r
+                               int cIndex = (i*resolution + index)*4;\r
+                               clrs[cIndex] = c.r;\r
+                               clrs[cIndex+1] = c.g;\r
+                               clrs[cIndex+2] = c.b;\r
+                               clrs[cIndex+3] = c.a;\r
+                       }\r
+               }\r
+       }\r
+       \r
+       private Vector3d getTangent(int i) {\r
+               Vector3d p,n;\r
+               if (i == 0) {\r
+                       p = vertices.get(0);\r
+                       n = vertices.get(1);\r
+               } else if (i == vertices.size() - 1) {\r
+                       p = vertices.get(i-1);\r
+                       n = vertices.get(i);\r
+               } else {\r
+                       p = vertices.get(i-1);\r
+                       n = vertices.get(i+1);\r
+               }\r
+               n = new Vector3d(n);\r
+               n.sub(p);\r
+               n.normalize();\r
+               return n;\r
+       }\r
+       \r
+       private void createIndices(int index[]) {\r
+               for (int c = 0; c < vertices.size() - 1; c++) {\r
+                       for (int s = 0; s < resolution; s++) {\r
+                               int ii = (c * resolution + s) * 6;\r
+                               int iv = c*resolution + s;\r
+                               \r
+                               /*\r
+                            iv+1 ---- iv + resolution + 1\r
+                                     | /|\r
+                                     |/ |\r
+                                  iv ---- iv + resolution \r
+                               */\r
+                               if (s < resolution - 1) {\r
+                                       index[ii+2] = iv;\r
+                                       index[ii+1] = iv+resolution;\r
+                                       index[ii+0] = iv+resolution+1;\r
+                                       \r
+                                       index[ii+5] = iv;\r
+                                       index[ii+4] = iv+resolution+1;\r
+                                       index[ii+3] = iv+1;\r
+                               } else {\r
+                                       index[ii+2] = iv;\r
+                                       index[ii+1] = iv+resolution;\r
+                                       index[ii+0] = iv+1;\r
+                                       \r
+                                       index[ii+5] = iv;\r
+                                       index[ii+4] = iv+1;\r
+                                       index[ii+3] = iv+1-resolution;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+}\r
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/system/SWTApplication.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/system/SWTApplication.java
new file mode 100644 (file)
index 0000000..d7a61a8
--- /dev/null
@@ -0,0 +1,44 @@
+package org.simantics.g3d.jme.system;\r
+\r
+import java.util.logging.Level;\r
+\r
+import com.jme3.app.Application;\r
+import com.jme3.system.AppSettings;\r
+import com.jme3.system.JmeContext;\r
+import com.jme3.system.JmeSystem;\r
+\r
+\r
+public class SWTApplication extends Application {\r
+       \r
+       SWTCanvas canvas;\r
+       \r
+       public SWTApplication(SWTCanvas canvas) {\r
+               this.canvas = canvas;\r
+       }\r
+       \r
+        public void createCanvas(){\r
+\r
+               if (settings == null){\r
+                   settings = new AppSettings(true);\r
+               }\r
+\r
+               context.setSystemListener(this);\r
+           }\r
+\r
+\r
+        public void start(JmeContext.Type contextType){\r
+               if (context != null && context.isCreated()){\r
+                   //logger.warning("start() called when application already created!");\r
+                   return;\r
+               }\r
+\r
+               if (settings == null){\r
+                   settings = new AppSettings(true);\r
+               }\r
+\r
+               //logger.log(Level.FINE, "Starting application: {0}", getClass().getName());\r
+               context = canvas;//JmeSystem.newContext(settings, contextType);\r
+               context.setSystemListener(this);\r
+               context.create(false);\r
+           }\r
+}\r
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/system/SWTCanvas.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/system/SWTCanvas.java
new file mode 100644 (file)
index 0000000..637d53e
--- /dev/null
@@ -0,0 +1,1099 @@
+package org.simantics.g3d.jme.system;\r
+\r
+\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+import java.util.logging.Level;\r
+import java.util.logging.Logger;\r
+\r
+import org.eclipse.swt.SWT;\r
+import org.eclipse.swt.events.KeyEvent;\r
+import org.eclipse.swt.events.KeyListener;\r
+import org.eclipse.swt.events.MouseEvent;\r
+import org.eclipse.swt.events.MouseListener;\r
+import org.eclipse.swt.events.MouseMoveListener;\r
+import org.eclipse.swt.events.MouseTrackListener;\r
+import org.eclipse.swt.events.MouseWheelListener;\r
+import org.eclipse.swt.events.PaintEvent;\r
+import org.eclipse.swt.events.PaintListener;\r
+import org.eclipse.swt.graphics.Point;\r
+import org.eclipse.swt.layout.FillLayout;\r
+import org.eclipse.swt.opengl.GLCanvas;\r
+import org.eclipse.swt.opengl.GLData;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.lwjgl.LWJGLException;\r
+import org.lwjgl.Sys;\r
+import org.lwjgl.input.Keyboard;\r
+import org.lwjgl.input.Mouse;\r
+import org.lwjgl.opengl.GLContext;\r
+import org.lwjgl.opengl.Pbuffer;\r
+import org.lwjgl.opengl.PixelFormat;\r
+\r
+import com.jme3.cursors.plugins.JmeCursor;\r
+import com.jme3.input.JoyInput;\r
+import com.jme3.input.KeyInput;\r
+import com.jme3.input.MouseInput;\r
+import com.jme3.input.RawInputListener;\r
+import com.jme3.input.event.InputEvent;\r
+import com.jme3.input.event.KeyInputEvent;\r
+import com.jme3.input.event.MouseButtonEvent;\r
+import com.jme3.input.event.MouseMotionEvent;\r
+import com.jme3.system.AppSettings;\r
+import com.jme3.system.JmeSystem;\r
+import com.jme3.system.Platform;\r
+import com.jme3.system.lwjgl.LwjglAbstractDisplay;\r
+import com.jme3.system.lwjgl.LwjglDisplay;\r
+import com.jme3.system.lwjgl.LwjglTimer;\r
+\r
+/**\r
+ * SWT OpenGL canvas for jME\r
+ * \r
+ * Note: this class is experimental, and contains questionable code.\r
+ * \r
+ * \r
+ * @author Marko Luukkainen <marko.luukkainen@vtt.fi>\r
+ *\r
+ */\r
+public class SWTCanvas extends LwjglAbstractDisplay {\r
+\r
+       protected static final boolean USE_SHARED_CONTEXT = false;\r
+\r
+       \r
+       private static final Logger logger = Logger.getLogger(LwjglDisplay.class.getName());\r
+       \r
+       GLCanvas canvas;\r
+       \r
+       private int width;\r
+    private int height;\r
+    \r
+    private boolean runningFirstTime = true;\r
+    private boolean mouseWasGrabbed = false;\r
+    \r
+    private boolean mouseWasCreated = false;\r
+    private boolean keyboardWasCreated = false;\r
+\r
+    private Pbuffer pbuffer;\r
+    private PixelFormat pbufferFormat;\r
+    private PixelFormat canvasFormat;\r
+    \r
+    private boolean disposed = false;\r
+    \r
+       public SWTCanvas(Composite parent) {\r
+               parent.setLayout(new FillLayout());\r
+               \r
+               GLData data = new GLData();\r
+               data.doubleBuffer = true;\r
+               data.blueSize = 8;\r
+               data.redSize = 8;\r
+               data.greenSize = 8;\r
+               data.depthSize = 32;\r
+               data.alphaSize = 8;\r
+               data.stencilSize = 8;\r
+               data.stereo = false;\r
+               data.accumAlphaSize = 0;\r
+               data.accumBlueSize = 0;\r
+               data.accumGreenSize = 0;\r
+               data.accumRedSize = 0;\r
+               canvas = new GLCanvas(parent, SWT.EMBEDDED|SWT.NO_REDRAW_RESIZE, data);\r
+               //canvas = new GLCanvas(parent, SWT.NONE, data);\r
+               \r
+               \r
+       }\r
+       \r
+       public void dispose() {\r
+               if (disposed)\r
+                       return;\r
+               \r
+               setCurrent();\r
+               deinitInThread();\r
+//             pauseCanvas();\r
+               canvas.dispose();\r
+               disposed = true;\r
+       }\r
+       \r
+       public boolean isDisposed() {\r
+               return disposed;\r
+       }\r
+       \r
+       @Override\r
+       public Type getType() {\r
+               return Type.Canvas; // TODO : is Canvas Correct?\r
+       }\r
+       \r
+       @Override\r
+       public void setTitle(String title) {\r
+               // do nothing\r
+       }\r
+       \r
+       @Override\r
+       public void restart() {\r
+                frameRate = settings.getFrameRate();\r
+       }\r
+       \r
+\r
+       private boolean c = false;\r
+       \r
+       public void create(boolean waitFor){\r
+               if (c)\r
+                       return;\r
+               c = true;\r
+               \r
+               setCurrent();\r
+               initInThread();\r
+               renderable.set(true);\r
+               //restoreCanvas();\r
+               \r
+//             canvas.addPaintListener(new PaintListener() {\r
+//                     \r
+//                     @Override\r
+//                     public void paintControl(PaintEvent arg0) {\r
+//                             repaint();\r
+//                     }\r
+//             });\r
+               \r
+               org.eclipse.swt.widgets.Display.getCurrent().asyncExec(new Runnable() {\r
+                       \r
+                       @Override\r
+                       public void run() {\r
+                               if (canvas.isDisposed())\r
+                                       return;\r
+                               repaint();\r
+                               org.eclipse.swt.widgets.Display.getCurrent().asyncExec(this);\r
+                               \r
+                       }\r
+               });\r
+\r
+       }\r
+       \r
+       @Override\r
+       protected void runLoop() {\r
+\r
+               if (renderable.get()){\r
+                       Point size = canvas.getSize();\r
+                       //System.out.println("Render " + size);\r
+            int newWidth = Math.max(size.x, 1);\r
+            int newHeight = Math.max(size.y, 1);\r
+            if (width != newWidth || height != newHeight){\r
+               System.out.println("Render resize " + size);\r
+                width = newWidth;\r
+                height = newHeight;\r
+                if (listener != null){\r
+                    listener.reshape(width, height);\r
+                }\r
+            }\r
+        }\r
+                if (!created.get())\r
+                   throw new IllegalStateException();\r
+                listener.update();\r
+                if (renderable.get()){\r
+                        assert checkGLError();\r
+                        \r
+                        // calls swap buffers, etc.\r
+                   try {\r
+                       canvas.swapBuffers();\r
+//                     Display.processMessages();\r
+//                     if (autoFlush){\r
+//                         Display.update(false);\r
+//                     }else{\r
+//                         Display.processMessages();\r
+//                         Thread.sleep(50);\r
+//                         // add a small wait\r
+//                         // to reduce CPU usage\r
+//                     }\r
+                   } catch (Throwable ex){\r
+                       listener.handleError("Error while swapping buffers", ex);\r
+                   }\r
+                }\r
+//              if (frameRate > 0)\r
+//                 Display.sync(frameRate);\r
+\r
+//             if (renderable.get()){\r
+//                 if (autoFlush){\r
+//                     // check input after we synchronize with framerate.\r
+//                     // this reduces input lag.\r
+//                     Display.processMessages();\r
+//                 }\r
+//             }\r
+       }\r
+       \r
+       public void repaint() {\r
+               setCurrent();\r
+//             if (renderable.get()){\r
+//            if (Display.isCloseRequested())\r
+//                listener.requestClose(false);\r
+                       \r
+//            if (wasActive != Display.isActive()) {\r
+//                if (!wasActive) {\r
+//                    listener.gainFocus();\r
+//                    timer.reset();\r
+//                    wasActive = true;\r
+//                } else {\r
+//                    listener.loseFocus();\r
+//                    wasActive = false;\r
+//                }\r
+//            }\r
+//        }\r
+\r
+        runLoop();\r
+       }\r
+       \r
+       @Override\r
+       public void run() {\r
+               // do nothing\r
+               //super.run();\r
+       }\r
+       \r
+       @Override\r
+       protected void destroyContext() {\r
+                try {\r
+                   // invalidate the state so renderer can resume operation\r
+                   if (!USE_SHARED_CONTEXT){\r
+                       renderer.cleanup();\r
+                   }\r
+                   \r
+                   //if (Display.isCreated()){\r
+                   if (!canvas.isDisposed()) {\r
+                       /* FIXES:\r
+                        * org.lwjgl.LWJGLException: X Error\r
+                        * BadWindow (invalid Window parameter) request_code: 2 minor_code: 0\r
+                        * \r
+                        * Destroying keyboard early prevents the error above, triggered\r
+                        * by destroying keyboard in by Display.destroy() or Display.setParent(null).\r
+                        * Therefore Keyboard.destroy() should precede any of these calls.\r
+                        */\r
+                       if (Keyboard.isCreated()){\r
+                           // Should only happen if called in \r
+                           // LwjglAbstractDisplay.deinitInThread().\r
+                           Keyboard.destroy();\r
+                       }\r
+\r
+                       //try {\r
+                           // NOTE: On Windows XP, not calling setParent(null)\r
+                           // freezes the application.\r
+                           // On Mac it freezes the application.\r
+                           // On Linux it fixes a crash with X Window System.\r
+                           if (JmeSystem.getPlatform() == Platform.Windows32\r
+                            || JmeSystem.getPlatform() == Platform.Windows64){\r
+                               //Display.setParent(null);\r
+                           }\r
+                       //} catch (LWJGLException ex) {\r
+                       //    logger.log(Level.SEVERE, "Encountered exception when setting parent to null", ex);\r
+                       //}\r
+\r
+//                     Display.destroy();\r
+                   }\r
+                   \r
+                   // The canvas is no longer visible,\r
+                   // but the context thread is still running.\r
+                   if (!needClose.get()){\r
+                       // MUST make sure there's still a context current here ..\r
+                       // Display is dead, make pbuffer available to the system\r
+                       makePbufferAvailable();\r
+                       \r
+                       renderer.invalidateState();\r
+                   }else{\r
+                       // The context thread is no longer running.\r
+                       // Destroy pbuffer.\r
+                       destroyPbuffer();\r
+                   }\r
+               } catch (LWJGLException ex) {\r
+                   listener.handleError("Failed make pbuffer available", ex);\r
+               }\r
+               \r
+       }\r
+       \r
+\r
+       \r
+       public void setFocus() {\r
+               canvas.setFocus();              \r
+       }\r
+       \r
+       public void setCurrent(GLCanvas canvas) {\r
+               // delegate to the GLContext\r
+               canvas.setCurrent();\r
+               try {\r
+                       GLContext.useContext(canvas);\r
+               } catch (LWJGLException e) {\r
+                       e.printStackTrace();\r
+               }\r
+       }\r
+    \r
+    public void setCurrent() {\r
+       setCurrent(canvas);\r
+    }\r
+    \r
+    \r
+    \r
+    private void pauseCanvas(){\r
+        if (Mouse.isCreated()){\r
+            if (Mouse.isGrabbed()){\r
+                Mouse.setGrabbed(false);\r
+                mouseWasGrabbed = true;\r
+            }\r
+            mouseWasCreated = true;\r
+            Mouse.destroy();\r
+        }\r
+        if (Keyboard.isCreated()){\r
+            keyboardWasCreated = true;\r
+            Keyboard.destroy();\r
+        }\r
+\r
+        renderable.set(false);\r
+        destroyContext();\r
+    }\r
+\r
+    /**\r
+     * Called to restore the canvas.\r
+     */\r
+    private void restoreCanvas(){\r
+       setCurrent();\r
+       logger.log(Level.INFO, "OGL: Waiting for canvas to become displayable..");\r
+        while (!canvas.getVisible()){\r
+            try {\r
+                Thread.sleep(10);\r
+            } catch (InterruptedException ex) {\r
+                logger.log(Level.SEVERE, "OGL: Interrupted! ", ex);\r
+            }\r
+        }\r
+        \r
+        logger.log(Level.INFO, "OGL: Creating display context ..");\r
+\r
+        // Set renderable to true, since canvas is now displayable.\r
+        renderable.set(true);\r
+        createContext(settings);\r
+\r
+        logger.log(Level.INFO, "OGL: Display is active!");\r
+\r
+        try {\r
+            if (mouseWasCreated){\r
+                Mouse.create();\r
+                if (mouseWasGrabbed){\r
+                    Mouse.setGrabbed(true);\r
+                    mouseWasGrabbed = false;\r
+                }\r
+            }\r
+            if (keyboardWasCreated){\r
+                Keyboard.create();\r
+                keyboardWasCreated = false;\r
+            }\r
+        } catch (LWJGLException ex){\r
+            logger.log(Level.SEVERE, "Encountered exception when restoring input", ex);\r
+        }\r
+\r
+        \r
+    }\r
+    /**\r
+     * It seems it is best to use one pixel format for all shared contexts.\r
+     * @see <a href="http://developer.apple.com/library/mac/#qa/qa1248/_index.html">http://developer.apple.com/library/mac/#qa/qa1248/_index.html</a>\r
+     */\r
+    protected PixelFormat acquirePixelFormat(boolean forPbuffer){\r
+        if (forPbuffer){\r
+            // Use 0 samples for pbuffer format, prevents\r
+            // crashes on bad drivers\r
+            if (pbufferFormat == null){\r
+                pbufferFormat = new PixelFormat(settings.getBitsPerPixel(),\r
+                                                0,\r
+                                                settings.getDepthBits(),\r
+                                                settings.getStencilBits(),\r
+                                                0);\r
+            }\r
+            return pbufferFormat;\r
+        }else{\r
+            if (canvasFormat == null){\r
+                int samples = getNumSamplesToUse();\r
+                canvasFormat = new PixelFormat(settings.getBitsPerPixel(),\r
+                                               0,\r
+                                               settings.getDepthBits(),\r
+                                               settings.getStencilBits(),\r
+                                               samples);\r
+            }\r
+            return canvasFormat;\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * Makes sure the pbuffer is available and ready for use\r
+     */\r
+    protected void makePbufferAvailable() throws LWJGLException{\r
+        if (pbuffer != null && pbuffer.isBufferLost()){\r
+            logger.log(Level.WARNING, "PBuffer was lost!");\r
+            pbuffer.destroy();\r
+            pbuffer = null;\r
+        }\r
+        \r
+        if (pbuffer == null) {\r
+            pbuffer = new Pbuffer(1, 1, acquirePixelFormat(true), null);\r
+            pbuffer.makeCurrent();\r
+            logger.log(Level.INFO, "OGL: Pbuffer has been created");\r
+            \r
+            // Any created objects are no longer valid\r
+            if (!runningFirstTime){\r
+                renderer.resetGLObjects();\r
+            }\r
+        }\r
+        \r
+        pbuffer.makeCurrent();\r
+        if (!pbuffer.isCurrent()){\r
+            throw new LWJGLException("Pbuffer cannot be made current");\r
+        }\r
+    }\r
+    \r
+    protected void destroyPbuffer(){\r
+        if (pbuffer != null){\r
+            if (!pbuffer.isBufferLost()){\r
+                pbuffer.destroy();\r
+            }\r
+            pbuffer = null;\r
+        }\r
+    }\r
+    \r
+    @Override\r
+    protected void createContext(AppSettings settings) {\r
+       setCurrent();\r
+       \r
+        // In case canvas is not visible, we still take framerate\r
+        // from settings to prevent "100% CPU usage"\r
+        frameRate = settings.getFrameRate();\r
+        \r
+        try {\r
+            if (renderable.get()){\r
+                if (!runningFirstTime){\r
+                    // because the display is a different opengl context\r
+                    // must reset the context state.\r
+                    if (!USE_SHARED_CONTEXT){\r
+                        renderer.cleanup();\r
+                    }\r
+                }\r
+                \r
+                // if the pbuffer is currently active, \r
+                // make sure to deactivate it\r
+                destroyPbuffer();\r
+                \r
+                if (Keyboard.isCreated()){\r
+                    Keyboard.destroy();\r
+                }\r
+                \r
+                try {\r
+                    Thread.sleep(1000);\r
+                } catch (InterruptedException ex) {\r
+                }\r
+                \r
+//                Display.setVSyncEnabled(settings.isVSync());\r
+                //Display.setParent(canvas);\r
+                \r
+//                if (USE_SHARED_CONTEXT){\r
+//                    Display.create(acquirePixelFormat(false), pbuffer);\r
+//                }else{\r
+//                    Display.create(acquirePixelFormat(false));\r
+//                }\r
+                \r
+                renderer.invalidateState();\r
+            }else{\r
+                // First create the pbuffer, if it is needed.\r
+                makePbufferAvailable();\r
+            }\r
+\r
+            // At this point, the OpenGL context is active.\r
+            if (runningFirstTime){\r
+                // THIS is the part that creates the renderer.\r
+                // It must always be called, now that we have the pbuffer workaround.\r
+                initContextFirstTime();\r
+                runningFirstTime = false;\r
+            }\r
+        } catch (LWJGLException ex) {\r
+            listener.handleError("Failed to initialize OpenGL context", ex);\r
+            // TODO: Fix deadlock that happens after the error (throw runtime exception?)\r
+        }\r
+    }\r
+\r
+    \r
+    public JoyInput getJoyInput() {\r
+       return null;\r
+    }\r
+\r
+    \r
+    SWTMouseInput mouseInput;\r
+    \r
+    public MouseInput getMouseInput() {\r
+        if (mouseInput == null){\r
+            mouseInput = new SWTMouseInput(this);\r
+        }\r
+        return mouseInput;\r
+    }\r
+\r
+    \r
+    SWTKeyInput keyInput;\r
+    \r
+    public KeyInput getKeyInput() {\r
+        if (keyInput == null){\r
+            keyInput = new SWTKeyInput(this);\r
+        }\r
+        return keyInput;\r
+    }\r
+    \r
+\r
+    \r
+    public class SWTMouseInput implements MouseInput, MouseListener, MouseMoveListener, MouseWheelListener, MouseTrackListener {\r
+       SWTCanvas canvas;\r
+       boolean init = false;\r
+       RawInputListener listener;\r
+       \r
+       public SWTMouseInput(SWTCanvas canvas) {\r
+               this.canvas = canvas;\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void destroy() {\r
+               this.canvas.canvas.removeMouseListener(this);\r
+               this.canvas.canvas.removeMouseMoveListener(this);\r
+               this.canvas.canvas.removeMouseWheelListener(this);\r
+               this.canvas.canvas.removeMouseTrackListener(this);\r
+       }\r
+       \r
+       @Override\r
+       public void initialize() {\r
+               this.canvas.canvas.addMouseListener(this);\r
+               this.canvas.canvas.addMouseMoveListener(this);\r
+               this.canvas.canvas.addMouseWheelListener(this);\r
+               this.canvas.canvas.addMouseTrackListener(this);\r
+               init = true;\r
+       }\r
+       \r
+       @Override\r
+       public int getButtonCount() {\r
+               return 3;\r
+       }\r
+       \r
+       @Override\r
+       public boolean isInitialized() {\r
+               return init;\r
+       }\r
+       \r
+       @Override\r
+       public void setInputListener(RawInputListener listener) {\r
+               this.listener = listener;\r
+\r
+       }\r
+       \r
+       public long getInputTimeNanos() {\r
+            return Sys.getTime() * LwjglTimer.LWJGL_TIME_TO_NANOS;\r
+        }\r
+       \r
+       @Override\r
+       public void setCursorVisible(boolean visible) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void setNativeCursor(JmeCursor cursor) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void update() {\r
+               if (listener == null || events.size() == 0)\r
+                       return;\r
+               listener.beginInput();\r
+               for (InputEvent e : events) {\r
+                       if (e instanceof MouseButtonEvent)\r
+                               listener.onMouseButtonEvent((MouseButtonEvent)e);\r
+                       else\r
+                               listener.onMouseMotionEvent((MouseMotionEvent)e);\r
+               }\r
+               events.clear();\r
+               listener.endInput();\r
+       }\r
+       \r
+       private List<InputEvent> events = new ArrayList<InputEvent>();\r
+       \r
+       @Override\r
+       public void mouseDoubleClick(MouseEvent e) {\r
+               //events.add(new MouseButtonEvent(e.button,true, e.x, e.y));\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mouseDown(MouseEvent e) {\r
+               events.add(new MouseButtonEvent(e.button,true, e.x, e.y));\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mouseUp(MouseEvent e) {\r
+               events.add(new MouseButtonEvent(e.button,false, e.x, e.y));\r
+               \r
+       }\r
+       \r
+       int px = 0;\r
+       int py = 0;\r
+       \r
+       @Override\r
+       public void mouseMove(MouseEvent e) {\r
+               events.add(new MouseMotionEvent(e.x, e.y, e.x - px, e.y - py, 0, 0));\r
+               px = e.x;\r
+               py = e.y;\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mouseScrolled(MouseEvent e) {\r
+               events.add(new MouseMotionEvent(e.x, e.y, 0, 0, e.button, e.count));\r
+       }\r
+       \r
+       @Override\r
+       public void mouseEnter(MouseEvent e) {\r
+               px = e.x;\r
+               py = e.y;\r
+       }\r
+       \r
+       @Override\r
+       public void mouseExit(MouseEvent e) {\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void mouseHover(MouseEvent e) {\r
+               \r
+       }\r
+    }\r
+    \r
+    public class SWTKeyInput implements KeyInput, KeyListener {\r
+       SWTCanvas canvas;\r
+       boolean init = false;\r
+       RawInputListener listener;\r
+       \r
+       public SWTKeyInput(SWTCanvas canvas) {\r
+               this.canvas = canvas;\r
+       }\r
+       \r
+       @Override\r
+       public void destroy() {\r
+               this.canvas.canvas.removeKeyListener(this);\r
+       }\r
+       \r
+       @Override\r
+       public void initialize() {\r
+               this.canvas.canvas.addKeyListener(this);\r
+               init = true;\r
+       }\r
+       \r
+       @Override\r
+       public boolean isInitialized() {\r
+               return init;\r
+       }\r
+       \r
+       @Override\r
+       public void setInputListener(RawInputListener listener) {\r
+               this.listener = listener;\r
+       }\r
+       \r
+       public long getInputTimeNanos() {\r
+            return Sys.getTime() * LwjglTimer.LWJGL_TIME_TO_NANOS;\r
+        }\r
+       \r
+       private List<KeyInputEvent> events = new ArrayList<KeyInputEvent>();\r
+       \r
+       KeyInputEvent prevEvent = new KeyInputEvent(0, (char)0, false, false);\r
+       \r
+       @Override\r
+       public void update() {\r
+               if (listener == null || events.size() == 0)\r
+                       return;\r
+               listener.beginInput();\r
+               \r
+               for (KeyInputEvent e : events) {\r
+                       //System.out.println("Key " + e.getKeyCode() + " " + e.getKeyChar() + " " + e.isPressed() + " " + e.isRepeating());\r
+                       \r
+                       // SWT reports wrong key code in released event for a key, if multiple keys are down at the same time\r
+                       // example:\r
+                       // press 'a'   -> event press a\r
+                       // press 'b'   -> event press b\r
+                       // release 'a' -> event release b\r
+                       // keep 'b' pressed -> event press b (with slight pause before events starts coming by)\r
+                       // release 'b' -> event release b\r
+                       \r
+                       // press 'a'   -> event press a\r
+                       // press 'b'   -> event press b\r
+                       // release 'b' -> event release b\r
+                       // keep 'a' pressed -> nothing happens.\r
+                       // release 'a' -> nothing happens\r
+                       \r
+                       if (e.isPressed()) {\r
+                               if (e.getKeyCode() != prevEvent.getKeyCode() && prevEvent.isPressed()) {\r
+                                       listener.onKeyEvent(new KeyInputEvent(prevEvent.getKeyCode(), prevEvent.getKeyChar(), false, false));\r
+                               }\r
+                       }\r
+                       \r
+                       listener.onKeyEvent(e);\r
+                       prevEvent = e;\r
+               }\r
+               events.clear();\r
+               listener.endInput();\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void keyPressed(KeyEvent e) {\r
+               events.add(new KeyInputEvent(getLWJGLKeyCode(e.keyCode), e.character, true, false));\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void keyReleased(KeyEvent e) {\r
+               \r
+               events.add(new KeyInputEvent(getLWJGLKeyCode(e.keyCode), e.character, false, false));\r
+       }\r
+       \r
+       private int getLWJGLKeyCode(int swtKeyCode) {\r
+               // TODO : LWJGL uses mapping/layout of US keyboard, these have to be checked   \r
+               if(swtKeyCode > 1024) {\r
+                   int keyCode = 0;\r
+                   switch (swtKeyCode) {\r
+                   case SWT.CTRL:\r
+                       keyCode = Keyboard.KEY_LCONTROL;\r
+                       break;\r
+                   case SWT.ALT:\r
+                       keyCode = Keyboard.KEY_LMETA;\r
+                       break;\r
+                   \r
+                   case SWT.SHIFT:\r
+                       keyCode = Keyboard.KEY_LSHIFT;\r
+                       break;\r
+                   case SWT.ARROW_LEFT:\r
+                       keyCode = Keyboard.KEY_LEFT;\r
+                       break;\r
+                   case SWT.ARROW_RIGHT:\r
+                       keyCode = Keyboard.KEY_RIGHT;\r
+                       break;\r
+                   case SWT.ARROW_UP:\r
+                       keyCode = Keyboard.KEY_UP;\r
+                       break;\r
+                   case SWT.ARROW_DOWN:\r
+                       keyCode = Keyboard.KEY_DOWN;\r
+                       break;\r
+                   case SWT.KEYPAD_0:\r
+                       keyCode = Keyboard.KEY_NUMPAD0;\r
+                       break;\r
+                   case SWT.KEYPAD_1:\r
+                       keyCode = Keyboard.KEY_NUMPAD1;\r
+                       break;\r
+                   case SWT.KEYPAD_2:\r
+                       keyCode = Keyboard.KEY_NUMPAD2;\r
+                       break;\r
+                   case SWT.KEYPAD_3:\r
+                       keyCode = Keyboard.KEY_NUMPAD3;\r
+                       break;\r
+                   case SWT.KEYPAD_4:\r
+                       keyCode = Keyboard.KEY_NUMPAD4;\r
+                       break;\r
+                   case SWT.KEYPAD_5:\r
+                       keyCode = Keyboard.KEY_NUMPAD5;\r
+                       break;\r
+                   case SWT.KEYPAD_6:\r
+                       keyCode = Keyboard.KEY_NUMPAD6;\r
+                       break;\r
+                   case SWT.KEYPAD_7:\r
+                       keyCode = Keyboard.KEY_NUMPAD7;\r
+                       break;\r
+                   case SWT.KEYPAD_8:\r
+                       keyCode = Keyboard.KEY_NUMPAD8;\r
+                       break;\r
+                   case SWT.KEYPAD_9:\r
+                       keyCode = Keyboard.KEY_NUMPAD9;\r
+                       break;\r
+                   case SWT.KEYPAD_CR:\r
+                       keyCode = Keyboard.KEY_NUMPADENTER;\r
+                       break;\r
+                   case SWT.NUM_LOCK:\r
+                       keyCode = Keyboard.KEY_NUMLOCK;\r
+                       break;\r
+                   case SWT.SCROLL_LOCK:\r
+                       keyCode = Keyboard.KEY_SCROLL;\r
+                       break;\r
+                   case SWT.CAPS_LOCK:\r
+                       keyCode = Keyboard.KEY_CAPITAL;\r
+                       break;\r
+                   case SWT.INSERT:\r
+                       keyCode = Keyboard.KEY_INSERT;\r
+                       break;\r
+                   case SWT.HOME:\r
+                       keyCode = Keyboard.KEY_HOME;\r
+                       break;\r
+                   case SWT.END:\r
+                       keyCode = Keyboard.KEY_END;\r
+                       break;\r
+                   case SWT.PAGE_UP:\r
+                       keyCode = Keyboard.KEY_NEXT;\r
+                       break;\r
+                   case SWT.PAGE_DOWN:\r
+                       keyCode = Keyboard.KEY_PRIOR;\r
+                       break;\r
+                   case SWT.PAUSE:\r
+                       keyCode = Keyboard.KEY_PAUSE;   \r
+                       break;\r
+                   case SWT.BREAK:\r
+                       keyCode = Keyboard.KEY_PAUSE;   \r
+                       break;\r
+                   case SWT.PRINT_SCREEN:\r
+                       keyCode = Keyboard.KEY_SYSRQ;   \r
+                       break;   \r
+                   case SWT.HELP:\r
+                       keyCode = 0;\r
+                       break;\r
+                   case SWT.KEYPAD_MULTIPLY:\r
+                       keyCode = Keyboard.KEY_MULTIPLY;\r
+                       break;\r
+                   case SWT.KEYPAD_DIVIDE:\r
+                       keyCode = Keyboard.KEY_DIVIDE;\r
+                       break;\r
+                   case SWT.KEYPAD_DECIMAL:\r
+                       keyCode = Keyboard.KEY_DECIMAL;\r
+                       break;\r
+                   case SWT.F1:\r
+                       keyCode = Keyboard.KEY_F1;\r
+                       break;\r
+                   case SWT.F2:\r
+                       keyCode = Keyboard.KEY_F2;\r
+                       break;\r
+                   case SWT.F3:\r
+                       keyCode = Keyboard.KEY_F3;\r
+                       break;\r
+                   case SWT.F4:\r
+                       keyCode = Keyboard.KEY_F4;\r
+                       break;\r
+                   case SWT.F5:\r
+                       keyCode = Keyboard.KEY_F5;\r
+                       break;\r
+                   case SWT.F6:\r
+                       keyCode = Keyboard.KEY_F6;\r
+                       break;\r
+                   case SWT.F7:\r
+                       keyCode = Keyboard.KEY_F7;\r
+                       break;\r
+                   case SWT.F8:\r
+                       keyCode = Keyboard.KEY_F8;\r
+                       break;\r
+                   case SWT.F9:\r
+                       keyCode = Keyboard.KEY_F9;\r
+                       break;\r
+                   case SWT.F10:\r
+                       keyCode = Keyboard.KEY_F10;\r
+                       break;\r
+                   case SWT.F11:\r
+                       keyCode = Keyboard.KEY_F11;\r
+                       break;\r
+                   case SWT.F12:\r
+                       keyCode = Keyboard.KEY_F12;\r
+                       break;\r
+                   default :\r
+                       keyCode = Keyboard.KEY_NONE;\r
+                       break;\r
+                   }\r
+                   \r
+                   return keyCode;\r
+               } else if (swtKeyCode == 8) {\r
+                       return Keyboard.KEY_BACK;\r
+               } else if (swtKeyCode == SWT.ESC) {\r
+                       return Keyboard.KEY_ESCAPE;\r
+               } else if (swtKeyCode == SWT.SPACE) {\r
+                       return Keyboard.KEY_SPACE;\r
+               } else if (swtKeyCode >= 49 && swtKeyCode < 58) { // 1 - 9\r
+                       return swtKeyCode - 47; \r
+               } else if (swtKeyCode == 48) {\r
+                       return Keyboard.KEY_0;\r
+               } else if (swtKeyCode == SWT.TAB) {\r
+                       return Keyboard.KEY_TAB;\r
+               } else if (swtKeyCode == 46) {\r
+                       return Keyboard.KEY_PERIOD;\r
+               } else if (swtKeyCode == 44) {\r
+                       return Keyboard.KEY_COMMA;\r
+               } else if (swtKeyCode == 39) { // '/* on SWE/FI keyboard\r
+                       return Keyboard.KEY_SLASH;\r
+               } else if (swtKeyCode == 45) {\r
+                       return Keyboard.KEY_MINUS;\r
+               } else if (swtKeyCode == 43) {\r
+                       return Keyboard.KEY_EQUALS; // +/? on SWE/FI keyboard\r
+               } else if (swtKeyCode == SWT.DEL) {\r
+                       return Keyboard.KEY_DELETE;\r
+               } else if (swtKeyCode == SWT.CR) {\r
+                       return Keyboard.KEY_RETURN;\r
+               } else if (swtKeyCode == 167) { // Â§ on SWE/FI keyboard\r
+                       return Keyboard.KEY_BACKSLASH;\r
+               }\r
+               else if (swtKeyCode >= 97 )\r
+                       swtKeyCode -= 32;\r
+               if (swtKeyCode >= 65 && swtKeyCode <= 90) {\r
+                       switch (swtKeyCode) {\r
+                               case 65:\r
+                                       return Keyboard.KEY_A;\r
+                               case 66:\r
+                                       return Keyboard.KEY_B;\r
+                               case 67:\r
+                                       return Keyboard.KEY_C;\r
+                               case 68:\r
+                                       return Keyboard.KEY_D;\r
+                               case 69:\r
+                                       return Keyboard.KEY_E;\r
+                               case 70:\r
+                                       return Keyboard.KEY_F;\r
+                               case 71:\r
+                                       return Keyboard.KEY_G;\r
+                               case 72:\r
+                                       return Keyboard.KEY_H;\r
+                               case 73:\r
+                                       return Keyboard.KEY_I;\r
+                               case 74:\r
+                                       return Keyboard.KEY_J;\r
+                               case 75:\r
+                                       return Keyboard.KEY_K;\r
+                               case 76:\r
+                                       return Keyboard.KEY_L;\r
+                               case 77:\r
+                                       return Keyboard.KEY_M;\r
+                               case 78:\r
+                                       return Keyboard.KEY_N;\r
+                               case 79:\r
+                                       return Keyboard.KEY_O;\r
+                               case 80:\r
+                                       return Keyboard.KEY_P;\r
+                               case 81:\r
+                                       return Keyboard.KEY_Q;\r
+                               case 82:\r
+                                       return Keyboard.KEY_R;\r
+                               case 83:\r
+                                       return Keyboard.KEY_S;\r
+                               case 84:\r
+                                       return Keyboard.KEY_T;\r
+                               case 85:\r
+                                       return Keyboard.KEY_U;\r
+                               case 86:\r
+                                       return Keyboard.KEY_V;\r
+                               case 87:\r
+                                       return Keyboard.KEY_W;\r
+                               case 88:\r
+                                       return Keyboard.KEY_X;\r
+                               case 89:\r
+                                       return Keyboard.KEY_Y;\r
+                               case 90:\r
+                                       return Keyboard.KEY_Z;\r
+                                       \r
+                       }\r
+               }\r
+               return Keyboard.KEY_UNLABELED;\r
+           }\r
+\r
+       \r
+        private int getAWTKeyCode(int swtKeyCode) {\r
+               if(swtKeyCode > 1024) {\r
+                   int keyCode = 0;\r
+                   switch (swtKeyCode) {\r
+                   case SWT.CTRL:\r
+                       keyCode = java.awt.event.KeyEvent.VK_CONTROL;\r
+                       break;\r
+                   case SWT.ALT:\r
+                       keyCode = java.awt.event.KeyEvent.VK_ALT;\r
+                       break;\r
+                   \r
+                   case SWT.SHIFT:\r
+                       keyCode = java.awt.event.KeyEvent.VK_SHIFT;\r
+                       break;\r
+                   case SWT.ARROW_LEFT:\r
+                       keyCode = java.awt.event.KeyEvent.VK_LEFT;\r
+                       break;\r
+                   case SWT.ARROW_RIGHT:\r
+                       keyCode = java.awt.event.KeyEvent.VK_RIGHT;\r
+                       break;\r
+                   case SWT.ARROW_UP:\r
+                       keyCode = java.awt.event.KeyEvent.VK_UP;\r
+                       break;\r
+                   case SWT.ARROW_DOWN:\r
+                       keyCode = java.awt.event.KeyEvent.VK_DOWN;\r
+                       break;\r
+                   case SWT.KEYPAD_0:\r
+                       keyCode = java.awt.event.KeyEvent.VK_NUMPAD0;\r
+                       break;\r
+                   case SWT.KEYPAD_1:\r
+                       keyCode = java.awt.event.KeyEvent.VK_NUMPAD1;\r
+                       break;\r
+                   case SWT.KEYPAD_2:\r
+                       keyCode = java.awt.event.KeyEvent.VK_NUMPAD2;\r
+                       break;\r
+                   case SWT.KEYPAD_3:\r
+                       keyCode = java.awt.event.KeyEvent.VK_NUMPAD3;\r
+                       break;\r
+                   case SWT.KEYPAD_4:\r
+                       keyCode = java.awt.event.KeyEvent.VK_NUMPAD4;\r
+                       break;\r
+                   case SWT.KEYPAD_5:\r
+                       keyCode = java.awt.event.KeyEvent.VK_NUMPAD5;\r
+                       break;\r
+                   case SWT.KEYPAD_6:\r
+                       keyCode = java.awt.event.KeyEvent.VK_NUMPAD6;\r
+                       break;\r
+                   case SWT.KEYPAD_7:\r
+                       keyCode = java.awt.event.KeyEvent.VK_NUMPAD7;\r
+                       break;\r
+                   case SWT.KEYPAD_8:\r
+                       keyCode = java.awt.event.KeyEvent.VK_NUMPAD8;\r
+                       break;\r
+                   case SWT.KEYPAD_9:\r
+                       keyCode = java.awt.event.KeyEvent.VK_NUMPAD9;\r
+                       break;\r
+                   case SWT.KEYPAD_CR:\r
+                       keyCode = java.awt.event.KeyEvent.VK_ENTER;\r
+                       break;\r
+                   case SWT.NUM_LOCK:\r
+                       keyCode = java.awt.event.KeyEvent.VK_NUM_LOCK;\r
+                       break;\r
+                   case SWT.SCROLL_LOCK:\r
+                       keyCode = java.awt.event.KeyEvent.VK_SCROLL_LOCK;\r
+                       break;\r
+                   case SWT.CAPS_LOCK:\r
+                       keyCode = java.awt.event.KeyEvent.VK_CAPS_LOCK;\r
+                       break;\r
+                   case SWT.INSERT:\r
+                       keyCode = java.awt.event.KeyEvent.VK_INSERT;\r
+                       break;\r
+                   case SWT.HOME:\r
+                       keyCode = java.awt.event.KeyEvent.VK_HOME;\r
+                       break;\r
+                   case SWT.END:\r
+                       keyCode = java.awt.event.KeyEvent.VK_END;\r
+                       break;\r
+                   case SWT.PAGE_UP:\r
+                       keyCode = java.awt.event.KeyEvent.VK_PAGE_UP;\r
+                       break;\r
+                   case SWT.PAGE_DOWN:\r
+                       keyCode = java.awt.event.KeyEvent.VK_PAGE_DOWN;\r
+                       break;\r
+                   case SWT.PAUSE:\r
+                       keyCode = java.awt.event.KeyEvent.VK_PAUSE;   \r
+                       break;\r
+                   case SWT.BREAK:\r
+                       keyCode = java.awt.event.KeyEvent.VK_PAUSE;   \r
+                       break;\r
+                   case SWT.PRINT_SCREEN:\r
+                       keyCode = java.awt.event.KeyEvent.VK_PRINTSCREEN;   \r
+                       break;   \r
+                   case SWT.HELP:\r
+                       keyCode = java.awt.event.KeyEvent.VK_HELP;\r
+                       break;\r
+                   default :\r
+                       keyCode = 0;\r
+                       break;\r
+                   }\r
+                   \r
+                   return keyCode;\r
+               } else if (swtKeyCode == 8) {\r
+                       return java.awt.event.KeyEvent.VK_BACK_SPACE;\r
+               }\r
+               else if (swtKeyCode >= 97 )\r
+                       return swtKeyCode - 32;\r
+               else\r
+                       return swtKeyCode;\r
+           }\r
+    }\r
+\r
+}\r
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/system/SimpleSWTApplication.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/system/SimpleSWTApplication.java
new file mode 100644 (file)
index 0000000..3bb991e
--- /dev/null
@@ -0,0 +1,46 @@
+package org.simantics.g3d.jme.system;\r
+\r
+import com.jme3.app.SimpleApplication;\r
+import com.jme3.system.AppSettings;\r
+import com.jme3.system.JmeContext;\r
+\r
+public abstract class SimpleSWTApplication extends SimpleApplication {\r
+\r
+       SWTCanvas canvas;\r
+       \r
+       public SimpleSWTApplication(SWTCanvas canvas) {\r
+               this.canvas = canvas;\r
+               showSettings = false;\r
+       }\r
+       \r
+       @Override\r
+       public void setShowSettings(boolean showSettings) {\r
+               \r
+       }\r
+       \r
+        public void createCanvas(){\r
+\r
+               if (settings == null){\r
+                   settings = new AppSettings(true);\r
+               }\r
+\r
+               context.setSystemListener(this);\r
+         }\r
+        \r
+        public void start(JmeContext.Type contextType){\r
+               if (context != null && context.isCreated()){\r
+                   //logger.warning("start() called when application already created!");\r
+                   return;\r
+               }\r
+\r
+               if (settings == null){\r
+                   settings = new AppSettings(true);\r
+               }\r
+\r
+               //logger.log(Level.FINE, "Starting application: {0}", getClass().getName());\r
+               context = canvas;//JmeSystem.newContext(settings, contextType);\r
+               context.setSystemListener(this);\r
+               context.create(false);\r
+           }\r
+\r
+}\r
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/test/JMETestViewPart.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/test/JMETestViewPart.java
new file mode 100644 (file)
index 0000000..7576c84
--- /dev/null
@@ -0,0 +1,403 @@
+package org.simantics.g3d.jme.test;\r
+\r
+import java.util.ArrayList;\r
+import java.util.List;\r
+\r
+import org.eclipse.swt.events.DisposeEvent;\r
+import org.eclipse.swt.events.DisposeListener;\r
+import org.eclipse.swt.widgets.Composite;\r
+import org.eclipse.ui.part.ViewPart;\r
+import org.simantics.g3d.jme.system.SWTCanvas;\r
+import org.simantics.g3d.jme.system.SimpleSWTApplication;\r
+\r
+import com.jme3.audio.AudioNode;\r
+import com.jme3.audio.LowPassFilter;\r
+import com.jme3.effect.ParticleEmitter;\r
+import com.jme3.effect.ParticleMesh;\r
+import com.jme3.input.controls.ActionListener;\r
+import com.jme3.input.controls.KeyTrigger;\r
+import com.jme3.light.DirectionalLight;\r
+import com.jme3.light.PointLight;\r
+import com.jme3.material.Material;\r
+import com.jme3.material.RenderState.BlendMode;\r
+import com.jme3.math.ColorRGBA;\r
+import com.jme3.math.FastMath;\r
+import com.jme3.math.Quaternion;\r
+import com.jme3.math.Vector3f;\r
+import com.jme3.post.FilterPostProcessor;\r
+import com.jme3.post.filters.BloomFilter;\r
+import com.jme3.post.filters.DepthOfFieldFilter;\r
+import com.jme3.post.filters.LightScatteringFilter;\r
+import com.jme3.renderer.Camera;\r
+import com.jme3.renderer.queue.RenderQueue.Bucket;\r
+import com.jme3.renderer.queue.RenderQueue.ShadowMode;\r
+import com.jme3.scene.Geometry;\r
+import com.jme3.scene.Node;\r
+import com.jme3.scene.Spatial;\r
+import com.jme3.scene.shape.Box;\r
+import com.jme3.scene.shape.Sphere;\r
+import com.jme3.terrain.geomipmap.TerrainQuad;\r
+import com.jme3.terrain.heightmap.AbstractHeightMap;\r
+import com.jme3.terrain.heightmap.ImageBasedHeightMap;\r
+import com.jme3.texture.Texture;\r
+import com.jme3.texture.Texture.WrapMode;\r
+import com.jme3.texture.Texture2D;\r
+import com.jme3.util.SkyFactory;\r
+import com.jme3.water.WaterFilter;\r
+\r
+public class JMETestViewPart extends ViewPart {\r
+       \r
+       \r
+       protected SWTCanvas canvas;\r
+       \r
+       \r
+       \r
+       @Override\r
+       public void createPartControl(Composite parent) {\r
+               \r
+               canvas = new SWTCanvas(parent);\r
+               \r
+               \r
+               parent.addDisposeListener(new DisposeListener() {\r
+                       \r
+                       @Override\r
+                       public void widgetDisposed(DisposeEvent arg0) {\r
+                               canvas.dispose();\r
+                       }\r
+               });\r
+               \r
+               TestApp app = new TestApp(canvas);\r
+               //TestPostWater app = new TestPostWater(canvas);\r
+               //app.createCanvas();\r
+               app.start();\r
+               \r
+               \r
+       }\r
+       \r
+       \r
+       \r
+       \r
+       @Override\r
+       public void setFocus() {\r
+               canvas.setFocus();\r
+               \r
+       }\r
+\r
+    public class TestApp extends SimpleSWTApplication {\r
+       \r
+       public TestApp(SWTCanvas canvas) {\r
+                       super(canvas);\r
+                       \r
+               }\r
+\r
+               float angle;\r
+       PointLight pl;\r
+       Spatial lightMdl;\r
+       \r
+        @Override\r
+           public void simpleInitApp() {\r
+               viewPort.setBackgroundColor(ColorRGBA.DarkGray);\r
+\r
+               Spatial bumpy = (Spatial) assetManager.loadModel("Models/MonkeyHead/MonkeyHead.mesh.xml");\r
+               rootNode.attachChild(bumpy);\r
+\r
+               lightMdl = new Geometry("Light", new Sphere(10, 10, 0.1f));\r
+               lightMdl.setMaterial(assetManager.loadMaterial("Common/Materials/RedColor.j3m"));\r
+               rootNode.attachChild(lightMdl);\r
+\r
+               // flourescent main light\r
+               pl = new PointLight();\r
+               pl.setColor(new ColorRGBA(0.88f, 0.92f, 0.95f, 1.0f));\r
+               rootNode.addLight(pl);\r
+\r
+               // sunset light\r
+               DirectionalLight dl = new DirectionalLight();\r
+               dl.setDirection(new Vector3f(-0.1f,-0.7f,1).normalizeLocal());\r
+               dl.setColor(new ColorRGBA(0.44f, 0.30f, 0.20f, 1.0f));\r
+               rootNode.addLight(dl);\r
+\r
+               // skylight\r
+               dl = new DirectionalLight();\r
+               dl.setDirection(new Vector3f(-0.6f,-1,-0.6f).normalizeLocal());\r
+               dl.setColor(new ColorRGBA(0.10f, 0.22f, 0.44f, 1.0f));\r
+               rootNode.addLight(dl);\r
+\r
+               // white ambient light\r
+               dl = new DirectionalLight();\r
+               dl.setDirection(new Vector3f(1, -0.5f,-0.1f).normalizeLocal());\r
+               dl.setColor(new ColorRGBA(0.50f, 0.40f, 0.50f, 1.0f));\r
+               rootNode.addLight(dl);\r
+           }\r
+\r
+           @Override\r
+           public void simpleUpdate(float tpf){\r
+               angle += tpf * 0.25f;\r
+               angle %= FastMath.TWO_PI;\r
+\r
+               pl.setPosition(new Vector3f(FastMath.cos(angle) * 6f, 3f, FastMath.sin(angle) * 6f));\r
+               lightMdl.setLocalTranslation(pl.getPosition());\r
+           }\r
+    }\r
+       \r
+       \r
+    public class TestPostWater extends SimpleSWTApplication {\r
+\r
+        public TestPostWater(SWTCanvas canvas) {\r
+                       super(canvas);\r
+               }\r
+        \r
+               private Vector3f lightDir = new Vector3f(-4.9236743f, -1.27054665f, 5.896916f);\r
+        private WaterFilter water;\r
+        TerrainQuad terrain;\r
+        Material matRock;\r
+        AudioNode waves;\r
+        LowPassFilter underWaterAudioFilter = new LowPassFilter(0.5f, 0.1f);\r
+        LowPassFilter underWaterReverbFilter = new LowPassFilter(0.5f, 0.1f);\r
+        LowPassFilter aboveWaterAudioFilter = new LowPassFilter(1, 1);\r
+\r
+\r
+\r
+        @Override\r
+        public void simpleInitApp() {\r
+\r
+          setDisplayFps(false);\r
+          setDisplayStatView(false);\r
+\r
+            Node mainScene = new Node("Main Scene");\r
+            rootNode.attachChild(mainScene);\r
+\r
+            createTerrain(mainScene);\r
+            DirectionalLight sun = new DirectionalLight();\r
+            sun.setDirection(lightDir);\r
+            sun.setColor(ColorRGBA.White.clone().multLocal(1.7f));\r
+            mainScene.addLight(sun);\r
+\r
+            DirectionalLight l = new DirectionalLight();\r
+            l.setDirection(Vector3f.UNIT_Y.mult(-1));\r
+            l.setColor(ColorRGBA.White.clone().multLocal(0.3f));\r
+//            mainScene.addLight(l);\r
+\r
+            flyCam.setMoveSpeed(50);\r
+\r
+            //cam.setLocation(new Vector3f(-700, 100, 300));\r
+             //cam.setRotation(new Quaternion().fromAngleAxis(0.5f, Vector3f.UNIT_Z));\r
+            cam.setLocation(new Vector3f(-327.21957f, 61.6459f, 126.884346f));\r
+            cam.setRotation(new Quaternion(0.052168474f, 0.9443102f, -0.18395276f, 0.2678024f));\r
+\r
+              \r
+            cam.setRotation(new Quaternion().fromAngles(new float[]{FastMath.PI * 0.06f, FastMath.PI * 0.65f, 0}));\r
+\r
+\r
+            Spatial sky = SkyFactory.createSky(assetManager, "Scenes/Beach/FullskiesSunset0068.dds", false);\r
+            sky.setLocalScale(350);\r
+          \r
+            mainScene.attachChild(sky);\r
+            cam.setFrustumFar(4000);\r
+            //cam.setFrustumNear(100);\r
+           \r
+            \r
+\r
+            //private FilterPostProcessor fpp;\r
+\r
+\r
+            water = new WaterFilter(rootNode, lightDir);\r
+\r
+            FilterPostProcessor fpp = new FilterPostProcessor(assetManager);\r
+            \r
+            fpp.addFilter(water);\r
+            BloomFilter bloom=new BloomFilter();\r
+            //bloom.getE\r
+            bloom.setExposurePower(55);\r
+            bloom.setBloomIntensity(1.0f);\r
+            fpp.addFilter(bloom);\r
+            LightScatteringFilter lsf = new LightScatteringFilter(lightDir.mult(-300));\r
+            lsf.setLightDensity(1.0f);\r
+            fpp.addFilter(lsf);\r
+            DepthOfFieldFilter dof=new DepthOfFieldFilter();\r
+            dof.setFocusDistance(0);\r
+            dof.setFocusRange(100);     \r
+            fpp.addFilter(dof);\r
+//            \r
+            \r
+         //   fpp.addFilter(new TranslucentBucketFilter());\r
+     //       \r
+            \r
+             // fpp.setNumSamples(4);\r
+\r
+\r
+            water.setWaveScale(0.003f);\r
+            water.setMaxAmplitude(2f);\r
+            water.setFoamExistence(new Vector3f(1f, 4, 0.5f));\r
+            water.setFoamTexture((Texture2D) assetManager.loadTexture("Common/MatDefs/Water/Textures/foam2.jpg"));\r
+            //water.setNormalScale(0.5f);\r
+\r
+            //water.setRefractionConstant(0.25f);\r
+            water.setRefractionStrength(0.2f);\r
+            //water.setFoamHardness(0.6f);\r
+\r
+            water.setWaterHeight(initialWaterHeight);\r
+          uw=cam.getLocation().y<waterHeight; \r
+          \r
+            waves = new AudioNode(assetManager, "Sound/Environment/Ocean Waves.ogg", false);\r
+            waves.setLooping(true);\r
+            waves.setReverbEnabled(true);\r
+            if(uw){\r
+                waves.setDryFilter(new LowPassFilter(0.5f, 0.1f));\r
+            }else{\r
+                waves.setDryFilter(aboveWaterAudioFilter);            \r
+            }\r
+            audioRenderer.playSource(waves);\r
+            //  \r
+            viewPort.addProcessor(fpp);\r
+\r
+            inputManager.addListener(new ActionListener() {\r
+\r
+                public void onAction(String name, boolean isPressed, float tpf) {\r
+                    if (isPressed) {\r
+                        if (name.equals("foam1")) {\r
+                            water.setFoamTexture((Texture2D) assetManager.loadTexture("Common/MatDefs/Water/Textures/foam.jpg"));\r
+                        }\r
+                        if (name.equals("foam2")) {\r
+                            water.setFoamTexture((Texture2D) assetManager.loadTexture("Common/MatDefs/Water/Textures/foam2.jpg"));\r
+                        }\r
+                        if (name.equals("foam3")) {\r
+                            water.setFoamTexture((Texture2D) assetManager.loadTexture("Common/MatDefs/Water/Textures/foam3.jpg"));\r
+                        }\r
+                    }\r
+                }\r
+            }, "foam1", "foam2", "foam3");\r
+            inputManager.addMapping("foam1", new KeyTrigger(keyInput.KEY_1));\r
+            inputManager.addMapping("foam2", new KeyTrigger(keyInput.KEY_2));\r
+            inputManager.addMapping("foam3", new KeyTrigger(keyInput.KEY_3));\r
+//            createBox();\r
+          //  createFire();\r
+        }\r
+        Geometry box;\r
+\r
+        private void createBox() {\r
+            //creating a transluscent box\r
+            box = new Geometry("box", new Box(new Vector3f(0, 0, 0), 50, 50, 50));\r
+            Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");\r
+            mat.setColor("Color", new ColorRGBA(1.0f, 0, 0, 0.3f));\r
+            mat.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);\r
+            //mat.getAdditionalRenderState().setDepthWrite(false);\r
+            //mat.getAdditionalRenderState().setDepthTest(false);\r
+            box.setMaterial(mat);\r
+            box.setQueueBucket(Bucket.Translucent);\r
+\r
+\r
+            //creating a post view port\r
+//            ViewPort post=renderManager.createPostView("transpPost", cam);\r
+//            post.setClearFlags(false, true, true);\r
+\r
+\r
+            box.setLocalTranslation(-600, 0, 300);\r
+\r
+            //attaching the box to the post viewport\r
+            //Don't forget to updateGeometricState() the box in the simpleUpdate\r
+            //  post.attachScene(box);\r
+\r
+            rootNode.attachChild(box);\r
+        }\r
+\r
+        private void createFire() {\r
+            /** Uses Texture from jme3-test-data library! */\r
+            ParticleEmitter fire = new ParticleEmitter("Emitter", ParticleMesh.Type.Triangle, 30);\r
+            Material mat_red = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");\r
+            mat_red.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));\r
+\r
+            fire.setMaterial(mat_red);\r
+            fire.setImagesX(2);\r
+            fire.setImagesY(2); // 2x2 texture animation\r
+            fire.setEndColor(new ColorRGBA(1f, 0f, 0f, 1f));   // red\r
+            fire.setStartColor(new ColorRGBA(1f, 1f, 0f, 0.5f)); // yellow\r
+            fire.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 2, 0));\r
+            fire.setStartSize(10f);\r
+            fire.setEndSize(1f);\r
+            fire.setGravity(0, 0, 0);\r
+            fire.setLowLife(0.5f);\r
+            fire.setHighLife(1.5f);\r
+            fire.getParticleInfluencer().setVelocityVariation(0.3f);\r
+            fire.setLocalTranslation(-350, 40, 430);\r
+\r
+            fire.setQueueBucket(Bucket.Transparent);\r
+            rootNode.attachChild(fire);\r
+        }\r
+\r
+        private void createTerrain(Node rootNode) {\r
+            matRock = new Material(assetManager, "Common/MatDefs/Terrain/TerrainLighting.j3md");\r
+            matRock.setBoolean("useTriPlanarMapping", false);\r
+            matRock.setBoolean("WardIso", true);\r
+            matRock.setTexture("AlphaMap", assetManager.loadTexture("Textures/Terrain/splat/alphamap.png"));\r
+            Texture heightMapImage = assetManager.loadTexture("Textures/Terrain/splat/mountains512.png");\r
+            Texture grass = assetManager.loadTexture("Textures/Terrain/splat/grass.jpg");\r
+            grass.setWrap(WrapMode.Repeat);\r
+            matRock.setTexture("DiffuseMap", grass);\r
+            matRock.setFloat("DiffuseMap_0_scale", 64);\r
+            Texture dirt = assetManager.loadTexture("Textures/Terrain/splat/dirt.jpg");\r
+            dirt.setWrap(WrapMode.Repeat);\r
+            matRock.setTexture("DiffuseMap_1", dirt);\r
+            matRock.setFloat("DiffuseMap_1_scale", 16);\r
+            Texture rock = assetManager.loadTexture("Textures/Terrain/splat/road.jpg");\r
+            rock.setWrap(WrapMode.Repeat);\r
+            matRock.setTexture("DiffuseMap_2", rock);\r
+            matRock.setFloat("DiffuseMap_2_scale", 128);\r
+            Texture normalMap0 = assetManager.loadTexture("Textures/Terrain/splat/grass_normal.jpg");\r
+            normalMap0.setWrap(WrapMode.Repeat);\r
+            Texture normalMap1 = assetManager.loadTexture("Textures/Terrain/splat/dirt_normal.png");\r
+            normalMap1.setWrap(WrapMode.Repeat);\r
+            Texture normalMap2 = assetManager.loadTexture("Textures/Terrain/splat/road_normal.png");\r
+            normalMap2.setWrap(WrapMode.Repeat);\r
+            matRock.setTexture("NormalMap", normalMap0);\r
+            matRock.setTexture("NormalMap_1", normalMap2);\r
+            matRock.setTexture("NormalMap_2", normalMap2);\r
+\r
+            AbstractHeightMap heightmap = null;\r
+            try {\r
+                heightmap = new ImageBasedHeightMap(heightMapImage.getImage(), 0.25f);\r
+                heightmap.load();\r
+            } catch (Exception e) {\r
+                e.printStackTrace();\r
+            }\r
+            terrain = new TerrainQuad("terrain", 65, 513, heightmap.getHeightMap());\r
+            List<Camera> cameras = new ArrayList<Camera>();\r
+            cameras.add(getCamera());\r
+            terrain.setMaterial(matRock);\r
+            terrain.setLocalScale(new Vector3f(5, 5, 5));\r
+            terrain.setLocalTranslation(new Vector3f(0, -30, 0));\r
+            terrain.setLocked(false); // unlock it so we can edit the height\r
+\r
+            terrain.setShadowMode(ShadowMode.Receive);\r
+            rootNode.attachChild(terrain);\r
+\r
+        }\r
+        //This part is to emulate tides, slightly varrying the height of the water plane\r
+        private float time = 0.0f;\r
+        private float waterHeight = 0.0f;\r
+        private float initialWaterHeight = 0.8f;\r
+    private boolean uw=false;\r
+        @Override\r
+        public void simpleUpdate(float tpf) {\r
+            super.simpleUpdate(tpf);\r
+            //     box.updateGeometricState();\r
+            time += tpf;\r
+            waterHeight = (float) Math.cos(((time * 0.6f) % FastMath.TWO_PI)) * 1.5f;\r
+            water.setWaterHeight(initialWaterHeight + waterHeight);\r
+            if(water.isUnderWater() && !uw){\r
+               \r
+                waves.setDryFilter(new LowPassFilter(0.5f, 0.1f));\r
+                uw=true;\r
+            }\r
+            if(!water.isUnderWater() && uw){\r
+                uw=false;\r
+                 //waves.setReverbEnabled(false);\r
+                 waves.setDryFilter(new LowPassFilter(1, 1f));\r
+                 //waves.setDryFilter(new LowPassFilter(1,1f));\r
+                 \r
+            }     \r
+        }\r
+    }\r
+       \r
+       \r
+       \r
+}\r
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/utils/JmeUtil.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/utils/JmeUtil.java
new file mode 100644 (file)
index 0000000..e680ffc
--- /dev/null
@@ -0,0 +1,89 @@
+package org.simantics.g3d.jme.utils;\r
+\r
+import java.util.Collection;\r
+\r
+import javax.vecmath.AxisAngle4d;\r
+import javax.vecmath.Quat4d;\r
+import javax.vecmath.Vector3d;\r
+\r
+import org.simantics.g3d.math.MathTools;\r
+\r
+import com.jme3.app.Application;\r
+import com.jme3.math.Quaternion;\r
+import com.jme3.renderer.RenderManager;\r
+import com.jme3.scene.Node;\r
+import com.jme3.scene.Spatial;\r
+\r
+public class JmeUtil {\r
+       \r
+       public static Node getRoot(Application app) {\r
+               return getRoot(app.getRenderManager());\r
+       }\r
+\r
+       public static Node getRoot(RenderManager manager) {\r
+               return (Node)(manager.getMainView("Default").getScenes().get(0));\r
+       }\r
+       \r
+       public static void updateTransform(Collection<Spatial> props, Vector3d pos, Quat4d q) {\r
+               double position[] = new double[]{pos.x,pos.y,pos.z};\r
+               updateTransform(props, position, q);\r
+       }\r
+       \r
+       public static void updateTransform(Spatial actor, double pos[], Quat4d quat) {\r
+               Quaternion q = new Quaternion((float)quat.x, (float)quat.y,(float)quat.z, (float)quat.w);\r
+               actor.setLocalRotation(q);\r
+               actor.setLocalTranslation((float)pos[0], (float)pos[1], (float)pos[2]);\r
+               \r
+       }\r
+       \r
+       public static void updateTransform(Collection<Spatial> props, double pos[], AxisAngle4d aa) {\r
+               Quat4d q = new Quat4d();\r
+               MathTools.getQuat(aa, q);\r
+               updateTransform(props, pos, q);\r
+       }\r
+       \r
+       public static void updateTransform(Collection<Spatial> props, double pos[], Quat4d quat) {\r
+               Quaternion q = new Quaternion((float)quat.x, (float)quat.y,(float)quat.z, (float)quat.w);\r
+               for (Spatial actor : props) {\r
+                       actor.setLocalRotation(q);\r
+                       actor.setLocalTranslation((float)pos[0], (float)pos[1], (float)pos[2]);\r
+               }\r
+       }\r
+       \r
+       public static void updateTransform(Collection<Spatial> props, Vector3d pos, Quat4d quat, double scale) {\r
+               Quaternion q = new Quaternion((float)quat.x, (float)quat.y,(float)quat.z, (float)quat.w);\r
+               for (Spatial actor : props) {\r
+                       actor.setLocalRotation(q);\r
+                       actor.setLocalTranslation((float)pos.x, (float)pos.y, (float)pos.z);\r
+                       actor.setLocalScale((float)scale);\r
+               }\r
+       }\r
+       \r
+       public static void updateTransform(Collection<Spatial> props, double pos[], Quat4d quat, double scale) {\r
+               Quaternion q = new Quaternion((float)quat.x, (float)quat.y,(float)quat.z, (float)quat.w);\r
+               for (Spatial actor : props) {\r
+                       actor.setLocalRotation(q);\r
+                       actor.setLocalTranslation((float)pos[0], (float)pos[1], (float)pos[2]);\r
+                       actor.setLocalScale((float)scale);\r
+               }\r
+       }\r
+       \r
+       public static void updateTransform(Spatial actor, Vector3d pos, Quat4d quat, double scalex, double scaley,double scalez) {\r
+               Quaternion q = new Quaternion((float)quat.x, (float)quat.y,(float)quat.z, (float)quat.w);\r
+\r
+               actor.setLocalRotation(q);\r
+               actor.setLocalTranslation((float)pos.x, (float)pos.y, (float)pos.z);\r
+               actor.setLocalScale((float)scalex,(float)scaley,(float)scalez);\r
+\r
+       }\r
+       \r
+       public static void updateTransform(Collection<Spatial> props, Vector3d pos, Quat4d quat, double scalex, double scaley,double scalez) {\r
+               Quaternion q = new Quaternion((float)quat.x, (float)quat.y,(float)quat.z, (float)quat.w);\r
+               for (Spatial actor : props) {\r
+                       actor.setLocalRotation(q);\r
+                       actor.setLocalTranslation((float)pos.x, (float)pos.y, (float)pos.z);\r
+                       actor.setLocalScale((float)scalex,(float)scaley,(float)scalez);\r
+               }\r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.opencascade.jme/.classpath b/org.simantics.opencascade.jme/.classpath
new file mode 100644 (file)
index 0000000..8a8f166
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/org.simantics.opencascade.jme/.project b/org.simantics.opencascade.jme/.project
new file mode 100644 (file)
index 0000000..246f046
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.opencascade.jme</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
diff --git a/org.simantics.opencascade.jme/.settings/org.eclipse.jdt.core.prefs b/org.simantics.opencascade.jme/.settings/org.eclipse.jdt.core.prefs
new file mode 100644 (file)
index 0000000..27353b8
--- /dev/null
@@ -0,0 +1,8 @@
+#Mon Aug 13 10:36:56 EEST 2012\r
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6\r
+org.eclipse.jdt.core.compiler.compliance=1.6\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.6\r
diff --git a/org.simantics.opencascade.jme/META-INF/MANIFEST.MF b/org.simantics.opencascade.jme/META-INF/MANIFEST.MF
new file mode 100644 (file)
index 0000000..3756782
--- /dev/null
@@ -0,0 +1,17 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: Jme
+Bundle-SymbolicName: org.simantics.opencascade.jme
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.simantics.opencascade.jme.Activator
+Bundle-Vendor: VTT
+Require-Bundle: org.eclipse.ui,
+ org.eclipse.core.runtime,
+ org.jcae.opencascade;bundle-version="6.5.2",
+ org.simantics.opencascade;bundle-version="1.0.0",
+ com.jme;bundle-version="1.0.0",
+ javax.vecmath;bundle-version="1.5.2",
+ org.simantics.utils.datastructures;bundle-version="1.1.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ActivationPolicy: lazy
+Export-Package: org.simantics.opencascade.jme
diff --git a/org.simantics.opencascade.jme/build.properties b/org.simantics.opencascade.jme/build.properties
new file mode 100644 (file)
index 0000000..41eb6ad
--- /dev/null
@@ -0,0 +1,4 @@
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+               .\r
diff --git a/org.simantics.opencascade.jme/src/org/simantics/opencascade/jme/Activator.java b/org.simantics.opencascade.jme/src/org/simantics/opencascade/jme/Activator.java
new file mode 100644 (file)
index 0000000..aa3471e
--- /dev/null
@@ -0,0 +1,50 @@
+package org.simantics.opencascade.jme;\r
+\r
+import org.eclipse.ui.plugin.AbstractUIPlugin;\r
+import org.osgi.framework.BundleContext;\r
+\r
+/**\r
+ * The activator class controls the plug-in life cycle\r
+ */\r
+public class Activator extends AbstractUIPlugin {\r
+\r
+       // The plug-in ID\r
+       public static final String PLUGIN_ID = "org.simantics.opencascade.jme"; //$NON-NLS-1$\r
+\r
+       // The shared instance\r
+       private static Activator plugin;\r
+       \r
+       /**\r
+        * The constructor\r
+        */\r
+       public Activator() {\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)\r
+        */\r
+       public void start(BundleContext context) throws Exception {\r
+               super.start(context);\r
+               plugin = this;\r
+       }\r
+\r
+       /*\r
+        * (non-Javadoc)\r
+        * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)\r
+        */\r
+       public void stop(BundleContext context) throws Exception {\r
+               plugin = null;\r
+               super.stop(context);\r
+       }\r
+\r
+       /**\r
+        * Returns the shared instance\r
+        *\r
+        * @return the shared instance\r
+        */\r
+       public static Activator getDefault() {\r
+               return plugin;\r
+       }\r
+\r
+}\r
diff --git a/org.simantics.opencascade.jme/src/org/simantics/opencascade/jme/JmeOCCTTool.java b/org.simantics.opencascade.jme/src/org/simantics/opencascade/jme/JmeOCCTTool.java
new file mode 100644 (file)
index 0000000..0184477
--- /dev/null
@@ -0,0 +1,441 @@
+package org.simantics.opencascade.jme;\r
+\r
+import java.nio.FloatBuffer;\r
+import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import javax.vecmath.Matrix4d;\r
+import javax.vecmath.Point3d;\r
+import javax.vecmath.Vector3d;\r
+import javax.vecmath.Vector3f;\r
+\r
+import org.jcae.opencascade.jni.BRepMesh_IncrementalMesh;\r
+import org.jcae.opencascade.jni.BRep_Tool;\r
+import org.jcae.opencascade.jni.GP_Trsf;\r
+import org.jcae.opencascade.jni.Poly_Triangulation;\r
+import org.jcae.opencascade.jni.TopAbs_Orientation;\r
+import org.jcae.opencascade.jni.TopAbs_ShapeEnum;\r
+import org.jcae.opencascade.jni.TopExp_Explorer;\r
+import org.jcae.opencascade.jni.TopLoc_Location;\r
+import org.jcae.opencascade.jni.TopoDS_Face;\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.opencascade.OCCTTool;\r
+import org.simantics.utils.datastructures.MapList;\r
+\r
+import com.jme3.scene.Geometry;\r
+import com.jme3.scene.Mesh;\r
+import com.jme3.scene.Mesh.Mode;\r
+import com.jme3.scene.Node;\r
+import com.jme3.scene.Spatial;\r
+import com.jme3.scene.VertexBuffer.Type;\r
+import com.jme3.scene.mesh.IndexBuffer;\r
+\r
+\r
+\r
+public class JmeOCCTTool {\r
+\r
+       \r
+       public static Spatial vtkOCCShapeToAssembly(TopoDS_Shape shape) {\r
+               double deflection = 0.001;\r
+\r
+               if (deflection <= 0.0) {\r
+                       deflection = 0.0005;\r
+                       System.out.println("Bad value for deflection. Using: " + deflection);\r
+               }\r
+\r
+               // FIXME : leaks memory!\r
+               //BRepTools.clean(shape);\r
+\r
+               double mass = OCCTTool.getMass(shape);\r
+\r
+               if (mass < 1.0e-12) {\r
+                       System.out.println("Non 3D-shape detected");\r
+                       System.out.println("The cad import features are currently limited to 3D models.");\r
+               }\r
+\r
+               double length = OCCTTool.getBoundingBoxDiagonal(shape);\r
+               deflection *= length; // use relative units\r
+\r
+               BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection);\r
+\r
+               int faceNumber = 0;\r
+               TopExp_Explorer expFace = new TopExp_Explorer();\r
+\r
+               Node node = new Node();\r
+               for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) {\r
+                       TopoDS_Face face = (TopoDS_Face) expFace.current();\r
+                       Mesh partGrid = createPartGrid(face);\r
+                       face.delete();\r
+                       if (partGrid == null)\r
+                               continue;\r
+                       faceNumber++;\r
+                       //gridToAssembly(assemblies, partGrid, stlSurfaceData, stlEdgeData);\r
+                       gridToAssembly(node, partGrid);\r
+                       \r
+               }\r
+               expFace.delete();\r
+               mesh.delete();\r
+\r
+               if (faceNumber == 0) {\r
+                       System.out\r
+                                       .println("Cad import: error: no surface triangulation was generated.");\r
+                       return null;\r
+               }\r
+\r
+               return node;\r
+       }\r
+       \r
+\r
+\r
+       public static void gridToAssembly(Node assemblies, Mesh partGrid) {\r
+               Geometry geom = new Geometry();\r
+               geom.setMesh(partGrid);\r
+               assemblies.attachChild(geom);\r
+           \r
+       }\r
+       \r
+       \r
+       \r
+       public static Mesh createPartGrid ( TopoDS_Face face)\r
+    {\r
+        TopLoc_Location Location = new TopLoc_Location();\r
+        \r
+        Poly_Triangulation triangulation = BRep_Tool.triangulation(face, Location);\r
+\r
+        if(triangulation == null) {\r
+               Location.delete();\r
+               System.out.println("Encountered empty triangulation after face");\r
+               return null;\r
+        }\r
+                \r
+        boolean reverse = face.orientation()==TopAbs_Orientation.REVERSED;\r
+\r
+        int[]triangles = triangulation.triangles();\r
+        double[]nodes = triangulation.nodes();\r
+\r
+        int nofTriangles = triangulation.nbTriangles();\r
+        int nofNodes = triangulation.nbNodes();\r
+        \r
+        triangulation.delete();\r
+\r
+        if(nofTriangles < 1) {\r
+          System.out.println("No triangles for mesh on face");\r
+          Location.delete();\r
+          return null;\r
+        }\r
+\r
+        if(nofNodes < 1) {\r
+            System.out.println("No nodes for mesh on face:");\r
+            Location.delete();\r
+            return null;\r
+        }\r
+        \r
+        Mesh mesh = new Mesh();\r
+      \r
+        int index[] = new int[nofTriangles*3];\r
+        \r
+        for(int i = 0; i < nofTriangles; i++) \r
+        {\r
+          int n0, n1, n2;          \r
+          if (!reverse) {\r
+                 n0 = triangles[3 * i];\r
+                 n1 = triangles[3 * i + 1];\r
+                 n2 = triangles[3 * i + 2];\r
+          } else {\r
+                 n0 = triangles[3 * i + 2];\r
+                 n1 = triangles[3 * i + 1];\r
+                 n2 = triangles[3 * i];\r
+          }\r
+\r
+\r
+          index[i*3] = n0;\r
+          index[i*3+1] = n1;\r
+          index[i*3+2] = n2;\r
+          \r
+        }\r
+       \r
+        \r
+        GP_Trsf transformation = Location.transformation();\r
+        Location.delete();\r
+\r
+        double d_mat[] = new double[16];\r
+        transformation.getValues(d_mat);\r
+        \r
+        Matrix4d mat = new Matrix4d(d_mat);\r
+        \r
+        float vertex[] = new float[nofNodes*3];\r
+        \r
+        for(int i = 0; i < nofNodes; i++) {     \r
+          // FIXME: GP_Trsf.transform(double[]) leaks memory\r
+               \r
+          //double xyz[] = new double[]{nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]};          \r
+          //transformation.transforms(xyz);\r
+          //partPoints.InsertPoint(i, xyz);\r
+               Point3d p = new Point3d(nodes[3 * i], nodes[3 * i + 1], nodes[3 * i + 2]);\r
+               mat.transform(p);\r
+               vertex[3 * i] = (float)p.x;\r
+               vertex[3 * i+1] = (float)p.y;\r
+               vertex[3 * i+2] = (float)p.z;\r
+        }\r
+        \r
+        transformation.delete();\r
+        \r
+        mesh.setBuffer(Type.Position, 3, vertex);\r
+        mesh.setBuffer(Type.Index, 3, index);\r
+        return mesh;\r
+    \r
+    }\r
+       \r
+       \r
+       \r
+       public static Mesh createPartGrid ( List<Double> meshPoints, List<Integer> meshTriangles)\r
+    {\r
+       \r
+                \r
+      \r
+\r
+        \r
+        int nofTriangles = meshTriangles.size() / 3;\r
+        int nofNodes = meshPoints.size() /3;\r
+        \r
+      \r
+        if(nofTriangles < 1) {\r
+          System.out.println("No triangles for mesh on face");\r
+          return null;\r
+        }\r
+\r
+        if(nofNodes < 1) {\r
+            System.out.println("No nodes for mesh on face:");\r
+            return null;\r
+        }\r
+        Mesh mesh = new Mesh();\r
+        //System.out.println("v " + nofNodes + " t " +nofTriangles);\r
+        int index[] = new int[nofTriangles*3];\r
+        \r
+        for(int i = 0; i < nofTriangles; i++) \r
+        {\r
+          int n0, n1, n2;          \r
+          n0 = meshTriangles.get(3 * i); \r
+          n1 = meshTriangles.get(3 * i + 1);\r
+          n2 = meshTriangles.get(3 * i + 2); \r
+\r
+          index[i * 3 ] = n0;\r
+          index[i * 3 + 1] = n1;\r
+          index[i * 3 + 2] = n2;\r
+          \r
+        }\r
+\r
+        float vertex[] = new float[nofNodes*3];\r
+       \r
+        for(int i = 0; i < nofNodes; i++) {     \r
+\r
+               \r
+               vertex[3 * i] = meshPoints.get(3*i).floatValue();\r
+               vertex[3 * i+1] = meshPoints.get(3*i+1).floatValue();\r
+               vertex[3 * i+2] = meshPoints.get(3*i+2).floatValue();\r
+               \r
+        }\r
+        float normal[] = calcNormals(vertex, index);\r
+        \r
+        \r
+        mesh.setBuffer(Type.Position, 3, vertex);\r
+        mesh.setBuffer(Type.Normal, 3, normal);\r
+        mesh.setBuffer(Type.Index, 3, index);\r
+        \r
+        return mesh;\r
+    }\r
+       \r
+       private static float[] calcNormals(float[] fnodes, int[] trias) {\r
+        float nnodes[] = new float[fnodes.length];\r
+        for (int i = 0; i < nnodes.length; i++) nnodes[i] = 0.f;\r
+        Vector3f v1 = new Vector3f();\r
+        Vector3f v2 = new Vector3f();\r
+        Vector3f v3 = new Vector3f();\r
+        Vector3f t1 = new Vector3f();\r
+        Vector3f t2 = new Vector3f();\r
+        Vector3f n = new Vector3f();\r
+        for (int i = 0; i < trias.length; i+=3) {\r
+            v1.x = fnodes[trias[i]*3];\r
+            v1.y = fnodes[trias[i]*3+1];\r
+            v1.z = fnodes[trias[i]*3+2];\r
+            v2.x = fnodes[trias[i+1]*3];\r
+            v2.y = fnodes[trias[i+1]*3+1];\r
+            v2.z = fnodes[trias[i+1]*3+2];\r
+            v3.x = fnodes[trias[i+2]*3];\r
+            v3.y = fnodes[trias[i+2]*3+1];\r
+            v3.z = fnodes[trias[i+2]*3+2];\r
+            t1.sub(v3,v1);\r
+            t2.sub(v2,v1);\r
+            n.cross(t2, t1);\r
+            //n.normalize();\r
+            nnodes[trias[i]*3] += n.x;\r
+            nnodes[trias[i]*3+1] += n.y;\r
+            nnodes[trias[i]*3+2] += n.z;\r
+            nnodes[trias[i+1]*3] += n.x;\r
+            nnodes[trias[i+1]*3+1] += n.y;\r
+            nnodes[trias[i+1]*3+2] += n.z;\r
+            nnodes[trias[i+2]*3] += n.x;\r
+            nnodes[trias[i+2]*3+1] += n.y;\r
+            nnodes[trias[i+2]*3+2] += n.z;\r
+        }\r
+        for (int i = 0; i < nnodes.length; i+=3) {\r
+            n.x = nnodes[i];\r
+            n.y = nnodes[i+1];\r
+            n.z = nnodes[i+2];\r
+            n.normalize();\r
+            nnodes[i] = n.x;\r
+            nnodes[i+1] = n.y;\r
+            nnodes[i+2] = n.z;\r
+        }\r
+        return nnodes;\r
+    }\r
+       \r
+       public static Mesh createEdgeMesh(Mesh triMesh) {\r
+\r
+               // list all edges in the mesh\r
+               MapList<Integer, Integer> triEdgeIndices = new MapList<Integer, Integer>();\r
+               for (int i = 0; i < triMesh.getTriangleCount(); i++) {\r
+                       int[] tri = new int[3];\r
+                       triMesh.getTriangle(i, tri);\r
+\r
+                       if (!triEdgeIndices.contains(tri[0], tri[1])) {\r
+                               triEdgeIndices.add(tri[0], tri[1]);\r
+                       }\r
+                       if (!triEdgeIndices.contains(tri[1], tri[2])) {\r
+                               triEdgeIndices.add(tri[1], tri[2]);\r
+                       }\r
+                       if (!triEdgeIndices.contains(tri[2], tri[0])) {\r
+                               triEdgeIndices.add(tri[2], tri[0]);\r
+                       }        \r
+               }\r
+               // find, which edges are listed only once; those are boundaries of the mesh.\r
+               MapList<Integer, Integer> edgeIndices = new MapList<Integer, Integer>();\r
+               for (int s : triEdgeIndices.getKeys()) {\r
+                       for (int e : triEdgeIndices.getValues(s)) {\r
+                               if (!triEdgeIndices.contains(e, s)) {\r
+                                       edgeIndices.add(s,e);\r
+                                       edgeIndices.add(e,s);\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               // create a new mesh, containing boundary vertices and edges of the original mesh.\r
+               \r
+               // create list of edge vertices in the original mesh\r
+               List<Integer> vertices = new ArrayList<Integer>();\r
+               FloatBuffer data = triMesh.getFloatBuffer(Type.Position);\r
+               for (Integer i : edgeIndices.getKeys()) {\r
+                       List<Integer> edges = edgeIndices.getValues(i);\r
+                       if (!vertices.contains(i))\r
+                               vertices.add(i);\r
+                       if (!vertices.contains(edges.get(0)))\r
+                               vertices.add(edges.get(0));\r
+                       if (!vertices.contains(edges.get(1)))\r
+                               vertices.add(edges.get(1));\r
+\r
+               }\r
+               // create vertices for edge mesh, and map new vertices to orignals.\r
+               float vertex[] = new float[vertices.size() * 3];\r
+               int i2 = 0;\r
+               Map<Integer,Integer> indexMap = new HashMap<Integer, Integer>();\r
+               for (int i : vertices) {\r
+                       vertex[i2*3] = data.get(i*3);\r
+                       vertex[i2*3+1] = data.get(i*3+1);\r
+                       vertex[i2*3+2] = data.get(i*3+2);\r
+                       \r
+                       indexMap.put(i, i2);\r
+                       i2++;\r
+                       \r
+               }\r
+               \r
+               // create line indices for the edge mesh.\r
+               List<Integer> indices = new ArrayList<Integer>();\r
+\r
+               for (int i = 0; i < vertices.size(); i++) {\r
+                       int s = vertices.get(i);\r
+                       List<Integer> edges = edgeIndices.getValues(s);\r
+                       for (int e : edges) {\r
+                               if (edgeIndices.contains(s, e) && indexMap.containsKey(s) && indexMap.containsKey(e)) {\r
+                                       indices.add(indexMap.get(s));\r
+                                       indices.add(indexMap.get(e));\r
+                               }\r
+                       }\r
+                       \r
+               }\r
+               \r
+               int index[] = new int[indices.size()];\r
+               for (int i = 0; i < indices.size(); i++) {\r
+                       index[i] = indices.get(i);\r
+               }\r
+               \r
+               Mesh mesh = new Mesh();\r
+               mesh.setMode(Mode.Lines);\r
+               mesh.setBuffer(Type.Position, 3, vertex);\r
+               mesh.setBuffer(Type.Index, 2, index);\r
+               \r
+               return mesh;\r
+       }\r
+       \r
+       public static Mesh createVertexMesh(Mesh edgeMesh) {\r
+\r
+               MapList<Integer, Integer> edgeIndices = new MapList<Integer, Integer>();\r
+               IndexBuffer indices = edgeMesh.getIndexBuffer();\r
+               for (int i = 0; i < indices.size(); i+=2) {\r
+                       int s = indices.get(i);\r
+                       int e = indices.get(i+1);\r
+\r
+                       if (!edgeIndices.contains(s, e)) {\r
+                               edgeIndices.add(s, e);\r
+                               edgeIndices.add(e, s);\r
+                       }\r
+                                \r
+               }\r
+                               \r
+               List<Integer> vertices = new ArrayList<Integer>();\r
+               float data[] = edgeMesh.getFloatBuffer(Type.Position).array();\r
+               for (Integer i : edgeIndices.getKeys()) {\r
+                       List<Integer> edges = edgeIndices.getValues(i);\r
+                       if (edges.size() != 2)\r
+                               vertices.add(i);\r
+                       else {\r
+                               Point3d t = new Point3d(data[i*3],data[i*3+1],data[i*3+2]);\r
+                               Vector3d v1 = new Vector3d(data[edges.get(0)*3],data[edges.get(0)*3+1],data[edges.get(0)*3+2]);\r
+                               Vector3d v2 = new Vector3d(data[edges.get(1)*3],data[edges.get(1)*3+1],data[edges.get(1)*3+2]);\r
+                               \r
+                               v1.sub(t);\r
+                               v2.sub(t);\r
+                               double angle = Math.PI - v1.angle(v2);\r
+                               if (angle > Math.PI/6)\r
+                                       vertices.add(i);\r
+                       }\r
+               }\r
+               \r
+               float vertex[] = new float[vertices.size() * 3];\r
+               int i2 = 0;\r
+               Map<Integer,Integer> indexMap = new HashMap<Integer, Integer>();\r
+               for (int i : vertices) {\r
+                       vertex[i2*3] = data[i*3];\r
+                       vertex[i2*3+1] = data[i*3+1];\r
+                       vertex[i2*3+2] = data[i*3+2];\r
+                       \r
+                       indexMap.put(i, i2);\r
+                       i2++;\r
+                       \r
+               }\r
+               \r
+               int index[] = new int[vertices.size()];\r
+               for (int i = 0; i < vertices.size(); i++) {\r
+                       index[i] = i;\r
+               }\r
+               \r
+               Mesh mesh = new Mesh();\r
+               mesh.setMode(Mode.Points);\r
+               mesh.setBuffer(Type.Position, 3, vertex);\r
+               mesh.setBuffer(Type.Index, 1, index);\r
+               \r
+               return mesh;\r
+       }\r
+       \r
+}\r
diff --git a/org.simantics.opencascade.jme/src/org/simantics/opencascade/jme/JmeSolidObject.java b/org.simantics.opencascade.jme/src/org/simantics/opencascade/jme/JmeSolidObject.java
new file mode 100644 (file)
index 0000000..620cdde
--- /dev/null
@@ -0,0 +1,291 @@
+package org.simantics.opencascade.jme;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.List;\r
+\r
+import org.eclipse.swt.widgets.Display;\r
+import org.jcae.opencascade.jni.BRepMesh_IncrementalMesh;\r
+import org.jcae.opencascade.jni.TopAbs_ShapeEnum;\r
+import org.jcae.opencascade.jni.TopExp_Explorer;\r
+import org.jcae.opencascade.jni.TopoDS_Face;\r
+import org.jcae.opencascade.jni.TopoDS_Shape;\r
+import org.simantics.opencascade.OCCTTool;\r
+\r
+import com.jme3.app.Application;\r
+import com.jme3.material.Material;\r
+import com.jme3.math.ColorRGBA;\r
+import com.jme3.renderer.RenderManager;\r
+import com.jme3.scene.Geometry;\r
+import com.jme3.scene.Mesh;\r
+import com.jme3.scene.Node;\r
+import com.jme3.scene.Spatial;\r
+\r
+public class JmeSolidObject {\r
+\r
+       \r
+       public static double deflection = 0.001;\r
+       \r
+       public static double featureAngle = 30;\r
+       public static boolean computeNormals = true;\r
+       public static boolean cleanPart = false;\r
+       public static boolean mergePoints = false;\r
+       \r
+       private Application app;\r
+       private TopoDS_Shape shape;\r
+       \r
+       private List<Spatial> actors = new ArrayList<Spatial>(2);\r
+       \r
+       private List<Spatial> solid = new ArrayList<Spatial>(1);\r
+       private List<Spatial> edges =  new ArrayList<Spatial>(1);\r
+       \r
+       public JmeSolidObject(Application app,TopoDS_Shape shape) {\r
+               this.shape = shape;\r
+               this.app = app;\r
+       }\r
+       \r
+       public void visualizeSolid(boolean showEdges, boolean showVertices) {\r
+               visualizeSolid(true, showEdges, showVertices);\r
+       }\r
+       \r
+       \r
+       public void visualizeSolid(boolean showFaces, boolean showEdges, boolean showVertices) {\r
+               clearActorsSWT();\r
+               Mesh data = createSolidMesh(shape);\r
+               if (data == null)\r
+                       return;\r
+               if (showFaces) {\r
+                       solid.add(createActor(data));           \r
+               }\r
+               if (showEdges) {\r
+                       Spatial edge = createEdgesActor(data);\r
+                       edges.add(edge);                        \r
+                       if (showVertices) {\r
+                               actors.add(createVerticesActor(edge));\r
+                       }\r
+               }\r
+               \r
+               actors.addAll(solid);\r
+               actors.addAll(edges);\r
+\r
+               showActorsSWT();\r
+       }\r
+       \r
+       public void visualizeFaces(boolean showEdges, boolean showVertices) {\r
+               clearActorsSWT();\r
+               Collection<Mesh> datas = createFaceMeshes(shape);\r
+               for (Mesh data : datas) {\r
+                       solid.add(createActor(data));\r
+                       \r
+                       if (showEdges) {\r
+                               Spatial edgesActor = createEdgesActor(data); \r
+                               edges.add(edgesActor);\r
+                               if (showVertices) {\r
+                                       actors.add(createVerticesActor(edgesActor));\r
+                               }\r
+                       }\r
+               }\r
+               actors.addAll(solid);\r
+               actors.addAll(edges);\r
+               \r
+               showActorsSWT();\r
+       }\r
+       \r
+       public List<Spatial> getActors() {\r
+               return actors;\r
+       }\r
+       \r
+       public List<Spatial> getSolid() {\r
+               return solid;\r
+       }\r
+       \r
+       public List<Spatial> getEdges() {\r
+               return edges;\r
+       }\r
+       \r
+\r
+       \r
+       public void showActorsSWT() {\r
+               assert (Thread.currentThread() == Display.getDefault().getThread());\r
+               Node root = (Node)(app.getRenderManager().getMainView("Default").getScenes().get(0));\r
+               for (Spatial act : actors) {\r
+                       root.attachChild(act);\r
+               }\r
+       }\r
+       \r
+       public void showActors() {\r
+               Display.getDefault().asyncExec(new Runnable() {\r
+                       \r
+                       @Override\r
+                       public void run() {\r
+                               showActorsSWT();\r
+                       }\r
+               });\r
+       }\r
+       \r
+       public void clearActorsSWT() {\r
+               assert (Thread.currentThread() == Display.getDefault().getThread());\r
+               if (actors.size() == 0)\r
+                       return;\r
+               for (Spatial act : actors) {\r
+                       act.removeFromParent();\r
+               }\r
+               actors.clear();\r
+               solid.clear();\r
+               edges.clear();\r
+       }\r
+       \r
+       private void clearActorsSWT(List<Spatial> actors) {\r
+               assert (Thread.currentThread() == Display.getDefault().getThread());\r
+               if (actors.size() == 0)\r
+                       return;\r
+               for (Spatial act : actors) {\r
+                       act.removeFromParent();\r
+               }\r
+       }\r
+       \r
+       public void clearActors() {\r
+               if (actors.size() == 0)\r
+                       return;\r
+               final List<Spatial> temp = new ArrayList<Spatial>(actors.size());\r
+               temp.addAll(actors);\r
+               actors.clear();\r
+               solid.clear();\r
+               edges.clear();\r
+               Display.getDefault().asyncExec(new Runnable() {\r
+                       \r
+                       @Override\r
+                       public void run() {\r
+                               clearActorsSWT(temp);\r
+                       }\r
+               });\r
+       }\r
+       \r
+       public void dispose() {\r
+               if (shape != null) {\r
+                       shape.delete();\r
+                       shape = null;\r
+               }\r
+               clearActors();\r
+       }\r
+       \r
+       public void delete() {\r
+               if (shape != null) {\r
+                       shape.delete();\r
+                       shape = null;\r
+               }\r
+               clearActorsSWT();\r
+       }\r
+       \r
+       private static double TOLERANCE = 0.01;\r
+       \r
+       public static Mesh createSolidMesh(TopoDS_Shape shape) {\r
+               \r
+               double volume = OCCTTool.getBoundingBoxDiagonal(shape);\r
+               if (volume < TOLERANCE)\r
+                       return null;\r
+               \r
+               BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection*volume);\r
+       \r
+               TopExp_Explorer expFace = new TopExp_Explorer();\r
+               \r
+               List<Double> meshPoints = new ArrayList<Double>();\r
+               List<Integer> meshTriangles = new ArrayList<Integer>();\r
+               for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) {\r
+                       TopoDS_Face face = (TopoDS_Face) expFace.current();\r
+                       OCCTTool.appendToMesh(face, meshPoints, meshTriangles);\r
+                       face.delete();\r
+               }\r
+               if (meshPoints.size() == 0 || meshTriangles.size() == 0)\r
+                       return null;\r
+                       \r
+               Mesh data = JmeOCCTTool.createPartGrid(meshPoints, meshTriangles);\r
+               \r
+               expFace.delete();\r
+               mesh.delete();\r
+               \r
+               return data;\r
+       }\r
+       \r
+       public static Collection<Mesh> createFaceMeshes(TopoDS_Shape shape) {\r
+               \r
+               double volume = OCCTTool.getBoundingBoxDiagonal(shape);\r
+               Collection<Mesh> faces = new ArrayList<Mesh>();\r
+               \r
+               if (volume > TOLERANCE) {\r
+               \r
+                       BRepMesh_IncrementalMesh mesh = new BRepMesh_IncrementalMesh(shape,deflection*volume);\r
+               \r
+                       TopExp_Explorer expFace = new TopExp_Explorer();\r
+                       \r
+                       \r
+                       for (expFace.init(shape, TopAbs_ShapeEnum.FACE); expFace.more(); expFace.next()) {\r
+                               TopoDS_Face face = (TopoDS_Face) expFace.current();\r
+                               Mesh data = JmeOCCTTool.createPartGrid(face);\r
+                               face.delete();\r
+                               faces.add(data);\r
+                       }\r
+                       \r
+                       expFace.delete();\r
+                       mesh.delete();\r
+               }\r
+               \r
+               return faces;\r
+       }\r
+       \r
+       \r
+       \r
+       public Spatial createActor(Mesh partGrid) {\r
+               \r
+               \r
+               Geometry geom = new Geometry();\r
+               \r
+               geom.setMesh(partGrid);\r
+               \r
+               ColorRGBA color = new ColorRGBA(1.0f, 1.0f, 0.0f, 1.0f);\r
+               //Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");\r
+               //mat.setColor("Color", color);\r
+               Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");\r
+               mat.setColor("Diffuse", color);\r
+               mat.setColor("Ambient", color);\r
+               mat.setColor("Specular", new ColorRGBA(1, 1, 1, 1));\r
+               mat.setBoolean("UseMaterialColors", true);\r
+               geom.setMaterial(mat);\r
+               geom.updateModelBound();\r
+               return geom;\r
+\r
+       }\r
+       \r
+       public Spatial createEdgesActor(Mesh partGrid) {\r
+               Mesh edgeMesh = JmeOCCTTool.createEdgeMesh(partGrid);\r
+               edgeMesh.setLineWidth(2.f);\r
+               Geometry geom = new Geometry();\r
+               geom.setMesh(edgeMesh);\r
+               \r
+               Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");\r
+           ColorRGBA color = new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f);\r
+               mat.setColor("Color", color);\r
+               geom.setMaterial(mat);\r
+               geom.updateModelBound();\r
+               return geom;\r
+       }\r
+       \r
+       public Spatial createVerticesActor(Spatial partEdgesActor) {\r
+               Geometry edgeGeom = (Geometry)partEdgesActor;\r
+               Mesh vertexMesh = JmeOCCTTool.createVertexMesh(edgeGeom.getMesh());\r
+               \r
+               Geometry geom = new Geometry();\r
+               geom.setMesh(vertexMesh);\r
+               \r
+               Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Unshaded.j3md");\r
+           ColorRGBA color = new ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f);\r
+               mat.setColor("Color", color);\r
+               geom.setMaterial(mat);\r
+               geom.updateModelBound();\r
+               return geom;\r
+       }\r
+       \r
+       \r
+       \r
+\r
+}\r