--- /dev/null
+<?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
--- /dev/null
+<?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
--- /dev/null
+#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
--- /dev/null
+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
--- /dev/null
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+ .,\\r
+ plugin.xml\r
--- /dev/null
+<?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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+<?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
--- /dev/null
+<?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
--- /dev/null
+#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
--- /dev/null
+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
--- /dev/null
+source.. = src/\r
+output.. = bin/\r
+bin.includes = META-INF/,\\r
+ .\r
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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