]> gerrit.simantics Code Review - simantics/3d.git/blobdiff - org.simantics.g3d.jme/src/org/simantics/g3d/jme/common/AbstractJMENodeMap.java
Alpha-version of jME-bindings for g3d.
[simantics/3d.git] / org.simantics.g3d.jme / src / org / simantics / g3d / jme / common / AbstractJMENodeMap.java
diff --git a/org.simantics.g3d.jme/src/org/simantics/g3d/jme/common/AbstractJMENodeMap.java b/org.simantics.g3d.jme/src/org/simantics/g3d/jme/common/AbstractJMENodeMap.java
new file mode 100644 (file)
index 0000000..162fbb3
--- /dev/null
@@ -0,0 +1,415 @@
+package org.simantics.g3d.jme.common;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.HashMap;\r
+import java.util.HashSet;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Set;\r
+import java.util.Stack;\r
+\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.ReadRequest;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.g3d.ontology.G3D;\r
+import org.simantics.g3d.scenegraph.IG3DNode;\r
+import org.simantics.g3d.scenegraph.RenderListener;\r
+import org.simantics.g3d.scenegraph.base.INode;\r
+import org.simantics.g3d.scenegraph.base.NodeListener;\r
+import org.simantics.g3d.scenegraph.base.ParentNode;\r
+import org.simantics.objmap.graph.IMapping;\r
+import org.simantics.objmap.graph.IMappingListener;\r
+import org.simantics.utils.datastructures.MapList;\r
+import org.simantics.utils.datastructures.MapSet;\r
+import org.simantics.utils.datastructures.Pair;\r
+\r
+import com.jme3.app.Application;\r
+import com.jme3.scene.Spatial;\r
+\r
+public abstract class AbstractJMENodeMap<E extends IG3DNode> implements JMENodeMap, IMappingListener, NodeListener, RenderListener {\r
+\r
+       protected Session session;\r
+       protected IMapping mapping;\r
+       protected Application app;\r
+//     protected InteractiveVtkPanel panel;\r
+       \r
+       protected MapList<E, Spatial> nodeToActor = new MapList<E, Spatial>();\r
+       protected Map<Spatial,E> actorToNode = new HashMap<Spatial, E>();\r
+\r
+       protected ParentNode<E> rootNode;\r
+       \r
+       public AbstractJMENodeMap(Session session, IMapping mapping, Application app, ParentNode<E> rootNode) {\r
+               this.session = session;\r
+               this.mapping = mapping;\r
+               this.rootNode = rootNode;\r
+               this.app = app;\r
+//             this.panel = panel;\r
+//             panel.addListener(this);\r
+               mapping.addMappingListener(this);\r
+               rootNode.addListener(this);\r
+       }\r
+       \r
+       protected abstract void addActor(E node);\r
+       protected abstract void removeActor(E node);\r
+       protected abstract void updateActor(E node,Set<String> ids);\r
+       \r
+       \r
+       public void repaint() {\r
+               \r
+       }\r
+       \r
+       public void populate() {\r
+               for (E node : rootNode.getNodes()) {\r
+                       receiveAdd(node, node.getParentRel(),true);\r
+               }\r
+               repaint();\r
+       }\r
+       \r
+       @Override\r
+       public IG3DNode getNode(Spatial prop) {\r
+               return actorToNode.get(prop);\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public Collection<Spatial> getRenderObjects(IG3DNode node) {\r
+               return nodeToActor.getValues((E)node);\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public ParentNode<IG3DNode> getRootNode() {\r
+               return (ParentNode<IG3DNode>)rootNode;\r
+       }\r
+       \r
+       @Override\r
+       public void commit() {\r
+               session.asyncRequest(new WriteRequest() {\r
+                       \r
+                       @Override\r
+                       public void perform(WriteGraph graph) throws DatabaseException {\r
+                               synchronized(syncMutex) {\r
+                                       graphUpdates = true;\r
+                                       mapping.updateDomain(graph);\r
+                                       graphUpdates = false;\r
+                               }\r
+                       }\r
+               });\r
+       }\r
+       \r
+       @Override\r
+       public boolean isChangeTracking() {\r
+               return changeTracking;\r
+       }\r
+       \r
+       @Override\r
+       public void setChangeTracking(boolean enabled) {\r
+               changeTracking = enabled;\r
+       }\r
+       \r
+       private boolean changeTracking = true;\r
+       \r
+       private Object syncMutex = new Object(); \r
+       \r
+\r
+       private List<Pair<E,String>> added = new ArrayList<Pair<E,String>>();\r
+       private List<Pair<E,String>> removed = new ArrayList<Pair<E,String>>();\r
+       //private List<Pair<E,String>> updated = new ArrayList<Pair<E,String>>();\r
+       private MapSet<E, String> updated = new MapSet<E, String>();//new MapSet.Hash<E, String>();\r
+\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public void updateRenderObjectsFor(IG3DNode node) {\r
+               List<Spatial> toDelete = new ArrayList<Spatial>();\r
+               for (Spatial prop : nodeToActor.getValues((E)node)) {\r
+//                     if (prop.GetVTKId() != 0) {\r
+//                             panel.GetRenderer().RemoveActor(prop);\r
+//                             //prop.Delete();\r
+//                             toDelete.add(prop);\r
+//                     }\r
+                       prop.removeFromParent();\r
+                       actorToNode.remove(prop);\r
+               }\r
+               nodeToActor.remove((E)node);\r
+               Collection<Spatial> coll = getActors((E)node);\r
+               if (coll == null)\r
+                       return;\r
+               for (Spatial prop : coll) {\r
+                       nodeToActor.add((E)node,prop);\r
+                       actorToNode.put(prop, (E)node);\r
+                       toDelete.remove(prop);\r
+               }\r
+               for (Spatial p : toDelete) {\r
+                       //p.Delete();\r
+               }\r
+       }\r
+       \r
+       protected abstract  Collection<Spatial> getActors(E node);\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       private void receiveAdd(E node, String id, boolean db) {\r
+               synchronized (syncMutex) {\r
+                       for (Pair<E, String> n : added) {\r
+                               if (n.first.equals(node))\r
+                                       return;\r
+                       }\r
+                       if (changeTracking) {\r
+                               mapping.rangeModified(node.getParent());\r
+                       }\r
+                       added.add(new Pair<E, String>(node, id));       \r
+               }\r
+               repaint();\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       private void receiveRemove(E node, String id, boolean db) {\r
+               synchronized (syncMutex) {\r
+                       for (Pair<E, String> n : removed) {\r
+                               if (n.first.equals(node))\r
+                                       return;\r
+                       }\r
+                       if (changeTracking && !db)\r
+                               mapping.rangeModified(node.getParent());\r
+                       removed.add(new Pair<E, String>(node, id));\r
+               }\r
+               repaint();\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       private void receiveUpdate(E node, String id, boolean db) {\r
+               synchronized (syncMutex) {\r
+//                     for (Pair<E, String> n : updated) {\r
+//                             if (n.first.equals(node))\r
+//                                     return;\r
+//                     }\r
+                       if (changeTracking && !db)\r
+                               mapping.rangeModified(node);\r
+                       //updated.add(new Pair<E, String>(node, id));\r
+                       updated.add(node, id);\r
+               }\r
+               repaint();\r
+       }\r
+       \r
+       private boolean graphUpdates = false;\r
+       private Set<Object> graphModified = new HashSet<Object>();\r
+       \r
+       @Override\r
+       public void domainModified() {\r
+               if (graphUpdates)\r
+                       return;\r
+               //System.out.println("domainModified");\r
+               session.asyncRequest(new ReadRequest() {\r
+                       \r
+                       @SuppressWarnings("unchecked")\r
+                       @Override\r
+                       public void run(ReadGraph graph) throws DatabaseException {\r
+                               graphUpdates = true;\r
+                               for (Object domainObject : mapping.getDomainModified()) {\r
+                                       Object rangeObject = mapping.get(domainObject);\r
+                                       if (rangeObject != null)\r
+                                               graphModified.add(rangeObject);\r
+                               }\r
+                               mapping.updateRange(graph);\r
+                               graphModified.clear();\r
+                               graphUpdates = false;\r
+                               if (mapping.isRangeModified())\r
+                                       commit();\r
+                       }\r
+               });\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void rangeModified() {\r
+               //System.out.println("rangeModified");\r
+\r
+       }\r
+       \r
+       @Override\r
+       public void postRender() {\r
+               \r
+       }\r
+       \r
+       List<Pair<E, String>> rem = new ArrayList<Pair<E,String>>();\r
+       List<Pair<E, String>> add = new ArrayList<Pair<E,String>>();\r
+       MapSet<E, String> mod = new MapSet<E, String>();//new MapSet.Hash<E, String>();\r
+       Set<E> propagation = new HashSet<E>();\r
+       Stack<E> stack = new Stack<E>();\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public synchronized void preRender() {\r
+               rem.clear();\r
+               add.clear();\r
+               mod.clear();\r
+               propagation.clear();\r
+               \r
+               synchronized (syncMutex) {\r
+                       rem.addAll(removed);\r
+                       add.addAll(added);\r
+                       //mod.addAll(updated);\r
+                       for (E e : updated.getKeys()) {\r
+                               for (String s : updated.getValues(e))\r
+                                       mod.add(e, s);\r
+                       }\r
+                       \r
+                       removed.clear();\r
+                       added.clear();\r
+                       updated.clear();\r
+               }\r
+               \r
+               for (Pair<E, String> n : rem) {\r
+                       stopListening(n.first);\r
+                       removeActor(n.first);\r
+               \r
+               }\r
+               \r
+               for (Pair<E, String> n : add) {\r
+                       addActor(n.first);\r
+                       listen(n.first);\r
+               }\r
+               \r
+               for (E e : mod.getKeys()) {\r
+                       Set<String> ids = mod.getValues(e);\r
+                       if (ids.contains(G3D.URIs.hasPosition) || ids.contains(G3D.URIs.hasOrientation)) {\r
+                               if (!propagation.contains(e))\r
+                                       propagation.add(e);\r
+                       }\r
+               }\r
+               \r
+               if (propagation.size() > 0) {\r
+                       stack.clear();\r
+                       stack.addAll(propagation);\r
+                       propagation.clear();\r
+                       while (!stack.isEmpty()) {\r
+                               E node = stack.pop();\r
+                               if (propagation.contains(node))\r
+                                       continue;\r
+                               propagation.add(node);\r
+                               for (NodeListener l : node.getListeners()) {\r
+                                       if (l == this) {\r
+                                               //changeTracking = false;\r
+                                               //l.propertyChanged(node, G3D.URIs.hasPosition);\r
+                                               //changeTracking = true;\r
+                                       } else {\r
+                                               l.propertyChanged(node, G3D.URIs.hasPosition);\r
+                                       }\r
+                               }\r
+                               if (node instanceof ParentNode) {\r
+                                       stack.addAll(((ParentNode<E>)node).getNodes());\r
+                               }\r
+                       }\r
+               }\r
+               \r
+               for (E e : mod.getKeys()) {\r
+                       Set<String> ids = mod.getValues(e);\r
+                       updateActor(e,ids);\r
+               }\r
+               \r
+               for (Pair<E, String> n : rem) {\r
+                       for (NodeListener l : nodeListeners)\r
+                               l.nodeRemoved(null, n.first, n.second);\r
+               }\r
+               for (Pair<E, String> n : add) {\r
+                       for (NodeListener l : nodeListeners)\r
+                               l.nodeAdded(n.first.getParent(), n.first, n.second);\r
+               }\r
+//             for (Pair<E, String> n : mod) {\r
+//                     for (NodeListener l : nodeListeners)\r
+//                             l.propertyChanged(n.first, n.second);\r
+//             }\r
+               for (E e : mod.getKeys()) {\r
+                       for (NodeListener l : nodeListeners)\r
+                               for (String s : mod.getValues(e))\r
+                                       l.propertyChanged(e, s);\r
+               }\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       private void listen(INode node) {\r
+               node.addListener(this);\r
+               if (node instanceof ParentNode<?>) {\r
+                       ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
+                       for (INode n : parentNode.getNodes())\r
+                               listen(n);\r
+               }\r
+       }\r
+       \r
+       private void stopListening(INode node) {\r
+               node.removeListener(this);\r
+               if (node instanceof ParentNode<?>) {\r
+                       @SuppressWarnings("unchecked")\r
+                       ParentNode<INode> parentNode = (ParentNode<INode>)node;\r
+                       for (INode n : parentNode.getNodes())\r
+                               stopListening(n);\r
+               }\r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public void propertyChanged(INode node, String id) {\r
+               //receiveUpdate((E)node, id, graphUpdates);\r
+               receiveUpdate((E)node, id, graphModified.contains(node));\r
+               \r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public <T extends INode> void nodeAdded(ParentNode<T> node, INode child,\r
+                       String rel) {\r
+               //receiveAdd((E)child, rel ,graphUpdates);\r
+               receiveAdd((E)child, rel ,graphModified.contains(node));\r
+               \r
+       }\r
+       \r
+       @SuppressWarnings("unchecked")\r
+       @Override\r
+       public <T extends INode> void nodeRemoved(ParentNode<T> node, INode child,\r
+                       String rel) {\r
+               //receiveRemove((E)child, rel, graphUpdates);\r
+               receiveRemove((E)child, rel, graphModified.contains(node));\r
+       }\r
+       \r
+       @Override\r
+       public void delete() {\r
+               changeTracking = false;\r
+               //panel.removeListener(this);\r
+               mapping.removeMappingListener(this);\r
+\r
+               List<E> nodes = new ArrayList<E>(nodeToActor.getKeySize());\r
+               nodes.addAll(nodeToActor.getKeys());\r
+               for (E node : nodes) {\r
+                       node.removeListener(this);\r
+                       removeActor(node);\r
+                       node.cleanup();\r
+               }\r
+               for (Spatial prop : actorToNode.keySet()) {\r
+                       prop.removeFromParent();\r
+                       //if (prop.GetVTKId() != 0) \r
+                       //      prop.Delete();\r
+               }\r
+               actorToNode.clear();\r
+               nodeToActor.clear();\r
+               \r
+       }\r
+       \r
+       \r
+       private List<NodeListener> nodeListeners = new ArrayList<NodeListener>();\r
+       @Override\r
+       public void addListener(NodeListener listener) {\r
+               nodeListeners.add(listener);\r
+               \r
+       }\r
+       \r
+       @Override\r
+       public void removeListener(NodeListener listener) {\r
+               nodeListeners.remove(listener);\r
+               \r
+       }\r
+\r
+}\r